Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add new method Colormap.with_alpha() #29525

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 29, 2025

Conversation

timhoffm
Copy link
Member

@timhoffm timhoffm commented Jan 26, 2025

We currently do not have a way of adjusting only the transparency of the
mapped colors of the artist, e.g. the fill in contourf(). Using the object-wide
Artist alpha parameter is not a solution as it also affects lines and hatches.

The simplest solution is to support creating semi-transparent colormaps, which can then be used via
contourf(..., cmap=plt.colormaps['jet'].with_alpha(0.5)). See also #29044 (comment).


Side-note: This is the minimal implementation for applying one global override. One could imagine other ways like merging with the existing alpha or providing an array of individual alpha values. I intentionally kept this PR focus and think that the overwrite behavior should be the default. One can later add optional parameters to allow for alpha-merging if desired.

new_cm = self.copy()
if not new_cm._isinit:
new_cm._init()
new_cm._lut[:, 3] = alpha
Copy link
Member

Choose a reason for hiding this comment

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

This has the unintended(?) consequence of allowing an array as well. If that array is the wrong size, folks are going to perhaps get cryptic size mismatch errors? Did we want to give thought to handling that, or just wait and see if it's a problem in real life? I'm actually unsure of how a user would get how big the lookup table is.

Copy link
Member Author

@timhoffm timhoffm Jan 26, 2025

Choose a reason for hiding this comment

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

Yes, I’m aware of this. I’ve intentionally specified this as float in the docstring and type annotation. Every other possibility accepted value is an implementation detail. I didn’t want to explicitly check for array and raise on that.

I’m also unsure how helpful a per-element alpha is. I assume varying alpha in a color map is less used compared to making the whole mapping semi-transparent.

Therefore, I’ve not included official varying alpha support for now. We can always later expand on it and also then decide whether the implementation just stays as is or whether we want additional safety checks and better error handling for arrays.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'll chime in here and say that I sometimes do use varying alpha in colormaps. This is useful for hiding/washing-out less important features/regions. Making a linear ramp that goes from 0.2-> 1 or something like that along with the low-high values. You can do that here with: alpha=np.linspace(0.2, 1, cmap.N) (are we getting rid of N though?) You can also imagine wanting to make the center white region of the RdBu transparent instead of just white, so a triangular ramp is helpful on diverging colormaps.

Example I added to mplcairo where the rendering of varying alpha between patches is better than with Agg: https://github.com/matplotlib/mplcairo/blob/247583de20b94d5c1a0d773e720d64e741b122df/examples/quadmesh.py#L22-L26

All this to say, I think the varying alpha is a useful feature, and making it easier would be nice!

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure. I’d like to postpone this to a follow -up. This PR was motivated so that #29044 can be done without the need to regenerate reference images. I’m interested in getting this in quickly, so that #29044 can move forward.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you've already got a nice enough way of doing that here? I guess I'm thinking that it might be helpful to do as Jody mentioned and put some validation on alpha right away. Raise if it is not a float(s) between 0-1 or if it is of a different length than N.

We also have the colorbar set_alpha method, so might be worth also thinking about how this will play with that (I think that colorbar.set_alpha() still wins on the colorbar, but the collections would be mapped with the cmap alpha here)
https://matplotlib.org/stable/api/colorbar_api.html#matplotlib.colorbar.Colorbar.set_alpha

Copy link
Member Author

Choose a reason for hiding this comment

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

Can we please focus on getting this through quickly as a minimal public API, so that #29044 can move forward?

I’m happy to discuss arrays, validation and Colorbar alpha in a follow-up.

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 not sure of the urgency here to avoid changing a visual test.

We have a continual problem with the color/alpha/facecolor/edgecolor dance - maybe this is the solution, but it doesn't seem right. OTOH, adding more ways to sculpt colormaps seems like a net positive regardless of the current issue that spurred this.

Copy link
Member Author

Choose a reason for hiding this comment

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

We have a continual problem with the color/alpha/facecolor/edgecolor dance - maybe this is the solution, but it doesn't seem right.

I don't understand the second half. If "this" means this PR, it's not supposed to solve any general problem with color/alpha/facecolor/edgecolor. This PR is a simple and straight forward extension of the Colormap functionality. It was motivated through a specific test in another PR that could better be written using this functionality. Not more not less.


I've added a range check for the float. I don't oversee whether array alpha is a meaningful API, in particular in the context of LinearSegementedColormap, where the lookup-table is basically an implementation detail. Therefore I want to keep things simple here.

@timhoffm timhoffm force-pushed the colormap-with_alpha branch from cbee37d to 2b12be4 Compare January 27, 2025 21:11
Copy link
Contributor

@greglucas greglucas left a comment

Choose a reason for hiding this comment

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

This is a good minimal update, and the check also removed the option of allowing an array alpha for now too so that can be revisited later.

alpha : float
The alpha blending value, between 0 (transparent) and 1 (opaque).
"""
if not 0 <= alpha <= 1:
Copy link
Member

@jklymak jklymak Jan 28, 2025

Choose a reason for hiding this comment

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

I think this is going to return ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() is someone inputs an array.

Suggested change
if not 0 <= alpha <= 1:
if (len(alpha) > 1) or (not 0 <= alpha <= 1)):

Copy link
Member Author

@timhoffm timhoffm Jan 28, 2025

Choose a reason for hiding this comment

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

Your observation on the error is correct, and to me this is intended. What's wrong with that? / What would you expect instead? I can't make sense of the suggestion, because it would raise on floats ("object of type 'float' has no len()").

Copy link
Member

@jklymak jklymak Jan 28, 2025

Choose a reason for hiding this comment

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

It is cryptic if someone passes an utterable iterable. You probably want something like:

if (isinstance(x, Iterable) and hasattr(x, "__len__") and len(alpha) > 1):
  raise(ValueError, 'alpha must be a single value, not a list or array')

Copy link
Member Author

Choose a reason for hiding this comment

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

Generally, we don't jump extra hoops to catch types that are not supported and give them a nicer error message.

But granted, Artist.set_alpha does something similar, so I've taken the same approach as there.

We currently do not have a way of adjusting only the transparency of the
 mapped colors of the artist, e.g. the fill in contourf(). The
 Artist alpha parameter also affects lines and hatches.

The simplest solution is to support creating semi-transparent
colormaps, which can then be used via
`contourf(..., cmap=plt.colormaps['jet'].with_alpha(0.5))`. See also
matplotlib#29044 (comment).
@timhoffm timhoffm force-pushed the colormap-with_alpha branch from 2b12be4 to 226b2f2 Compare January 29, 2025 00:18
Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

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

Feel free to self merge if green

Co-authored-by: Elliott Sales de Andrade <[email protected]>
@timhoffm timhoffm merged commit 71f5cf3 into matplotlib:main Jan 29, 2025
41 checks passed
@timhoffm timhoffm deleted the colormap-with_alpha branch January 29, 2025 11:51
@QuLogic QuLogic added this to the v3.11.0 milestone Jan 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants