pygraphviz
pygraphviz copied to clipboard
Unable to add node and edge attributes in subgraph
Hi,
python-pygraphviz 1.7-1 with python 3.9.2
First, thank you for your job ;o)
I'm using pygraphviz to draw Pert graph and I use subgraph to isolate critical path, timeline path...
This version was unable to add node and edge attributes ? here is my code :
viz = pygraphviz.AGraph()
sb_tl = viz.add_subgraph(name='timeline')
sb_tl.node_attr.update(fixedsize=True, width=0.5, fontcolor='blue')
sb_tl.edge_attr.update(fontcolor='red')
the part of print of viz:
subgraph timeline {
graph [fixedsize=True,
fontcolor=red,
width=0.5
is there a good or a missing implementation ? or a bug ?
Thank you ;o)
I forget this
The subgraph inherits well many properties from the parent
@aguytech is this issue resolved in your second comment or is there still something that needs to be addressed?
This subgraph example doesn't have any nodes in the subgraph to make the node attributes and edge attributes show up. Try something like this:
A=pygraphviz.AGraph()
sg=A.add_subgraph(name="subgraph_1", fontcolor="purple", shape="oval")
sg.add_node(5, fontcolor="blue")
sg.add_edge(3, 4, fontcolor="red")
output:
strict graph "" {
subgraph subgraph_1 {
graph [fontcolor=purple,
shape=oval
];
5 [fontcolor=blue];
3 -- 4 [fontcolor=red];
}
}
Not also that there is a single subgraph attribute for fontcolor. The default value will hold for both nodes and edges. If you want nodes' attribute to be different from edges you should assign the attributes to the nodes and edges directly.
Hi,
Thanks for your helps ;o)
Of course, I used the additions of attributes by nodes. But from my point of view, it's sad not to use the ability of DOT to put attributes in the definition of the subgraph.
it's lighter, simpler and more elegant.
It is hard to tell what you are getting and what you want to happen instead. As far as I can tell, it is doing what you want it to do -- except maybe that fontcolor is being set for the entire subgraph instead of just for nodes or edges. That is a Graphviz restriction as far as I can tell.
I'm sorry but all I'm asking to "pygraphviz" is to respect the graphviz possibilties.
When I put my subgraph of ranks definition on the top of definition of graph, graphviz rendering on an website or in the bash executable works very nicely.
i just want to produce a specific dot file, not to manage graphviz rendering motor
Have a nice day ;o)
Hi I agree with @aguytech as I am having similar issues. Maybe I can explain the problem a bit better.
Let's say I want to make a simple graph as follows (image generated with [http://viz-js.com/]:
The pygraphviz code I would use would look like this:
# make the main graph
A = pgv.AGraph()
A.node_attr["color"] = "purple"
A.node_attr["shape"] = "oval"
# make a subgraph/cluster
B = A.add_subgraph(name="cluster_1")
B.graph_attr["color"]="lightgrey"
B.graph_attr["label"]="cluster#1"
B.node_attr["color"] = "red"
B.node_attr["shape"] = "triangle"
B.add_edge("b1","b2")
#Create and connect nodes
A.add_edge("start", "a1")
A.add_edge("a1", "a2")
A.add_edge("a2", "end")
A.add_edge("start", "b1")
A.add_edge("b2", "end")
# print dot file to standard output
print(A.string())
#generate png file
A.draw("subgraph.png", prog="dot")
Note the attributes for the triangle shape and red colour of the nodes in the subgraph, are being added to the subgraph B attributes and not to individual nodes.
The expected Dot output would be:
strict graph "" {
node [color=purple,
shape=oval
];
subgraph cluster_1 {
graph [color=lightgrey,
label="cluster#1"
];
node[color=red,
shape=triangle
];
b1 -- b2;
}
b2 -- end;
start -- b1;
start -- a1;
a1 -- a2;
a2 -- end;
}
Again note how subgraph cluster_1 has both graph and node attributes that override the main graph attributes and apply only to nodes "b1" and "b2", defined in the subgraph. This is the Dot output used to generate the first image.
However pygraphviz output looks like this instead:
strict graph "" {
node [color=purple,
shape=oval
];
subgraph cluster_1 {
graph [color=red,
label="cluster#1",
shape=triangle
];
b1 -- b2;
}
b2 -- end;
start -- b1;
start -- a1;
a1 -- a2;
a2 -- end;
}
The node attributes (and edge attributes if used) are missing from the subgraph despite being defined in the pygraphviz code. Instead pygraphviz keeps on using the node attributes defined in the main graph for the subgraph as well i.e. the subgraph inherits the main graph node attributes. Furthermore the node attributes defined for the subgraph are mistakenly used as graph attributes for the subgraph. In this example the subgraph nodes should have a red colour and the subgraph cluster itself a lightgrey outline. Instead the lightgrey graph parameter is being overwritten by the red node parameter. This results in this graph being produced:
Is the problem clearer now?
Thanks @laspir for the excellent minimal reproducer + analysis! It does indeed seem like some of the attributes are not being mapped to the appropriate objects (node_attr on the subgraph mapping to the subgraph itself rather than the subgraph nodes, for example).
This example makes this issue more clear. Thank you! It sure looks like the attributes within a subgraph are all treated as subgraph attributes, instead of allowing default node/edge attributes within a subgraph. We had trouble implementing both the default attributes on the main graphs and subgraph attributes themselves due to holes in the documentation for the graphc library. Hopefully there is some better documentation now to help us figure out how to manage default node/edge attributes within a subgraph. :}
It would be great to get this solved! Does anyone know if it's going to be solved anytime soon?
As a temporary workaround, I like using add_nodes_from and add_edges_from instead of respectively node_attr.update and edge_attr.update (which don't work on subgraphs) as the code is more efficient and its structure is somewhat preserved (although attributes are still added to individual nodes with this method, also placement of the add_nodes_from is relevant):
# make the main graph
A = pgv.AGraph()
# make the main graph
A = pgv.AGraph()
A.node_attr.update(color="purple", shape="oval")
A.edge_attr.update(color="purple", style="solid", penwidth=1)
# make a subgraph/cluster
B = A.add_subgraph(name="cluster_1", color="lightgrey", label="cluster#1")
B.add_edge("b1","b2")
B.add_nodes_from(B.nodes(), color="red", shape='triangle')
B.add_edges_from(B.edges(), color="red", style="dashed", penwidth=2)
#Create and connect nodes
A.add_edge("start", "a1")
A.add_edge("a1", "a2")
A.add_edge("a2", "end")
A.add_edge("start", "b1")
A.add_edge("b2", "end")
# print dot file to standard output
print(A.string())
#generate png file
A.draw("subgraph.png", prog="dot")
The result is:
The workaround of setting attributes on the nodes themselves work of course. But it would be great to have the node [color=white];
syntax available for subgraphs too because it makes the generated dot file much cleaner.