Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork8.1k
VectorMappable with data type objects#28428
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
Uh oh!
There was an error while loading.Please reload this page.
Conversation
story645 commentedJun 27, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
attn@timhoffm, can you take a quick skim to see if this is a reasonable API and plan/share any concerns? |
timhoffm commentedJun 28, 2024
trygvrad commentedJun 28, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I rebased this code so that it correctly builds on#28454 |
8ae3a0d to6fb5884Compare6fb5884 toe889929Comparee889929 to81181c9Comparetimhoffm commentedJul 9, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
The current scalar mapping works like this. How do VectorMappable and the new colormap types change the picture? Edit: I think the OP is sufficient. I‘ll have a closer look. |
81181c9 tof11c3bfComparetrygvrad commentedJul 9, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
The This PR does not contain changes to the plotting methods, but it is intended to go something like this. classAxes:defpcolor(self,data,cmap=None,norm=None,vmin=None,vmax=None):cmap=colors._ensure_cmap(cmap)data,norm,vmin,vmax=colors._ensure_multivariate_params(cmap.n_variates,data,norm,vmin,vmax) Which transforms *I prefer an input signature of (cmap.n_variates, n, m) for multivariate data, but we could use (n, m, cmap.n_variates) instead. Edit:@timhoffm Thank you for taking a look, I didn't see your edit before I made the additional figure :D |
timhoffm commentedJul 11, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
trygvrad commentedJul 11, 2024
It is not quite clear to me what the distinction between between the Having a
The alternative, as this PR suggests, is by simply attaching a list of norms to However, (all of) you are more experienced to evaluate what makes code more easy to maintain than I am, and if you think a
I have been thinking we need to determine how the equivalent to
To me, the intuitive behavior has always been that each axis has a separate norm: ax.imshow((A,B),cmap='BiOrangeBlue')# orax.imshow((A,B),cmap='BiOrangeBlue',norm='LogNorm') should give two separate norms with independent limits. I further believe that the intuitive action for a user to take if they want identical limits on both axis is to simply set the limits: ax.imshow((A,B),cmap='BiOrangeBlue',vmin=-1,vmax=2) However, advanced users might want the behavior you describe above, a shared norm, and we should therefore support the following: n=mpl.colors.Normalize()ax.imshow((A,B),cmap='BiOrangeBlue',norm=(n,n)) Where both axis are explicitly declared to have the same norm. n=mpl.colors.Normalize()norm.vmin=np.min((A,B))norm.vmax=np.max((A,B))ax.imshow((A,B),cmap='BiOrangeBlue',norm=(n,n)) NOTE: I made acommit this morning that explicitly forbids the call following call signature: n=mpl.colors.Normalize()ax.imshow((A,B),cmap='BiOrangeBlue',norm=n)# → ValuError('When using a colormap with more than one variate, norm must be None,# a valid string, a sequence of strings, or a sequence of mpl.Colors.Normalize objects.' because it I found it unclear if this should be a shared norm (shared limits) or if the norm should be duplicated (independent limits), and I believe we should only accept input where the users intent is clear. @timhoffm As I understand it, the weekly development meeting today is cancelled, but I will try to be there next week. |
timhoffm commentedJul 11, 2024
Thanks for the detailed answer, I'll have a closer look later. Re: 3. Multiple mappables with one colorbar: |
trygvrad commentedJul 11, 2024
I took a look, and the norm now seems to connect automatically, but you still need to manually connect the images before you swap out the colormap. If we made a 'Mappable' class, we could definitely simplify this, by having a single object that holds the norm+colormap for all images in the example above. I imagine this class would then handle everything that deals with the data→norm→colormap transform, i.e. I think you are right that if we want to implement this, it would be a good idea to bundle it with this PR. Personally I would suggest nac=mpl.cm.NormAndColor(norm='LogNorm',cmap='Viridis')ax[0].imshow(A,norm=nac)ax[1].imshow(B,norm=nac) If this rhymes with what you are thinking, I'll take a look at implementing it. |
story645 commentedJul 11, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Maybe the usecase in#19515 (by@greglucas ) of choosing vmin and vmax, which I've often done that based on histograms so a linked zoom on histogram and update vmin and vmax w/ the corresponding values. Also just to make sure I'm on the same page, I'm interpreting the figures above as: And now I'm wondering where one of the use cases I was originally thinking of fits: ETA: nvariate is also weird cause it could maybe work w/ scalermappables and the hard part is it knowing how to input match. And yes these all have the same top level signature: |
trygvrad commentedJul 11, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@story645 The PR as it stands works like this: as you say it does not support:
When I was talking about a coupled norm, I was thinking of norms that take two arguments, i.e. If we want to introduce norms that take two arguments, we definitely need a EDIT: I'll take a look at implementing a |
trygvrad commentedJul 12, 2024
I took a crack at implementing a importmatplotlibmatplotlib.use('qtagg')importmatplotlib.pyplotaspltimportnumpyasnpnp.random.seed(19680801)data=np.linspace(0.1,0.6,6)[:,np.newaxis,np.newaxis]*np.random.rand(6,10,20)nac=matplotlib.cm.NormAndColor()nac.vmin=np.min(data)nac.vmax=np.max(data)fig,axs=plt.subplots(2,3)fig.suptitle('Multiple images')fori,axinenumerate(axs.ravel()):im=ax.imshow(data[i],norm=nac)ax.label_outer()cb=fig.colorbar(im,ax=axs,orientation='horizontal',fraction=.1)plt.show() The video shows how the images couple: multiple_images.mp4(Additionally, inhttps://matplotlib.org/stable/gallery/images_contours_and_fields/multi_image.html, changing the colormap on the colorbar does not propagate to the images, but these changes propagate in the video above) This implementation also allows us to couple ND colormaps and 1D colormaps, so that changes in one propagates to the others: importmatplotlibmatplotlib.use('qtagg')importmatplotlib.pyplotaspltimportnumpyasnpnp.random.seed(19680801)data=np.random.rand(2,10,20)fig,axes=plt.subplots(1,3,figsize=(10,3))im_2D=axes[0].imshow(data,cmap='BiOrangeBlue')im_0=axes[1].imshow(data[0],norm=im_2D.nac[0])im_1=axes[2].imshow(data[1],norm=im_2D.nac[1])cb=fig.colorbar(im_0)cb=fig.colorbar(im_1)foraxinaxes:ax.label_outer()plt.show() coupled_bivar.mp4@timhoffm Is this what you had in mind? I had to build this in a branch further down the pipeline than this PR, because it needs some features of the plotting functions not available in this PR. If you want to take a look, the |
Creation and tests for classes containing multivariate and bivariate colormaps.
Adds support for __getitem__ on colors.BivarColormap, i.e.: BivarColormap[0] and BivarColormap[1], which returns (1D) Colormap objects along the selected axes
removal of ColormapBaseAddition of _repr_png_() for MultivarColormapaddition of _get_rgba_and_mask() for Colormap to clean up __call__()
Also adds a an improvement to colors.BIvarColormap.__getitem__() so that this returns a ListedColormap object instead of a Colormap object
Also removed all set_ functions, and replaced them with with_extremes()
trygvrad commentedAug 1, 2024
I pushed some updates to this branch, but this is largely just because I want to see the code coverage, and this is the easiest way for me to see how the code coverage changes. Provisional names are |
trygvrad commentedAug 1, 2024
We discussed this in the Matplotlib weekly meeting today, and we will split this into 2 PRs:
I'll make a comment here once 1. is ready. |
f9b2bf0 toe271b85CompareVectorMappable with data type objectsCreation of the VectorMappable classcorrectetion to _ensure_multivariate_norm()since colors.Normalize does not have a copy() function, we cannot easily convert a single norm to a sequence of norms.better use of union for colormap typesDefines ColorMapType as Union[colors.Colormap, colors.BivarColormap, colors.MultivarColormap] in typing.pySuport for multivariate colormaps in imshow, pcolor and pcolormeshsafe_masked_invalid() for data types with multiple fieldsNormAndColor classcleanup of _ImageBase._make_image()Rename To Mapper and reorganizatinochanged name of new class from Mapper to Colorizer and removed calls to old apichanged name of new class from Mapper to ColorizerMapper → ColorizerScalarMappableShim → ColorizerShimColorableArtist → ColorizingArtistalso removed all internal calls using the ColorizerShim api
e271b85 tob4af71eComparetrygvrad commentedAug 3, 2024
story645 commentedAug 4, 2024
4a87c8b toc5b1d06Comparetimhoffm commentedOct 23, 2025
@trygvrad I think this is superseeded. Can this be closed? |
trygvrad commentedOct 23, 2025
yes |





Uh oh!
There was an error while loading.Please reload this page.
Creation of the VectorMappable class
**NOTE: This PR builds upon the BivarColormap and MultivarColormap classes introduced in **#28454
PR summary
This PR has been in development during 2024 GSOC as a responese to#14168 Feature request: Bivariate colormapping.
This requires the introduction of multiple new classes, and changes to different parts of the codebase. It has therefore been suggested to introduce this functionality over multiple PRs, so that the changes are easier to reviewthis is the 1st of 3(?)PRs that willresolve#14168.
The end goal of this is to allow for the following funcitonality:
The current class hierarchy can be visualized as follows:

This PR proposes to replace ScalarMappable with a new class VectorMappable, so that multivariate functionality can be inherited by all the relevant plotting methods, as shows below. This includes support for multiple norms (the private variable

._normalways stores a list), support for multiple arguments to .set_vmin(), .set_vmax(), changes to .to_rgba() to support bivariate and multivariate colormaps, as well as support functions to parse multivariate data (top level functions in cm.py).This PR does not contain the changes needed in the plotting functions and docs. These will follow a separate PR, as outlined in the figure above. (a (slightly outdated) full implementation is available in the branchhere)
PR checklist
¹This is the 2nd out of a series of PRs, and cannot by itselfclose#14168. Most features are tested, but some private functions do not have complete tests, as they are better tested in a later PR where the private API is tested via the publicly available API (colors._ensure_multivariate_params() etc.)