I am trying to plot several lines which partially overlap and occlude each other. This is what I tried:
# Create the figure
fig = plt.figure(figsize=(7, 4))
ax = plt.subplot(111)
# remove grid
ax.set_xticks([])
ax.set_yticks([])
# define data
X = np.linspace(-2*np.pi, 2*np.pi, 400)
Y1 = np.cos(2*X)
Y2 = X**2/10-0.5
ax.plot(X, Y1, lw=1)
ax.fill_between(X, Y1, -1, facecolor=(1,0,0,1))
ax.plot(X, Y2)
ax.fill_between(X, Y2, -1, facecolor=(1,1,1,1))
plt.show()
which produces
but when the second fill_between goes down to -1, I would like it to also occlude the blue graph. Like so:
Any suggestions are appreciated.
My solution:
# Create the figure
fig = plt.figure(figsize=(7, 4))
ax = plt.subplot(111)
# remove grid
ax.set_xticks([])
ax.set_yticks([])
# define data
X = np.linspace(-2*np.pi, 2*np.pi, 400)
Y1 = np.cos(2*X)
Y2 = X**2/10-0.5
# NEW #########################
for i in range(Y1.size):
if Y1[i] < Y2[i] :
Y1[i] = Y2[i]
###############################
ax.plot(X, Y1, lw=1, color="blue")
ax.fill_between(X, Y1, -1, facecolor=(1,0,0,1))
ax.plot(X, Y2, color="orange")
ax.fill_between(X, Y2, -1, facecolor=(1,1,1,1))
plt.show()
Output:
Basically at any point Y1 is less than Y2 we set the point on Y1 equal to Y2.
I ended up going with #JohanC's suggestion, as it makes it easier to generalize to more graphs. So for example
ax.plot(X, Y1, lw=1)
ax.fill_between(X, Y1, -1, facecolor=(1,0,0,1), zorder=2)
ax.plot(X, Y2)
ax.fill_between(X, Y2, -1, facecolor=(1,1,1,1), zorder=3)
ax.plot(X, Y3, lw=1, zorder=1)
ax.fill_between(X, Y3, -1, facecolor=(0,0,1,1), zorder=1)
ax.plot(X, Y4, lw=1, zorder=0)
ax.fill_between(X, Y4, -1, facecolor=(0,1,0,0.5), zorder=0)
Can plot something like this:
Related
I am trying to fill colours between two-step line plots. I have tried to do the same using fill_between function with step and interpolate parameters. However, I am not getting the output as expected. I am filling the region between two lines after comparing their values. Below is the code. Any help will be appreciated.
fig = plt.figure()
fig.tight_layout()
plt.subplot(2, 2, 1)
p1 = plt.step(df2['datetime'], df2['T1'], color='b', linewidth=3, where = 'post', label ='P1')
p2 = plt.step(df2['datetime'], df2['T3'], color='m', linewidth=3, where = 'post', label ='P2')
p3 = plt.fill_between(df2['datetime'], df2['T1'],df2['T3'], where = df2['T1'] <
df2['T3'],facecolor="blue", color='blue', alpha=0.25, step = 'post',interpolate = True ,label ='A1')
p4 = plt.fill_between(df2['datetime'], df2['T1'],df2['T3'], where = df2['T1'] >
df2['T3'],facecolor="red", color='red', alpha=0.25, step = 'post',interpolate = True, label ='A2')
plt.ylabel("T1", fontsize=12, color='black')
plt.xlabel("Hour", fontsize=12, color='black')
plt.grid(True)
plt.legend(loc='best',fontsize = 10)
plt.xticks(rotation = 90)
plt.subplot(2, 2, 2)
p1 = plt.step(df2['datetime'], df2[‘T2’], color='k', linewidth=3, where = 'post', label ='P1')
p2 = plt.step(df2['datetime'], df2['T3'], color='m', linewidth=3, where = 'post', label ='P2')
p3 = plt.fill_between(df2['datetime'], df2[‘T2’],df2['T3'], where = df2[‘T2’] <
df2['T3'],facecolor="blue", color='blue', alpha=0.25, step = 'post',label ='A1')
p4 = plt.fill_between(df2['datetime'], df2[‘T2’],df2['T3'], where = df2[‘T2’] >
df2['T3'],facecolor="red", color='red', alpha=0.25, step = 'post',label ='A2')
plt.ylabel("T2", fontsize=12, color='black')
plt.xlabel("Hour", fontsize=12, color='black')
plt.grid(True)
plt.legend(loc='best',fontsize = 10)
plt.xticks(rotation = 90)
I am also attaching my output for reference.
Left plot is with step = post and interpolate = True
Right plot is without interpolate.
As you can see filling in not working as expected near cross overs.
Apparently, fill_between between step plots and using a where parameter doesn't fill as expected.
A workaround is to mimic the step function via np.repeat:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(20)
y1 = np.random.rand(20)
y2 = np.random.rand(20)
xx = np.repeat(x, 2)[1:]
yy1 = np.repeat(y1, 2)[:-1]
yy2 = np.repeat(y2, 2)[:-1]
fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, figsize=(18, 4))
for ax in (ax1, ax2, ax3):
ax.step(x, y1, color='r', lw=3, where='post')
ax.step(x, y2, color='b', lw=3, where='post')
ax1.fill_between(x, y1, y2, color='b', alpha=0.3, step='post', where=y1 < y2)
ax1.fill_between(x, y1, y2, color='r', alpha=0.3, step='post', where=y1 > y2)
ax1.set_title('fill_between with step and where')
ax2.fill_between(x, y1, y2, color='b', alpha=0.3, step='post', where=y1 < y2, interpolate=True)
ax2.fill_between(x, y1, y2, color='r', alpha=0.3, step='post', where=y1 > y2, interpolate=True)
ax2.set_title('setting interpolate=True')
ax3.fill_between(xx, yy1, yy2, color='b', alpha=0.3, where=yy1 < yy2)
ax3.fill_between(xx, yy1, yy2, color='r', alpha=0.3, where=yy1 > yy2)
ax3.set_title('mimicking step')
plt.tight_layout()
plt.show()
I want to make the lines of the following graph smooth. I tried to search and it seems that we have to represent the x-axis in terms of a float or some type such as date time. Here since the x-axis are just labels, I could not figure out how I should change my code. Any help is appreciated.
import matplotlib.pyplot as plt
x1 = [">1", ">10",">20"]
y1 = [18,8,3]
y2 = [22,15,10]
y3=[32,17,11]
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.scatter(x1, y1, color='blue', label='Heuristic')
ax1.scatter(x1, y2, color='green', label='SAFE')
ax1.scatter(x1, y3, color='red', label='discovRE')
plt.plot(x1, y2, '.g:')
plt.plot(x1, y1, '.b:')
plt.plot(x1, y3, '.r:')
plt.ylabel('False Positives',fontsize=8)
plt.xlabel('Function instruction sizes',fontsize=8)
plt.legend()
plt.show()
Following is the graph that I get right now.
Maybe you can fit a curve to 'smooth' the curve
import matplotlib.pyplot as plt
x1 = [">1", ">10",">20"]
y1 = [18,8,3]
y2 = [22,15,10]
y3=[32,17,11]
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.scatter(x1, y1, color='blue', label='Heuristic')
ax1.scatter(x1, y2, color='green', label='SAFE')
ax1.scatter(x1, y3, color='red', label='discovRE')
buff_x = np.linspace(0,2,100)
def reg_func(y):
params = np.polyfit(range(len(y)),y,2)
return np.polyval(params,buff_x)
plt.plot(buff_x, reg_func(y2), 'g',linestyle='dotted')
plt.plot(buff_x, reg_func(y1), 'b',linestyle='dotted')
plt.plot(buff_x, reg_func(y3), 'r',linestyle='dotted')
plt.ylabel('False Positives',fontsize=8)
plt.xlabel('Function instruction sizes',fontsize=8)
plt.legend()
plt.show()
as you can see, I use a function reg_func to fit your data, and plot the predicted curves
I want to draw a picture like this one, the top and right axes have different labels and ticks, anyone can help me?
To double both axes you have to use ax1.twinx().twiny().
Here an example:
# Create some mock data
x1 = np.arange(0, 10, 1)
y1 = [random.randint(1,5) for n in x1]
#print(x1,y1)
x2 = np.arange(0, 100, 10)
y2 = [random.randint(10,50) for n in x2]
#print(x2,y2)
fig, ax1 = plt.subplots()
ax1.set_xlabel('x1', color='red')
ax1.set_ylabel('y1', color='red')
ax1.plot(x1, y1, color='red')
ax1.tick_params(axis='both', labelcolor='red')
ax2 = ax1.twinx().twiny() #here is the trick!
ax2.set_xlabel('x2', color='blue')
ax2.set_ylabel('y2', color='blue')
ax2.plot(x2, y2, color='blue')
ax2.tick_params(axis='both', labelcolor='blue') #y2 does not get blue... can't yet figure out why
plt.show()
Here the result:
Since both datasets are completely independent, one would probably not use twin axes here. Instead, just use two different axes.
import numpy as np
import matplotlib.pyplot as plt
# Create some mock data
x1 = np.linspace(0,1,11)
y1 = np.random.rand(11)
x2 = np.linspace(1,0,101)
y2 = np.random.rand(101)*20+20
fig, ax1 = plt.subplots()
ax2 = fig.add_subplot(111, label="second axes")
ax2.set_facecolor("none")
ax1.set_xlabel('x1', color='red')
ax1.set_ylabel('y1', color='red')
ax1.plot(x1, y1, color='red')
ax1.tick_params(colors='red')
ax2.set_xlabel('x2', color='blue')
ax2.set_ylabel('y2', color='blue')
ax2.plot(x2, y2, color='blue')
ax2.xaxis.tick_top()
ax2.xaxis.set_label_position('top')
ax2.yaxis.tick_right()
ax2.yaxis.set_label_position('right')
ax2.tick_params(colors='blue')
for which in ["top", "right"]:
ax2.spines[which].set_color("blue")
ax1.spines[which].set_visible(False)
for which in ["bottom", "left"]:
ax1.spines[which].set_color("red")
ax2.spines[which].set_visible(False)
plt.show()
You should use twinx and twiny functions, take a look at this link
I'm using the function below to plot three lines with two different scales.
def plot2(x1, y1, x2, y2, x3, y3):
fig, ax1 = plt.subplots()
ax1.plot(x1, y1, 'b')
ax1.plot(x2, y2, 'g')
ax2 = ax1.twinx()
ax2.plot(x3, y3, 'r')
fig.tight_layout()
plt.show()
However, ax2 is shadowing ax1 in the plot.
I can't reproduce the problem. By extending the code to a minimal running example:
import matplotlib.pyplot as plt
def plot2(x1, y1, x2, y2, x3, y3):
fig, ax1 = plt.subplots()
ax1.plot(x1, y1, 'b')
ax1.plot(x2, y2, 'g')
ax2 = ax1.twinx()
ax2.plot(x3, y3, 'r')
fig.tight_layout()
plt.show()
x1 = [1,2,3,4,5]
x2 = [1.25,2.25,3.25,4.25,5.25]
x3 = [1.5, 2.5, 3.5, 4.5, 5.5]
y1 = [1,2,3,4,5]
y2 = [6,7,8,9,10]
y3 = [11,12,13,14,15]
plot2(x1,y1,x2,y2,x3,y3)
I get the following result:
png
The tracker in the lower-right corner (highlighted in red) reports y-values relative to the y-axis on the right.
How can I get the tracker to report y-values relative to the y-axis on the left instead?
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(6)
numdata = 100
t = np.linspace(0.05, 0.11, numdata)
y1 = np.cumsum(np.random.random(numdata) - 0.5) * 40000
y2 = np.cumsum(np.random.random(numdata) - 0.5) * 0.002
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax1.plot(t, y1, 'r-', label='y1')
ax2.plot(t, y2, 'g-', label='y2')
ax1.legend()
plt.show()
I know swapping y1 with y2 will make the tracker report y1-values,
but this also places the y1 tickmarks on the right-hand side, which is not what I want to happen.
ax1.plot(t, y2, 'g-', label='y2')
ax2.plot(t, y1, 'r-', label='y1')
Ah, found it: ax.yaxis.set_ticks_position("right").
Instead of trying to "control the tracker", you can swap the location of the y-axes.
ax1.yaxis.set_ticks_position("right")
ax2.yaxis.set_ticks_position("left")
ax1.plot(t, y2, 'g-', label='y1')
ax2.plot(t, y1, 'r-', label='y2')
AFAIK, the tracker always follows ax2 when using twinx.
Please note that if you create an ax3= ax1.twiny() axes after ax1 and ax2, the tracker goes to ax3 and you have again it reporting y1 values.
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(6)
numdata = 100
t = np.linspace(0.05, 0.11, numdata)
y1 = np.cumsum(np.random.random(numdata) - 0.5) * 40000
y2 = np.cumsum(np.random.random(numdata) - 0.5) * 0.002
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax1.plot(t, y1, 'r-', label='y1')
ax2.plot(t, y2, 'g-', label='y2')
ax1.legend()
ax3 = ax1.twiny()
ax3.set_xticks([])
plt.show()