scverse / spatialdata-plot

Static plotting for spatialdata
BSD 3-Clause "New" or "Revised" License
27 stars 13 forks source link

Point sizes disagree between matplotlib and datashader #315

Open Sonja-Stockhaus opened 1 month ago

Sonja-Stockhaus commented 1 month ago

For plotting points with matplotlib, we use the s argument of scatter(). The square root of s specifies the width and height of the markers in points.

In the datashader approach, we use ds.tf.spread(agg, px=px) to regulate the size of the markers. Here, px is calculated like this: px = int(np.round(np.sqrt(render_params.size))), to make the behavior agree to the matplotlib approach.

Problem: If you alter the dpi in pl.show(), the point size of the datashader points remains the same, whileit changes for matplotlib, leading to different sizes:

dpi=100, mpl=blue, ds=white

blob.pl.render_points(element="blobs_points", size=400, color="blue").pl.render_points(element="blobs_points", size=400, color="white", method="datashader", alpha=1).pl.show(dpi=100)

grafik

dpi=200, mpl=blue, ds=white

blob.pl.render_points(element="blobs_points", size=400, color="blue").pl.render_points(element="blobs_points", size=400, color="white", method="datashader", alpha=1).pl.show(dpi=200)

grafik

dpi=50, ds=blue, mpl=white (note: colors and order swapped!)

blob.pl.render_points(element="blobs_points", size=400, color="blue", method="datashader", alpha=1).pl.render_points(element="blobs_points", size=400, color="white").pl.show(dpi=50)

grafik

Sonja-Stockhaus commented 1 month ago

Btw I think for dpi=100, the mpl points are slightly larger than the ds points because marker edges are drawn (default linewidth = 1.5), see https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.scatter.html. However, this is not the actual problem

Sonja-Stockhaus commented 1 month ago

Solution for now: use dpi/100 as a factor to adapt px to varying dpi

Sonja-Stockhaus commented 1 month ago

Now it looks like this, for dpi [50, 100, 200, 300] using blob.pl.render_points(element="blobs_points", size=400, color="blue").pl.render_points(element="blobs_points", size=400, color="yellow", method="datashader", alpha=1).pl.show(dpi=100) Should be correct imo

(matplotlib points bluse, datashader yellow) grafik grafik grafik grafik

LucaMarconato commented 1 month ago

Looks good to me. The tiny pixel offset is probably inevitable and acceptable.