Thanks to visit codestin.com
Credit goes to github.com

Skip to content

ENH: Add gridspec method to figure, and subplotspecs #11010

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

Merged
merged 1 commit into from
Jul 16, 2018

Conversation

jklymak
Copy link
Member

@jklymak jklymak commented Apr 9, 2018

PR Summary

For contrained_layout, I'm trying to encourage attaching a figure to GridSpecs. This PR makes a add_gridspec method available to Figure.

Old

import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec

fig = plt.figure()
gs = GridSpec(2, 2, figure=fig)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
# spans two rows:
ax3 = fig.add_subplot(gs[:, 1])

New

import matplotlib.pyplot as plt
fig = plt.figure()
gs = fig.add_gridspec(2, 2)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
# spans two rows:
ax3 = fig.add_subplot(gs[:, 1])

New SubplotSpec method:

It also makes a convenience method available to SubplotSpec to create SubplotspecGridSpecs

Old

import matplotlib.gridspec as gridspec

fig = plt.figure()
gs0 = gridspec.GridSpec(3, 1)
ax1 = fig.add_subplot(gs0[0])
ax2 = fig.add_subplot(gs0[1])
gssub = GridSpecFromSubplotSpec(1, 3, gs0[2])
for i in range(3):
    fig.add_subplot(gssub[0, i])

New

fig = plt.figure()
gs0 = fig.add_gridspec(3, 1)
ax1 = fig.add_subplot(gs0[0])
ax2 = fig.add_subplot(gs0[1])
gssub = gs0[2].subgridspec(1, 3)
for i in range(3):
    fig.add_subplot(gssub[0, i])

PR Checklist

  • Update gridspec tutorial and constrained_layout tutorial.
  • Has Pytest style unit tests
  • Code is PEP 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)

@jklymak jklymak added topic: geometry manager LayoutEngine, Constrained layout, Tight layout status: work in progress labels Apr 9, 2018
@ImportanceOfBeingErnest
Copy link
Member

I don't feel that removing gridspec.Gridspec completely from the tutorial is a good idea. After all this is the gridspec tutorial. And Gridspec is in principle not bound to any figure. I.e. you can define a GridSpec and use it for several figures.

The add_gridspec is a really nice idea and it's really useful in most cases. I would just not replace the complete tutorial with it.


I would not use constrained_layout by default throughout the tutorial. This makes it hard to see where it plays a role. Just as it was before, when tight_layout got called in certain examples, one should use contrained_layout where necessary/useful/desired; but within the individual example itself.

I have a problem with the call to canvas.draw() and the sentence

Sometime constrained_layout needs an extra draw...

If contrained layout needs to draw the figure twice it needs to take care of that by itself. It's not useful to show examples with undeterministic behaviour. Up till now you never ever needed to draw a figure before showing it in matplotlib. Introducing this practice between the lines is really 👎 .

@jklymak
Copy link
Member Author

jklymak commented Apr 10, 2018

@ImportanceOfBeingErnest Fair enough about keeping a few GridSpec examples in there. I was looking at it as akin to Legend, which we rarely need to call directly. I appreciate that GridSpec need not belong to a specific figure, but in my opinion that is a mistake, because a GridSpec is an organizational element in complicated figures, and in order for constrained_layout to work, it needs to associate a figure with each GridSpec. (Of course that would help a lot of tight_layout problems as well, but...

tight_layout was called in all the examples where I use constrained_layout.

I appreciate the problem about fig.canvas.draw(). You don't need to call this, but the plot where I do is slightly cropped if you don't. This is a mild flaw of constrained_layout. I think there are actually plenty of places where we tell people they need to trigger a draw to get layout to work properly.

The alternative, from constrained_layout point of view is to always call it twice behind the scenes, and that is expensive. I'm personally of the opinion its just as well to admit our flaws for something that works 95% of the time, and let the user deal with the result. However, I'll look into it; maybe I can make the padding a bit bigger to take care of most cases...

@jklymak jklymak force-pushed the enh-add-gridspec-methods branch 2 times, most recently from 7f4d162 to c0f64eb Compare April 10, 2018 04:33
@timhoffm
Copy link
Member

I'm stumbling over the name add_gridspec. There is nothing added to the figure here. It's just creating a GridSpec holding a reference to the figure.


Not knowing if an additional draw() is needed for a layout to be correct is off-settling. If possible that should be solved. I don't know anything about constrained_layout, but maybe you can check if artists are clipped and then trigger a redraw?

If this cannot be solved easily, can we please use examples that do not require workaround for flaws, unless the example is explicitly designed to show the limitations and explain how to cope with them.

@ImportanceOfBeingErnest
Copy link
Member

I just saw that this example disappeared from the tutorial.

image

This is the most useful of all to show how to use Gridspec and would really like it not to be thrown away. (I guess that happened already in a previous version, but still...)

My point about the constrained_layout use is that you define it at the very beginning. Instead it should be inside the example itself. Otherwise users copy the example, run it and get a different figure. You cannot expect them to check for some setting being done at some completely different place.

Personally I would prefer there to be a separete section which explains how you may use add_gridspec() instead of gridspec.Gridspec() and show the advantages of it. Those are:

  • no need to import matplotlib.gridspec
  • the ability to use one of the grid managers, namely contrained_layout, with it.

I do think those weight strong enough to actually add this function. But I do not see that they help in understanding gridspec; instead they add a dimension of complexity to the examples, which is not needed, and potentially distracts from the actual point of the tutorial.

@jklymak
Copy link
Member Author

jklymak commented Apr 10, 2018

@timhoffm

I'm stumbling over the name add_gridspec. There is nothing added to the figure here. It's just creating a GridSpec holding a reference to the figure.

Agreed. I contemplated adding a list of gridspecs to figure, but decided it wasn't totally necessary. But from user's point of view, they are adding a gridspec, and I'd argue the name makes sense. I could be convinced that it should be just figure.gridspec, but I'm not a huge fan of that because it makes it sound like that is a property. While there is a case to be made that each figure should only have one parent gridspec, thats not the case now. Other suggestions for method names that are easily discoverable would be welcome.

@ImportanceOfBeingErnest

My point about the constrained_layout use is that you define it at the very beginning.

OK, fair enough - I'll change that. And I can add back in the complicated example. I liked that one too, and in fact prefer it to the somewhat messy double nested thing at the end of the current tutorial.

Personally I would prefer there to be a separete section which explains how you may use add_gridspec() instead of gridspec.Gridspec()

I understand what you are saying. I just disagree that gridspec.GridSpec() needs ever be directly referenced and explained if we adopt these new convenience methods. The only reason would be if

a) someone wants to use the abstraction ability of having a GridSpec they drag from one figure to the next, a feature I find of dubious value.
b) so that folks can make sense of old examples.

But more to the point, the new convenience methods are exactly the same as the direct method, so I don't think any understanding is lost.

@ImportanceOfBeingErnest
Copy link
Member

What I mean is that you'd create the gridspec once and use it for all figures you create.

import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec

gs = GridSpec(2, 2, left=0.2, right=0.93, wspace=0.05, hspace=0.12,
             width_ratios=[1, 2], height_ratios=[4, 1])

fig = plt.figure()
ax1 = fig.add_subplot(gs[0, :])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[1, 1])

fig2 = plt.figure()
ax21 = fig2.add_subplot(gs[0, 0])
ax22 = fig2.add_subplot(gs[1, 0])
ax23 = fig2.add_subplot(gs[:, 1])

fig3 = ...

@jklymak
Copy link
Member Author

jklymak commented Apr 10, 2018

Yeah I understand the use-case. Pretty skeptical that gets used much in practice though. If we completely got rid of that interface you’d still get the same thing by packing the args in a dict. Not that I think we should get rid of the fundamental interface at all.

Would an example like the above explaining the advantage of not using the convenience method make sense?

The big disadvantage of your example is that constrained_layout won’t work at all, whereas it works fine for the new interface.

My overarching point for a while is that we have this nice hierarchical way of organizing subplots, but we don’t keep track of that hierarchy, and hence lose information about the users desires. Without that hierarchy automating layout is impossible for general layouts. This is a small step to enforcing that hierarchy at a slight loss of convenience in some obscure use cases.

@jklymak jklymak force-pushed the enh-add-gridspec-methods branch 2 times, most recently from 65cdd57 to 6ae08fe Compare April 10, 2018 17:06
@jklymak
Copy link
Member Author

jklymak commented Apr 10, 2018

Removing WIP as this is the extent of what I am planning. However, open to

  • changing the name of .Figure.add_gridspec
  • further refinement or changes in the tutorials

@jklymak jklymak force-pushed the enh-add-gridspec-methods branch 2 times, most recently from 8618fda to 2d337ac Compare April 10, 2018 17:50
@jklymak jklymak changed the title ENH/WIP: Add gridspec method to figure, and subplotspecs ENH: Add gridspec method to figure, and subplotspecs Apr 10, 2018
@phobson
Copy link
Member

phobson commented Apr 10, 2018

I'm strongly in favor of this and I understand concerns about the naming.

what about fig.[set|make|create]_gridspec?

@anntzer
Copy link
Contributor

anntzer commented Apr 10, 2018

set_gridspec strongly suggests that a figure can only ever have one gridspec attached at a time, which seems a bit too strong (even though "mostly" true). make_/create_/attach_ may sound better?

@jklymak
Copy link
Member Author

jklymak commented Apr 10, 2018

Re name:

I just think of it as parallel to add_subplot. I appreciate that add_subplot actually adds a subplot to the figure, whereas add_gridspec doesn't until a subplot is added, but thats arguing consitency from the point of view of the developer. I think from the user's point of view its more consistent and easier to remember:

  1. add a gridspec
  2. add a subplot

If it would make things nicer, I'd love it if a figure kept track of it's child gridspec. But thats consistency from our point of view.

I think set_gridspec is out of the question, just as fig.gridspec is, because it connotes a property.

If I don't prevail in my argument here, make_gridspec or create_gridspec are not too bad...

@phobson
Copy link
Member

phobson commented Apr 10, 2018

Agreed. set_ is off the table.

attach_ sounds like it would accept an existing gridspec as a parameter.

@timhoffm
Copy link
Member

Both add_ and set_ imply that the gridspec is somehow attached to the figure and there is something like get_gridspec(s). The semantic difference between add_ and set_ would be if a figure can have multiple or just one gridspec.

If there would be an agreement that the figure should keep a reference to the gridspec (as suggested by @jklymak), it would be ok to use these terms in anticipation of the future functionality. Then again, it's probably better think of a more general API like:

  • set_layout(layout)
  • get_layout(layout)
  • set_gridspec_layout(rows, cols, ...) convenience function similar to the add_gridspec above and equivalent to set_layout(GridSpec(rows, cols, ...).

So -0.5 on add_ and set_.

For now, I think make_ and create_ are the best options (slight personal preference on make_).

@jklymak jklymak added this to the v3.0 milestone Apr 11, 2018
@jklymak
Copy link
Member Author

jklymak commented Apr 11, 2018

OK, due to popular demand, I added figure._gridspecs as a private list of gridspecs added using add_gridspec. We can add convenience functions for getting the list if and when the need arises.

@phobson
Copy link
Member

phobson commented Apr 11, 2018

Though I still prefer make_gridspec, I think adding to a private list is a good move and makes add_gridspec something I would support.

@jklymak jklymak force-pushed the enh-add-gridspec-methods branch from 5e31375 to 4a64f3d Compare April 11, 2018 19:27
@Tillsten
Copy link
Contributor

Why not let the figure have a gridspec by default?

@jklymak
Copy link
Member Author

jklymak commented Apr 12, 2018

@Tillsten A gridspec needs the grid parameters (m, n) before it means anything, so that needs user input I think... We could just put a default one in, and indeed thats what happens if there is just one axes in the figure.

@jklymak
Copy link
Member Author

jklymak commented Apr 12, 2018

Actually, this probably should at least look for where subplots adds a GridSpec and include that in the list. WIP until I get to it! Done!

@jklymak
Copy link
Member Author

jklymak commented May 24, 2018

This had a lot of good input; anyone up for a full review? Its not a big conceptual change, though I did edit the tutorial a fair bit...

@jklymak
Copy link
Member Author

jklymak commented Jun 15, 2018

Pinging for review on this. Its a pretty straightforward enhancement, and I think I addressed the concerns about the name add_gridspec by actually adding a property to the figure...

@jklymak jklymak force-pushed the enh-add-gridspec-methods branch from e1bd2d2 to d138cda Compare June 19, 2018 17:31
@jklymak
Copy link
Member Author

jklymak commented Jun 19, 2018

...rebased

Copy link
Member

@phobson phobson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this represents a good improvement in usability. Thanks for sticking with this, @jklymak

@jklymak jklymak force-pushed the enh-add-gridspec-methods branch from d138cda to aec8d6a Compare July 10, 2018 17:32
@jklymak
Copy link
Member Author

jklymak commented Jul 10, 2018

Squash and rebase. I think it'd be wrong to say that this is release critical, but it'd be nice to include in 3.0; its pretty straightforward, just adding new access points to the gridspec w/o the user having to know all the magical incantations...

@jklymak
Copy link
Member Author

jklymak commented Jul 10, 2018

EDIT: fixed now...

Doc build fails w/

Warning, treated as error:
/home/circleci/project/doc/users/next_whats_new/fig_gridspec.rst:document isn't included in any toctree

I forget how to fix that. Note that the next_whats_new got cleaned out in the 3.0 doc prep...

@jklymak jklymak force-pushed the enh-add-gridspec-methods branch 4 times, most recently from 30a8265 to b712200 Compare July 10, 2018 20:46
Copy link
Member

@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a useful simplification.


Other Parameters
----------------
*kwargs* are passed to `.GridSpec`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must be formatted like parameters:

    Other Parameters
    ----------------
    **kwargs
        All other parameters are passed to `.GridSpec`.

@jklymak jklymak force-pushed the enh-add-gridspec-methods branch from b712200 to c366d9b Compare July 10, 2018 20:52
@jklymak jklymak force-pushed the enh-add-gridspec-methods branch from c366d9b to 2977f37 Compare July 16, 2018 16:11
@jklymak
Copy link
Member Author

jklymak commented Jul 16, 2018

Self merging. This did pass AppVeyor before the rebase, and the rebase was trivial, and had no Windows related changes.

@jklymak jklymak merged commit 250c33e into matplotlib:master Jul 16, 2018
@jklymak jklymak deleted the enh-add-gridspec-methods branch July 16, 2018 17:07
@anntzer anntzer mentioned this pull request Jun 3, 2019
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API: changes topic: geometry manager LayoutEngine, Constrained layout, Tight layout
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants