Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
523 views
in Technique[技术] by (71.8m points)

Graphviz: create non overlapping edges from a struct to itself

I am trying to recreate in graphviz a diagram similar to the one taken from the CLR book: enter image description here

I am using the following code in Python:

s = Digraph(node_attr={'shape': 'record'})
s.node('struct', '<f0> 3|<f1> 13|<f2> 1|<f3> 2|<f4> 8|<f5> 5')
s.edge("struct:f0", "struct:f1")
s.edge("struct:f0", "struct:f2")
s.edge("struct:f1", "struct:f3")
s.edge("struct:f1", "struct:f4")
s

The result is: enter image description here

Which is very close to what I want, except the edges overlap the nodes instead of going above/below them.

I couldn't find a way to modify edge behavior. Also, I have a feeling I am misusing the struct feature of graphviz, but I don't know how to force the graph elements to stick together in one row otherwise.

Can I avoid edge overlaps (except by modifying the SVG myself, of course) or use a different approach altogether?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You can use "ports" to set the points of connection.

I tried your graph on the online service, it seems your rendering is with dot http://dreampuf.github.io/GraphvizOnline

You can test with the others, Circo and the rest do not cross the cells, but by default they all draw on one side (bottom) and the edges are messy.

However there are "ports" properties which allow to solve that by specifying suffixes ":s", ":n" etc. n, s, e, w, nw, ne, sw, s. - i.e. south, north etc.... .

It seems that Dot has different default ports than Circo and Neato, the latter are fine with that:

digraph Structs {
    node [shape=record];        
    s [label="<f0> 3|<f1> 13|<f2> 1|<f3>2|<f4>8|<f5>5"];
    s:f0 -> s:f1;
    s:f0 -> s:f2;
    s:f1:n -> s:f3:n;
    s:f1:n -> s:f4:n;
}

enter image description here

Dot needs to specify the ports of the first two nodes, too:

digraph Structs {
    node [shape=record];       
    s [label="<f0> 3|<f1> 13|<f2> 1|<f3>2|<f4>8|<f5>5"];
    s:f0:s -> s:f1:s;
    s:f0:s -> s:f2:s;
    s:f1:n -> s:f3:n;
    s:f1:n -> s:f4:n;
}

So I guess, in your code:

s.edge("struct:f0:s", "struct:f1:s")
s.edge("struct:f0:s", "struct:f2:s")
s.edge("struct:f1:n", "struct:f3:n")
s.edge("struct:f1:n", "struct:f4:n")

See: How to prevent edges in graphviz to overlap each other

Graphviz Dot Edge Ports for Family Tree


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...