How to center text in custom html-style GraphViz/DiagrammeR node?

49 Views Asked by At

Following the helpful answer of a previous question, there is still an unresolved issue, that the hourglass symbol (i.e. the text in custom node) is not centered, so that vertical edges are not in the middle. I tried also different html-style centering options, but with no success. Any method or a completely different approach would be welcome.

library(DiagrammeR)

graph <- "
digraph logistic_growth {

  graph [rankdir = 'LR', bgcolor='none', fontsize=10]

  node [shape = circle, fontsize=8, penwidth=0.7, fontname='Open Sans']
   r [xlabel=' intrinsic growth rate']
   K [xlabel=' carrying capacity']

  node [shape = box, penwidth=2]
    N [label='Population N']

  node [shape = octagon, width='', penwidth=0.5, style='rounded', fixedsize=25]
    Source Sink

  node [shape=plaintext, width=0.2, height=0.2]
    growth [label=<<table cellpadding='0' border='0' cellspacing='0'><tr><td height='10'></td></tr><tr><td><FONT POINT-SIZE='20'>&#10710;</FONT></td></tr><tr><td>growth</td></tr></table>>]

  edge [penwidth=1.5]
    Source -> growth [dir = none, color = 'blue' headclip=false]
    growth -> N      [dir = left, color = 'blue' tailclip=false]
    N -> Sink

  edge [penwidth=0.7, tailport = 'n', headport = 'n', constraint = false, color=tomato]
    N -> growth

  edge [penwidth=0.7, tailport = 'e', headport = 'n', constraint = false, color=tomato]
    r -> growth
    K -> growth
}
"

grViz(graph)

digraph of a logistic model

1

There are 1 best solutions below

1
sroush On BEST ANSWER

Here is a convoluted but solid solution.

  • run dot (format=dot) with a simple "growth" node. label="", xlabel="growth", and a new attribute hourglass=1 (yep, Graphviz allows user-defined attributes)
  • run the output into a gvpr program (https://www.graphviz.org/pdf/gvpr.1.pdf) that will
    • move the xlabel
    • define a new (bogus) edge with a path (pos) that we will contort into the hourglass shape
  • run that output into neato -n2 ... that will produce the final, complete image
    Result:
    enter image description here

dot input:

digraph logistic_growth {

  graph [rankdir = "LR", XXbgcolor="none", fontsize=10]

  node [shape = circle, fontsize=8, penwidth=0.7, fontname="Open Sans"]
   r [xlabel=" intrinsic growth rate"]
   K [xlabel=" carrying capacity"]

  node [shape = box, penwidth=2]
    N [label="Population N"]

  node [shape = octagon, width="", penwidth=0.5, style="rounded", fixedsize=25]
    Source Sink

  node [shape=plaintext, width=0.2, height=0.2]
    growth [label="" xlabel="\N" hourglass=1]  // any undefined attribute name

  edge [penwidth=1.5]
    Source -> growth [dir = none, color = "blue" headclip=false]
    growth -> N      [dir = left, color = "blue" tailclip=false]
    N -> Sink

  edge [penwidth=0.7, tailport = "n", headport = "n", constraint = false, color=tomato]
    N -> growth:n

  edge [penwidth=0.7, tailport = "e", headport = "n", constraint = false, color=tomato]
    r -> growth:n
    K -> growth:n
}

gvpr program (save as hourglass.gvpr):

BEGIN{
  int i;
  edge_t hGlass;
  string x1, y1, x2, y2, pp1, p2, p3, p4, segment1, segment2, segment3, segment4;
}

N[hourglass=="1"]{
  // first, move xlabel
  oldXLP=xlp;
  xlp=(string)$.X + ","+ (string) yOf($.xlp);
  // create a very bogus edge that will become the hourglass figure
  // need to convert inches to points then divide by 2 == *72/2 == *36
  x1=(string)($.X-(((float)$.width/2)*72));
  x2=(string)($.X+(((float)$.width/2)*72));  
  y1=(string)($.Y-(((float)$.height/2)*72));
  y2=(string)($.Y+(((float)$.height/2)*72));
  p1=x1 + "," + y1 + " ";
  p2=x2 + "," + y1 + " ";
  p3=x1 + "," + y2 + " ";
  p4=x2 + "," + y2 + " ";
  segment1=p1 + p1 + p1 + p2;
  segment2=p2 + p2 + p3;
  segment3=p3 + p3 + p4;
  segment4=p4 + p4 + p1;
  hGlass=edge($, $, "");           //$.name + "->" + $.name);
  hGlass.pos=segment1 + segment2 + segment3 + segment4;
  hGlass.color="black";
}

Finally, the command line (Linux) (Windows can be broken into separate steps)

dot myFile.gv |gvpr -cfhourglass.gvpr |neato -n2 -Tsvg >myFile.svg