Skip to content

Maximum Alpha for Scatter #28284

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

Open
schniti269 opened this issue May 23, 2024 · 7 comments
Open

Maximum Alpha for Scatter #28284

schniti269 opened this issue May 23, 2024 · 7 comments

Comments

@schniti269
Copy link

schniti269 commented May 23, 2024

Problem

When Overlaying multiple sets using scatter and alpha a previously plotted set can become occluded entirely if the density is too high as the summed alpha goes to full occlusion.
Using low alphas for pointclouds leads to outliars being *almost invisible.

Objective:

Introduce a parameter to cap the maximum alpha value in scatter plots to maintain visibility of underlying sets when overlaying multiple point clouds.

Use Case:

Overlaying point clouds from different datasets without obscuring underlying data, avoiding the need to manipulate z-order.

Implementation Details

•	Parameter: max_alpha
•	Type: Float (range: 0.0 to 1.0)
•	Default: None (no cap on alpha)
•	Function: Limits the cumulative alpha value for overlapping points.

Benefits

Enhanced Visualization: Maintains clarity and readability of plots with multiple overlaid datasets.
Flexibility: Users can control transparency to prevent complete opacity in densely populated areas.

Example Usage

import matplotlib.pyplot as plt

Sample data

x1, y1 = [1, 2, 3], [4, 5, 6]
x2, y2 = [2, 3, 4], [5, 6, 7]

Scatter plot with max_alpha

plt.scatter(x1, y1, alpha=0.5, max_alpha=0.8)
plt.scatter(x2, y2, alpha=0.5, max_alpha=0.8)
plt.show()

Conclusion

Implementing a max_alpha parameter in Matplotlib’s scatter plot functionality will provide greater control over data visualization, ensuring that underlying datasets remain visible even when multiple layers are overlaid.

Proposed solution

No response

@jklymak
Copy link
Member

jklymak commented May 23, 2024

This is going to be very hard to achieve with the way Matplotlib is architected. We send markers for the renderer and ask it to put them in the image. We don't compose the result, so we can't control the color of individual pixels in the final output.

Something that would be possible with our model is to rasterize each scatter call and then add an alpha for the raster of all the points before putting it on the parent raster. But that would be a complex API that I would not hold my breath to see implemented.

As you are finding - at some point scatter with alpha becomes impractical and you may want to consider other methods like 2D histogramming.

@tacaswell
Copy link
Member

To add a bit more detail, when we rasterize the output we composite the layers one at a time and the updated color of a pixel is

updated_color = old_color * (1-alpha) + new_color * alpha

so we do not have access to the history of why the pixel we are updating is the color it is so we can not dynamically turn down the alpha.

I am not aware of this ability existing in svg or pdf (the vector formats we support that also support alpha at all) so even if we could come up with a way to do this in Agg (which I do not think is possible without major changes), it would still be a heavy lift to get into Matplotlib as we try to keep the backends as feature parity as possible.

@schniti269
Copy link
Author

@tacaswell @jklymak Thank you guys for the Insights!
I always thought that there was an alpha channel per layer and that it would be quite easy to cap that way.. but as the calculations are as you described i also dont see that this will be easy in any way.

I also appreciate the Input for separate Ideas to try ;)

@anntzer
Copy link
Contributor

anntzer commented May 27, 2024

Actually there are some tricks that can be played using agg_filter:

from pylab import *

x0, y0, x1, y1 = rand(4, 5000)  # Fake data.

# The default case.
figure()
scatter(x0, y0, alpha=.5)
scatter(x1, y1, alpha=.5)

# Rescale alpha by 0.8.  Perhaps not the best, but that's the idea...

def rescale_alpha_filter(im, dpi):
    im[..., 3] *= .8  # Decrease alpha.
    return im, 0, 0

figure()
scatter(x0, y0, alpha=.5, agg_filter=rescale_alpha_filter)
scatter(x1, y1, alpha=.5, agg_filter=rescale_alpha_filter)

show()

On a vector backend this will lead to the artists getting rasterized, but I guess this is connected to the idea of adding support for knockout groups (#26971 (comment)), which I think may be supported by at least some vector formats. (A proper design would require looking into what svg/pdf/ps actually supports and take it from there :-))

@WeatherGod
Copy link
Member

WeatherGod commented Jun 1, 2024 via email

@anntzer
Copy link
Contributor

anntzer commented Jun 1, 2024

It is not clear to me how this could help, but I'm all ears.

@WeatherGod
Copy link
Member

WeatherGod commented Jun 2, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants