GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Update colorbar with new colorizer API by trygvrad · Pull Request #30008 · matplotlib/matplotlib

Conversation

@trygvrad

@trygvrad trygvrad commented May 4, 2025

Copy link
Copy Markdown
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 of colorizer.Colorizer and colorizer.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.

Consider this 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 replace cm.ScalarMappable above with colorizer.Colorizer, however, this is currently not possible, and one must instead replace cm.ScalarMappable above with colorizer.ColorizingArtist, which requires a colorizer.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 to self.mappable.get_array() within colorbar.Colorbar().

This PR updates colorbar.colorbar() so that it can accept a colorizer.Colorizer as an alternative to colorizer.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 referencing cm.ScalarMappable to colorizer.ColorizingArtist.
  • Updates colorbar.Colorbar to the new colorizer API by adding .colorizer as a mutable property on a colorbar.Colorbar [this must be mutable as it is mutable for ColorizingArtist 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 a colorbar.Colorbar explicitly immutable.

PR checklist

  • new and changed code is tested
  • [¹] Plotting related features are demonstrated in an example
  • New Features and API Changes are noted with a directive and release note
  • Documentation complies with general and docstring guidelines

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

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@trygvrad
Allow colorbar to accept a colorizer
026e48a
Updates colorbar.colorbar to accept a colorizer.Colorizer object, in addition to colorizer.ColorizingArtist. This commit also changes the docs from referencing cm.ScalarMappable
@github-actions github-actions Bot added topic: color/color & colormaps topic: figures and subfigures labels May 4, 2025
@trygvrad

trygvrad commented May 22, 2025

Copy link
Copy Markdown
Contributor Author

Another example where this PR is relevant is as follows:

import matplotlib.pyplot as plt
import numpy as np

fig, axes = plt.subplots(1, 3, figsize=(8,2))

im0 = axes[0].imshow(np.random.random((5,5)))
colorizer = im0.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)

Untitled

Where a colorizer 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 to https://matplotlib.org/stable/gallery/images_contours_and_fields/multi_image.html , which I will make PR for following this PR)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@timhoffm

timhoffm commented May 22, 2025

Copy link
Copy Markdown
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 use fig.colorbar(im0, ax=axes). This is because there's a skew in that autoscaling is done on the first array only (it's part of imshow(), 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 the colorbar() 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.
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@trygvrad trygvrad mentioned this pull request May 26, 2025
Update to docs with regards to colorbar and colorizer #30112
Merged
1 task done
@trygvrad

trygvrad commented May 26, 2025

Copy link
Copy Markdown
Contributor Author

@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
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@github-actions github-actions Bot added the status: needs rebase label Jun 2, 2025
@QuLogic QuLogic added this to Bivariate and Multivariate Colormapping Aug 26, 2025
@trygvrad trygvrad moved this to In Progress in Bivariate and Multivariate Colormapping Sep 8, 2025
@trygvrad

trygvrad commented Oct 30, 2025

Copy link
Copy Markdown
Contributor Author

I will close this seeing as #30112 was merged

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@trygvrad trygvrad closed this Oct 30, 2025
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Bivariate and Multivariate Colormapping Oct 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

status: needs rebase topic: color/color & colormaps topic: figures and subfigures

Projects

Bivariate and Multivariate Colormapping
Status: Done

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@trygvrad @timhoffm
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.