-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
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
Conversation
There was a problem hiding this 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 = \ |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
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:
|
lib/matplotlib/gridspec.py
Outdated
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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...).
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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.
cc8eb22
to
944a2d0
Compare
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)}" |
There was a problem hiding this comment.
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}"
There was a problem hiding this comment.
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) | ||
# +-+-+-+ |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
dfae504
to
b7db9ce
Compare
b7db9ce
to
f4412c0
Compare
This changed the |
Yes. Thanks for catching this error! |
See changelog.
PR Summary
PR Checklist