-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
ENH: Subfigures #18356
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
ENH: Subfigures #18356
Conversation
I haven't yet looked into the details, but the overall idea seems reasonable. What is the motivation to name this "SubPanel"? IMHO just "Panel" would be simpler and is equally expressive. |
One thing I should have mentioned above is that this is recursive. i.e. a |
https://en.wikipedia.org/wiki/Panel#Visual_arts
To me, there's enough "sub" notion in |
I agree with you that a panel can be a subdivision. Or it can be a single thing. https://www.merriam-webster.com/dictionary/panel The argument for adding fig = plt.figure()
gs = fig.add_gridspec(2, 1)
# LHS
ax = fig.add_subplot(gs[0])
#RHS
panel = fig.add_subpanel(gs[1])
subaxs = panel.subplots(2,2) Originally, it was |
804cb31
to
eb78a4e
Compare
I am very 👍 on this in principle. |
21cfca1
to
d53565e
Compare
Ok, so I moved a bunch of methods from |
Any chance of getting https://discourse.matplotlib.org/t/discsusion-feature-request-subplot-managed-axis-labels/21164 in here? |
Yes Absolutley. I already have a pr for that but dont want to rebase it all the time. |
Awesome! Also, regarding the name, I feel like when discussing figures in journal articles, "panel" is the term often used for what in matplotlib would be a called a subplot or axes, e.g. "Panel (A) shows the mean frobexity over time, Panel (B) shows blah blah blah". Having "subpanel" be concept that is actually super-ordinate to that object might be confusing... |
Originally, it was just Edit: but open to other names as well... |
bc6bb31
to
2b39faa
Compare
Thanks to some help I got the docs to build. Thanks @larsoner. This does change the This needs input for the name, otherwise ready-is to go.... |
As pointed out by @story645 on gitter, |
There is a user-contributed matlab subfigure, but it is a window tiler (not something I think we should have ;-) https://www.mathworks.com/matlabcentral/fileexchange/23426-subfigure |
On call we decided that Also noted that need to make sure |
9f6e0e6
to
1dd462d
Compare
7e91ab1
to
5752a94
Compare
Example was expanded. Which was good, because I had a bug in the suptitle placement code.... |
8a73a4b
to
835175b
Compare
@tacaswell Just one main enquiry for you about the compositing of images... Not sure I understood the comment. |
454f97f
to
e373a36
Compare
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.
My review is somewhat cursory and raises only few minor questions.
axsLeft = subfigs[0].subplots(1, 2, sharey=True) | ||
subfigs[0].set_facecolor('0.75') | ||
for ax in axsLeft: | ||
pc = example_plot(ax) |
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.
Indentation is off.
lib/matplotlib/figure.py
Outdated
is used and `.projections.polar.PolarAxes` if polar projection | ||
is used. The returned axes is then a subplot subclass of the | ||
are used and `.projections.polar.PolarAxes` if polar projection | ||
are used. The returned axes is then a subplot subclass of the |
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 "are" instances were correct before as "is".
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.
Thats a strange one. I don't think I changed that. Maybe I missed it in a rebase? Anyhow, fixed....
for examples. (Note: does not work with `add_subplot` or | ||
`~.pyplot.subplot2grid`.) | ||
""" | ||
def __init__(self): | ||
super().__init__() | ||
# remove the non-figure artist _axes property | ||
# as it makes no sense for a figure to be _in_ an axes | ||
# this is used by the property methods in the artist base class | ||
# which are over-ridden in this class |
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 did you leave the comment, but move the deletion to the subclass? Doesn't the deletion make sense as a base class operation?
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.
Agreed. re-added the deletion in the base class and removed it from class Figure
.
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.
It is difficult to find a place to comment on it, but the legend
docstring seems to be missing the Call signatures, the 3 examples of them, and the See Also section.
Thanks @QuLogic - I still have to look at the legend issue, so I'll mark as draft until I sort that out. |
OK think I fixed up legend: https://47262-1385122-gh.circle-artifacts.com/0/doc/build/html/api/figure_api.html#matplotlib.figure.Figure.legend Again, I must have missed that in a rebase... |
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.
Hopefully last round, I think.
def get_size_inches(self): | ||
return self._parent.get_size_inches() | ||
|
||
def get_constrained_layout(self): |
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.
These two could get a docstring, then?
10da45d
to
f542c0b
Compare
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.
One remaining typo.
Co-authored-by: Elliott Sales de Andrade <quantum.analyst@gmail.com>
OK, let's see how this goes... |
Thanks a lot @QuLogic, @efiring and @tacaswell! @QuLogic, hopefully this helps when you make your next all-matplotlib slide deck ;-) |
🎉 I swear reviewing this was on my todo list.... |
PR Summary
This PR re-introduces subfigures:
Subfigures are created via:
fig.subfigures
(likefig.subplots
) andfig.add_subfigure
(likefig.add_subplots
). Before these would have been added withGridspecFromSubgridspec
objects and those objects would not have had the ability to have subtitles, or their own legends.Subfigures are basically figures without the figure management. Anything you can add to a figure you can add to a sub-panel. That required significant refactoring in
figure.py
where all the artist methods infigure.py
are movedFigureBase
, and thenSubFigurel
andFigure
are subclasses.This is relatively major surgery to
figure.py
though the newFigure
class should be exactly the same as the old one.Test Changes:
test_polar.py
: Increased tolerance for two annotation teststest_plot_3d_from_2
: increased tolerance from 0.01 to 0.015.ax=Axes3D(fig)
; previouslyAxes3D.__init__
would add the axes to the figure (which is not an unreasonable expectation, but not one that is supported byAxes
). This caused the axes to be added twice to the figure. So that extrafig.add_axes
has been removed inAxes3D.__init__
and the two tests in the suite that used that grammar were changed to explicitly add the axes:ax=Axes3D(fig); fig.add_axes(ax)
.PR Checklist
subplot_mosaic
?