Open iosonofabio opened 1 year ago
Regarding the stretching of plots: IMO the right approach here is to just use the natural aspect ratio, and simply not stretch. Unfortunately, matplotlib stretches by default, and requires an extra setting to avoid this. People often skip this, which is why so many plots I see in papers are just slightly off, circles being just slightly oval ...
With almost all graph layouts, the horizontal and vertical coordinates are comparable (i.e. effectively have the same unit). Thus stretching will mess up not only the node rendering, but also the layout. Ideally, the default would be a natural aspect ratio. If someone truly needs to stretch the layout, which should be rare, they can still easily rescale the horizontal coordinates while leaving the vertical ones intact.
All that said, the feature to keep the aspect ratio of nodes even the plot aspect ratio is changed is not a bad one.
But please do consider what tradeoffs need to be made to implement this feature. If there's no tradeoff, go for it. However, if there's a drawback, or if it constrains what we can do in the future, then perhaps it's better not to do it.
Looking at the two proposed solutions, I'm definitely in favour of option 2 instead of option 1. But, I was wondering whether this closes the door for other directions, like adding images, pie charts or other custom artists as nodes.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.
Maybe another answer could be to use a PathCollection instead but I'm not an expert in matplotlib...
Thank you, this is all done in the develop
branch
Taken from #638 where @alex180500 requests matplotlib plots where vertices (e.g. circles) do not become ellipses upon stretching the x-axis. Here is his example, which reproduces on my machine:
The question from the user is whether we can make the matplotlib plot look closer to how it looks in Cairo.
Now the issue is that matplotlib has two ways of drawing e.g. circles:
matplotlib.patches.Circle
: currently used, uses consistent transform for location and radius -transData
ax.scatter
: apart from the weird square-root radius quirk, it usestransData
for location but other units (dots?) for radius (they call its
)The current choice works in such a way that when you zoom in the circles become bigger. That is what you would get by literally using a loupe on a raster image with the plot - i.e. what you get with Cairo + manual zoom. However, because the circle is defined in data units, it really dislikes changes of aspect ratio (e.g. zoom in only one axis), in which cases the circles become ellipses. Notice that in Cairo's result (e.g. PNG), if you zoomed in only horizontally you would get the same artifact.
The alternative would be friendly to changes of aspect ratios, but the dot size is independent of zoom, i.e. the radius is fixed in dots/pixels.
The short answer is that unless we create a customized third way of making circles in matplotlib (and triangles, etc.) which is currently out of question because of time constraints, we cannot reproduce Cairo's behaviour exactly within matplotlib.
Proposed solutions One way to reproduce something close to (but not exactly equal to) Cairo would be to rescale manually the markers for x and y axis separately (e.g. circles would become ellipses). We would need to:
The main issue with this - in addition to the fact it's hacky - is that as soon as the user starts changing the aspect ratio or zooming around, it will all fall apart. The other problem is that an
Axes
does not really have a fixed number of pixels - aFigure
does, but ourAxes
could be a subplot and the padding between subplots can be adjusted post-facto: all of that would change the aspect ratio, sometimes slightly, sometimes not so much, and circles are not circles anymore.The other way to solve this would be to switch to scale-free
ax.scatter
for our vertices. That could be done but because we allow per-vertex setting of shapes, we would need to create aPolyCollection
for each vertex. Not a problem, just hacky. We would also need to undo the square-root size thing likeseaborn
has done long ago. Finally, we would be constrained in terms of shapes to the ones covered byax.scatter
, listed inmatplotlib.markers
. Tbh, I'm having a look right now and there's everything we need there including custom vertices and paths.Next steps If we implement this, especially solution 2, this will change quite significantly the way matplotlib + igraph plots behave. I'm generally in favour but it'd be best to hear a few people's feedback including @tacaswell if possible. I did notice that the old project
grave
(networkx
+matplotlib
container artist) faced the exact same issue and there did not appear to be a straight solution there.