Vertex size scaling is broken, it is not resolution-independent
Describe the bug
When plotting graphs, the size of vertices should be independent of the resolution.
In short, the vertex sizes should be independent of the output format and of the output resolution.
To reproduce
Method 1:
from igraph import Graph, plot
g = Graph.Lattice([3,3])
plot(g, backend='matplotlib')
Now change the resolution and plot again:
import matplotlib as mpl
mpl.rcParams['figure.dpi'] = 300
plot(g, backend='matplotlib')
Notice that the thickness of edges stays constant (they are just rendered at a higher resolution), but the size of vertices changes.
Method 2:
In a Jupyter notebook, set:
%matplotlib inline
Now plot, plot(g, backend='matplotlib')
Then set
%config InlineBackend.figure_format = 'retina'
and plot again.
Sizes in an SVG are different again.
Version information
0.11.2
Is there a reasonably quick fix to this, @iosonofabio ?
Not sure, we use the same units for edge thickness and vertex size AFAIK. Perhaps you could try to reproduce using vanilla matplotlib with lines vs dots and ask on their forum?
I keep bumping into this, it would be great to prioritize it if possible ...
This is more complicated than it seems. First, we can't just change this overnight because that would break the layout of existing plots. Second, we would need to define formally what the units mean for vertex sizes or edge thicknesses. Right now the vertex size is defined in the units of the plotting backend. This is already confusing enough: for instance, a vertex size of 20 is probably going to be 20 pixels in the Cairo backend when plotting to PNG but 20 points when plotting to PDF. Matplotlib also has multiple backends on its own (PyQt, wxWidgets, Agg, Tkinter, PNG, PDF etc). Add the complexity of having multiple backends on top of that and you end up with the mess that we have now.
The problem is that we cannot simply say that "okay, from now on, a vertex size of 20 will mean 20 points" because then we'd have to write shedloads of additional code for the Cairo backend to take care of conversion into pixels for the PNG backend, and we'd also have to go through the Matplotlib code and its various backends to see how the Matplotlib backend handles sizes and whether it's consistent with what we expect. I don't think there's a quick solution for this.
Note that there are also inconsistencies in how Jupyter Notebook handles the "retina" resolution of its InlineBackend: in Jupyter Notebook, the figures are of the same size but higher resolution when you turn it on. However, in an HTML rendering of the notebook, the figures are of the same resolution but twice the size. Illustration here. The VSCode Jupyter Notebook extension also had a bug similar to this in the past - it's solved now, but it shows how hard it is to get this right.
I think that we need to limit the scope of this issue in order to make some progress. I cannot reasonably aim to provide consistent plotting of vertex sizes across all backends at this stage. What we can probably aim for is to ensure that switching between retina and non-retina rendering in Jupyter Notebook does not change the vertex sizes relative to the entire figure. Would that be enough as a first step?
What we can probably aim for is to ensure that switching between retina and non-retina rendering in Jupyter Notebook does not change the vertex sizes relative to the entire figure. Would that be enough as a first step?
Absolutely.
It's good to note that NetworkX's plotter does not have this issue with the vertex sizes changing when switching to retina. It might be worth looking at how they do it.
IMO the main use case is being able to change the resolution when exporting to bitmap formats. Interactive backends are not as important. This is not just for using "retina" resolutions on a Mac. It's for creating publication quality figures in scenarios where vector formats are not ideal. It should be possible to render the same plot at arbitrary resolutions without changing the plot appearance.
That should already be possible using matplotlib savefig with explicit dpi setting. Give it a shot if you haven't yet
This is what I tried:
igraph.plot(g, backend='matplotlib')
plt.savefig("grfg.png", dpi=144)
with different dpi values. The larger the dpi setting, the smaller the vertices get. What are you doing differently @iosonofabio ?
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.
I'll take this on in iplotx: fabilab/iplotx#5 -because the codebase over there is much easier to work with.