You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Long axis title alters xaxis length and direction with plt.tight_layout() #4413
I originally reported this as a seaborn issue, but it turns out that it is the tight_layout property that causes the xaxis to get narrower, then reverse and eventually throw an error if the axis title is too long. See this example notebook for details using both matplotlib and seaborn.
As I mentioned on the seaborn page, I don't think this is especially important and it's easy for the user to adjust by shrinking or splitting the title. I was just confused initially when my plots changed direction on the axis and didn't immediately relate it to the title length. Maybe a warning message can pop up when the axis title is very long, saying that it might have unexpected effects on the plot appearance?
changed the title [-]Axis title alters xaxis length and direction with `plt.tight_layout()`[/-][+]Long axis title alters xaxis length and direction with `plt.tight_layout()`[/+]on May 7, 2015
Can you reproduce this with out facet grid? Please include the code to reproduce the bug in the thread here rather than external link (which will rot).
It looks like what is happening is that the right edge of the first axes is getting pushed to match the left edge of the center title and the titles are always centered over the axes.
I am not sure what the correct behavior here is. I suspect you would want the title to wrap which we have a PR in to add (#4342).
@jklymak I just ran the code without sns.despine and I see the same issue as before (I am now on matplotlib 2.1.2). It appears that plt.tight_layout causes the reversed axis (and the error message for really long titles), so I think this should be reopened.
Narrow x-axis
importseabornassnsimportmatplotlib.pyplotasplt%matplotlibinlineiris=sns.load_dataset('iris')
# Plotting with different title lengths# narrower axisfig, axes=plt.subplots(1,3, figsize=(8,4))
foraxinaxes.ravel():
ax.hist(iris.petal_length)
ax.set(title='long_title'*5 )
plt.tight_layout()
# without `plt.tight_layout()` the axis is not reversedfig, axes=plt.subplots(1,3, figsize=(8,4))
foraxinaxes.ravel():
ax.hist(iris.petal_length)
ax.set(title='long_title'*8 )
# plt.tight_layout()
This is totally independent on seaborn and indeed only due to tight_layout in conjunction with long titles. The following animation shows that @tacaswell's comment from some years ago
the right edge of the first axes is getting pushed to match the left edge of the center title and the titles are always centered over the axes.
is indeed correct.
There does not seem to be a canonical way to solve this though. Options could be:
Check if title overlaps the next plot and if so
shrink title fontsize
wrap title
leave out the title width completely from the adjustments
Provide the user with arguments to do the above.
None of those seem very appealing. And one may also just leave it to the user to take care of not using too long titles.
It assumes that the extra space needed for ticklabels, axis labels, and titles is independent of original location of axes. This is often true, but there are rare cases where it is not.
which seems to suggest exactly this. Maybe it should just be written more comprehensively?
Is subplots_adjust getting negative numbers at some point? If so, either tight_layout could be changed to not emit negative numbers to subplots_adjust or subplots_adjust could not adjust if it gets any negative numbers.
It's not negative numbers per se, but rather the wspace which grows and grows indefinitely up to a jump where it changes sign.
Code for reproduction
import numpy as np; np.random.seed(42)
import matplotlib.pyplot as plt
import matplotlib.animation
import copy
a = np.random.randn(30)
fig = plt.figure(figsize=(8,4))
title = [""]
param = []
def init():
fig.clf()
title[:] = ["titletitletitle"]
def update(i):
fig.clf()
fig.subplots_adjust(.1,.1,.9,.9,0.1,0.1)
axes = [plt.subplot(1,3,j+1) for j in range(3)]
title.append(str(i%10))
for l,ax in enumerate(axes):
ax.hist(a)
for k,bar in enumerate(ax.patches):
bar.set_color(plt.cm.jet(k/10.))
ax.set_title("".join(title), y=1+0.04*l , color="C"+str(l))
fig.tight_layout()
f = fig.subplotpars.__dict__
param.append([len("".join(title)),copy.copy(f)])
text = []
for k,v in f.items():
text.append("{}: {}".format(k,v))
axes[1].text(0,1,"\n".join(text))
#ani = matplotlib.animation.FuncAnimation(fig,update,frames=60,
# interval=120, init_func=init)
##ani.save("tight_layout.gif", writer="imagemagick")
#plt.show()
param = []
for i in range(60):
update(i)
fig, ax = plt.subplots()
letters = [p[0] for p in param]
wspace = [p[1]["wspace"] for p in param]
ax.plot(letters, wspace)
ax.set_xlabel("number of characters in title")
ax.set_ylabel("value of fig.subplotpars.wspace")
ax.set_yscale("symlog", nonposy='clip')
plt.show()
But where would you draw the line, is a wspace of 0.5, still acceptable? Or one of 1 or 10?
wspace should stop growing when the axes collapse on themselves and a warning should get emitted. If you try and do this w/ constrained_layout=True instead of tight_layout, the axes just collapse to zero width.
Yep, but it's not like you would run this kind of continuous checking when doing tight_layout. So you cannot use wspace as a criterion, but instead need to check the actual axes width. And even that is not sufficient, as the axes width itself may be ok, but with an inverted x axis, which not desired. So one might check for the axes width and whether the axes has been inverted; but the latter is cumbersome I suppose.
It's all less than ideal. I suppose it is impossible to find out if it fails due to a long title or due to e.g. too long axis labels (which I suppose would show a similar issue?)? Thinking about it, from a user's perspective it would make most sense to go with the "leave out the title width completely from the adjustments" option. That would then allow to have plots like
So if it is possible to find out that it's the title that causes the problem I would issue a warning informing the user about the title-problem and even suggesting to first call tight_layout and only after that set the title.
If it is not possible to find that out, I would issue a warning of general nature.
In any case option /1. ("I'm collapsing the axes to zero width and emitting a warning") seems the most useful one to me. The user will directly see how this is problematic and can decide to leave the tight layout out or not. Option /2. calls for trouble ("It's not working; I only get error." without any visual feedback for the user). And option /3. has the look and feel of "This damn thing is simply not having any effect.".
From a user's perspective, I agree that option 1 would be the most helpful as per the reasons laid out by @ImportanceOfBeingErnest above (perhaps also indicating that the plot appearance will be affected by this). If the long title could be pinpointed as the underlying issue that would be even better, but I don't think it's a big deal if it is cumbersome/not possible to implement (maybe it could just be suggested as a possible underlying issue?).
Activity
[-]Axis title alters xaxis length and direction with `plt.tight_layout()`[/-][+]Long axis title alters xaxis length and direction with `plt.tight_layout()`[/+]tacaswell commentedon May 7, 2015
Can you reproduce this with out facet grid? Please include the code to reproduce the bug in the thread here rather than external link (which will rot).
joelostblom commentedon May 7, 2015
Yeah I had an example with matplotlib further down in the notebook. I'm including the relevant code in this post also.
Below is the output, the last graph looks normal because I comment the
plt.tight_layout. Throws an error othervise.tacaswell commentedon May 7, 2015
It looks like what is happening is that the right edge of the first axes is getting pushed to match the left edge of the center title and the titles are always centered over the axes.
I am not sure what the correct behavior here is. I suspect you would want the title to wrap which we have a PR in to add (#4342).
jklymak commentedon Mar 8, 2018
The flipping the axis is an
sns.despineissue. I'm going to close as there isn't much that we can do about this. Feel free to re-open if I'm wrong.1 remaining item
joelostblom commentedon Mar 28, 2018
@jklymak I just ran the code without
sns.despineand I see the same issue as before (I am now on matplotlib 2.1.2). It appears thatplt.tight_layoutcauses the reversed axis (and the error message for really long titles), so I think this should be reopened.Narrow x-axis
Reversed x-axis
Error message for long title
Output:
ImportanceOfBeingErnest commentedon Mar 28, 2018
This is totally independent on seaborn and indeed only due to
tight_layoutin conjunction with long titles. The following animation shows that @tacaswell's comment from some years agois indeed correct.
There does not seem to be a canonical way to solve this though. Options could be:
None of those seem very appealing. And one may also just leave it to the user to take care of not using too long titles.
There is this sentence in the tight_layout guide
which seems to suggest exactly this. Maybe it should just be written more comprehensively?
jklymak commentedon Mar 28, 2018
Is
subplots_adjustgetting negative numbers at some point? If so, eithertight_layoutcould be changed to not emit negative numbers tosubplots_adjustorsubplots_adjustcould not adjust if it gets any negative numbers.ImportanceOfBeingErnest commentedon Mar 28, 2018
It's not negative numbers per se, but rather the
wspacewhich grows and grows indefinitely up to a jump where it changes sign.Code for reproduction
But where would you draw the line, is a
wspaceof0.5, still acceptable? Or one of1or10?jklymak commentedon Mar 28, 2018
wspaceshould stop growing when the axes collapse on themselves and a warning should get emitted. If you try and do this w/constrained_layout=Trueinstead oftight_layout, the axes just collapse to zero width.ImportanceOfBeingErnest commentedon Mar 28, 2018
Yep, but it's not like you would run this kind of continuous checking when doing
tight_layout. So you cannot usewspaceas a criterion, but instead need to check the actual axes width. And even that is not sufficient, as the axes width itself may be ok, but with an inverted x axis, which not desired. So one might check for the axes width and whether the axes has been inverted; but the latter is cumbersome I suppose.jklymak commentedon Mar 28, 2018
This is a pretty easy check. PR coming. What is the preferred failure behaviour?
constrained_layoutcurrently does.tight_layoutthrow an error and then downstream packages (i.e. seaborn) could catch the error.tight_layoutat all.ImportanceOfBeingErnest commentedon Mar 29, 2018
It's all less than ideal. I suppose it is impossible to find out if it fails due to a long title or due to e.g. too long axis labels (which I suppose would show a similar issue?)? Thinking about it, from a user's perspective it would make most sense to go with the "leave out the title width completely from the adjustments" option. That would then allow to have plots like
So if it is possible to find out that it's the title that causes the problem I would issue a warning informing the user about the title-problem and even suggesting to first call tight_layout and only after that set the title.
If it is not possible to find that out, I would issue a warning of general nature.
In any case option /1. ("I'm collapsing the axes to zero width and emitting a warning") seems the most useful one to me. The user will directly see how this is problematic and can decide to leave the tight layout out or not. Option /2. calls for trouble ("It's not working; I only get error." without any visual feedback for the user). And option /3. has the look and feel of "This damn thing is simply not having any effect.".
joelostblom commentedon Mar 29, 2018
Thanks for spending time on this!
From a user's perspective, I agree that option 1 would be the most helpful as per the reasons laid out by @ImportanceOfBeingErnest above (perhaps also indicating that the plot appearance will be affected by this). If the long title could be pinpointed as the underlying issue that would be even better, but I don't think it's a big deal if it is cumbersome/not possible to implement (maybe it could just be suggested as a possible underlying issue?).
jklymak commentedon Mar 29, 2018
Please see #10915 It mostly does 1, but the axes doesn't go to zero width...