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
Adding subplots dynamically with constrained_layout #19730
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)
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.
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?
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.
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...
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:
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):
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...)
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.
Activity
jklymak commentedon Mar 18, 2021
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.
jklymak commentedon Mar 18, 2021
BTW, users are always welcome to use the internal API, they just can't complain if it changes ;-)
juliospain commentedon Mar 18, 2021
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?
jklymak commentedon Mar 18, 2021
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.
juliospain commentedon Mar 20, 2021
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...
jklymak commentedon Mar 20, 2021
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.
juliospain commentedon Mar 21, 2021
Ok, let me see:
For the initial plots, tight_layout and constrained_layout offer the same results. When adding a new one, tight_layout is working:
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):

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...)
jklymak commentedon Mar 21, 2021
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.