Make marker size absolute in scatterplot
It seems that when creating a scatterplot, the marker sizes are always in pixels. The result is that when zooming into the plot, the points remain small. Is there a way to have them dynamically resize? Or set the size to be absolute instead of pixel?
A code snippet to showcase the point
import pandas as pd
import numpy as np
import plotly.express as px
some_data = pd.DataFrame({"id":list(range(50_000)), "x":np.random.normal(size=50_000), "y":np.random.normal(size=50_000)})
some_data["c"] = pd.Categorical(np.random.randint(low=0,high=2,size=50_000))
fig = px.scatter(some_data, x="x", y="y", color="c")
fig.update_traces(marker=dict(size=3, opacity=0.5),
selector=dict(mode='markers'))
fig.update_layout({
'plot_bgcolor': 'rgba(0, 0, 0, 0)',
'paper_bgcolor': 'rgba(0, 0, 0, 0)',
})
fig.update_yaxes(matches=None, showticklabels=False, visible=False)
fig.update_xaxes(matches=None, showticklabels=False, visible=False)
config = dict({'scrollZoom': True})
fig.show(config=config)
Zoomed out, this is a nice graph that shows the distribution clearly, but when zooming in, the points are so small it's nearly impossible to interact with any individual one.
https://user-images.githubusercontent.com/22605641/147709359-34eb5036-d96e-4feb-a32f-f9076a7f3b4d.mov
Is there a way for those points to have absolute sizes instead of fixed ones? Such that zooming in would cause them to increase (as would be intuitive naturally)?
Thanks!
+1 would love to see this as well. Would love a way to set their absolute size without having to dig too deep into plotly internals or plotly.js callbacks.
+1 I looked into this for some time a little while back with no success :(. It would be amazing to finally find a solution to this!
+2 tried to forge a hand-made solution for this but failed
+1, also looking for a solution
+1 d3 does this out of the box.
- 1 we also didn't found a solution yet
kiiiiind of a 'solution' would be to draw shapes instead of scatter points for each scatter point with add_shape() here, zooming includes an increase of objects size when coming closer. However there are drawbacks because shapes are not meant to be plot objects but rather drawings/annotations. Therefore things like hover info need to be implemented with invisible scatter points etc. Feels very dodgy but for my purposes it does the job.
+1 this would be very nice to have
I currently need this feature for work :)
+1 Drawing spheres do provide a solution. However, it can be too heavy when I have to draw over tens of thousands of points in the 3D plot. Waiting for an upgrade.
+1 This would be a big help in a dataset I'm working with where the size-generating data spans orders of magnitude and where there are dense regions of smaller-size markers.
This would be very useful!
Came here to see a solution. Looks like they've added documentation based on @luggie's solution https://plotly.com/python/shapes/#circles-positioned-relative-to-the-axis-data
Came here to see a solution. Looks like they've added documentation based on @luggie's solution https://plotly.com/python/shapes/#circles-positioned-relative-to-the-axis-data
Useful when there is little data.
This would be also useful in order to be able to become independent of rescaling the figure dpi after plotting
+1 I have been searching for a solution to this problem and am yet to find one. This should be standard behaviour.
I could imagine 2 different APIs for this.
- To add
sizexandsizeytomarker. In this case the a circle marker become anellipsewhen scaled in on direction. - To add a constant
sizemode. In this case a circle marker remains circle when scaled in one direction as it is adjusted in other direction to maintain the area.
For those of you interested in this feature: the key next step is to design the API, and for that we need to know a bit more about the use cases you have in mind. The crux of the issue is that zooming in and out does not generally preserve aspect ratio, so if we're trying to set the marker size in reference to the axis scaling rather than pixels, the question is which axis? I guess the options could be:
- Give two sizes, one for x and one for y. This means in general as you zoom the markers will change aspect ratio, to become ellipses, rectangles, etc, but if the marker size really is supposed to mean something related to each axis scale, that might be the right solution. (note: this solution doesn't scale to 3D, because the markers maintain their orientation as the scene is rotated).
- Size the markers based on one of the axis scales, but maintain aspect ratio regardless of the scale of the other axis.
- Size the markers based on the data-scale area they cover, meaning when converted to linear size, markers grow with the geometric mean of the x and y (and z, this flavor would scale to 3D) axis scales. (@archmoj I guess this is what you meant with your variant 2? I like it!) This feels to me like it may be the best if the goal is "make the markers bigger when you've zoomed in so there are only a few of them." I worry though that it'll be hard to use, as you'll need to figure out a reasonable scale on both axes and multiply these together, giving a number that might not be very meaningful to you, so you'd likely end up just trying a few things until something looks good.
- I wonder if there's a calculation we could do as an "auto" input to the above variant - something like the std deviation along each axis of all the traces with markers, divided by the total number of markers?
And for all variants, I bet it'll also be important to constrain the max and min resulting sizes. For array-sized markers we already have a marker.sizemin attribute, we should be able to reuse that here, and perhaps add marker.sizemax as well.
I can't imagine any use case where somebody wants an absolute scale, but not absolute in both axes.
What I would use is a fixed radius, which means, r = xscale = yscale. That means it would be an ellipse when zoomed in.
What's the situation when you might want a fixed scale in one axis but not the other?
That said, if you want an ellipse API and a circle API, just make two different shapes?
I would also like to have this feature. If we have same units on each axis like a coordinates in meter for each axis and radius or diameter in meter for each marker we could associate this data to sizing each marker. As proposed by @archmoj I think it would be a good approach for circle data, the markers will appears as circle if axis x and y are orthonormal, as an ellipsis if not.
kiiiiind of a 'solution' would be to draw shapes instead of scatter points for each scatter point with add_shape() here, zooming includes an increase of objects size when coming closer. However there are drawbacks because shapes are not meant to be plot objects but rather drawings/annotations. Therefore things like hover info need to be implemented with invisible scatter points etc. Feels very dodgy but for my purposes it does the job.
Unfortunately, this only really works for small datasets. I managed to plot >100k datapoints as circles using this stack overflow answer but there are so many shapes in the figure that it is essentially impossible to render.