In pyplot, you can change the order of different graphs using the zorder option or by changing the order of the plot() commands. However, when you add an alternative axis via ax2 = twinx(), the new axis will always overlay the old axis (as described in the documentation).
Is it possible to change the order of the axis to move the alternative (twinned) y-axis to background?
In the example below, I would like to display the blue line on top of the histogram:
import numpy as np
import matplotlib.pyplot as plt
import random
# Data
x = np.arange(-3.0, 3.01, 0.1)
y = np.power(x,2)
y2 = 1/np.sqrt(2*np.pi) * np.exp(-y/2)
data = [random.gauss(0.0, 1.0) for i in range(1000)]
# Plot figure
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax2.hist(data, bins=40, normed=True, color='g',zorder=0)
ax2.plot(x, y2, color='r', linewidth=2, zorder=2)
ax1.plot(x, y, color='b', linewidth=2, zorder=5)
ax1.set_ylabel("Parabola")
ax2.set_ylabel("Normal distribution")
ax1.yaxis.label.set_color('b')
ax2.yaxis.label.set_color('r')
plt.show()
Edit: For some reason, I am unable to upload the image generated by this code. I will try again later.
You can set the zorder of an axes, ax.set_zorder(). One would then need to remove the background of that axes, such that the axes below is still visible.
ax2 = ax1.twinx()
ax1.set_zorder(10)
ax1.patch.set_visible(False)
Related
The objective is to plot a scatter plot and create secondary y-axis. Here, the secondary y-axis is just scaled copy of the original scatter plot.
Assume the scaling can be calculated
y2=y1/2.5
where, y1 and y2 is the y axis from the scatter plot,and scaled copy of the original scatter plot, respectively.
This can be visualized as below.
However, using the code below,
import numpy as np
import matplotlib.pyplot as plt
x, y = np.random.random((2,50))
fig, ax1 = plt.subplots()
ax1.scatter(x, y*10, c='b')
ax2 = ax1.twinx()
y2=y/2.5
ax2.plot(1, 1, 'w-')
ax1.set_xlabel('X1_z')
ax1.set_ylabel('x1_y', color='g')
ax2.set_ylabel('x2_y', color='r')
which produced
There are three issues
The secondary y-axis is not scaled properly
As expected but not intended the existence multiple horizontal line root from the secondary y-axis
Is there a possible way to create the scaled y-axis without the need of the line ax2.plot(1, 1, 'w-')
May I know how to handle this?
As suggested in the comment, using secondary_yaxis
x, y = np.random.random((2,50))
fig, ax = plt.subplots()
ax.scatter(x, y*10, c='b')
ax.set_xlabel('X1_z')
ax.set_ylabel('x1_y')
ax.set_title('Adding secondary y-axis')
def a2b(y):
return y/2.5
def b2a(y):
return 2.5*y
secax = ax.secondary_yaxis('right', functions=(a2b,b2a))
secax.set_ylabel('x2_y')
plt.show()
Produced
I have some datasets that I'm visualizing in a scatter plot. I have a bunch of mean values, and a global mean. What I'm after, but cant really achieve,is to have a scatter plot that is centered in the plot, while also placing the origin at the global mean.
This is the code that defines the layout of the plot:
plt.figure(1)
plt.suptitle('Example')
plt.xlabel('x (pixels)')
plt.ylabel('y (pixels)')
ax = plt.gca()
ax.spines['left'].set_position('center')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('center')
ax.spines['top'].set_color('none')
ax.scatter(x_data, y_data, color=color, alpha=0.08, label=csv_file_name)
ax.plot(global_mean[0], global_mean[1], color='green',
marker='x', label='Global mean')
This produces the following plot (the ax.scatter() is called multiple times for each dataset, but it's not in the code above):
I've tried playing around with the ax.set_position() parameters but nothing have worked well so far. Is there a way to do what I'm after with matplotlib, or do I need to use some other plot library?
You can use the ax.spines() method to move them around.
import numpy as np
import random
import matplotlib.pyplot as plt
#generate some random data
x = np.linspace(1,2, 100)
y = [random.random() for _ in range(100)]
fig = plt.figure(figsize=(10,5))
# original plot
ax = fig.add_subplot(1,2,1)
ax.scatter(x, y)
# same plot, but with the spines moved
ax2 = fig.add_subplot(1,2,2)
ax2.scatter(x, y)
# move the left spine (y axis) to the right
ax2.spines['left'].set_position(('axes', 0.5))
# move the bottom spine (x axis) up
ax2.spines['bottom'].set_position(('axes', 0.5))
# turn off the right and top spines
ax2.spines['right'].set_visible(False)
ax2.spines['top'].set_visible(False)
plt.show()
I was trying to make a graph with two secondary vertical axis (y-axis), with python matplotlib.
I was using twinx() method, where one of the two new axis is with the default behavior (labels on the right)
and the other with labels on the left, like the example of tan(x) on the figure bellow (created in an specific software).
Is there an easy way to do that? I'm not restricted to use the twinx() method, if there is another way
Here is a way to add two secondary y-axis, one towards the inside:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(.5, 10, 1000)
y1 = np.cos(x)
y2 = np.sin(2 * x)
y3 = np.clip(np.tan(x * .6), -75, 75)
fig, ax1 = plt.subplots()
color = 'dodgerblue'
ax1.set_ylabel('$cos(x)$', color=color)
ax1.plot(x, y1, color=color)
ax1.tick_params(axis='y', labelcolor=color)
ax2 = ax1.twinx()
color = 'limegreen'
ax2.set_ylabel('$sin(2 x)$', color=color)
ax2.plot(x, y2, color=color)
ax2.tick_params(axis="y", labelcolor=color)
ax3 = ax1.twinx()
color = 'crimson'
ax3.set_ylabel('$tan(.6 x)$', color=color, labelpad=-40)
ax3.plot(x, y3, color=color)
ax3.tick_params(axis="y", labelcolor=color, direction="in", pad=-5)
plt.setp(ax3.get_yticklabels(), ha="right")
ax1.set_xlim(0, 12)
fig.tight_layout()
plt.show()
I'm trying to create a plot with two Y axes (left and right) for the same data, that is, one is a scaled version of the other. I would like also to preserve the tick positions and grid positions, so the grid will match the ticks at both sides.
I'm trying to do this by plotting twice the same data, one as-is and the other scaled, but they are not coincident.
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(17, 27, 0.1)
y1 = 0.05 * x + 100
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(x, y1, 'g-')
ax2.plot(x, y1/max(y1), 'g-')
ax1.set_xlabel('X data')
ax1.set_ylabel('Y data', color='g')
ax2.set_ylabel('Y data normalized', color='b')
plt.grid()
plt.show()
Any help will be appreciated.
Not sure if you can achieve this without getting ugly-looking numbers on your normalized axis. But if that doesn't bother you, try adding this to your code:
ax2.set_ylim([ax1.get_ylim()[0]/max(y1),ax1.get_ylim()[1]/max(y1)])
ax2.set_yticks(ax1.get_yticks()/max(y1))
Probably not the most elegant solution, but it scales your axis limits and tick positions similarly to what you do with the data itself so the grid matches both axes.
I'd like to plot a series with x and y error bars, then plot a second series with x and y error bars on a second y axis all on the same subplot. Can this be done with matplotlib?
import matplotlib.pyplot as plt
plt.figure()
ax1 = plt.errorbar(voltage, dP, xerr=voltageU, yerr=dPU)
ax2 = plt.errorbar(voltage, current, xerr=voltageU, yerr=currentU)
plt.show()
Basically, I'd like to put ax2 on a second axis and have the scale on the right side.
Thanks!
twinx() is your friend for adding a secondary y-axis, e.g.:
import matplotlib.pyplot as pl
import numpy as np
pl.figure()
ax1 = pl.gca()
ax1.errorbar(np.arange(10), np.arange(10), xerr=np.random.random(10), yerr=np.random.random(10), color='g')
ax2 = ax1.twinx()
ax2.errorbar(np.arange(10), np.arange(10)+5, xerr=np.random.random(10), yerr=np.random.random(10), color='r')
There is not a lot of documentation except for:
matplotlib.pyplot.twinx(ax=None)
Make a second axes that shares the x-axis. The new axes will overlay ax (or the current axes if ax is None). The ticks for ax2 will be placed on the right, and the ax2 instance is returned.
I was struggling to share the x-axis, but thank you #Bart you saved me!
The simple solution is use twiny instead of twinx
ax1.errorbar(layers, scores_means[str(epoch)][h,:],np.array(scores_stds[str(epoch)][h,:]))
# Make the y-axis label, ticks and tick labels match the line color.
ax1.set_xlabel('depth', color='b')
ax1.tick_params('x', colors='b')
ax2 = ax1.twiny()
ax2.errorbar(hidden_dim, scores_means[str(epoch)][:,l], np.array(scores_stds[str(epoch)][:,l]))
ax2.set_xlabel('width', color='r')
ax2.tick_params('x', colors='r')
fig.tight_layout()
plt.show()