Skip to content

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

Closed

Description

@douglase

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.

Activity

  1. tacaswell commented on Aug 21, 2015

    @tacaswell
    Member

    ... what

    I can reproduce this on current master.

  2. tacaswell commented on Aug 21, 2015

    @tacaswell
    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.

  3. douglase commented on Aug 21, 2015

    @douglase
    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...

  4. tacaswell commented on Aug 21, 2015

    @tacaswell
    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()
  5. added this to the milestone on Aug 21, 2015
  6. WeatherGod commented on Aug 22, 2015

    @WeatherGod
    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)
    .

  7. Hongyu1230 commented on Mar 2, 2016

    @Hongyu1230

    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

  8. tacaswell commented on Mar 2, 2016

    @tacaswell
    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?

  9. Hongyu1230 commented on Mar 2, 2016

    @Hongyu1230

    #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.

  10. modified the milestones: , on Oct 3, 2017
  11. adizhol commented on Sep 14, 2021

    @adizhol

    Was this fixed? I have the same problem

  12. jklymak commented on Sep 14, 2021

    @jklymak
    Member

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

  13. jklymak commented on Sep 14, 2021

    @jklymak
    Member

    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.

  14. anntzer commented on Sep 14, 2021

    @anntzer
    Contributor

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

  15. jklymak commented on Sep 14, 2021

    @jklymak
    Member

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

  16. anntzer commented on Sep 14, 2021

    @anntzer
    Contributor

    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?

  17. fzyzcjy commented on Sep 24, 2021

    @fzyzcjy

    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

  18. jklymak commented on Sep 24, 2021

    @jklymak
    Member

    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)

  19. fzyzcjy commented on Sep 24, 2021

    @fzyzcjy

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

  20. back2yes commented on Nov 30, 2021

    @back2yes

    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.

  21. modified the milestones: needs sorting, v3.6.0 on Mar 29, 2022
  22. Godfreyoise commented on Mar 17, 2024

    @Godfreyoise

    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')
    
  23. Godfreyoise commented on Mar 17, 2024

    @Godfreyoise
  24. Godfreyoise commented on Mar 17, 2024

    @Godfreyoise
  25. rcomer commented on Mar 17, 2024

    @rcomer
    Member

    @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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions