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

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

Open
trygvrad wants to merge5 commits intomatplotlib:main
base:main
Choose a base branch
Loading
fromtrygvrad:multivariate-plot-prapare

Conversation

trygvrad
Copy link
Contributor

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:

  • AMultiNorm class. This is a subclass ofcolors.Normalize and holdsn_variate norms.
  • Testing of theMultiNorm class

Featuresnot included in this PR:

  • changes to colorizer.py needed to expose the MultiNorm class
  • Exposes the functionality provided byMultiNorm together withBivarColormap andMultivarColormap to the plotting functionsaxes.imshow(...),axes.pcolor, and `axes.pcolormesh(...)
  • Testing of the new plotting methods
  • Examples in the docs

Comment on lines 4103 to 4105
in the case where an invalid string is used. This cannot use
`_api.check_getitem()`, because the norm keyword accepts arguments
other than strings.
Copy link
Member

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).

Copy link
ContributorAuthor

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 .

@trygvradtrygvradforce-pushed themultivariate-plot-prapare branch from55b85e3 tof42d65bCompareApril 17, 2025 15:18
Copy link
Contributor

@anntzeranntzer left a 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?

@trygvrad
Copy link
ContributorAuthor

Thank you for the feedback@anntzer !
Hopefully we can hear if@timhoffm has any thoughts on n_input / input_dims naming within the coming week.

@timhoffm
Copy link
Member

See#29876 (comment)

@trygvrad
Copy link
ContributorAuthor

Thank you@timhoffm
The PR should now be as we agreed (#29876 (comment)) :)

@trygvrad
Copy link
ContributorAuthor

@QuLogic Thank you again and apologies for my tardiness (I was sick)
@timhoffm Do you think you could approve this PR now?

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.
Copy link
Member

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.

Copy link
ContributorAuthor

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 :)

Copy link
ContributorAuthor

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.

@trygvradtrygvradforce-pushed themultivariate-plot-prapare branch from6b86d63 to32247f5CompareJune 4, 2025 21:01
@trygvrad
Copy link
ContributorAuthor

This is on hold until we sort out#30149 (Norm Protocol)
see#29876 (comment)

@trygvrad
Copy link
ContributorAuthor

I have rebased this PR and updated the MultiNorm to inherit from the Norm ABC now that#30178 has been merged :)

@trygvradtrygvradforce-pushed themultivariate-plot-prapare branch 2 times, most recently from47b5116 to63feb6bCompareJune 29, 2025 14:09
assert norm.vmax[0] == 2
assert norm.vmax[1] == 2

# test call with clip
Copy link
Member

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.

Copy link
ContributorAuthor

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?

Copy link
Member

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.

@trygvrad
Copy link
ContributorAuthor

@timhoffm Thank you for taking the time to give detailed comments!

@trygvrad
Copy link
ContributorAuthor

trygvrad commentedJul 3, 2025
edited
Loading

@timhoffm You made a comment here#29876 (comment):

Then (if we still want to expose MultiNorm), let's just call this n_variables and keep it private.

The variable has since changed name ton_components, but I feel like we haven't really explored the merits of keeping it private/public.

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:

  1. The current status: A public property.
  2. Removen_components completely, and replace it withlen(self._norms) wherever it occurs. (This would require a type-check for MultiNorm beforelen(self._norms) is accessed, if the object could also be aNormalize).
  3. Maken_components private.

This impacts how we communicate with the user via docstrings, i.e. inMultiNorm.__call__()
image

Here we could have:

  1. - If tuple, must be of length n_components
  2. - If tuple, must be of length equal to the number of norms held by this MultiNorm

i.e. we can choose to maken_components part of the vocabulary we use, or we can choose not to. My hunch is that this is a useful term to have for both internal discussions, and external communications.
It is also useful to keep in mind thatMultiNorm should mirror the situation with colormaps, where currentlyColormap,BivarColormap andMultivarColormap hasn_components with value 1, 2, andlen(self), respectively.

Once the top level plotting functions are made, there will be a check if the data pipeline is consistent, i.e.
number of fields in the data == cmap.n_components == norm.n_components
If we believe that there are users (i.e. developers of packages that rely on matplotlib) that want to use this functionality in some interesting way, I think it would be useful for them to have access ton_components

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 ton_components which in reality is most important for error handling etc, and the typical user does not write custom error messages.


@timhoffm Let me know if I should removen_components or make it private. Also if I should do the same for the colormap classes.

@github-actionsgithub-actionsbot added the Documentation: APIfiles in lib/ and doc/api labelJul 3, 2025
@trygvradtrygvradforce-pushed themultivariate-plot-prapare branch 2 times, most recently fromab61439 to910b343CompareJuly 3, 2025 12:54
@timhoffm
Copy link
Member

I 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.

trygvrad reacted with thumbs up emoji

@trygvradtrygvradforce-pushed themultivariate-plot-prapare branch from910b343 todbeca30CompareJuly 10, 2025 19:18
"""
Parameters
----------
norms : list of (str, `Normalize` or None)
Copy link
Member

@timhoffmtimhoffmJul 10, 2025
edited
Loading

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.

Copy link
Member

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?

Copy link
Member

@timhoffmtimhoffmJul 11, 2025
edited
Loading

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.

Copy link
ContributorAuthor

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)

Copy link
Member

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]?

Copy link
ContributorAuthor

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.

Copy link
Member

@story645story645Jul 16, 2025
edited
Loading

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']?

@trygvradtrygvradforce-pushed themultivariate-plot-prapare branch from23777b3 to3a4f6b9CompareJuly 12, 2025 09:52
@trygvrad
Copy link
ContributorAuthor

Thank you@timhoffm , the changes should now be in :)

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`
Copy link
Member

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.

Copy link
ContributorAuthor

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') or

ax.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 whereGDP_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.

Copy link
Member

@timhoffmtimhoffmJul 13, 2025
edited
Loading

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

Copy link
ContributorAuthor

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.

Copy link
Member

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.

Copy link
ContributorAuthor

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 thisMultiNorm 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 thisMultiNorm 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.)

Copy link
Member

@jklymakjklymakJul 20, 2025
edited
Loading

Choose a reason for hiding this comment

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

I'd argue structured arrays are rarely used and that most people who need "structured arrays" usexarray. I'd remove the last sentence of the first error. If someone doesn't already have the data as a structured array, I doubt they really want to make it one for plotting (versus just making a list or tuple). If you want a second sentence, then I'd show them how to make a listdata_as_list = [data[:, i] for i in range(data.shape[1])].

The second error should use the same name:data_as_list = list(data). However, I do think that we should just let that pass silently, even if we don't document such arrays as being a legitimate argument.

Copy link
Member

Choose a reason for hiding this comment

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

I agree with@jklymak that structured arrays are too special so that we should not recommend them if people are not using them already. - They should be mentioned in the docstring but not in a suggestion in an error message. If the array is 2Dlist(data.T) is the simplest way, and[data[..., i] for i in range(data.shape[-1])] for more than 2D.

I do think that we should just let that pass silently, even if we don't document such arrays as being a legitimate argument.

I'm coming to the conclusion that we should simply accept "sequence of arrays". This means

  • We can check thatlen(data) == n_components
  • We can iterate over the component arrays.
  • It works for list/tuple.
  • It works for n-dim arrays - since they are a sequence of n-1 dim arrays.

Bonus points if you give a helpful error message in case oflen(data) != n_components if it is an array withshape(data)[-1] == n_components.

The ambiguity argument, which led me to propose not accepting arrays is actually not that strong. Either it has the right shape, solist(data) is just extra work, or the order is different, but we can fail with a clear error message then. The only case we cannot dect whether the use has organized the data correctly are (n, n) shaped arrays, but that should be rare as typically2 <= n_components <= few but values are either 1 or many.

jklymak reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

thank you@jklymak and@timhoffm for the feedback :D

I'm coming to the conclusion that we should simply accept "sequence of arrays". This means

The way I have implemented this is a type checkisinstance(data, (tuple, list)). We could accept other container classes as well, but in my mind it is reasonable to lock it down (and this simplifies the typing/errors).


Usingmulti_norm = mpl.colors.MultiNorm(['linear', 'linear']) there are now 7 different error messages. All of them start with the text:

ValueError: The input to thisMultiNorm must be a list or tuple of length 2, or be structured array with 2 fields.

multi_norm(np.zeros((2, 3))) gives:

ValueError: The input to thisMultiNorm must be a list or tuple of length 2, or be structured array with 2 fields. You can usedata_as_list = list(data) to convert the input data of shape (2, 3) to a compatible list

multi_norm(np.zeros((3, 2))) gives:

ValueError: The input to thisMultiNorm must be a list or tuple of length 2, or be structured array with 2 fields. You can usedata_as_list = list(data.T) to convert the input data of shape (3, 2) to a compatible list

multi_norm(np.zeros((3, 3, 2))) gives:

ValueError: The input to thisMultiNorm must be a list or tuple of length 2, or be structured array with 2 fields. You can usedata_as_list = [data[..., i] for i in range(data.shape[-1])] to convert the input data of shape (3, 3, 2) to a compatible list

If the axis is inconsistent so that both first and last or neither first or last matches: i.e.multi_norm(np.zeros((2, 2))) gives:

ValueError: The input to thisMultiNorm must be a list or tuple of length 2, or be structured array with 2 fields. An np.ndarray of shape (2, 2) is not compatible

The above covers the cases with a scalar np.ndarray. There is also:

For a structured array with the wrong number of fields:

ValueError: The input to thisMultiNorm must be a list or tuple of length 2, or be structured array with 2 fields. A structured array with 3 fields is not compatible

For an unsupported class:multi_norm(1)

ValueError: The input to thisMultiNorm must be a list or tuple of length 2, or be structured array with 2 fields. Input of type <class 'int'> is not supported

and finally, for a list/tuple of wrong length:multi_norm((1, 1, 1))

ValueError: The input to thisMultiNorm must be a list or tuple of length 2, or be structured array with 2 fields. A <class 'tuple'> of length 3 is not compatible

Copy link
Member

Choose a reason for hiding this comment

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

I would have thought that this is a sufficient and reasonable implementation:

def_iterable_components_in_data(data,n_components):ifisinstance(data,np.ndarray)anddata.dtype.fieldsisnotNone:# structured arrayiflen(data.dtype.fields)!=n_components:raiseValueError("Structured array inputs to MultiNorm must have the same ""number of fields as components in the MultiNorm. Expected "f"{n_components}, but got{len(data.dtype.fields} fields"else:returntuple(data[field]forfieldindata.dtype.names)try:n_elements=len(data)exceptTypeError:raiseValueError("MultiNorm expects a sequence with one element per "f"component as input, but got{data!r} instead")ifn_elements!=n_components:raiseValueError("MultiNorm expects a sequence with one element per component. "f"This MultiNorm has{n_components} components, but got a sequence "f"with{n_elements} elements"returntuple(data[i]foriinrange(n_elements))

This implicitly accepts arrays and other sequence-like containers. Do you see inputs where the error messages are not clear enough. Optionally, one can add special messages for incorrectly shaped arrays in the last if to give the conversion guidance.

@trygvradtrygvradforce-pushed themultivariate-plot-prapare branch 3 times, most recently fromdd8f0c6 to67b8264CompareJuly 13, 2025 11:56
trygvradand others added4 commitsJuly 20, 2025 16:05
This commit merges a number of commits now contained inhttps://github.com/trygvrad/matplotlib/tree/multivariate-plot-prapare-backup , keeping only the MultiNorm class
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Comment on lines +3544 to +3548
data = tuple(data[descriptor[0]] for descriptor in data.dtype.descr)
if len(data) != n_components:
raise ValueError(f"{MultiNorm._get_input_err(n_components)}"
f". A structured array with "
f"{len(data)} fields is not compatible")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
data=tuple(data[descriptor[0]]fordescriptorindata.dtype.descr)
iflen(data)!=n_components:
raiseValueError(f"{MultiNorm._get_input_err(n_components)}"
f". A structured array with "
f"{len(data)} fields is not compatible")
iflen(data.dtype.fields)!=n_components:
raiseValueError(
"Structured array inputs to MultiNorm must have the same "
"number of fields as components in the MultiNorm. Expected "
f"{n_components}, but got{len(data.dtype.fields} fields.")
else:
returntuple(data[field]forfieldindata.dtype.names)

I think we can:

  • separate the cases better. Withif raise else return it's obviously clear that the structured array case is handled exhaustively. creatingdata and letting it fall through to the finalreturn data increases mental load.
  • use a more focussed error message for structured arrays. If people are inputting structured arrays, they should be very much know what they want and likely just have the wrong number of elements. They don't need the full possible set of inputs.

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`
Copy link
Member

Choose a reason for hiding this comment

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

I would have thought that this is a sufficient and reasonable implementation:

def_iterable_components_in_data(data,n_components):ifisinstance(data,np.ndarray)anddata.dtype.fieldsisnotNone:# structured arrayiflen(data.dtype.fields)!=n_components:raiseValueError("Structured array inputs to MultiNorm must have the same ""number of fields as components in the MultiNorm. Expected "f"{n_components}, but got{len(data.dtype.fields} fields"else:returntuple(data[field]forfieldindata.dtype.names)try:n_elements=len(data)exceptTypeError:raiseValueError("MultiNorm expects a sequence with one element per "f"component as input, but got{data!r} instead")ifn_elements!=n_components:raiseValueError("MultiNorm expects a sequence with one element per component. "f"This MultiNorm has{n_components} components, but got a sequence "f"with{n_elements} elements"returntuple(data[i]foriinrange(n_elements))

This implicitly accepts arrays and other sequence-like containers. Do you see inputs where the error messages are not clear enough. Optionally, one can add special messages for incorrectly shaped arrays in the last if to give the conversion guidance.

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

@QuLogicQuLogicQuLogic left review comments

@story645story645story645 left review comments

@anntzeranntzeranntzer left review comments

@jklymakjklymakjklymak left review comments

@timhoffmtimhoffmtimhoffm left review comments

@oscargusoscargusoscargus left review comments

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

Assignees
No one assigned
Labels
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

Feature request: Bivariate colormapping
7 participants
@trygvrad@timhoffm@QuLogic@story645@anntzer@jklymak@oscargus

[8]ページ先頭

©2009-2025 Movatter.jp