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
New Feature: Add sub-figure plotting #3343
base: RELEASE_next_minor
Are you sure you want to change the base?
New Feature: Add sub-figure plotting #3343
Conversation
Some other things: We can have multiple signals. Of course both of them respond to the key press events however that is kind of nice I guess in some cases. It might be nice to give the option to pair the two or keep them seperate. %matplotlib ipympl
import matplotlib.pyplot as plt
import hyperspy.api as hs
import numpy as np
rng = np.random.default_rng()
s = hs.signals.Signal2D(rng.random((10,10,10,10)))
s2 = hs.signals.Signal2D(rng.random((11,11,10,10)))
fig = plt.figure(figsize=(8,7))
subfigs = fig.subfigures(2, 2, wspace=0.07)
s.plot(navigator_kwds=dict(fig=subfigs[0,0]), fig=subfigs[0,1])
s2.plot(navigator_kwds=dict(fig=subfigs[1,0]), fig=subfigs[1,1]) Screen.Recording.2024-03-26.at.6.29.56.PM.mov |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## RELEASE_next_minor #3343 +/- ##
======================================================
- Coverage 80.54% 80.53% -0.01%
======================================================
Files 147 147
Lines 21868 21880 +12
Branches 5147 5150 +3
======================================================
+ Hits 17613 17621 +8
- Misses 3037 3042 +5
+ Partials 1218 1217 -1 ☔ View full report in Codecov by Sentry. |
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 wasn't aware of matplotlib.figure.SubFigure
and it seems that this is exactly what we need! This will be very convenient!
- This PR introduce an issue:
s._plot.signal_plot.figure
can now be amatplotlib.figure.SubFigure
instead ofmatplotlib.figure.Figure
this breaks closing figure interactively or programmatically: we need access to thematplotlib.figure.Figure
object:- fix call to
MPL_HyperExplorer.close
when usingSubfigure
- fix on close event figure connection when using
Subfigure
- fix call to
- If there are now issue with events/marker and only matplotlib 3.9 works fine, should we prevent the use of subfigure with matplotlib < 3.9?
- Should we had an option to the preference to enable plotting using subfigure by default (as an experimental feature)?
- good default of aspect ratio of figure will most likely be needed for subfigure
- may be worth adding some
plt.tight_layout
to remove some of the empty space around the subfigure?
examples/plotting/ROI_insets.py
Outdated
navigator.plot(fig=sub1, colorbar=False, axes_off=True, title="", plot_indices=False) | ||
s2.plot(fig=sub2, colorbar=False, axes_off=True, title="", plot_indices=False) | ||
s3.plot(fig=sub3, colorbar=False, axes_off=True, title="", plot_indices=False) | ||
s4.plot(fig=sub4, colorbar=False, axes_off=True, title="", plot_indices=False) |
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 it make sense to make these signals interactive when moving the ROI?
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.
Yea it would make sense. That requires matplotlib==3.9
otherwise you can't move the ROI's :)
@@ -571,6 +573,8 @@ def format_coord(x, y): | |||
# `draw_all` is deprecated in matplotlib 3.6.0 | |||
if Version(matplotlib.__version__) <= Version("3.6.0"): | |||
self._colorbar.draw_all() | |||
elif isinstance(self.figure, SubFigure): | |||
self.figure.canvas.draw_idle() # draw without rendering not supported for sub-figures |
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.
Add a test for this block?
Creating Custom Layouts | ||
======================= | ||
|
||
Custom layouts for hyperspy figures can be created using the `matplotlib.figure.SubFigure` class. Passing |
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.
Custom layouts for hyperspy figures can be created using the `matplotlib.figure.SubFigure` class. Passing | |
Custom layouts for hyperspy figures can be created using the :class:`matplotlib.figure.SubFigure` class. Passing |
========== | ||
|
||
ROI's can be powerful tools to help visualize data. In this case we will define ROI's in hyperspy, sum | ||
the data within the ROI, and then plot the sum as a signal. Using the `matplotlib.figure.SubFigure` 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.
the data within the ROI, and then plot the sum as a signal. Using the `matplotlib.figure.SubFigure` class | |
the data within the ROI, and then plot the sum as a signal. Using the :class:`matplotlib.figure.SubFigure` class |
gs = fig.add_gridspec(6, 10) | ||
sub1 = fig.add_subfigure(gs[0:6, 0:6]) | ||
sub2 = fig.add_subfigure(gs[0:2, 6:8]) | ||
sub3 = fig.add_subfigure(gs[2:4, 7:9]) | ||
sub4 = fig.add_subfigure(gs[4:6, 6:8]) |
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.
Simplify the grid to make easier to understand (and also when looking at the image, the reason for this layout is not obvious)?
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.
@ericpre that is a good point. I might have to play around with this one slightly and make some fake data. I use something like this to show average diffraction patterns from ROI's in real space.
Here's a gif which is similar to the second example.
Making Custom Layouts for Plots | ||
=============================== |
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.
Wondering if this is not too specific?
Making Custom Layouts for Plots | |
=============================== | |
Data visualization | |
================== |
To make the corresponding heading in the user guide?
@ericpre I just realized this the other day using this. Apparently, I never tried to replot anything.
This issue is that you can't drag the navigator. Markers still work but it also causes issues with interactive ROIs. I still think this is useful for figure composition without that interactivity but it would be good to throw a warning that if you want to use subfigures you are going to be happier with matplotlib 3.9.
I think that would be great. I'm sure there are a lot of people interested in this feature as it's one of the more commonly requested ones.
Yea that was something we could play around with.
It might be a good default behavior to have |
@ericpre the closing is a bit more complicated and I wonder what the best way to do that is? We can create a new class which allows you to wrap the |
I suspect that they may be two options:
I would go for the second one because it should be simple. The first one will need a refactor which (as far as I understand) will bring any significant benefit. Do you want me to make a PR to this branch to try to fix the close event business? One thing that I didn't check (and don't know off the top of my head): how does using subfigures impact the plotting performance? With backend supporting blitting, most likely not that much, because only the relevant part of the figure redrawn but for other backend, the size/number of elements in the figure to redraw may end up being typically 2x larger? |
You can give it a shot if you want. I'm not sure that I completely follow the |
The current logic on closing figure is:
The issue with subfigure is that the logic will run for all of them and it is not obvious how to close the matplotlib figure. As you said, maybe we need a separate Figure class to handle the "main" closing loop separately from the SubFigure! 😄 |
@CSSFrancis, the close event should be sorted now. Instead of tight_layout, we should use constrained layout, because tight_layout has shortcomings: colorbar is ignored and label get cropped or overlap when changing the figure size, etc.) Adapting one of your example: import hyperspy.api as hs
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng()
s = hs.signals.Signal2D(rng.random((100, 100, 100)))
fig = plt.figure(figsize=(15, 7), layout="constrained")
subfigs = fig.subfigures(1, 2)
s.plot(
navigator_kwds=dict(fig=subfigs[0]),
fig=subfigs[1],
) Matplotlib 3.9rc2 has been released yesterday, it would be good to make the example interactive as discussed above with a warning if matplotlib <3.9 is installed. |
@ericpre Thank you for doing that! I can look into the interactive example later tonight and the warning with matplotlib 3.9 unless you want to do that. |
436db30
to
570bb41
Compare
See matplotlib/matplotlib#28177 for getting the matplotlib figure or subfigure. |
Description of the change
This is still a fairly new
matplotlib
feature and still Provisional but I think there is/ will be a fair bit of ongoing support for it as many people are interested in this.Additionally picking and dragging the marker isn't supported until matplotlib 3.9 (matplotlib/matplotlib#27343) and the
draw_without_rendering
function isn't supported which causes a small bug related to the color bar. Replacing withdraw_idle
works fine though.I think this is ultimately (going to be) a better choice than the previous horizontal plotting option but there are still some bugs related to it.
A few sentences and/or a bulleted list to describe and motivate the change:
fig
when plotting to specify a figure outputProgress of the PR
upcoming_changes
folder (seeupcoming_changes/README.rst
),readthedocs
doc build of this PR (link in github checks)Minimal example of the bug fix or the new feature