x-ticks disappear when plotting on subplots sharing x-axis [duplicate] - python

This question already has answers here:
matplotlib - No xlabel and xticks for twinx axes in subploted figures
(2 answers)
Closed 5 years ago.
This happens when I try to plot a line and an area on the same subplot. I found the my x-ticks disappear after I call ay=ax.twinx() and plot on ay.
Here's my code that causes this error.
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=[12,12])
data=pd.DataFrame([[1,2,3],[2,3,4],[3,2,4]])
ix = np.unravel_index(0, axes.shape)
ax=axes[ix]
y=pd.DataFrame(data.iloc[:,0]-data.iloc[:,1])
ax2=ax.twinx()
data.plot(ax=ax,color=['navy','red'])
ax2.plot(y.values, linewidth=2.0)
As you can see, the x-ticks disappear.
However, if you continue plotting, you can find the last subplot isn't affected.
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=[12,12])
data=pd.DataFrame([[1,2,3],[2,3,4],[3,2,4]])
ix = np.unravel_index(0, axes.shape)
ax=axes[ix]
y=pd.DataFrame(data.iloc[:,0]-data.iloc[:,1])
ax2=ax.twinx()
data.plot(ax=ax,color=['navy','red'])
ax2.plot(y.values, linewidth=2.0)
ix = np.unravel_index(1, axes.shape)
ax=axes[ix]
y=pd.DataFrame(data.iloc[:,0]-data.iloc[:,1])
ax2=ax.twinx()
data.plot(ax=ax,color=['navy','red'])
ax2.plot(y.values, linewidth=2.0)

There are two options. One is based on the answer to this question: matplotlib - pandas - No xlabel and xticks for twinx axes in subploted figures
which is to reverse the order of plotting. First plot to the two subplots, then create the twin axes for both.
import matplotlib.pyplot as plt
import pandas as pd
fig, axes = plt.subplots(nrows=2, ncols=1)
data=pd.DataFrame([[1,2,3],[2,3,4],[3,2,4]])
ax=axes[0]
y=pd.DataFrame(data.iloc[:,0]-data.iloc[:,1])
data.plot(ax=ax)
ax3=axes[1]
y=pd.DataFrame(data.iloc[:,0]-data.iloc[:,1])
data.plot(ax=ax3)
ax2=ax.twinx()
ax2.plot(y.values)
ax4=ax3.twinx()
ax4.plot(y.values)
plt.show()
Now sometimes the above may not be an option, so the second possible solution would be to set the ticks visible again after the complete plot has been generated.
[t.set_visible(True) for t in ax.get_xticklabels()]
Complete example:
import matplotlib.pyplot as plt
import pandas as pd
fig, axes = plt.subplots(nrows=2, ncols=1)
data=pd.DataFrame([[1,2,3],[2,3,4],[3,2,4]])
ax=axes[0]
y=pd.DataFrame(data.iloc[:,0]-data.iloc[:,1])
ax2=ax.twinx()
data.plot(ax=ax)
ax2.plot(y.values)
ax3=axes[1]
y=pd.DataFrame(data.iloc[:,0]-data.iloc[:,1])
ax4=ax3.twinx()
data.plot(ax=ax3)
ax4.plot(y.values)
[t.set_visible(True) for t in ax.get_xticklabels()]
plt.show()

Related

matplotlib: Tick labels disappeared after set sharex in subplots [duplicate]

This question already has answers here:
Show tick labels when sharing an axis in matplotlib
(3 answers)
Closed 4 years ago.
When use sharex or sharey in subplots, the tick labels would disappeared, how to turn them back?
Here is an example just copied from the official website:
fig, axs = plt.subplots(2, 2, sharex=True, sharey=True)
axs[0, 0].plot(x)
plt.show()
And we will see:
As we can see, the top-right plot doesn't have any tick labels, and others also lack some labels because of the axis was shared.
I think I should use something like plt.setp(ax.get_xticklabels(), visible=True), but it doesn't work.
You can use the tick_params() to design the plot:
f, ax = plt.subplots(2, 2, sharex=True, sharey=True)
for a in f.axes:
a.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=True,
top=False,
labelbottom=True) # labels along the bottom edge are on
plt.show()

How to use twinx and still get square plot

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()

GridSpec on Seaborn Subplots

I currently have 2 subplots using seaborn:
import matplotlib.pyplot as plt
import seaborn.apionly as sns
f, (ax1, ax2) = plt.subplots(2, sharex=True)
sns.distplot(df['Difference'].values, ax=ax1) #array, top subplot
sns.boxplot(df['Difference'].values, ax=ax2, width=.4) #bottom subplot
sns.stripplot([cimin, cimax], color='r', marker='d') #overlay confidence intervals over boxplot
ax1.set_ylabel('Relative Frequency') #label only the top subplot
plt.xlabel('Difference')
plt.show()
Here is the output:
I am rather stumped on how to make ax2 (the bottom figure) to become shorter relative to ax1 (the top figure). I was looking over the GridSpec (http://matplotlib.org/users/gridspec.html) documentation but I can't figure out how to apply it to seaborn objects.
Question:
How do I make the bottom subplot shorter compared to the top
subplot?
Incidentally, how do I move the plot's title "Distrubition of Difference" to go above the top
subplot?
Thank you for your time.
As #dnalow mentioned, seaborn has no impact on GridSpec, as you pass a reference to the Axes object to the function. Like so:
import matplotlib.pyplot as plt
import seaborn.apionly as sns
import matplotlib.gridspec as gridspec
tips = sns.load_dataset("tips")
gridkw = dict(height_ratios=[5, 1])
fig, (ax1, ax2) = plt.subplots(2, 1, gridspec_kw=gridkw)
sns.distplot(tips.loc[:,'total_bill'], ax=ax1) #array, top subplot
sns.boxplot(tips.loc[:,'total_bill'], ax=ax2, width=.4) #bottom subplot
plt.show()
If you're using a FacetGrid (either directly or through something like catplot, which uses it indirectly), then you can pass gridspec_kws.
Here is an example using a catplot, where "var3" has two values, i.e. there are two subplots, which I am displaying at a ratio of 3:8, with un-shared x-axes.
g = sns.catplot(data=data, x="bin", y="y", col="var3", hue="var4", kind="bar",
sharex=False,
facet_kws={
'gridspec_kws': {'width_ratios': [3, 8]}
})
# Make the first subplot have a custom `xlim`:
g.axes[0][0].set_xlim(right=2.5)
Result, with labels hidden because I just copied my actual data's output, so the labels wouldn't make sense.

wrong y axis range using matplotlib subplots and seaborn

I'm playing with seaborn for the first time, trying to plot different columns of a pandas dataframe on different plots using matplotlib subplots. The simple code below produces the expected figure but the last plot does not have a proper y range (it seems linked to the full range of values in the dataframe).
Does anyone have an idea why this happens and how to prevent it? Thanks.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pds
import seaborn as sns
X = np.arange(0,10)
df = pds.DataFrame({'X': X, 'Y1': 4*X, 'Y2': X/2., 'Y3': X+3, 'Y4': X-7})
fig, axes = plt.subplots(ncols=2, nrows=2)
ax1, ax2, ax3, ax4 = axes.ravel()
sns.set(style="ticks")
sns.despine(fig=fig)
sns.regplot(x='X', y='Y1', data=df, fit_reg=False, ax=ax1)
sns.regplot(x='X', y='Y2', data=df, fit_reg=False, ax=ax2)
sns.regplot(x='X', y='Y3', data=df, fit_reg=False, ax=ax3)
sns.regplot(x='X', y='Y4', data=df, fit_reg=False, ax=ax4)
plt.show()
Update: I modified the above code with:
fig, axes = plt.subplots(ncols=2, nrows=3)
ax1, ax2, ax3, ax4, ax5, ax6 = axes.ravel()
If I plot data on any axis but the last one I obtain what I'm looking for:
Of course I don't want the empty frames. All plots present the data with a similar visual aspect.
When data is plotted on the last axis, it gets a y range that is too wide like in the first example. Only the last axis seems to have this problem. Any clue?
If you want the scales to be the same on all axes you could create subplots with this command:
fig, axes = plt.subplots(ncols=2, nrows=2, sharey=True, sharex=True)
Which will make all plots to share relevant axis:
If you want manually to change the limits of that particular ax, you could add this line at the end of plotting commands:
ax4.set_ylim(top=5)
# or for both limits like this:
# ax4.set_ylim([-2, 5])
Which will give something like this:

How can I remove xtics from an axis in matplotlib? [duplicate]

This question already has answers here:
Remove xticks in a matplotlib plot?
(11 answers)
Closed 8 years ago.
I'm using subplots in matplotlib. Since all of my subplots have the same x-axis, I only want to label the x-axis on my bottom plot. How can I remove xtics from just one axis?
As pointed out here, the following works!
plt.tick_params(\
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom='off', # ticks along the bottom edge are off
top='off', # ticks along the top edge are off
labelbottom='off') # labels along the bottom edge are off
Dan, if you've set up your plots in an OOP way using
import matplotlib.pyplot as plt
fig, ax_arr = subplots(3, 1, sharex=True)
then it should be easy to hide the x-axis labels using something like
plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=False)
# or
plt.setp([a.get_xticklabels() for a in ax_arr[:-1]], visible=False)
But check out this link and some of the further down examples will prove useful.
Edit:
If you can't use plt.subplots(), I'm still assuming you can do
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
ax1.plot(x1, y1)
ax2.plot(x2, y2)
plt.setp(ax1.get_xticklabels(), visible=False)
If you have more than 2 subplots, such as
ax1 = fig.add_subplot(N11)
ax2 = fig.add_subplot(N12)
...
axN = fig.add_subplot(N1N)
plt.setp([a.get_xticklabels() for a in (ax1, ..., axN-1)], visible=False)

Categories