dominikbraun / graph

A library for creating generic graph data structures and modifying, analyzing, and visualizing them.
https://graph.dominikbraun.io
Apache License 2.0
1.8k stars 94 forks source link

Add support for vertex attributes in `draw` package #32

Closed dominikbraun closed 1 year ago

dominikbraun commented 2 years ago

Coloring edges when rendering a graph using draw.DOT is no problem, because edges can have arbitrary attributes:

_ = g.AddEdge("A", "B", graph.EdgeAttribute("color", "red"))

These attributes are rendered into the DOT description. So everything's fine here.

This doesn't work for vertices, because vertices are of no dedicated type defined by the library, but of any type T instead. Therefore, there is no straightforward way to add "vertex attributes" like there is for edges.

At the moment, the only viable solution I see is to provide a map when rendering the graph: Each vertex hash is mapped against a set of custom attributes.

attributes := map[string]map[string]string{
    "A": map[string]string{"color": "red"},
    "B": map[string]string{"color": "blue"},
}

_ = draw.DOT(g, myFile, attributes)

I'm open to other ideas and approaches.

tobikris commented 1 year ago

I think the idea with the mapping of the Vertices' hash value is correct. However I think it is possible to store this map in the graph and expose it similarly to the EdgeAttribute option. I will create a PR that implements this.

asphaltbuffet commented 1 year ago

A suggestion that could go along with the implementation so far...

What about putting the mapping directly into the gv output? If you generate a map inside the file with a runtime-generate name for each node, you could add the attributes there instead of spread around the graph. I'm thinking something like:

    q0 [label="0", color="red"]
    q1 [label="1", color="blue", weight="3"]
    q2 [label="2" ]
    q3 [label="3"]

The label could be the hash value or, what I like more, something for user to define how it labels nodes (ie, func(T)string). I will play around with creating something here and provide an example if I get it working.

dominikbraun commented 1 year ago

This is implemented.