Skip to content

Improve handling of subplots spanning multiple gridspec cells. #13544

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
Sep 6, 2019

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented Feb 28, 2019

See changelog.

PR Summary

PR Checklist

  • Has Pytest style unit tests
  • Code is Flake 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)
  • Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way

@jklymak jklymak added this to the v3.2.0 milestone Feb 28, 2019
Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

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

  • The new rowspan/colspan need tests.
  • This needs an example of label_outer I think, unless one already exists. But in particular for the more complicated labelling cases.

Not 100% convinced by the new API, but subplotspecs are kind of low level, so maybe slices are OK. I find slices a bit abstract versus lists.

@@ -121,26 +121,33 @@ def get_gridspec(self):

def update_params(self):
"""update the subplot position from fig.subplotpars"""

self.figbox, self.rowNum, self.colNum, self.numRows, self.numCols = \
self.figbox, _, _, self.numRows, self.numCols = \
Copy link
Member

Choose a reason for hiding this comment

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

Why keep self.numRows\Cols around?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because I don't have a particularly good reason to deprecate them, whereas I'd say rowNum and colNum are actively encouraging people (... the few who'd touch that part of the codebase) to ignore the case of subplots spanning multiple cells.

@anntzer
Copy link
Contributor Author

anntzer commented Feb 28, 2019

rowspan and colspan are indirectly tested by the tests for label_outer: there's the one this PR adds, and the one just above it (test_shared).

subplots_demo.py explicitly documents label_outer:

# `.label_outer` is a handy method to remove labels and ticks from subplots
# that are not at the edge of the grid.

def colspan(self):
"""The columns spanned by this subplot, as a `slice` object."""
_, _, _, _, col_start, col_stop = self.get_rows_columns()
return slice(col_start, col_stop + 1)
Copy link
Member

Choose a reason for hiding this comment

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

get_rows_columns was just written as a helper (prob should have been private?, sorry!) Does it make more sense for this slice just to be an actual attribute that gets set at init, and get_rows_columns just uses that?

Copy link
Contributor Author

@anntzer anntzer Feb 28, 2019

Choose a reason for hiding this comment

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

The problem is that it is explicitly allowed to change a subplotspec's position in the grid by assigning to it (there's even a test for that!), so then you need to keep both num1/num2 and rowspan/colspan in sync, which just sounds overkill (it's not as if recomputing the rowspan and colspan every time was going to be a bottleneck...).

Copy link
Member

Choose a reason for hiding this comment

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

Oh good lord, someone overthought that!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed these 1) to not use get_rows_columns() as I'll just deprecate it in a later PR (especially if you suggest it should have been private :)) in favor of using rowspan/colspan, and 2) to return a range object rather than a slice object (the difference is small, but basically the range always has start and stop as integers (whereas a slice could have start or stop = None (corresponding to obj[:stop] or obj[start:]) or use negative values to mean "from the end", even though here I did normalize them to positive integers); plus, ranges support x in range and are hashable if we ever need that).

Copy link
Member

Choose a reason for hiding this comment

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

That all seems reasonable to me.

@anntzer anntzer force-pushed the subplotspans branch 2 times, most recently from cc8eb22 to 944a2d0 Compare March 3, 2019 16:25
for l in ax.get_xticklabels() + [ax.get_xaxis().offsetText]:
assert l.get_visible() == vx, \
"X axis was incorrectly %s" % (tostr(vx))
f"X axis #{i} is incorrectly {tostr(vx)}"
Copy link
Member

Choose a reason for hiding this comment

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

Would just go for

            visibility = "invisible" if vx else "visible"
            assert l.get_visible() == vx, \
                "x-axis of Axes {i} was incorrectly {visibility}"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but then you need to do the same for y. rephrased the thing.

def test_label_outer_span():
fig = plt.figure()
gs = fig.add_gridspec(3, 3)
# +-+-+-+
Copy link
Member

Choose a reason for hiding this comment

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

    # +---+---+---+
    # |   1   |   |
    # +---+---+---+
    # |   |   | 3 |
    # + 2 +---+---+
    # |   | 4 |   |
    # +---+---+---+

I was a bit confused by the 2 in the condensed form.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@anntzer anntzer force-pushed the subplotspans branch 3 times, most recently from dfae504 to b7db9ce Compare September 6, 2019 14:46
@timhoffm timhoffm merged commit da5c232 into matplotlib:master Sep 6, 2019
@anntzer anntzer deleted the subplotspans branch September 7, 2019 09:03
@ksunden
Copy link
Member

ksunden commented Jan 13, 2020

This changed the [row|col]Num from attributes to functions. Should these be decorated with @property for the deprecation period?

@timhoffm
Copy link
Member

Yes. Thanks for catching this error!

timhoffm added a commit to timhoffm/matplotlib that referenced this pull request Jan 13, 2020
timhoffm added a commit to timhoffm/matplotlib that referenced this pull request Jan 13, 2020
NelleV added a commit that referenced this pull request Jan 14, 2020
meeseeksmachine pushed a commit to meeseeksmachine/matplotlib that referenced this pull request Jan 14, 2020
timhoffm added a commit that referenced this pull request Jan 14, 2020
…212-on-v3.2.x

Backport PR #16212 on branch v3.2.x (Fix deprecation from #13544)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants