I am trying to make scatter plot, where I can specify the marker size in data units, instead of display-area units.
I tried to look at the PathCollection object produced by Axes.scatter, but I wasn’t able to work out how to set the transforms. I’m willing to mess around with _ methods, but ideally there’s a way to do that.
There’s a couple of things at play here, but you shouldn’t have to use any private methods for this.
Generate your plot first, and set the x and y axis limits. Once this is done, you can use the standard transformation functions documented in https://matplotlib.org/3.2.1/tutorials/advanced/transforms_tutorial.html
to get the conversion factor from data units to pixels, then just call scatter with the appropriate scaling factor applied to your “s” kwarg.
desired_data_width = 0.5
fig, ax = plt.subplots()
ax.set_xlim([-1, 1])
ax.set_ylim([-1, 1])
M = ax.transData.get_matrix()
xscale = M[0,0]
yscale = M[1,1]
# has desired_data_width of width
plt.scatter(0, -1, marker='s', s=(xscale*desired_data_width)**2)
# has desired_data_width of height
plt.scatter(-1, 0, marker='s', s=(yscale*desired_data_width)**2)
# # for plt.plot, don't square
# plt.plot(0, -1, marker='s', markersize=xscale*desired_data_width)
That said, please note that you may not get the “width” you desire from some markers, since marker’s “default” sizes don’t really make much sense (see e.g. https://github.com/matplotlib/matplotlib/issues/16623). A fix is in the works but will take some time.
For now, if you want to get the “real” widths or heights of the markers, you’ll have to pull from https://github.com/matplotlib/matplotlib/pull/16832, then use code like the following to get the “true” width and height of the marker (for markersize=1):
If you have a more intricate use case (using e.g. log scales), then you can’t use this simple trick and only then will you need to start dealing with the Transform of the PathCollection manually.
I’m interested in the interactivity, which would require me to set the markersize on any change of ax.transData. So if there is a way to access the transformation pipeline from marker path to screen data, I am hoping I could set it once, and then let matplotlib take care of the rest.