Search code examples
graphviz

Can I do this kind of shape in graphviz?


I would like to recreate a diagram similar to the following in graphviz as faithfully as possible.

API Diagram

I am failing with the edges however. There does not seem to be a way to add images to an edge. I also tried to add the image as a separate node with custom image, but this does not rotate the image correctly. Additionally having the text on the edge is something I did not find out how to do (but is much less important). The placement of the nodes is not important but the rotation of the icon is.

So especially for the icon in the center of the edge: is something close to this possible using graphviz? Specifically is should be able to handle the different angles, so that the edges enter and exit at the correct locations.

The following is what I tried:

graph {
  api1 [style="invisible" image="api.png"]
  api2 [style="invisible" image="api.png"]
  api3 [style="invisible" image="api.png"]
  
  A -- api1 -- B
  A -- api2 -- C
  A -- api3 -- D
}

This is api.png:

api.png

This is the output:

Output


Solution

  • While it seems that you can't reproduce the diagram with a single Graphviz engine, it appears that you can produce your desired diagram using multiple Graphviz programs plus some postprocessing.
    Here is a "pretty close" proof-of-concept and the Graphviz input that generated it.
    Use ``neato -n2 ...` to generate the diagram.
    The proof-of-concept was created manually, except for the two half-circles, just because it was quicker. For "real" use, you would want to generate the edge-label-node, the small circle, and the half circle components (with required rotation) with a post-processor like python or gvpr (https://www.graphviz.org/pdf/gvcolor.1.pdf).

    enter image description here

    graph cnc {
      // all layout done be "eye"
      // use neato -n to produce result
    
      "component 1" [pos="100,400"]
      "component 2" [pos="500,400"]
      "component 3" [pos="100,100"]
      "component 4" [pos="500,100"]
    
      lbl1  [pos="330,400" shape=plaintext label="API 1\nHTTP"]
      c1a   [pos="230,400" label="" shape=circle height=".3"]
      c1b   [pos="230,400" label="" shape=circle height=".5" style=invis]
    
      lbl2  [pos="330,220" shape=plaintext label="API 2\nHTTP"]
      c2a   [pos="230,300" label="" shape=circle height=".3"]
      c2b   [pos="230,300" label="" shape=circle height=".5" style=invis]
    
      "component 1" -- c1b
      c1a -- lbl1 -- "component 2"
    
      "component 1" -- c2b
      c2a -- lbl2 -- "component 4"
    
      __Xnode__1  [label=" ",
                   pos="210,400 ",
                   shape=point,
                   style=invis];
      __Xnode__2  [label=" ",
                   pos="230,420 ",
                   shape=point,
                   style=invis];
      __Xnode__3  [label=" ",
                   pos="250,400 ",
                   shape=point,
                   style=invis];
      __Xnode__4  [label=" ",
                   pos="230,380 ",
                   shape=point,
                   style=invis];
    
      __Xnode__1 -- __Xnode__1  [cmd=cw,
                                 color=black,
                                 dir=none,
                                 pos="210,400 210,411.046 218.954,420 230,420 "];
    
      __Xnode__4 -- __Xnode__4  [cmd=cw,
                                 color=black,
                                 dir=none,
                                 pos="230,380 218.954,380 210,388.954 210,400 "];
    
    
    
      __Xnode__21 [label=" ",
                   pos="210,300 ",
                   shape=point,
                   style=invis];
      __Xnode__22 [label=" ",
                   pos="230,320 ",
                   shape=point,
                   style=invis];
      __Xnode__23 [label=" ",
                   pos="250,300 ",
                   shape=point,
                   style=invis];
      __Xnode__24 [label=" ",
                   pos="230,280 ",
                   shape=point,
                   style=invis];
    
      __Xnode__21 -- __Xnode__21  [cmd=cw,
                                   color=black,
                                   dir=none,
                                   pos="210,300 210,311.046 218.954,320 230,320 "];
    
      __Xnode__24 -- __Xnode__24  [cmd=cw,
                                   color=black,
                                   dir=none,
                                   pos="230,280 218.954,280 210,288.954 210,300 "];
    
    }