The answer to this question suggests that I play around with the set_ylim/get_ylim in order to align two twin axes. However, this does not seem to be working out for me.
Code snippet:
fig, ax1 = plt.subplots()
yLim = [minY, maxY]
xLim = [0, 0.01]
for x in analysisNumbers:
ax1.plot(getData(x), vCoords, **getStyle(x))
ax1.set_yticks(vCoords)
ax1.grid(True, which='major')
ax2 = ax1.twinx()
ax2.set_yticks(ax1.get_yticks())
ax2.set_ylim(ax1.get_ylim())
ax2.set_ylim(ax1.get_ylim())
plt.xlim(xLim[0], xLim[1])
plt.ylim(yLim[0], yLim[1])
plt.minorticks_on()
plt.show()
Graph output (open image in a new window):
The twin axes should be the same, but they are not. Their labels are the same, but their alignment is not (see that the zeroes do not line up). What's wrong?
As tcaswell points out in a comment, plt.ylim() only affects one of the axes. If you replace these lines:
ax2.set_ylim(ax1.get_ylim())
ax2.set_ylim(ax1.get_ylim())
plt.xlim(xLim[0], xLim[1])
plt.ylim(yLim[0], yLim[1])
with this:
ax1.set_ylim(yLim[0], yLim[1])
ax2.set_ylim(ax1.get_ylim())
plt.xlim(xLim[0], xLim[1])
It'll work as I'm guessing you intended.
Related
I am using Python 3.9 on MacOS. Shortly, I have to make a plot with 4 subplots, and they share axis. The code looks like this:
#take some data
gs = gridspec.GridSpec(2, 2, height_ratios = [3, 1])
ax0 = plt.subplot(gs[0])
#plot data, make legend, etc.
ax2 = plt.subplot(gs[2], sharex = ax0)
#plot data, make legend, etc.
#take more data
ax1 = plt.subplot(gs[1], sharey = ax0)
#plot data, make legend, etc.
ax3 = plt.subplot(gs[3], sharex = ax1, sharey = ax2)
#plot data, make legend, etc.
plt.show()
As you can see, some plots share an axis with each other. The problem is that on the x-axis everything is fine, while it is not on the y-axis (see picture). Getting to the point: how can I remove the numbers on the vertical axis of the right plot but not on the left? I've seen many posts in which the problem was solved with things like
ax.set_yticklabels([])
but that removes the numbers from the left plot as well.
Try this:
ax1.tick_params('y', labelleft=False)
I do not really understand why this code is not working
fig, ax = plt.subplots()
ax.plot(Vg_vec, sigma_i)
ax.set_xlabel('$V_\mathrm{g}$ ($\mathrm{V}}$)')
ax.set_ylabel('$\sigma_\mathrm{i}$ ($\mathrm{C/m^2}$)')
peaks, _ = find_peaks(sigma_i, height=0.006415)
plt.axvline(Vg_vec[peaks], color='red')
ax2 = ax.twiny()
ax2.set_xticks(Vg_vec[peaks])
ax2.tick_params(axis='x', colors='red')
My result
There should be a red tick in the top x axis.
Thanks
the issue with your code is twofold:
By using twiny instead of secondary_axis, the upper x-axis will be different to the bottom one, and I assume you want them to be the same. That's extra work to fix, so I used secondary_axis in my example.
This is something I don't know why it happens, but it has happened to me before. When supplying the tick values, the first one is always "ignored", so you have to supply two or more values. I used 0, but you can use anything.
Here's my code:
fig, ax = plt.subplots()
ax.plot(Vg_vec, sigma_i)
ax.set_xlabel('$V_\mathrm{g}$ ($\mathrm{V}}$)')
ax.set_ylabel('$\sigma_\mathrm{i}$ ($\mathrm{C/m^2}$)')
peaks, _ = find_peaks(sigma_i, height=None)
plt.axvline(Vg_vec[peaks], color='red')
ax2 = ax.secondary_xaxis('top')
ax2.tick_params(axis='x', color='red')
ax2.set_xticks([0, *Vg_vec[peaks]], minor=False)
And the resulting plot:
I am using seaborn and twinx to plot two lines in one figure. However, as replicated below, the blue line is below the horizontal line because it is overlayed by the second plot:
import seaborn as sns
import matplotlib.pyplot as plt
l1 = sns.lineplot(x=[0,1,2],y=[1,2,3],color="#0188A8")
ax1 = plt.gca()
ax2 = ax1.twinx()
l2 = sns.lineplot(x=[0,1,2], y=[100,200,300],color="#D42227")
plt.xlabel('Number of Selves',fontsize=13)
ax1.set_xticks([0,1,2])
ax1.set_yticks([0,1,2])
ax2.set_yticks([100,200,300])
After doing some googling, I found this which was close, but didn't help. Trying out their solution, the axis ticks will get distorted, as both lines are plotted on the second plot:
ax1 = plt.gca()
ax2 = ax1.twinx()
l1 = sns.lineplot(x=[0,1,2],y=[1,2,3],color="#0188A8")
l2 = sns.lineplot(x=[0,1,2], y=[100,200,300],color="#D42227")
plt.xlabel('Number of Selves',fontsize=13)
ax1.set_xticks([0,1,2])
ax1.set_yticks([0,1,2])
ax2.set_yticks([100,200,300])
My question is, how can the blue line be on top of the horizontal grid lines while maintaining the ticks to be at the same position as they are in the first picture?
You cannot easily obtain the desired effect because all the artists of ax2 are drawn above the artists of ax1, regardless of their respective z-order.
The only "good" solution that I can suggest, is, as you had found out, draw both lines on ax2, but you have to use the data transform of ax1 for the first line so that it matches the numbers on the left axis.
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
l1 = sns.lineplot(x=[0,1,2],y=[1,2,3],color="#0188A8", ax=ax2, transform=ax1.transData)
l2 = sns.lineplot(x=[0,1,2], y=[100,200,300],color="#D42227", ax=ax2)
ax1.set_xlabel('Number of Selves',fontsize=13)
ax1.set_xticks([0,1,2])
ax1.set_yticks([0,1,2])
ax2.set_yticks([100,200,300])
ax1.set_ylim(-0.5,3.5)
Note that, because there are actually no data on ax1, you have to manually specify the y-axis limits, it won't autoscale for you.
How do I show a plot with twin axes such that the aspect of the top and right axes are 'equal'. For example, the following code will produce a square plot
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.plot([0,1],[0,1])
But this changes as soon as you use the twinx function.
ax2 = ax.twinx()
ax2.set_ylim([0,2])
ax3 = ax.twiny()
ax3.set_xlim([0,2])
Using set_aspect('equal') on ax2 and ax3 seems to force it the the aspect of ax, but set_aspect(0.5) doesn't seem to change anything either.
Put simply, I would like the plot to be square, the bottom and left axes to run from 0 to 1 and the top and right axes to run from 0 to 2.
Can you set the aspect between two twined axes? I've tried stacking the axes:
ax3 = ax2.twiny()
ax3.set_aspect('equal')
I've also tried using the adjustable keyword in set_aspect:
ax.set_aspect('equal', adjustable:'box-forced')
The closest I can get is:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_aspect('equal', adjustable='box-forced')
ax.plot([0,1],[0,1])
ax2=ax.twinx()
ax3 = ax2.twiny()
ax3.set_aspect(1, adjustable='box-forced')
ax2.set_ylim([0,2])
ax3.set_xlim([0,2])
ax.set_xlim([0,1])
ax.set_ylim([0,1])
Which produces:
I would like to remove the extra space to the right and left of the plot
It seems overly complicated to use two different twin axes to get two independent set of axes. If the aim is to create one square plot with one axis on each side of the plot, you may use two axes, both at the same position but with different scales. Both can then be set to have equal aspect ratios.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.plot([0,1],[0,1])
ax2 = fig.add_axes(ax.get_position())
ax2.set_facecolor("None")
ax2.set_aspect('equal')
ax2.plot([2,0],[0,2], color="red")
ax2.tick_params(bottom=0, top=1, left=0, right=1,
labelbottom=0, labeltop=1, labelleft=0, labelright=1)
plt.show()
I want to draw a plot with matplotlib with axis on both sides of the plot, similar to this plot (the color is irrelevant to this question):
How can I do this with matplotlib?
Note: contrary to what is shown in the example graph, I want the two axis to be exactly the same, and want to show only one graph. Adding the two axis is only to make reading the graph easier.
You can use tick_params() (this I did in Jupyter notebook):
import matplotlib.pyplot as plt
bar(range(10), range(10))
tick_params(labeltop=True, labelright=True)
Generates this image:
UPD: added a simple example for subplots. You should use tick_params() with axis object.
This code sets to display only top labels for the top subplot and bottom labels for the bottom subplot (with corresponding ticks):
import matplotlib.pyplot as plt
f, axarr = plt.subplots(2)
axarr[0].bar(range(10), range(10))
axarr[0].tick_params(labelbottom=False, labeltop=True, labelleft=False, labelright=False,
bottom=False, top=True, left=False, right=False)
axarr[1].bar(range(10), range(10, 0, -1))
axarr[1].tick_params(labelbottom=True, labeltop=False, labelleft=False, labelright=False,
bottom=True, top=False, left=False, right=False)
Looks like this:
There are a couple of relevant examples in the online documentation:
Two Scales (seems to do exactly what you're asking for)
Dual Fahrenheit and Celsius
I've done this previously using the following:
# Create figure and initial axis
fig, ax0 = plt.subplots()
# Create a duplicate of the original xaxis, giving you an additional axis object
ax1 = ax.twinx()
# Set the limits of the new axis from the original axis limits
ax1.set_ylim(ax0.get_ylim())
This will exactly duplicate the original y-axis.
Eg:
ax = plt.gca()
plt.bar(range(3), range(1, 4))
plt.axhline(1.75, color="gray", ls=":")
twin_ax = ax.twinx()
twin_ax.set_yticks([1.75])
twin_ax.set_ylim(ax.get_ylim())