Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

BUG: fix normalizing image data contained in np.ndarray subclass#27682

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
neutrinoceros wants to merge1 commit intomatplotlib:main
base:main
Choose a base branch
Loading
fromneutrinoceros:robust_lim_comparison

Conversation

neutrinoceros
Copy link
Contributor

PR summary

This fixes a downstream issue with plotting data from aastropy.units.Quantity object (which derives fromnp.ndarray), namelyastropy/astropy#11306

Although the external issue was also linked to#19476, this patch doesnot fix that problem.
As a result, I am unsure how to write a test for the astropy bug here, though I could easily add a test in astropy itself (which is regularily tested against matplotlib dev).

PR checklist

@story645
Copy link
Member

story645 commentedJan 22, 2024
edited
Loading

As a result, I am unsure how to write a test for the astropy bug here, though I could easily add a test in astropy itself (which is regularily tested against matplotlib dev).

Can you create a fake unit that mimics the astropy behavior? Something like a very thin wrapper over nd.array that triggers the error but is fixed here? Something like#26953

@neutrinoceros
Copy link
ContributorAuthor

Thank you for your suggestion ! I wasn't able to construct such a mock with a bottom-up approach (build one from the ground up), supposedly because of the sheer complexity ofastropy.units.Quantity, so I'm now trying a top-down approach (take astropy and iteratively remove parts that don't play a role in the error). It's taking a while but I'm getting there.

story645 reacted with heart emoji

@story645
Copy link
Member

so I'm now trying a top-down approach (take astropy and iteratively remove parts that don't play a role in the error). It's taking a while but I'm getting there.

Is much appreciated since that helps us better understand what's going wonky here.

@neutrinoceros
Copy link
ContributorAuthor

Ok I think it's now ready for review.

@neutrinocerosneutrinoceros marked this pull request as ready for reviewJanuary 22, 2024 19:57
@pllim
Copy link

Thanks!

Re: mocking astropy.units.Quantity --@mhvk can double check if needed.

@rcomer
Copy link
Member

Apologies for asking this several hours late, but are either of these relevant here?


classQuantityND(np.ndarray):

story645 reacted with thumbs up emoji

@pllim
Copy link

@rcomer , not sure. I tracked that to#9049 and onlypint was mentioned, notastropy.units.

rcomer reacted with thumbs up emoji

@pllim
Copy link

And the second one to#18286 that mentionedunyt and notastropy.units.

@neutrinoceros
Copy link
ContributorAuthor

@rcomer Indeed these classes will not reproduce the issue we're currently seeing withastropy.units.Quantity. I think I may have used too broad a title for this PR, but it's really about some corner case specific toastropy.units.Quantity. For instance,astropy.units.Quantity intentionally overrides thendarray.item method so that it doesn't return numerical scalars, but if I removedef item(...) from my reduced mock, the test passes without a patch.

rcomer and story645 reacted with thumbs up emoji

Copy link
Contributor

@mhvkmhvk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Certainly looks like a reasonable mock-up ofQuantity!

@@ -461,12 +461,12 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
vmid = np.float64(self.norm.vmin) + dv / 2
fact = 1e7 if scaled_dtype == np.float64 else 1e4
newmin = vmid - dv * fact
if newmin < a_min:
if newmin <np.float64(a_min):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'd maybe do this just below whereA itself is converted to a plain array, ie.,

A_scaled = np.array(A, dtype=scaled_dtype)a_min = np.float64(a_min)a_max = np.float64(a_max)

(Arguably,scaled_dtype.type might be more logical thannp.float64, but then one should adjust other things too)

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

done

@story645
Copy link
Member

but if I remove def item(...) from my reduced mock, the test passes without a patch.

Can you add a comment that that's the important bit?

@neutrinoceros
Copy link
ContributorAuthor

Actually I thinkevery part of the mock class is crucial to reproduce the problem, should I really comment all of them ?
In the real-life use case (withastropy.units.Quantity), the error we see is raised throughthree nestedtry/except blocks 🙃

@story645
Copy link
Member

In the real-life use case (with astropy.units.Quantity), the error we see is raised through three nested try/except blocks

😬 No, if it's a combination of the things then yeah it doesn't need a specific comment.

@dstansby
Copy link
Member

I've been trying to understand what's going on here. It seems:

  • _make_image(A, ...) is givenA as a unitful array
  • a_min = A.min() /a_max = A.max() therefore have units
  • so the fix in this PR is to just strip the units by callingnp.float64

I think the better long term fix here is to add proper support for the image data to have units in the_ImageBase class. This would provide a path to solving other bugs and feature requests around images with units, e.g.#25062,#19476.

So it's unclear to me whether it's worth merging this PR as a bit of a stopgap fix, or whether we should be aiming to add proper support for unitful data in_ImageBase instead. It would be good to hear what@ksunden thinks on this front from a Matplotlib/units point of view?

@dstansby
Copy link
Member

dstansby commentedJan 24, 2024
edited
Loading

As a quick proof of concept, the following diff fixes the original issue, also allows mousing over the data to work (that's still broken with this PR), and opens the door to further improvements like labelling the colorbar with the units.

diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.pyindex e326906269..88325a59ed 100644--- a/lib/matplotlib/image.py+++ b/lib/matplotlib/image.py@@ -26,6 +26,7 @@ import matplotlib.colors as mcolors from matplotlib.transforms import (     Affine2D, BboxBase, Bbox, BboxTransform, BboxTransformTo,     IdentityTransform, TransformedBbox)+import matplotlib.units as munits  _log = logging.getLogger(__name__)@@ -724,6 +725,13 @@ class _ImageBase(martist.Artist, cm.ScalarMappable):         ----------         A : array-like or `PIL.Image.Image`         """+        converter = munits.registry.get_converter(A)+        if converter is not None:+            self._units = converter.default_units(A, self)+            A = converter.convert(A, self._units, self)+        else:+            self._units = None+         if isinstance(A, PIL.Image.Image):             A = pil_to_array(A)  # Needed e.g. to apply png palette.         self._A = self._normalize_image_array(A)

It does have the issue that the last arguments to the converter methods are meant to be of typeAxis and not_ImageBase though, but in reality I'm not sure that's a huge issue...

@neutrinoceros
Copy link
ContributorAuthor

Happy to drop this PR in favour of a better fix if needed !

@jklymak
Copy link
Member

We don't have converter logic for data passed to color mapping. Folks are asked to pass a numpy array to scalar mappables. Maybe its OK to normalize those mappable to so something without units earlier, but I don't know that we have enough infrastructure in place to actually use unit converters here.

@story645
Copy link
Member

story645 commentedJan 25, 2024
edited
Loading

but I don't know that we have enough infrastructure in place to actually use unit converters here.

I still think that throwing a convertor on NoNorm (or possibly writing aUnitNorm() if we want to avoid any magic) might do the trick?

I think the complicated part has always been propagating the correct labels back to the colorbar.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@mhvkmhvkmhvk left review comments

At least 1 approving review is required to merge this pull request.

Assignees
No one assigned
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

7 participants
@neutrinoceros@story645@pllim@rcomer@dstansby@jklymak@mhvk

[8]ページ先頭

©2009-2025 Movatter.jp