顶部对齐节点

5

问题

以下图片展示了一个组织结构图:

不期望的输出

Full Name 的方框是以它们的中心对齐。然而,期望的布局是将这些框沿着顶部对齐:

期望的输出

源代码

该图表的代码如下:

digraph G {
  fixedwidth = true;

  node [
    shape="box",
    style="rounded",
    penwidth = 1,
    width=2.0,
    fontname = "Arial",
    fontsize = 12
  ];

  edge [
    color="#142b30",
    arrowhead="vee",
    arrowsize=0.75,
    penwidth = 2,
    weight=1.0
  ];

  A1 [ label = <
    <TABLE BORDER="0" CELLSPACING="5">
      <TR>
        <TD><FONT POINT-SIZE="16">Top Level</FONT></TD>
      </TR>
      <TR>
        <TD><FONT POINT-SIZE="18">Owner</FONT></TD>
      </TR>
    </TABLE>>
  ];

  B3 [ label = <
    <TABLE BORDER="0" CELLSPACING="5">
      <TR>
        <TD><FONT POINT-SIZE="12">Second Level<BR/>(1)</FONT></TD>
      </TR>
      <TR>
        <TD><FONT POINT-SIZE="14">Owner</FONT></TD>
      </TR>
    </TABLE>>
  ];

  B4 [ label = <
    <TABLE BORDER="0" CELLSPACING="5">
      <TR>
        <TD><FONT POINT-SIZE="12">Second Level<BR/>(2)</FONT></TD>
      </TR>
      <TR>
        <TD><FONT POINT-SIZE="14">Owner</FONT></TD>
      </TR>
    </TABLE>>
  ];

  B5 [ label = <
    <TABLE BORDER="0" CELLSPACING="5">
      <TR>
        <TD><FONT POINT-SIZE="12">Second Level<BR/>(3)</FONT></TD>
      </TR>
      <TR>
        <TD><FONT POINT-SIZE="14">Owner</FONT></TD>
      </TR>
    </TABLE>>
  ];

  B6 [ label = <
    <TABLE BORDER="0" CELLSPACING="5">
      <TR>
        <TD><FONT POINT-SIZE="12">Second Level<BR/>(4)</FONT></TD>
      </TR>
      <TR>
        <TD><FONT POINT-SIZE="14">Owner</FONT></TD>
      </TR>
    </TABLE>>
  ];

  C4 [ label = <
    <TABLE BORDER="0" CELLPADDING="0" ALIGN="LEFT">
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
    </TABLE>>
  ];

  C5 [ label = <
    <TABLE BORDER="0" CELLPADDING="0" ALIGN="LEFT">
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
    </TABLE>>
  ];

  C6 [ label = <
    <TABLE BORDER="0" CELLPADDING="0" ALIGN="LEFT">
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
    </TABLE>>
  ];

  C7 [ label = <
    <TABLE BORDER="0" CELLPADDING="0" ALIGN="LEFT">
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
      <TR>
        <TD ALIGN="LEFT"><FONT POINT-SIZE="10">Full Name</FONT></TD>
      </TR>
    </TABLE>>
  ];

  { rank = same; B3; B4; B5; B6; }

  A1 -> B3:n;
  A1 -> B4:n;
  A1 -> B5:n;
  A1 -> B6:n;

  { rank = same; C4; C5; C6; C7; }

  B3 -> C4;
  B4 -> C5;
  B5 -> C6;
  B6 -> C7;
}

问题

如何将"全名"文本框顶部对齐?

谢谢!

3个回答

2

也许不完全符合您的要求,但是您可以通过设置盒子的高度相同来实现(使用fixedsize=true,height="some number"),然后文本可以默认居中。因此,添加以下行:

C4 [fixedsize=true,height=2];
C5 [fixedsize=true,height=2];
C6 [fixedsize=true,height=2];
C7 [fixedsize=true,height=2];

会导致如下结果: 如果不完全存在,看起来更好...

1

1

[更完整的答案可以在这里找到:https://forum.graphviz.org/t/is-there-a-way-to-justify-align-nodes-on-the-same-rank/1494/4]
它是可以实现的,但需要几个步骤:

  • rankjustify= X添加到您想要对齐的所有节点的新属性中,其中X可以是t|b|l|r|c|max|min。不同的节点可以具有不同的rankjustify值。
  • 运行dotgvprneato以生成所需的图形
    • dot -Tdot myfile.gv | gvpr -cf rankJustify.gvpr | neato -n -Tpng >myfile.png

gvpr是Graphviz软件包的一部分,请参见https://www.graphviz.org/pdf/gvpr.1.pdf

这是rankJustify.gvpr:

//
// justify nodes that are on the same rank
//
BEGIN {
  int nxt=0, i, vert, rankPos[], OK[], checked[];
  string RankDir;
  float num, deltaX, deltaY, maxHeight[], maxWidth[];
  graph_t aGraph, Root, Parent[];
  node_t  aNode; 
  ///////////////////////////////////////////////////////////////////////////////
  void nodeJustify(node_t aN){
    float XX, YY;
    int err;

    if(checked[aN]==1) return;
    checked[aN]=1;    
    if (! hasAttr(aN, "rankjustify") || aN.rankjustify=="") continue;
    XX=aN.X;
    YY=aN.Y;
    deltaX=0.;
    deltaY=0.;
    if (vert==1){
      deltaY=72.*(maxHeight[aN.Y]-(float)aN.height)/2.;  // inches to points
    }else{
      deltaX=72.*(maxWidth[aN.X]-(float)aN.width)/2.;    // inches to points
    }
    aN.oldPos=aN.pos;
    switch(OK[aN.rankjustify]){
      case "1":
        break;
      case "-1":
        deltaX=-deltaX;
        deltaY=-deltaY;
        break;
      case "0":
        deltaX=0.;
        deltaY=0.;
        break;    
      default:
        print("//  Error:: node ",aN.name, " has invalid rankjustify value (", aN.rankjustify,")");
        printf(2, "Error:: node %s, has invalid rankjustify value (%s)\n", aN.name, aN.rankjustify);      
        continue 2;  // exit two levels
        break;
    }
    aN.pos=sprintf("%.2f,%.2f", (aN.X + deltaX), (aN.Y + deltaY));  
    if (hasAttr(aN,"xlp") && aN.xlp!="") {
      sscanf (aN.xlp, "%lf,%lf", &XX, &YY);
      aN.xlp=sprintf("%.2f,%.2f", (XX + deltaX), (YY + deltaY));
    }
  }
  ///////////////////////////////////////////////////////////////////////////////
  void checkaGraph(graph_t aGraph){
      for (aNode=fstnode(aGraph);aNode;aNode = nxtnode_sg(aGraph, aNode)){
        Parent[aNode]=aGraph;
        // first pass through the nodes
        // find max width/height for each rank/cluster (based on common Y or X)
        if (RankDir=="TB|BT"){
          rankPos[aNode.Y]=1;
          if (maxHeight[aNode.Y]<aNode.height){
            maxHeight[aNode.Y]=aNode.height;
          }
        } else {   // LR or RL
          rankPos[aNode.X]=1;
          if (maxWidth[aNode.X]<aNode.width)
            maxWidth[aNode.X]=aNode.width;
        }
      }
      for (aNode=fstnode(aGraph);aNode;aNode = nxtnode_sg(aGraph, aNode)){
        nodeJustify(aNode);
      }
  }
  ///////////////////////////////////////////////////////////////////////////////
  graph_t graphTraverse(graph_t thisG){
    for (aGraph = fstsubg(thisG); aGraph; aGraph = nxtsubg(aGraph)) {
      if (match(aGraph.name,"cluster")==0 || (hasAttr(aGraph, "cluster") && aGraph.cluster=="true")){
        unset(maxWidth);
        unset(maxHeight);   
        checkaGraph(aGraph);
      }
      aGraph = graphTraverse(aGraph);
    }
    return thisG;
  }  // end of graphTraverse
}
BEG_G{
  Root=$G;
  if (hasAttr(Root, "layout")){
    // other values (including "") cause problems with later execution
    Root.layout="neato";  
  }
  if (! hasAttr(Root, "splines") || Root.splines==""){
    // dot defaults to true, neato defaults to false
    Root.splines="true";  
  }  
  //  determine acceptable justification values
  if (! hasAttr($G, "rankdir") || $.rankdir==""){
    RankDir="TB";
  }else{
    RankDir=$G.rankdir;
  }
  vert=1;
  OK["c"]   =0;
  if (RankDir=="TB") {
    OK["t"]   =1;
    OK["b"]   =-1;
    //OK["max"] =1;
    //OK["min"] =-1;
    OK["max"] =-1;
    OK["min"] =1;
    OK["l"]   =1;
    OK["r"]   =-1;
  }  else if (RankDir=="BT"){
    OK["t"]   =1;
    OK["b"]   =-1;
    //OK["max"] =-1;
    //OK["min"] =1;
    OK["max"] =1;
    OK["min"] =-1;
    // do we really want these next two?
    OK["l"]   =1;
    OK["r"]   =-1;  
  }  else if (RankDir=="LR"){
    vert=0;
    OK["l"]   =-1;
    OK["r"]   =1;
    //OK["max"] =-1;
    //OK["min"] =1;
    OK["max"] =1;
    OK["min"] =-1;
    // do we really want these next two?
    OK["t"]   =-1;
    OK["b"]   =1;
  }  else if (RankDir=="RL"){
    vert=0;
    OK["l"]   =-1;
    OK["r"]   =1;
    //OK["max"] =1;
    //OK["min"] =-1;
    OK["max"] =-1;
    OK["min"] =1;
  }
  // traverse the graph
  //   find all clusters
  //      within each cluster, find all nodes (at highest level
  //        find max & min Y (or X) within the set of nodes
  //        then revisit all of the nodes and adjust Y (or X) as desired
  // (finally) for all nodes not visited
  //        find max & min Y (or X) within the set of nodes
  //        then revisit all of the nodes and adjust Y (or X) as desired
  graphTraverse (Root);
  unset(maxWidth);
  unset(maxHeight);
  checkaGraph(Root);
}

这是对齐后的原始输入:
在此输入图像描述


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接