Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
MultiNorm class#29876
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
base:main
Are you sure you want to change the base?
MultiNorm class#29876
Conversation
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
lib/matplotlib/colors.py Outdated
in the case where an invalid string is used. This cannot use | ||
`_api.check_getitem()`, because the norm keyword accepts arguments | ||
other than strings. |
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.
I'm confused because this function is only called forisinstance(norm, str)
.
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.
So this function exists because the norm keyword acceptsNormalize
objects in addition to strings.
This is fundamentally the same error you get if you give an invalid norm to aColorizer
object.
In main, the@norm.setter
oncolorizer.Colorizer
reads:
@norm.setterdefnorm(self,norm):_api.check_isinstance((colors.Normalize,str,None),norm=norm)ifnormisNone:norm=colors.Normalize()elifisinstance(norm,str):try:scale_cls=scale._scale_mapping[norm]exceptKeyError:raiseValueError("Invalid norm str name; the following values are "f"supported:{', '.join(scale._scale_mapping)}" )fromNonenorm=_auto_norm_from_scale(scale_cls)() ...
The_get_scale_cls_from_str()
exists in this PR because this functionality is now needed by bothcolorizer.Colorizer.norm()
andcolors.MultiNorm
.
Note this PR does not include changes tocolorizer.Colorizer.norm()
so that it makes use of_get_scale_cls_from_str()
. These changes follow in the next PR:#29877 .
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
55b85e3
tof42d65b
CompareUh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
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.
Just some minor points, plus re-pinging@timhoffm in case he has an opinion re: n_input / input_dims naming?
Thank you@timhoffm |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
vmin, vmax : float, None, or list of float or None | ||
Limits of the constituent norms. | ||
If a list, each value is assigned to each of the constituent | ||
norms. Single values are repeated to form a list of appropriate size. |
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.
Is broadcasting reasonable here? I would assume that most MultiNorms have different scales and thus need per-element entries anyway. It could also be an oversight to pass a single value instead of multiple values.
I'm therefore tempted to not allow scalars here but require exactly n_variables values. A more narrow and explicit interface may be the better start. We can always later expand the API to broadcast scalars if we see that's a typical case and reasonable in terms of usability.
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.
@timhoffm Perhaps this is also a topic for the weekly meeting :)
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.
I'm perfectly fine with removing this here, and perhaps that is a good starting point.
My entry into this topic was a use case (dark-field X-ray microscopy, DFXRM) where we typically wantvmax0 = vmax1 = -vmin0 =-vmin1
, i.e. equal normalizations, and centered on zero, and given that entry point it felt natural to me to include broadcasting.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
6b86d63
to32247f5
CompareThis is on hold until we sort out#30149 (Norm Protocol) |
32247f5
tod49737f
CompareI have rebased this PR and updated the MultiNorm to inherit from the Norm ABC now that#30178 has been merged :) |
47b5116
to63feb6b
CompareUh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
assertnorm.vmax[0]==2 | ||
assertnorm.vmax[1]==2 | ||
# test call with clip |
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 need more extensive testing for call with multiple values.
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.
Agreed, we need some more tests.
Should we make them here, or test via the top level plotting functions once they are implemented?
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.
I would do the tests here because you can directly test the numeric result of the norm function. With plotting functions, you'll get colors as the result, which are much harder to test / have less expressiveness.
Here you can do a lot of cases as one-liners.
@timhoffm Thank you for taking the time to give detailed comments! |
trygvrad commentedJul 3, 2025 • 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.
@timhoffm You made a comment here#29876 (comment):
The variable has since changed name to The current status is the public property: @propertydefn_components(self):"""Number of norms held by this `MultiNorm`."""returnlen(self._norms) I think we actually have 3 options:
This impacts how we communicate with the user via docstrings, i.e. in Here we could have:
i.e. we can choose to make Once the top level plotting functions are made, there will be a check if the data pipeline is consistent, i.e. On the other hand, while I am quite certain that mulitvariate plotting functionality will be used by a number of users, it is unclear to me if any/how many will build advanced functionality that requires access to @timhoffm Let me know if I should remove |
ab61439
to910b343
CompareI think making it public is the right way to go. While it slightly complicates the mental model for all the current 1d norms, it is by design that it’s now only the special case and hence itis slightly more complicated. |
Uh oh!
There was an error while loading.Please reload this page.
This commit merges a number of commits now contained inhttps://github.com/trygvrad/matplotlib/tree/multivariate-plot-prapare-backup , keeping only the MultiNorm class
910b343
todbeca30
CompareUh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
lib/matplotlib/colors.py Outdated
""" | ||
Parameters | ||
---------- | ||
norms : list of (str, `Normalize` or None) |
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.
why do we acceptNone
here? I don't see an advantage of[None, None]
over["linear", "linear"]
. Quite the opposite, the first one is less readable.
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.
Maybe in case folks want to update the list later?
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.
That doesn't make sense to me. (1)None
is resolved to Normalize
immediately. (2) Not sure why one wanted to lated update but that's possible either way.
I rather suspect that it's because it along the lines of: In 1D some other places - e.g.ScalarMappable.set_norm
- accept None. But likely the othe places only accept it intentionally or unintentionally because norm=None is somewhere a default kwarg and that is passed 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.
I rather suspect that it's because it along the lines of: In 1D some other places - e.g. ScalarMappable.set_norm - accept None. But likely the othe places only accept it intentionally or unintentionally because norm=None is somewhere a default kwarg and that is passed through.
Exactly this.
My thinking was that a common use case is not to supply a norm:
ax.imshow((A,B),cmap='BiOrangeBlue')
In this case thenorm
keyword (default:None
) is singular, but to be compatible with the data/cmap it needs to have a length of 2, so in this case the norm keyword is repeated and becomes[None, None]
, and this then gets passed to theMultiNorm
constructor.
In any case, it is better if, as you say we only accept strings.
I will make the change later.
see colorizer.py →_ensure_norm(norm, n_variates=n_variates)
here for the proposed implementation. (This can also be simplified if we no longer acceptNone
)
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.
That doesn't make sense to me. (1) None is resolved to Normalize immediately. (2) Not sure why one wanted to lated update but that's possible either way.
What happens with['linear', None]
?
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.
It would be parsed to['linear', 'linear']
, but will now (with the update) produce an error.
If we find we need this functionality, we can always bring it back in a later PR.
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.
So how do you denote['linear', mpl.NoNorm()]
? is that['linear', 'none']
?
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
23777b3
to3a4f6b9
CompareThank you@timhoffm , the changes should now be in :) |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
lib/matplotlib/colors.py Outdated
Data to normalize, as tuple, scalar array or structured array. | ||
- If tuple, must be of length `n_components` | ||
- If scalar array, the first axis must be of length `n_components` |
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.
Did we have a discussion on the axis order? I would have expected it the other way round. Note that we represent RGB arrays as (N, 3), where in is the color count and 3 are the r, g, b values. The call here should be comparable, i.e. the components are the second dimension.
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.
@anntzer had the same question above (#29876 (comment)) I will repeat my answer (#29876 (comment)) here:
We had a brief discussion on this here#14168 (comment), but we followed that up on a weekly meeting 14 September 2023https://hackmd.io/@matplotlib/Skaz1lrh6#Mutlivariate-colormapping .
The argument is not formulated well in the log, but basically
(V, N, M)
because there areV
cmaps and norms, and in this way the input for the data mirrors that of the vmin, vmax and norm keywords, i.e.:ax.imshow((data0, data1), vmin=(vmin0, vmin1), cmap='BiOrangeBlue')
orax.imshow((preassure,temperature),vmin=(vmin_preassure,vmin_temperature),cmap='BiOrangeBlue')Quite often the data is qualitatively different, like the example at the bottom of the page here:https://trygvrad.github.io/mpl_docs/Multivariate%20colormaps.html where
GDP_per_capita
andAnnual_growth
are plotted together. I find it is not very intuitive to wrap these in a single array.(also: this allows the different variates to have different data types)
While I see the argument that this has similarities to RGB images, I believe it is also qualitatively quite different, because this works through the norm→colormap pipeline while RGB images bypasses that machinery bydesign.
The way I see it is that the three values of a pixel in an RGB image (in the typical case, i.e. a drawing/diagram or picture taken with a camera) work together to encode one piece of information (color), while if you plotGDP_per_capita
andAnnual_growth
together using separate norms and a 2D colormap, you have two pieces of information at each point, even though those two pieces are represented by a single color via a colormap.
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.
Thanks for repeating the answer. The topic is so large that it’s difficult to keep an overview of the state of the discussion.
Your arguments are valid, but only cover the case of list/tuple of 1d array-like, and there I agree. However, I argue that 2d arrays are a separate topic and should be handled differently, because there datasets is typically structured in columns. See e.g. theheights parameter inhttps://matplotlib.org/devdocs/api/_as_gen/matplotlib.axes.Axes.grouped_bar.html#matplotlib.axes.Axes.grouped_bar
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.
Aha!
Just to make sure, you are arguing that a tuple/list of 2D arrays should be handled differently than a 3D array?
I have no problems with this, if you think it is OK from a syntax point of view :)
In practice this would change only
""" - If scalar array, the first axis must be of length `n_components`"""
to:
""" - If scalar array, the last axis must be of length `n_components`"""
And in the implementation, this would add anelse:
toMultiNorm._iterable_components_in_data()
:
@staticmethoddef_iterable_components_in_data(data,n_components):""" Provides an iterable over the components contained in the data. An input array with `n_components` fields is returned as a list of length n referencing slices of the original array. Parameters ---------- data : np.ndarray, tuple or list The input data, as tuple, scalar array or structured array. - If tuple, must be of length `n_components` - If scalar array, the last axis must be of length `n_components` - If structured array, must have `n_components` fields. Returns ------- tuple of np.ndarray """ifisinstance(data,np.ndarray):ifdata.dtype.fieldsisnotNone:data=tuple(data[descriptor[0]]fordescriptorindata.dtype.descr)else:data=tuple(data[...,i]foriinrange(data.shape[-1]))iflen(data)!=n_components:raiseValueError("The input to this `MultiNorm` must be of shape "f"({n_components}, ...), or be structured array or scalar "f"with{n_components} fields.")returndata
There will also be some implications when we check consistency between the data, colormap and norm in colorizer, but that is a problem for a later PR.
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.
Yes, this is my idea.
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.
RGB images are a recurring topic whenever this is discussed, and I find the comparison to RGB images is useful only in the abstract, seeing how:
- Matplotlib can already show RGB images
- Plotting RGB images with the colormaps discussed here is not very useful
- I see limited use for MultiNorm in an image processing pipeline for RGB images
Similarly, I don't see how this is of particular use for tabulated data.
- The tools for visualizing tabulated are well developed, with additional parameters such as marker/linesize, symbol/dashed line and scalar color. Typical use cases therefore do not need multidimensional colormaps.
- It is much more difficult to use multidimensional colormaps in a scatter plot on a white (or black) background, since changing the luminosity also changes the visibility of the markers. This makes multidimensional colormaps difficult to utilize for scatter/line plots.
When I say that this feature is not particularly useful for scatter/line plots, that isbecause I have actually tried.
You can go tohttps://colorstamps.readthedocs.io/en/latest/lineplots.html and see the following lineplot:
This plot would have much greater clarity if it was shown instead as.
- Single line with scalar color + error bars in each group (𝜔)
- Different markers or dash style for each group
If the data was shown in one of these ways, it would also be accessible for those that are colorblind, which the above plotis not.
I believe this feature is most useful when not looking at a single image, but multiple images.
For example comparing two images taken at different times:
A two pictures showing the same scene, shown using the 'BiOrangeBlue' colormap, highlighting the differences. Cars can be seen to have changed position, and the effect of the wind is visible on the bushes.
A sequence of images is typically stored as a data-cube [i, n, m], and storing it [n, m, i] would be quite odd. This is true for regular camera images, as above, but also for X-ray images and X-ray diffraction [my domain of expertise]. It is also how I have seen Z-stacks or T-series in an optical microscopy stored, and I imagine an infrared camera, a telescope, an electron microscope, and a satellite would store data in the same way.
This feature is also very useful when comparing before/after a processing [or filtering] step as part of an image processing pipeline. Again, it would be odd to store the before and after a processing step as thelast index of an array.
If you wish to argue that we shouldonly allow the channels to be encoded at the last index, I would really appreciate it if that was backed up with some use-cases where that would be the intuitive use caseand where this feature is needed. Because I do not see how:
complex=np.stack([a,phi],axis=-1)ax.imshow(complex,vmin=(0,0),vmax=(1,360),cmap='BiOrangeBlue')
improves the user experience as compared to:
ax.imshow((a,phi),vmin=(0,0),vmax=(1,360),cmap='BiOrangeBlue')
That said, it will not kill me to writecomplex = np.stack([a, phi], axis=-1)
.
However, how would you handle the case where the two channels have different data type?
Consider the feature where you can useNoNorm
to address the colors in a (resampled) colormap directly. I.e.:
a=np.random.randint(0,5, (5,10))cmap=mpl.colormaps['RdBu']cmap=cmap.resampled(5)norm=mpl.colors.NoNorm()plt.imshow(a,norm=norm,cmap=cmap)plt.colorbar()

which is triggered when the data sent to the colormap is of dtype int.
I would like be able to support this functionality also with multiple channels. Thiscould be achieved with the syntax:
ax.imshow((a,phi),norm=(mpl.color.NoNorm(),'linear'), ...)
But if this syntax is not allowed, I struggle to see how this functionality can be achieved in an intuitive and pedagogical way, given that most users are not familiar with structured numpy arrays.
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.
I think we can agree on the sequence-of-array case: The sequence goes over the components. This would be compatible with your image example if you have two images as separate arrays:imshow([image_before, image_after], ...)
.
The array-only representation is difficult as we run into the standard first-vs-last dimension encoding discussion. I think there are arguments for both. My other question would be: How large cann_components
reasonably be? I think the most common case is 2, maybe sometimes 3. One solution could be to circumvent the discussion by only supportingsequence-of-array
(and optionally stuctured arrays).
If you actually have an image cube [i, n, m], you'd need to explcitily select the elements e.g.imshow([cube[0], cube[1]])
.
That would put the responsibility to interpret the data clearly to the user, and be in strict analogy to the sequence inputs to all other parameters (norm
,vmin
,vmax
). Sincen_components
is low that may be bearable in terms of typing effort and performance.
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.
How large can n_components reasonably be? I think the most common case is 2, maybe sometimes 3.
This is an example, from a quick image search for 'edx element map' [Yang, T., et al. "Nanoparticles-strengthened high-entropy alloys for cryogenic applications showing an exceptional strength-ductility synergy." Scripta Materialia 164 (2019): 30-35.] shows 6 channels.
However, I do not think it is commonplace even with EDX/EDS to plot so many channels in one image, as the visual clarity is greater with fewer channels, as below [O’Boyle, Sarah K., et al. "Expanded Tunability of Intraparticle Frameworks in Spherical Heterostructured Nanoparticles through Substoichiometric Partial Cation Exchange." ACS Materials Au 2.6 (2022): 690-698.]:

When I designed colormaps for possible future use in matplotlib, (link) I designed colormaps for up to 8 variables, with use cases like EDX/EDS in mind.
In other words: I think there will be users who go up to around half-a-dozen channels, and we should support that use, but I don't think it will be a typical use case.
Also: in this use case it is quite typical that you want individual colormaps for a number of elements, but never plot them all together in one plot, as in this example [Cook, Nigel J., et al. "Micron-to atomic-scale investigation of rare earth elements in iron oxides." Frontiers in Earth Science 10 (2022): 967189.]:
We will need some example demonstrating how to do this, but the MultivarColormap class is designed so that you can create subsets:
cmap=mpl.colormaps['6VarAddA']# a MultivarColormap with 6 componentscmap_35=mpl.colors.MultivarColormap([cmap[3],cmap[5]],combination_mode=cmap.combination_mode)ax.imshow([data[3],data[5]],cmap=cmap_35)
(if needed we can add a simplified syntax for this once everything is in)
And this is perhaps the main reason why I want to include MultivarColormaps that go as high as 8, but that is a topic for later :)
One solution could be to circumvent the discussion by only supporting sequence-of-array (and optionally stuctured arrays).
I think this could be a reasonable approach.
As you say, some users may find the need to do a conversion of the kind
data_as_list= [data[0],data[1]]
or
data_as_list= [data[i]foriinrange(data.shape[0])]
or, if the axis is the last in the data:
data_as_list= [data[...,i]foriinrange(data.shape[-1])]
or even
dtype=np.dtype([(f'{i}',data.dtype)foriinrange(data.shape[-1])])as_structured_array=data.view(dtype=dtype)[...,0]
For conversion to list or structured array, respectively.
I'll have a think about what the error message should be if the user gives a not-structured array and only a list/tuple or structured array is allowed. We can perhaps be quite detailed here? with bespoke error messages depending on if the input is an array and if so, what size it has.
"""ValueError: Invalid input to MultiNorm with 3 components, the input array of shape (3, 7 25) must be converted to a list or tuple of length 3, i.e.: `data_as_list = [data[i] for i in range(data.shape[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.
Conversion is even simpler than that 😄
data_as_list= [data[i]foriinrange(data.shape[0])]
is just
list(data)
dtype=np.dtype([(f'{i}',data.dtype)foriinrange(data.shape[-1])])as_structured_array=data.view(dtype=dtype)[...,0]
is just
numpy.lib.recfunctions.unstructured_to_structured(data)
It's possibly good to add this to the documentation.
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.
I updated the MultiNorm so that only tuples, lists, or structured arrays are acceptable as input to call, inverse, etc.
The details are inMultiNorm._iterable_components_in_data(data, n_components)
I made an attempt to have error messages that steer the user in the right direction.
multi_norm=mpl.colors.MultiNorm(['linear','linear'])multi_norm(np.zeros((3,2)))
gives the error:
ValueError: The input to this
MultiNorm
must be a list or tuple of length 2, or be structured array with 2 fields. You can userfn.unstructured_to_structured(data)
available withfrom numpy.lib import recfunctions as rfn
to convert the input array of shape (3, 2) to a structured format
while
multi_norm(np.zeros((3,2)))
gives:
The input to this
MultiNorm
must be a list or tuple of length 2, or be structured array with 2 fields. You can uselist(data)
to convert the input data of shape (2, 3) to a compatible list
Does this make sense to you@timhoffm?
I would really like to point users in the right direction, but I have limited experience writing errors of this kind :)
(PS: we may want to revisit the wording here in a later PR, because I suspect this error message will come up most commonly form the top level plotting functions, and in that case I would prefer a error message of the kind "Usingaxes.imshow(...)
with a bivariate or multivariate colormap requires the input data..." rather than mentioningMultiNorm
by name, but time will tell how easily that can be achieved, and if it is worth it.)
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
a19c5ad
todd8f0c6
CompareCo-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
dd8f0c6
to67b8264
Compare
PR summary
This PR continues the work of#28658 and#28454, aiming toclose#14168. (Feature request: Bivariate colormapping)
This is part one of the former PR,#29221. Please see#29221 for the previous discussion
Featuresincluded in this PR:
MultiNorm
class. This is a subclass ofcolors.Normalize
and holdsn_variate
norms.MultiNorm
classFeaturesnot included in this PR:
MultiNorm
together withBivarColormap
andMultivarColormap
to the plotting functionsaxes.imshow(...)
,axes.pcolor
, and `axes.pcolormesh(...)