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

Update colorbar with new colorizer API#30008

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
trygvrad wants to merge1 commit intomatplotlib:main
base:main
Choose a base branch
Loading
fromtrygvrad:colorbar-with-colorizer

Conversation

trygvrad
Copy link
Contributor

Updates colorbar.colorbar to accept a colorizer.Colorizer object, in addition to colorizer.ColorizingArtist. This commit also changes the docs from referencing cm.ScalarMappable to referencing colorizer.ColorizingArtist.

PR summary

With the introduction ofcolorizer.Colorizer andcolorizer.ColorizingArtist (#28658) we have separated the norm→color pipeline from the artist. However, the colorbar API has not been updated since these changes took effect.

Considerthis example:

fig, ax = plt.subplots(figsize=(6, 1), layout='constrained')norm = mpl.colors.Normalize(vmin=5, vmax=10)fig.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap='cool'),             cax=ax, orientation='horizontal', label='Some Units')

image

With the new colorizer API, one would expect be able to replacecm.ScalarMappable above withcolorizer.Colorizer, however, this is currently not possible, and one must instead replacecm.ScalarMappable above withcolorizer.ColorizingArtist, which requires acolorizer.Colorizer as input.

fig.colorbar(mpl.colorizer.ColorizingArtist(mpl.colorizer.Colorizer(norm=norm,cmap='cool')),cax=ax,orientation='horizontal',label='Some Units')

This is despite the fact that the norm→color pipeline is entirely contained in the colorizer, and it fails only because of a single call toself.mappable.get_array() withincolorbar.Colorbar().

This PR updatescolorbar.colorbar() so that it can accept acolorizer.Colorizer as an alternative tocolorizer.ColorizingArtist.

fig.colorbar(mpl.colorizer.Colorizer(norm=norm,cmap='cool'),cax=ax,orientation='horizontal',label='Some Units')

The following additional changes are included in this PR:

  • Changes the docs from referencingcm.ScalarMappable tocolorizer.ColorizingArtist.
  • Updatescolorbar.Colorbar to the new colorizer API by adding.colorizer as a mutable property on acolorbar.Colorbar [this must be mutable as it is mutable forColorizingArtist and when it changes on the artist it must change on the colorbar]
  • makes the.norm and.cmap of a colorbar properties that get the relevant property from the colorizer. This also makes the explicitly immutable.
  • makes the.mappable on acolorbar.Colorbar explicitly immutable.

PR checklist

¹ I would like to updatehttps://matplotlib.org/stable/users/explain/colors/colorbar_only.html andhttps://matplotlib.org/stable/gallery/images_contours_and_fields/multi_image.html but I think that would benefit from having this PR be implemented first.

Updates colorbar.colorbar to accept a colorizer.Colorizer object, in addition to colorizer.ColorizingArtist. This commit also changes the docs from referencing cm.ScalarMappable
@trygvrad
Copy link
ContributorAuthor

Another example where this PR is relevant is as follows:

importmatplotlib.pyplotaspltimportnumpyasnpfig,axes=plt.subplots(1,3,figsize=(8,2))im0=axes[0].imshow(np.random.random((5,5)))colorizer=im0.colorizeraxes[1].imshow(2*np.random.random((5,5)),colorizer=colorizer)axes[2].imshow(0.5*np.random.random((5,5)),colorizer=colorizer)fig.colorbar(colorizer,ax=axes)

Untitled

Where acolorizer object is used to synchronize the cmap+norm of all subplots, and in that case it follows naturally that the colorizer object should also be the input for the colorbar.

(This is similar tohttps://matplotlib.org/stable/gallery/images_contours_and_fields/multi_image.html , which I will make PR for following this PR)

@timhoffm
Copy link
Member

Just to be sure: Is this correct? - Previously colorbar must reference a ScalarMappable. If norm limits were not fixed, we use the ScalarMappable's data (if available) to autoscale, i.e. fix norm limits). The Colorizer now behaves like a scalar mappable without data.

I'm not yet 100% convinced, we need colorbars to accept colorizers right now.

  • Advantage: You can create a bare colorbar without the need for a "dummy" mappable. - But how often do you need this?
  • Disadvantage: The API and code becomes a little less clean because you allow different types.
  • I'm torn on the shared colorizer example. It's fundamentally desirable that you can share a colorizer. - But I would say we are not really sharing, we are re-using. Technically, the example will have the same result if you usefig.colorbar(im0, ax=axes). This is because there's a skew in that autoscaling is done on the first array only (it's part ofimshow(), which calls,im._scale_norm()). Passing the colorizer gives a false impression/desire that the colorbar does not specifically reflect the first data.
    I think accepting a colorbar primarily makes sense if we could get this to take into account all data:
    colorizer = mpl.colorizer.Colorizer()axes[0].imshow(np.random.random((5,5)), colorizer=colorizer)axes[1].imshow(2 * np.random.random((5,5)), colorizer=colorizer)axes[2].imshow(0.5 * np.random.random((5,5)), colorizer=colorizer)fig.colorbar(colorizer, ax=axes)
    But that's difficult. You cannot fix the scale in the fist imshow. But you also cannot defer to thecolorbar() call because we don't have the data there. The only way I see would be a rearchitecting that norms could "collect" autoscaling i.e. unless fixed by some event, they would expand their range. Though I suspect that has its own set of problems.
    Unless we can get there, I'm not sure accepting a colorizer is a real advantage.

@trygvrad
Copy link
ContributorAuthor

@timhoffm Thank you for considering this.

While I would of course have like to see this included, I cannot fault the logic leading you to the conclusion that this is not required.

In light of this, I have opened a new PR here, which simply updates the examples and documentation, but makes no changes to the API:#30112


Regarding auto-setting the norm, I am not convinced that it is worthwhile to seek a new solution here when multiple subplots are used, as I believe that best use is to set the limits manually, as is done in the example in the docs:https://matplotlib.org/stable/gallery/images_contours_and_fields/multi_image.html

norm = colors.Normalize(vmin=np.min(datasets), vmax=np.max(datasets))...

And we are better served by steering users to that solution rather than complicating the default behavior.

My opinion on this matter is informed by the fact that I find the auto-scaler to be fine for prototyping, but whenever I need to make a publication-quality or complicated figure, I find that I have to manually set the limits anyways. (i.e. the autoscaler sets limits to 0.007373 to 0.99633 when 0 and 1 and much more reasonable limits.) The convenience of the auto-scaler is great for simple plots, but once I have multiple plots that need to share a colorbar, I would argue that it is no longer a simple plot and the user can be expected to know how to set the limits according to their needs.

timhoffm reacted with thumbs up emoji

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers
No reviews
Assignees
No one assigned
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

2 participants
@trygvrad@timhoffm

[8]ページ先頭

©2009-2025 Movatter.jp