Skip to content

FR: Figure.subplots add optional SubplotSpec parameter #11288

Closed

Description

@attoblarg

Figure.subplots is a convenient method for creating a grid of subplots with shared axes, with the redundant tick labels and such automatically handled for you. It would be helpful if this method could also be used to help create more complicated layouts, such as ones with a few independent sets of shared axes that you would create with several calls to gridspec.GridSpecFromSubplotSpec.

For example:

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np

fig = plt.figure()
gs = gridspec.GridSpec(1,2)

####
# The following block could be replaced by this proposed function call:
#fig.subplots(nrows=2, ncols=2, subplotspec=gs[0], sharex='col', sharey='all',
#             squeeze=False, gridspec_kw=dict(hspace=0.07))
gs0 = gridspec.GridSpecFromSubplotSpec(2, 2, gs[0], hspace=0.07)
ax0_00 = fig.add_subplot(gs0[0,0])
ax0_01 = fig.add_subplot(gs0[0,1], sharey=ax0_00)
ax0_10 = fig.add_subplot(gs0[1,0], sharex=ax0_00, sharey=ax0_00)
ax0_11 = fig.add_subplot(gs0[1,1], sharex=ax0_00, sharey=ax0_00)
ax0s = np.array([[ax0_00, ax0_01], [ax0_10, ax0_11]])

for ax in ax0s[:-1].flatten():
    ax.tick_params(axis='x', which='both', labelbottom=False)
for ax in ax0s[:,1:].flatten():
    ax.tick_params(axis='y', which='both', labelleft=False)
####

####
# The following block could be replaced by this proposed function call:
#fig.subplots(nrows=3, ncols=1, subplotspec=gs[1], sharex='all', sharey='all',
#             squeeze=False, gridspec_kw=dict(hspace=0.1))
gs1 = gridspec.GridSpecFromSubplotSpec(3, 1, gs[1], hspace=0.1)
ax10 = fig.add_subplot(gs1[0])
ax11 = fig.add_subplot(gs1[1], sharex=ax10, sharey=ax10)
ax12 = fig.add_subplot(gs1[2], sharex=ax10, sharey=ax10)
ax1s = np.array([[ax10], [ax11], [ax12]])

for ax in ax1s[:-1].flatten():
    ax.tick_params(axis='x', which='both', labelbottom=False)
for ax in ax1s[:,1:].flatten():
    ax.tick_params(axis='y', which='both', labelleft=False)
####

fig.tight_layout()

plt.show()

figure_1

Adding a subplotspec optional argument to Figure.subplots, which when supplied would call gridspec.GridSpecFromSubplotSpec (with the provided SubplotSpec) instead of gridspec.GridSpec, would be all that is required.

The exception to this is for constrained layouts, which I'm not familiar with. gridspec.GridSpecFromSubplotSpec doesn't accept a figure parameter, but seems to inherit that information from the SubplotSpec, and so would rely on passing the figure to the "parent" GridSpec in the first place?

Activity

  1. jklymak commented on May 23, 2018

    @jklymak
    Member

    I think something like this can/would be useful. I think its exactly what I am proposing in #11010 except I'm not proposing a kwarg to figure.subplots, which maybe is a good idea, maybe is a little too crufty...

  2. attoblarg commented on May 23, 2018

    @attoblarg
    Author

    I think what I'm requesting be added is independent of #11010. My request is not about creating/managing GridSpec and related objects, but about being able to use the conveniences provided by Figure.subplots (automatic managing or shared axes setup and display) for multiple independent times in smaller subsections of the same figure (using gridspec.GridSpecFromSubplotSpec).

    I believe this would be an easy pull request except that I'm not sure how to handle the constrained layout case if the passed SubplotSpec argument was not setup to use a constrained layout. I am hoping for advice/recommendations on this point.

  3. jklymak commented on May 23, 2018

    @jklymak
    Member

    I agree this is a bit different from #11010, but I don't want it to be independent. I don't think that figure is the correct class for this. I'm trying to get us thinking about these layouts more heirarchically, and I'd prefer this be a method on SubplotSpec, so you'd call

    axs = gs[0].subplots(3, 1, sharex=True, sharey=True)

    instead of adding a kwarg to the figure method...

    In either case, so long as you use SubplotSpec this should all work fine w/ constrained_layout. The only thing in the code above that you need to change is to do:

    fig = plt.figure(constrained_layout=True)
    gs = gridspec.GridSpec(1, 2, figure=fig)

    (i've also proposed adding gs = figure.GridSpec(1, 2) in #11010 to get arpund the akward passing of the figure kwarg)

    figure_1000

    I'm not vetoing making this part of the figure.subplot api, but it would make organization of the plotting hierarchy clearer to have the public API be that this is a method of SuplotSpec. One may implement it as a private kwarg to figure.subplots if that is more convenient...

  4. attoblarg commented on May 23, 2018

    @attoblarg
    Author

    I understand now what you meant, and I agree that, in your proposed changes, a call like

    axs = gs[0].subplots(3, 1, sharex=True, sharey=True)

    is exactly what I'm requesting. However, even if what you are proposing is accepted, I think adding this to figure.subplots is still helpful, unless it would be deprecated.

  5. jklymak commented on Sep 26, 2018

    @jklymak
    Member

    I'm going to close this as covered by the merged #11010. If those additions are not adequte we can re-open discussion....

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: geometry managerLayoutEngine, Constrained layout, Tight layout

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions