Skip to content

missing imshow() subplots when using tight_layout() #4976

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

Closed
douglase opened this issue Aug 21, 2015 · 22 comments · Fixed by #22418
Closed

missing imshow() subplots when using tight_layout() #4976

douglase opened this issue Aug 21, 2015 · 22 comments · Fixed by #22418

Comments

@douglase
Copy link

Hello, I've found an unexpected behavior when I make grids of subplots with imshow and tight_layout the second to last plot is missing, for example:

import numpy as np
import matplotlib.pyplot as plt
plt.figure()
for i in range(16):
    ax= plt.subplot(4,4 ,i+1)
    im=ax.imshow(np.random.normal(size=100).reshape([10,10]))
    plt.tight_layout()
    plt.title(i)
plt.savefig("imshow_4x4.png")

generates:
imshow_4x4
Whereas the same loop with pcolor works:

import numpy as np
import matplotlib.pyplot as plt
plt.figure()
for i in range(16):
    ax= plt.subplot(4,4 ,i+1)
    im=ax.pcolor(np.random.normal(size=100).reshape([10,10]))
    plt.tight_layout()
    plt.title(i)
plt.savefig("pcolor_4x4.png")

gives:
pcolor_4x4

If I omit the tight_layout() call from the first example it works:
imshow_nottight_4x4

I'm using matplotlib 1.4.3 and numpy 1.9.2 in Anaconda 2.2.0.

@tacaswell
Copy link
Member

... what

I can reproduce this on current master.

@tacaswell
Copy link
Member

plt.tight_layout() is removing an axes from the fig.axes list.

There is a simple work around here, just call plt.tight_layout once outside of the loop and it works correctly.

@douglase
Copy link
Author

yes, the work around works, thanks. Calling tight_layout inside the loop is admittedly an inefficient approach but not one I expected to delete a figure...

@tacaswell
Copy link
Member

I agree, something very strange is going on here. Removing the call to imshow makes it work correctly. The bug is in some interaction between plt.tight_layout and plt.subplot(...).

I suggest re-writing this loop as

import numpy as np
import matplotlib.pyplot as plt

fig, axes = plt.subplots(4, 4)

for i, ax in enumerate(axes.ravel()):
    im = ax.imshow(np.random.normal(size=100).reshape([10,10]))
    ax.set_title(i)


plt.tight_layout()

@tacaswell tacaswell added this to the proposed next point release milestone Aug 21, 2015
@WeatherGod
Copy link
Member

That is f-ed up. I wonder if the axes isn't really removed, just misplaced?
On Aug 21, 2015 4:50 PM, "Thomas A Caswell" notifications@github.com
wrote:

plt.tight_layout() is removing an axes from the fig.axes list.

There is a simple work around here, just call plt.tight_layout once
outside of the loop and it works correctly.


Reply to this email directly or view it on GitHub
#4976 (comment)
.

@Hongyu1230
Copy link

This is my attempted fix of the problem

It seems like tight_layout is not removing the subplots but when you tried to call tight_layout on the figure it resized the subplots that were already on it(which made them bigger because it had avaliable space), then when you add another subplot to the figure with the already resized plot they will disappear because subplot is plotting in their region.

I'm not really sure if this is a good fix though.
https://github.com/Hongyu1230/matplotlib/commit/f21fc17117ee67cf39dae218bf88ea1ef2d572fc

@tacaswell
Copy link
Member

@hamgyu1230 Can you open a pull request with that change (with a better commit message!).

Can you explain why clipping these values at 0 fixes the problem?

@Hongyu1230
Copy link

#6096

by making these at 0, the subplot can only shrink or stay the same even when there is avaliable space, thus the existing subplots shouldn't be overwritten by any new ones when a new subplot is plotted.

@tacaswell tacaswell modified the milestones: 2.1 (next point release), 2.2 (next next feature release) Oct 3, 2017
@adizhol
Copy link

adizhol commented Sep 14, 2021

Was this fixed? I have the same problem

@jklymak
Copy link
Member

jklymak commented Sep 14, 2021

Not really, but if you just call tight_layout once, at the end, it all works fine.

@jklymak
Copy link
Member

jklymak commented Sep 14, 2021

This is caused by fully_overlaps returning True for the last axes, and hence the old one gets deleted, as pointed out by #7393. What happens is that the "tight" axes is larger and the new axes overlaps the old axes and deletes it. I'm not sure what we can do to fix this, since the stated behaviour is that if you (partially) cover an axes it gets deleted. Better is to create the axes first (fig, axs = plt.subplots(4, 4)) and then call tight_layout, hence avoiding too much magic.

@anntzer
Copy link
Contributor

anntzer commented Sep 14, 2021

I actually think the "remove overlapping subplots" behavior is pretty bad and should be deprecated and removed; see #11435 and #7377 (comment).

@jklymak
Copy link
Member

jklymak commented Sep 14, 2021

I agree, but I'm not sure how you deprecate that without a huge rigamarole.

@anntzer
Copy link
Contributor

anntzer commented Sep 14, 2021

I think(?) you just emit a warning if an axes that would have been removed under the old behavior will no longer be removed with the new one? (telling whoever was relying on the old behavior that they need to explicitly call ax.remove() to suppress the warning)
That means no one can actually benefit from the new behavior until the deprecation elapses, but that seems OK?

@fzyzcjy
Copy link

fzyzcjy commented Sep 24, 2021

I have the same problem

MacOS, matplotlib 3.1.3, MacOSX backend

In my case, @jklymak 's workaround does not work. Once in a while some figures disappear.

I do not want to call subplots since it will create a new figure but I want to use the old one.

code:

        plt.figure(1, figsize=(14, 5))
        plt.clf()
        nr, nc = 1, 2

        ax1 = plt.subplot(nr, nc, 1)
        plt.imshow(im_in, cmap='gray', vmin=0, vmax=255)
        for tbl_idx, tbl in enumerate(all_trace_back_lines):
            plt.plot(np.arange(0, tbl.yarr.shape[0], 1.0), tbl.yarr, c=c, linewidth=w)
            plt.scatter([tbl.x_seed], [tbl.y_seed], c=c, s=3)
            plt.text(tbl.x_seed, tbl.y_seed, f'#{tbl_idx}', size=8)

        plt.gca().add_collection(mc.LineCollection([
            [(20, 20), (20, 20 + global_average_text_scale)]
        ], linewidths=2, colors='orange'))
        plt.text(20, 20, f'{global_average_text_scale:.1f}', size=5)

        plt.subplot(nr, nc, 2, sharex=ax1, sharey=ax1)
        plt.imshow(im_vis_r2l_dp)

        plt.tight_layout()
        plt.show()

example result (once in a while)

20210923_092615

@jklymak
Copy link
Member

jklymak commented Sep 24, 2021

Here you are only calling tight layout at the end. If this is indeed reproducible then please provide a self-contained example and open a new issue. If it's not reproducible, because you are really calling tight_layout in the middle of the process sometimes, then it is the same bug. Also if you want to add subplots to an existing figure just call fig.subplots(1,2)

@fzyzcjy
Copy link

fzyzcjy commented Sep 24, 2021

@jklymak Thanks I will look at it to see how to reproduce it

@back2yes
Copy link

plt.tight_layout() is removing an axes from the fig.axes list.

There is a simple work around here, just call plt.tight_layout once outside of the loop and it works correctly.

@jklymak Thanks you saved my day.

@Godfreyoise
Copy link

Please why is this code not running
plt.figure(figsize=(10, 10))
for image, labels in data_train.take(1):
for i in range(9):
plt.subplot(3,3,i+1)

    plt.imshow(image[i]).numpy.()astype ('uint8'))
    plt.title(data_cat[labels[i]])
    plt.axis('off')

2 similar comments
@Godfreyoise

This comment was marked as duplicate.

@Godfreyoise

This comment was marked as duplicate.

@rcomer
Copy link
Member

rcomer commented Mar 17, 2024

@Godfreyoise for usage questions please go to https://discourse.matplotlib.org/. You will need to provide a complete code example so that others can reproduce the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.