-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Adding subfigure_mosaic #26061
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
base: main
Are you sure you want to change the base?
Adding subfigure_mosaic #26061
Conversation
I have a question about **kwargs. Am I correct in thinking that we should be using that in |
I think what you have done makes sense. |
@rcomer Thank you for answering! def subfigure_mosaic(self, mosaic, **kwargs):
ret = self._sub_prep(mosaic, self.add_subfigure, kwargs) instead of what is currently happening. But the definition of |
lib/matplotlib/figure.py
Outdated
} | ||
|
||
per_subplot_kw = self._norm_per_subplot_kw(per_subplot_kw) | ||
per_subthing_kw = self._norm_per_subplot_kw(per_subthing_kw) |
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.
Does this normalization also need to be changed?
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.
Do you mean changing the name to _norm_per_subthing_kw
or changing the internal implementation? I checked and it seems to be working both for add_subplot_mosaic
and add_subfigure_mosaic
.
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.
ah, just went and checked the source, this is a class method that is making sure that the multiple ways to reference a sub-object do not end up trying to address a given element more than once.
The classmethod needs a better name (I named it and the current name is....bad), maybe _check_for_subthing_kw_conflicts
?
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 first thought was _flatten_subthing_kw
but your version sounds more descriptive of what the method's actually being used for. Should I go ahead and change it to 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.
flatten
is also pretty good (maybe better). In general, the prior should be "Tom is bad at naming things".
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.
Is something like _check_duplication_and_flatten_subthing_kw
too long?
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 an internal method, so no ;)
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.
Got you :) I'll change it to that if you're ok with it, then.
Edit: this was two symbols too long for flake8, so I renamed it to _check_duplication_and_flatten_kwargs
The reason we do not use Currently |
It looks like the mosaic tests all passed so that is a good sign! |
Code is looking good, now it needs docs, examples and whats new :) @turnipseason What are the odds of you having time to get this done in the next two weeks? We are getting ready for the 3.8 release and it would be great to get this in for that! |
@tacaswell I've been a bit busy the past week but now I think I will have the time to do this! |
@tacaswell Hi! I've been trying to write small examples and discovered some problems.
inner = [ ["inner A"], ["inner B"], ]
outer_nested_mosaic = [["main", inner], ["bottom", "bottom"],]
axda = plt.figure(layout="constrained").subfigure_mosaic(outer_nested_mosaic) This (with some keywords for clarity + identify_axes) gives us: Is this expected? Should I try to fix this behavior or just write into the docs that it shouldn't be used like that?
|
Please try to fix this or make it error in this case
|
This look related to this PR. |
|
||
This is a helper function to build complex GridSpec layouts visually. | ||
|
||
See :doc:`/gallery/subplots_axes_and_figures/subfig_mosaic` |
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.
This does not appear to have been added?
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.
Yes, I haven't added the example yet. Working on it, though!
lib/matplotlib/figure.py
Outdated
# separate SubFigures for nested layouts, | ||
# otherwise they will all create without nesting. | ||
subfigs_for_nested = {} | ||
if sub_add_func.__name__ == 'add_subfigure': |
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.
Checking the name of a passed in method is generally a bad sign!
To understand the problem here it is that when there are nested sub figures we need to switch which (sub) figures add_subfigure
we pass down through?
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.
Essentially, yes. I wanted to keep track of all of the nested figures (in any 'level' of nesting) with the subfigs_for_nested
dictionary, so that later on I could assign the correct nested figures their parent 'dummy' figure (and they got positioned correctly). Since subplot_mosaic
worked just fine with nesting already, I did this.
lib/matplotlib/figure.py
Outdated
@@ -2084,7 +2062,9 @@ def _do_layout(gs, mosaic, unique_ids, nested): | |||
nested_output = _do_layout( | |||
gs[j, k].subgridspec(rows, cols), | |||
nested_mosaic, | |||
*_identify_keys_and_nested(nested_mosaic) | |||
*_identify_keys_and_nested(nested_mosaic), | |||
sub_add_func, |
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.
If you did this as
subadd_func if subfigs_for_nested.get(key) is None else subfigs_for_nested[key].add_subfigure:
then you would still only need to pass one piece of information into the recursive call
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.
Ok, I think I see what you mean. I changed it to what you suggested, plus the internal code for the _get_subfigs_from_nested
and it seems to work. I'll test it a bit more and amend the PR if it looks good. Thank you!
|
||
A visual layout of how you want your Axes to be arranged | ||
labeled as strings. For example :: | ||
sub_add_func : `.Figure.add_subplot` for `.Figure.subplot_mosaic` and |
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.
ok, so I think the fix to this nested figure problem is to change the signature sub_add_func
. The input should stay the same, but the return should be the returned thing and the next sub_add_func
to use.
For axes it would be
def _add_func(*args, **kwargs):
return self.add_subplot(*args, **kwargs), _add_func
return self._sub_prec(mosaic, _add_func, ...)
and for subfigures it would be a bit fancier like
def _factory(fig):
def _add_sub_func(*arg, **kwargs):
new_fig = fig.add_subfigure(*args, **kwargs)
return new_fig, _factory(new_fig)
return self._sub_prec(mosaic, _factory(self), ...)
and then where you call it it would be
new_thing, sub_add_func = sub_add_func(....)
That way we do not have to special case anything in the _sub_prep
code or have the awkward sometimes we use one input sometimes we use the other behavior on the internal API.
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 also have not tried this code so it is probably only 90% correct, but I am pretty confident it is pointing in the right direction.
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.
Just to not leave this unanswered after my previous comments elsewhere - this will definitely require some thought. Sorry I can't do it right away, but I'll get on it in the morning and, hopefully, make it work :)
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.
"recursion" is called that because you curse it again and again.....
sf.set_linewidth(2.1) | ||
identify_subfigs(subfigs) | ||
|
||
# %% |
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 subplot_mosaic example also has a version of this using gridspec_kw. But for subfigures the following analogous code:
mosaic = """AA
BC"""
fig = plt.figure()
subfigs = fig.subfigure_mosaic(
mosaic,
subfigure_kw={'edgecolor':'black','linewidth':2},
gridspec_kw={
"bottom": 0.25,
"top": 0.95,
"left": 0.1,
"right": 0.5,
"wspace": 0.5,
"hspace": 0.5,
},
)
identify_subfigs(subfigs)
subfigs = fig.subfigure_mosaic(
mosaic,
subfigure_kw={'edgecolor':'black','linewidth':2},
gridspec_kw={
"bottom": 0.05,
"top": 0.75,
"left": 0.5,
"right": 1,
"wspace": 0.5,
"hspace": 0.5,
},
)
identify_subfigs(subfigs)
gives this:
when it should look like this:
So the only gridspec_kws that are actually being taken into account (if specified) are width/height ratios.
1e3b3e7
to
7c450a2
Compare
I took the liberty of rebasing this again + a few little fix ups at it seems to work. |
…e method subfigure_mosaic, added a method for both of them to use.
fb45567
to
9f8563e
Compare
I thought I was going to need |
PR summary
Resolves #25949
Made initial changes:
subplot_mosaic
_sub_prep
method that contains thesubplot_mosaic
logicsubfigure_mosaic
Still needs to be done:
PR checklist