-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Allow unit-ful ScalarMappable data #20962
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
Fixes matplotlib#20516 PGF's `random steps` decoration seems to be the most similar, but does not exactly match the behaviour described in matplotlib's docs. Therefore I repurposed the `randomness` argument as a seed to give control on how the line looks afterwards.
Co-authored-by: Elliott Sales de Andrade <[email protected]>
Switch documented deprecations in mathtext by `__getattr__` deprecations
Co-authored-by: Tim Hoffmann <[email protected]>
…_output API: rename draw_no_output to draw_without_rendering
Make warning for no-handles legend more explicit.
Remove unused HostAxes._get_legend_handles.
Redirect to new 3rd party packages page
legend_handler_map cleanups.
Clean up some Event class docs.
- parse() already normalizes prop=None to prop=FontProperties(). - We don't need to explicitly attach a canvas to a plain Figure() before calling savefig() anymore; FigureCanvasBase is always attached and handles the dispatching to the correct concrete canvas class.
d7f73ab
to
6d6db91
Compare
6d6db91
to
a142369
Compare
lib/matplotlib/image.py
Outdated
@@ -733,6 +735,31 @@ def set_data(self, A): | |||
self._rgbacache = None | |||
self.stale = True | |||
|
|||
def _convert_units(self, A): | |||
# Take the first element since units expects a 1D sequence, not 2D | |||
converter = munits.registry.get_converter(A[0]) |
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.
We probably want to stash the converter the first time 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.
Makes sense. It does raise the question of making converter immutable once it has been set once (ie. the first time set_data()
is called). Should this be the case, or should we provide a method to manually change the converter after a set_data()
call?
This required fewer changes than I had naively expected :) |
99c8151
to
d0c3a62
Compare
If I pass a mappable with units "mega-joules" and another to the same axes with units "giga-joules" and they use the same norm, what happens? I would expect they would be converted to the same units, and plotted comparably. I don't think that happens here... If that doesn't happen, then I'm not clear what I am gaining from unit support, and I should just strip the bare array. |
Good point - can you write some (pseudo-)code that does what you're describing? More specifically how you're adding those two mappables to the Axes, and how you're getting them to share a norm (or a colorbar). I may be wrong, but I don't think we have the concept of two mappables sharing a norm or colorbar at the moment? |
The point is that if they are not sharing the norm or colorbar, what is the advantage of dealing with the units versus just stripping the values out of the container? Just formatting the colorbar? |
Yes, I think that's correct. |
Currently we use units to format axises for datetime and categorical. Are there other uses? I can maybe see it being nice to format a colorbar with datetime, though I am skeptical. What are the other use cases you envision for this? |
Why are you skeptical? Is it not a good new feature to have colorbar ticks automatically formatted and located for data with units? |
I am skeptical because units do not currently work as advertised for univariate axes, and here they only work in the restricted sense of formatting the axes with no design for unit conversion of the scalars. I am also concerned because the new ability of colorbars to behave like other axes is very new, and this will definitely stress the new behaviour. If you look on Stackoverflow, unit conversion, particularly for categoricals (but datetime is a close second), is one of the leading sources of confusion. I think we should be very cautious about adding to the unit API. |
Can you expand a bit on this? I'm not sure I follow
As I said above, I don't think this is an issue because we don't have the concept of two mappables sharing a norm or colorbar at the moment. Do you want to block this PR on adding support for two mappables sharing a colorbar? |
The original goal was that you could pass (104, 'cm') and (72, 'inches') to an axis, set its units to ('m') and the data would be plotted at 1.04 and 1.83. There is an example to this effect and it does not work. The dream was also that you could eventually change the axis units to 'cubits' and that would also convert the data. Fixing this was supposed to be something done with the CZI support, but I'm not sure if the work ended up going that way.
I often have one colorbar representing many mappables, usually in different axes. They don't "share" the colorbar in code, because we don't do that, but they do share the colorbar conceptually. |
It seems to work for me (albeit with an external units library): import astropy.units as u
from astropy.visualization import quantity_support
import numpy as np
import matplotlib.pyplot as plt
quantity_support()
x = np.arange(10)
y_rad = np.linspace(0, 2 * np.pi, 10) * u.rad
y_deg = np.linspace(0, 180, 10) * u.deg
fig, ax = plt.subplots()
ax.scatter(x, y_rad)
ax.scatter(x, y_deg)
# ax.xaxis.set_units(u.deg) # This doesn't work
plt.show() Changing the units does not though...
Right, but you have to manually make sure that all your data is comparable and have to manually ensure they're plotted with the same norm and colormap, and then add a colorbar from a single mappable, so something like: norm = Norm(vmin=vmin, vmax=vmax)
cmap = cmap
im1 = ax1.imshow(data1, norm=norm, cmap=cmap)
im2 = ax2.imshow(data2, norm=norm, cmap=cmap)
fig.colorbar(im2)
As it stands with this PR the behaviour is exactly the same, ie. you would have to manually make sure multiple scalarmappables are scaled correctly for one colorbar. I think what you're getting at (please correct me if I'm wrong!) is having an API like: cbar = fig.colobar(norm=Norm(vmin, vmax), cmap=cmap)
im1 = ax1.imshow(data1, colobar=cbar)
im2 = ax2.imshow(data2, colobar=cbar) and units/vmin/vmax being taken into account by the colorbar correctly? I think this would be an awesome API, and am +/-0 blocking this PR on such an API existing (if it's desirable). So I'm happy to put this PR on hold, but I think it is a nice new feature, and want to be sure there's good reasons for putting it on hold. |
Don't put on hold just because of my skepticism! I think we were hoping to discuss last week during the meeting. I imagine we can take a look at it this week if you want a definitive decision. Happy to wait for a week when you can attend, or maybe some other core devs are interested in weighing in on the feature's behalf. |
There's definitely no rush - I'll try and come along to the meeting this week though, thanks for the heads up! |
This PR is affected by a re-writing of our history to remove a large number of accidentally committed files see discourse for details. To recover this PR it will need be rebased onto the new default branch (main). There are several ways to accomplish this, but we recommend (assuming that you call the matplotlib/matplotlib remote git remote update
git checkout main
git merge --ff-only upstream/main
git checkout YOUR_BRANCH
git rebase --onto=main upstream/old_master
# git rebase -i main # if you prefer
git push --force-with-lease # assuming you are tracking your branch If you do not feel comfortable doing this or need any help please reach out to any of the Matplotlib developers. We can either help you with the process or do it for you. Thank you for your contributions to Matplotlib and sorry for the inconvenience. |
@dstansby let us know if/when you can make a meeting to discuss this. If you can't make it, let us know and we can try and discuss without you |
@dstansby this needs a rebase so I moved to drafts.... |
@jklymak thanks - I don't have any bandwidth to pick this back up and discuss it in the near future, so if anyone else wants to take it up feel free. |
We discussed this on the call last week, and should discuss again. However, I will give my screed about categoricals: My point being that I strongly feel people should have to manually opt in to categorical plotting. I actually think they should have to manually opt into any unit handling, including dates ( For expanding categoricals into scalar mappables, I'm fine with the feature, but I think if we just do it via object inspection, folks will end up not understanding what has happened to their data, and will again think Matplotlib is broken. In my opinion this API should be accompanied by some way of manually opting in. |
PR Summary
Allows 2D data with units attached to be used by
imshow
. Fixes #19476, and supersedes #19481.PR Checklist
pytest
passes).flake8
on changed files to check).flake8-docstrings
and runflake8 --docstring-convention=all
).doc/users/next_whats_new/
(follow instructions in README.rst there).doc/api/next_api_changes/
(follow instructions in README.rst there).