Skip to content

Adding subplots dynamically with constrained_layout #19730

Closed

Description

@juliospain

For an interactive interface where the user can add more plots, it seems impossible to use constrained_layout.
The whole adding a new axes is unnecesarily complex but it can be done. A new gridspec is set-up and the current axes are repositioned into their new "slots". This is working.

However the constrained_layout solver fails (error that height or width is 0).

Proposed Solution

It seems that some work has already been performed as part of setting a colorbar. It seems to me that with some effort it would be possible to extend that solution to be more generic.

Otherwise the whole layout boxes set-up could be exposed to the external API, such that the users can use it in a similar fashion.

(Ideally the matploplib API could make simpler adapating the gridspec after it has been created)

Additional context and prior art

None

Activity

  1. jklymak commented on Mar 18, 2021

    @jklymak
    Member

    Can you give us some more explanation of what doesn't work, preferably with some code? If you mean you keep tearing gridspecs down and adding new ones, and reassigning axes to the new one, that could indeed be problematic. OTOH, did you try this on matplotlib master? constrained_layout has had a rewrite that makes the layout properties less dependent on the axes and more so on the gridspec. But I wouldn't expect miracles - it is written assuming a known gridspec and isn't meant to be changed dynamically on the fly.

  2. jklymak commented on Mar 18, 2021

    @jklymak
    Member

    Otherwise the whole layout boxes set-up could be exposed to the external API, such that the users can use it in a similar fashion.

    BTW, users are always welcome to use the internal API, they just can't complain if it changes ;-)

  3. juliospain commented on Mar 18, 2021

    @juliospain
    Author

    Can you give us some more explanation of what doesn't work, preferably with some code? If you mean you keep tearing gridspecs down and adding new ones, and reassigning axes to the new one, that could indeed be problematic. OTOH, did you try this on matplotlib master? constrained_layout has had a rewrite that makes the layout properties less dependent on the axes and more so on the gridspec. But I wouldn't expect miracles - it is written assuming a known gridspec and isn't meant to be changed dynamically on the fly.

    Thanks for the quick reply. I will try the master and report back.

    However, yes, I do change gridspecs a lot! Isn't there a simple way to "restart" the layout solver with a complete new gridspec?

  4. jklymak commented on Mar 18, 2021

    @jklymak
    Member

    Isn't there a simple way to "restart" the layout solver with a complete new gridspec?

    Yes - clear the figure.

    If I need to change the number of subplots I just restructure my script to do so and rerun it. I don't think that it is more efficient to move things around, rather than just start over.

  5. juliospain commented on Mar 20, 2021

    @juliospain
    Author

    Isn't there a simple way to "restart" the layout solver with a complete new gridspec?

    Yes - clear the figure.

    If I need to change the number of subplots I just restructure my script to do so and rerun it. I don't think that it is more efficient to move things around, rather than just start over.

    This is a little bit inconvenient. I can understand you do not support arbitrary changes of gridspec, but the complete gridspec of the figure and full reset of constrained layout would be nice.

    The approach you suggest works for generating static figures (for publications for instance). But adding a little bit of interaction like in my case where I just want to add another stacked axes, reformatting and reading all the existing lines and artists that are already there it is painful and inefficient.

    Unfortunately, I was not able to run directly the master branch, some unexpected error. I will keep trying...

  6. jklymak commented on Mar 20, 2021

    @jklymak
    Member

    Again, it would be nice if you gave us a sequence of what you are doing, as runnable code, so we can see what the problem is.

  7. juliospain commented on Mar 21, 2021

    @juliospain
    Author

    Ok, let me see:

    import matplotlib as mpl
    import matplotlib.pyplot as plt
    
    for constrained_layout in (False, True):
        fig = plt.figure(constrained_layout=constrained_layout)
        
        # Initial plots
        nb_plots = 2
        gs = fig.add_gridspec(nb_plots, 1)
        
        axes = []
        for i in range(nb_plots):
            ax = fig.add_subplot(gs[i])
            ax.plot(range(5), range(5))
            axes.append(ax)
    
        if not constrained_layout:
            fig.tight_layout()
            
        fig.show()
        
        # Now to add another plot
        # First reposition the existing axes
        gs = fig.add_gridspec(nb_plots + 1, 1)
        
        for i in range(nb_plots):
            axes[i].set_position(gs[i].get_position(fig))
            axes[i].set_subplotspec(gs[i])
        
        # And add the new one...
        ax = fig.add_subplot(gs[-1])
        ax.plot(range(5), range(5))
        axes.append(ax)
        
        # Tight layout if not constrained (works)
        if not constrained_layout:
            fig.tight_layout()
            
        fig.show()
        
    

    For the initial plots, tight_layout and constrained_layout offer the same results. When adding a new one, tight_layout is working:

    image

    However constrained_layout does not with the previous axes. I just put the example to show you my intention. I know this is exepcted given the current design (set_position put the axes out of the constrained_layout solver):
    image

    Strangely, I get different results with this MRE. In my previous tries the new plot was not correctly displayed saying that either height or width collapsed to 0 or something similar.

    Of course I could go for tight_layout, but constrained_layout seems logically better and from my perspective this "adding axes" should not be that complicated (maybe if I understand the layout boxes better...)

  8. jklymak commented on Mar 21, 2021

    @jklymak
    Member

    Thanks for the reproducible example. I didn't even know we had set_subplotspec. But, fortuitously, this works fine on master and 3.4 release candidate. CL got a major rewrite a few months ago. Closed by #17494 and will be in the 3.4 release.

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

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions