Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vertex size scaling is broken, it is not resolution-independent #722

Open
szhorvat opened this issue Oct 15, 2023 · 9 comments
Open

Vertex size scaling is broken, it is not resolution-independent #722

szhorvat opened this issue Oct 15, 2023 · 9 comments

Comments

@szhorvat
Copy link
Member

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.

image

Sizes in an SVG are different again.

image

Version information

0.11.2

@szhorvat
Copy link
Member Author

Is there a reasonably quick fix to this, @iosonofabio ?

@iosonofabio
Copy link
Member

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?

@szhorvat
Copy link
Member Author

I keep bumping into this, it would be great to prioritize it if possible ...

@ntamas
Copy link
Member

ntamas commented Jan 24, 2024

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.

@ntamas
Copy link
Member

ntamas commented Jan 24, 2024

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?

@szhorvat
Copy link
Member Author

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.

@szhorvat
Copy link
Member Author

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.

@iosonofabio
Copy link
Member

That should already be possible using matplotlib savefig with explicit dpi setting. Give it a shot if you haven't yet

@szhorvat
Copy link
Member Author

szhorvat commented Jan 24, 2024

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 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants