-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
'bottom cannot be >= top' when using tight_layout
#5456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Could you provide a minimal example of what you are trying to do. That makes it easier to understand if this is a bug and how to fix it. |
I have seen exceptions like this before if you have strings (in this case probably ylabels) on a multi-Axes figure where the text is wider than two axes. Without a minimal example there is not much we can do as, (as you point out) the tight layout code is rather complicated. |
I'm currently trying to build a minimal example, but what I can already say is that this indeed has to do with ylabels. If I shorten my label by 4 letters, the bug doesn't show up. |
Here's an example: #!/usr/bin/env python
import matplotlib
matplotlib.use("PDF")
import matplotlib.pyplot as plt
import sys
n = int(sys.argv[1])
x = [1, 2, 3, 4, 5, 6, 7, 8]
xmin = min(x)
xmax = max(x)
data1_f = [9.2579827408192e-05,
0.0003372918804693761,
0.0007482795416375103,
0.0008833191108781534,
0.0006607025669975578,
0.00032707300226202557,
0.00018651452667246514,
3.514019691439356e-05]
data1_r = [2.605700651541691e-05,
2.89119480988452e-05,
4.2170270917124425e-05,
4.998876011255778e-05,
3.1114424088781854e-05,
1.3605595433950519e-05,
5.257642663359189e-06,
3.5083320041254324e-06]
data2_f = [8.470149678300792e-05,
0.0003150887959573901,
0.0007836372284836411,
0.0010760646463750388,
0.0008765372009137937,
0.00048812392173035456,
0.00029758922448336404,
5.93581217984265e-05]
data2_r = [1.816789924161253e-05,
2.4672634481371817e-05,
4.221322246098976e-05,
6.554534103019158e-05,
4.963479723751039e-05,
3.1058180581352124e-05,
1.2640321929190978e-05,
4.019617548011485e-06]
# I want data1 and data2 on separate graphics, but with the same vertical scale.
ymin = - max(max(data1_r), max(data2_r))
ymax = max(max(data1_f), max(data2_f))
y_span = ymax - ymin
margin = y_span * 0.05
plt.axis([xmin - 0.5, xmax + 0.5, ymin - margin, ymin + margin])
axis = plt.gca()
axis.set_autoscale_on("False")
axis.bar(x, data1_f, facecolor="red", align="center")
axis.bar(x, [-v for v in data1_r], facecolor="blue", align="center")
axis.set_ylabel(" ".join(["data1"] * n))
plt.tight_layout()
plt.savefig("data1.pdf")
plt.cla()
plt.axis([xmin - 0.5, xmax + 0.5, ymin - margin, ymin + margin])
axis = plt.gca()
axis.set_autoscale_on("False")
axis.bar(x, data2_f, facecolor="red", align="center")
axis.bar(x, [-v for v in data2_r], facecolor="blue", align="center")
axis.set_ylabel(" ".join(["data2"] * n))
plt.tight_layout()
plt.savefig("data2.pdf")
plt.cla() If I call this with n = 15, the bug doesn't occur. With n = 16, it does:
|
fig, ax = plt.subplots()
ax.set_ylabel('a'*50000)
plt.tight_layout() is a minimal example. There is a check in |
Hey guys we've written up a quick fix for this one and put in a pull request. Let us know if it's cool with you. Thanks! |
I've got another example that doesn't involve a label that's too long (but maybe too tall?): from matplotlib import pyplot
fig, ax = pyplot.subplots(figsize=(8, 3))
ax.set_xscale('logit')
ax.set_xlim(left=0.02, right=0.98)
ax.set_xlabel('new logit scale')
ax.set_yticks([])
fig.tight_layout() Which produces the following (full traceback from jupyter notebook):
Dropping into to the debugger, bottom is being set to |
Affects me on version 2.2.2 |
This probably needs a better error message (its possible there already is one for 3.0, I’ve not checked, though I recall this coming up before). However, if you get this error, it means your decorators are not leaving room for your axes, and its size has shrunk to nothing. Either make your decorators smaller or your figure larger. |
The error message is still the same on master. |
It happens when tight_layout() is called. It is resizing the elements that were OK before it was called. So it's a bug there, it must figure automatically if there's no room and leave all as is. |
@maahn That should be what it is doing and it is notifying you it can not satisfy the constraints by raising an exception. You can then catch this and do what ever the right thing for your application is. |
Right. Or conversely, how small do you want it to make the axes before it errors? |
I got the same error as a result of calling
|
Using @tacaswell's minimum example now gives >>> plt.tight_layout()
/Users/dstansby/miniconda3/lib/python3.7/site-packages/matplotlib/tight_layout.py:181: UserWarning: Tight layout not applied. The bottom and top margins cannot be made large enough to accommodate all axes decorations.
warnings.warn('Tight layout not applied. ' Which I think is good enough to close this as "fixed with a sensible warning". If I've missed anything, feel free to comment or re-open this issue. |
Running the code above still results in the stack trace below, in matplotlib 3.0.3, the latest version available for Python 2.
|
3.0.3 is not py2 compatible. Maybe you mean 2.2.3? Doubt this fix will be back ported |
Apologies, it appears the version of matplotlib I was using as 1.5.1, not 2.2.4. Upgrading to that version makes the above code function as expected. |
I'm trying to understand why sometimes I get a
ValueError
when usingtight_layout
.The code of
matplotlib
is too complicated for me, but I'm trying to see what's happening usingpdb
.It seems that the problem comes from what
get_tight_layout_figure
returns:I guess this in turns comes from what happens in
auto_adjust_subplotpars
, in the output of_get_bottom
and_get_top
:I don't know what
ax_bbox
andtight_bbox
exactly are.I just guess the algorithm to determine the figure properties do not play well with the data I want to plot. Can this be considered a bug ?
The text was updated successfully, but these errors were encountered: