igraph / python-igraph

Python interface for igraph
GNU General Public License v2.0
1.28k stars 247 forks source link

SVG output should preserve vertex/edge attributes #608

Open n8willis opened 1 year ago

n8willis commented 1 year ago

What is the feature or improvement you would like to see? Graphs can currently support arbitrary attributes on each vertex and edge. Furthermore, graphs written to some external file formats (such as GraphViz .dot) support attaching id and class and other SVG attributes. But iGraph's SVG writer drops these attributes.

Preserving attributes, primarily, class, in SVG output would allow users to export their network plots with metadata that allows interactive styling in browsers (or perhaps other applications). Just preserving the class and related attributes opens up the possibility of CSS and JavaScript manipulation of vertices and edges without requiring additional work within the iGraph library itself.

Use cases for the feature One of the major benefits of SVG output is that it permits on-the-fly styling of network elements via CSS. Such as highlighting edges with a particular attribute in their class.

Notably, GraphViz already supports this, and GraphViz-exported SVGs can be controlled in-browser with styling tools. E.g., "bolding" the edges connecting some subset of vertices or changing the color of some vertex, just by using CSS rules and a .class selector

References This is standard CSS; nothing out of the ordinary.

szhorvat commented 1 year ago

Which interface of igraph are you using? The core igraph C library does not have an SVG writer. High-level interfaces have differing and independent ways to produce graphics.

n8willis commented 1 year ago

As in bindings? Almost always Python. I've tinkered with R stuff once in a while, but although I don't particularly think I could speak for the R community, I can't see why it would have different expectations. This is exclusively about what gets written into the .svg output file.

szhorvat commented 1 year ago

As I said, the plotting systems of high-level interfaces are entirely separate and unrelated, so this would need to be a separate request for each. I am transferring this to the python-igraph issue tracker.

@iosonofabio Is this feasible for python-igraph? Does matplotlib support metadata that gets preserved upon export to SVG? I know that in Mathematica this is not currently possible. While the graphics system supports annotations, Mathematica's own SVG exporter does not preserve those annotations.

ntamas commented 1 year ago

SVG is actually sort of a special case in the plotting subsystem. Both the Cairo backend and the Matplotlib backend can export figures in SVG format, but at that point all references to igraph itself are lost; you only have a generic "figure" that you can save into SVG.

However, igraph also has a write_svg() method on the Graph class; the implementation currently resides in src/igraph/io/images.py in _write_graph_to_svg(). I am somewhat in favour of allowing the user to specify class attributes for elements of the graph in the exported SVG somehow - but we cannot blindly add all attributes as the result would not be valid SVG according to the SVG specification; for instance, class is an allowed attribute on <path> tags, but some-arbitrary-attribute is not.

n8willis commented 1 year ago

As I said, the plotting systems of high-level interfaces are entirely separate and unrelated, so this would need to be a separate request for each. I am transferring this to the python-igraph issue tracker.

Well, when I was writing my reply, it just said "what interface of igraph are you using". Certainly not objecting to the move; I merely don't want to be the one that the pitchfork-wielding Rillagers come after if the feature-sets drift apart....

Back to the main point, if I can clarify this:

specify class attributes for elements of the graph in the exported SVG somehow - but we cannot blindly add all attributes as the result would not be valid SVG according

(a) The class attribute is, by far, the one that matters the most. For the CSS/JS access mentioned. It's not hard, at least in Python, to convert "foo:x" attributes into "foo_x" class components when one needs to export an SVG.

(b) Secondarily, I would also say that other "valid SVG tags" ought to be preservable. Clearly id matters there, but there might be others; drawing a line somewhere I'm sure has to be done, but I'm not expert enough at on-the-fly CSS and in-browser SVG trickery to have a perspective there.

(c) Personally, I would make a case that the "other, random/arbitrary attributes" in a vs or es should get a look at being preservable through the SVG data-* attribute mechanism. It's certainly not widely-used (in SVG or in HTML, AFAICT), but this seems like a clear application of what it's supposedly for....

Like I said, class does essentially what I need it to, but just saying "everything else gets turned into a data-* and you're on your own at that point" sounds defensible to me. After all, the whole point of data-* is supposedly that you can put non-string values into it, and I can sure see how that would be useful to some people. There could be pathological cases, but IMO that could be handled by slapping big red Warning stickers on the API and reminding everyone that the W3C invented this mechanism. For example.

iosonofabio commented 1 year ago

@n8willis as @ntamas mentioned, there are art least two ways to get svgs out of igraph, i.e. using matplotlib or via write_svg.

Which one are you trying/have you tried to use?

n8willis commented 1 year ago

@n8willis as @ntamas mentioned, there are art least two ways to get svgs out of igraph, i.e. using matplotlib or via write_svg.

Which one are you trying/have you tried to use?

Neither method supports preserving attributes, @iosonofabio.

This is not something I'm "trying" and failing to use; it's behavior that is not currently supported. Hence the feature request.

iosonofabio commented 1 year ago

Ok no immediate need, that's good to know.

I recommend you also ask matplotlib whether they can include custom attributes in their SVG, that'd be the preferred route AFAIAC.

szhorvat commented 1 year ago

Apparently there is some support for this in matplotlib: https://stackoverflow.com/a/46040257/695132

iosonofabio commented 1 year ago

Great to hear! @n8willis why don't you look up or ask the mpl folks about class and once we have an answer we see how to best implement it?