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
Matplotlib 3.2.1 savefig empty image when fig size matches data size exactly #17542
Saving a figure to an image file with the same pixel dimensions as data loaded with imshow does not work in 3.2.1, producing an empty image. If the dimensions are changed by even one pixel, normal behavior returns.
This bug appeared in 3.2.1 and I have confirmed that it does not occur with 3.1.1.
I noticed in the release notes for 3.2.0 that some changes were made to the default image interpolation; perhaps an unhandled condition was introduced here when no interpolation is required. However, I note that changing the interpolation mode had no effect on this bug.
Code for reproduction
importnumpyasnpfrommatplotlibimportpylabaspltx_size, y_size= (100, 100)
fig=plt.figure(frameon=False, dpi=100, figsize=(y_size/100, x_size/100))
ax=plt.Axes(fig, [0., 0., 1., 1.])
fig.add_axes(ax)
ax.set_axis_off()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
data=np.random.rand(100, 100)
ax.imshow(data)
fig.savefig('/tmp/image.png', bbox_inches='tight', pad_inches=0)
# In matplotlib 3.2.1, empty file with size 100x100 pixels output# if random data shape is changed to something other than 100x100, output# works correctly.# In matplotlib 3.1.1, file output is 100x100 with data shown correctly.
Furthermore, if you do pad_inches=0.0000000001 it works fine, or the axes size to 0.999999 etc it works fine. So its definitely that you are hitting a precise integer somehow. But if you don't do the tight_bbox, or pad_inches, you get exactly what you want.
Thanks for the quick response and work-around. Hopefully it will be possible to get to the underlying issue.
I don't recall the origin of the pad and bbox options in this code, though I would note that it is surprising that not specifying the pad_inches and bbox_inches options results in no padding in this case. From the documentation, the default value for pad_inches is 0.1 inch.
This was broken by #16734 which disables the draw methods on the renderer (because to compute the bounding boxes we don't need to actually draw turn the crank on the renderer methods, only the artist methods) but we never re-set the methods to their original values.
This is not normally a problem as the tight bounding box is a different size that original size so the caching in
misses and we get a new, un-patched renderer. However, in this case the figure is already the correct size so we hit the cache and get back the renderer with the draw methods stripped off which then results in an empty output.
I can see a bunch of hacky ways to fix this, but not sure which one is the best.
The problem is that where we know if we have flagged it as draw_disabled (in backend bases) is not where we know if there is a cache or not (deep in the print_XYZ functions in the backends).
Activity
jklymak commentedon May 31, 2020
If you remove
pad_inches=0this works fine.This stopping working seems to bisect to a9b8b6e which I think has more to do with extents than the image work. #16734
jklymak commentedon May 31, 2020
Furthermore, if you do
pad_inches=0.0000000001it works fine, or the axes size to 0.999999 etc it works fine. So its definitely that you are hitting a precise integer somehow. But if you don't do the tight_bbox, or pad_inches, you get exactly what you want.rdgraham commentedon May 31, 2020
Thanks for the quick response and work-around. Hopefully it will be possible to get to the underlying issue.
I don't recall the origin of the pad and bbox options in this code, though I would note that it is surprising that not specifying the pad_inches and bbox_inches options results in no padding in this case. From the documentation, the default value for pad_inches is 0.1 inch.
jklymak commentedon May 31, 2020
pad_inchesonly matters if you usebbox_inches='tight'tacaswell commentedon Jun 3, 2020
This was broken by #16734 which disables the draw methods on the renderer (because to compute the bounding boxes we don't need to actually draw turn the crank on the renderer methods, only the artist methods) but we never re-set the methods to their original values.
This is not normally a problem as the tight bounding box is a different size that original size so the caching in
matplotlib/lib/matplotlib/backends/backend_agg.py
Lines 411 to 421 in 4356b67
I can see a bunch of hacky ways to fix this, but not sure which one is the best.
jklymak commentedon Jun 3, 2020
It seems to me that
draw_disabled=Trueshould just make a new un-cached renderer?tacaswell commentedon Jun 3, 2020
The problem is that where we know if we have flagged it as
draw_disabled(in backend bases) is not where we know if there is a cache or not (deep in theprint_XYZfunctions in the backends).FIX: do not let no-op monkey patches to renderer leak out
FIX: do not let no-op monkey patches to renderer leak out
FIX: do not let no-op monkey patches to renderer leak out