Graphviz分层显示子图树

时间:2019-11-28 07:04:04

标签: graphviz dot

我有一个程序可以自动生成graphviz .dot文件,其内容是子图树。当我观察该文件的呈现方式时,树似乎已“展平”,无法很好地显示层次结构。我想知道如何解决此问题,并正确渲染此树。

过去,我曾使用fdp布局程序来渲染此图。它能够显示树的层次结构,但是作为子图的节点的内容不是很可读。我想使用点布局程序,因为它可以更好地对子图的节点进行分层,并且据说是分层图的理想选择。

请参见下面的图片,查看显示渲染效果较差的树的示例图。

enter image description here

生成此图形的代码为:

digraph G {
compound=true
subgraph cluster_649 {label = EPISODE649count3
subgraph cluster_STATE650 {
label = State_1;
EPISODE649HEIGHT643[label="HEIGHT",shape=oval,color=blue];
EPISODE649LEN642[label="LEN",shape=oval,color=blue];
EPISODE649Y641[label="Y",shape=oval,color=blue];
EPISODE649X640[label="X",shape=oval,color=blue];
EPISODE649BLOCK639[label="BLOCK",shape=oval,color=blue];
EPISODE649HEIGHT638[label="HEIGHT",shape=oval,color=blue];
EPISODE649LEN637[label="LEN",shape=oval,color=blue];
EPISODE649Y636[label="Y",shape=oval,color=blue];
EPISODE649X635[label="X",shape=oval,color=blue];
EPISODE649TRIANGLE634[label="TRIANGLE",shape=oval,color=blue];
EPISODE649ON645[label="ON",shape=oval,color=blue];
EPISODE649ON555[label="ON",shape=oval,color=blue];
EPISODE649CLEAR647[label="CLEAR",shape=oval,color=blue];
EPISODE649CLEAR557[label="CLEAR",shape=oval,color=blue];
EPISODE649CLEAR558[label="CLEAR",shape=oval,color=blue];
EPISODE649ON556[label="ON",shape=oval,color=blue];
EPISODE649BLOCK545[label="BLOCK",shape=oval,color=blue];
EPISODE649X546[label="X",shape=oval,color=blue];
EPISODE649Y547[label="Y",shape=oval,color=blue];
EPISODE649LEN548[label="LEN",shape=oval,color=blue];
EPISODE649HEIGHT549[label="HEIGHT",shape=oval,color=blue];
EPISODE649BLOCK550[label="BLOCK",shape=oval,color=blue];
EPISODE649X551[label="X",shape=oval,color=blue];
EPISODE649Y552[label="Y",shape=oval,color=blue];
EPISODE649LEN553[label="LEN",shape=oval,color=blue];
EPISODE649HEIGHT554[label="HEIGHT",shape=oval,color=blue];
EPISODE649BLOCK639 -> EPISODE649HEIGHT643;
EPISODE649BLOCK639 -> EPISODE649LEN642;
EPISODE649BLOCK639 -> EPISODE649Y641;
EPISODE649BLOCK639 -> EPISODE649X640;
EPISODE649TRIANGLE634 -> EPISODE649HEIGHT638;
EPISODE649TRIANGLE634 -> EPISODE649LEN637;
EPISODE649TRIANGLE634 -> EPISODE649Y636;
EPISODE649TRIANGLE634 -> EPISODE649X635;
EPISODE649ON645 -> EPISODE649HEIGHT643;
EPISODE649ON645 -> EPISODE649LEN642;
EPISODE649ON645 -> EPISODE649Y641;
EPISODE649ON645 -> EPISODE649X640;
EPISODE649ON645 -> EPISODE649BLOCK639;
EPISODE649ON645 -> EPISODE649HEIGHT638;
EPISODE649ON645 -> EPISODE649LEN637;
EPISODE649ON645 -> EPISODE649Y636;
EPISODE649ON645 -> EPISODE649X635;
EPISODE649ON645 -> EPISODE649TRIANGLE634;
EPISODE649ON555 -> EPISODE649ON645;
EPISODE649ON555 -> EPISODE649ON556;
EPISODE649CLEAR647 -> EPISODE649HEIGHT638;
EPISODE649CLEAR647 -> EPISODE649LEN637;
EPISODE649CLEAR647 -> EPISODE649Y636;
EPISODE649CLEAR647 -> EPISODE649X635;
EPISODE649CLEAR647 -> EPISODE649TRIANGLE634;
EPISODE649CLEAR557 -> EPISODE649CLEAR647;
EPISODE649CLEAR557 -> EPISODE649CLEAR558;
EPISODE649CLEAR558 -> EPISODE649BLOCK545;
EPISODE649CLEAR558 -> EPISODE649X546;
EPISODE649CLEAR558 -> EPISODE649Y547;
EPISODE649CLEAR558 -> EPISODE649LEN548;
EPISODE649CLEAR558 -> EPISODE649HEIGHT549;
EPISODE649ON556 -> EPISODE649BLOCK545;
EPISODE649ON556 -> EPISODE649X546;
EPISODE649ON556 -> EPISODE649Y547;
EPISODE649ON556 -> EPISODE649LEN548;
EPISODE649ON556 -> EPISODE649HEIGHT549;
EPISODE649ON556 -> EPISODE649BLOCK550;
EPISODE649ON556 -> EPISODE649X551;
EPISODE649ON556 -> EPISODE649Y552;
EPISODE649ON556 -> EPISODE649LEN553;
EPISODE649ON556 -> EPISODE649HEIGHT554;
EPISODE649BLOCK545 -> EPISODE649X546;
EPISODE649BLOCK545 -> EPISODE649Y547;
EPISODE649BLOCK545 -> EPISODE649LEN548;
EPISODE649BLOCK545 -> EPISODE649HEIGHT549;
EPISODE649BLOCK550 -> EPISODE649X551;
EPISODE649BLOCK550 -> EPISODE649Y552;
EPISODE649BLOCK550 -> EPISODE649LEN553;
EPISODE649BLOCK550 -> EPISODE649HEIGHT554;
}
649[shape=point style=invis]
}
subgraph cluster_559 {label = EPISODE559count1
subgraph cluster_STATE651 {
label = State_1;
EPISODE559CLEAR557[label="CLEAR",shape=oval,color=blue];
EPISODE559CLEAR558[label="CLEAR",shape=oval,color=blue];
EPISODE559ON555[label="ON",shape=oval,color=blue];
EPISODE559ON556[label="ON",shape=oval,color=blue];
EPISODE559BLOCK545[label="BLOCK",shape=oval,color=blue];
EPISODE559X546[label="X",shape=oval,color=blue];
EPISODE559Y547[label="Y",shape=oval,color=blue];
EPISODE559LEN548[label="LEN",shape=oval,color=blue];
EPISODE559HEIGHT549[label="HEIGHT",shape=oval,color=blue];
EPISODE559BLOCK550[label="BLOCK",shape=oval,color=blue];
EPISODE559X551[label="X",shape=oval,color=blue];
EPISODE559Y552[label="Y",shape=oval,color=blue];
EPISODE559LEN553[label="LEN",shape=oval,color=blue];
EPISODE559HEIGHT554[label="HEIGHT",shape=oval,color=blue];
EPISODE559CLEAR557 -> EPISODE559CLEAR558;
EPISODE559CLEAR558 -> EPISODE559BLOCK545;
EPISODE559CLEAR558 -> EPISODE559X546;
EPISODE559CLEAR558 -> EPISODE559Y547;
EPISODE559CLEAR558 -> EPISODE559LEN548;
EPISODE559CLEAR558 -> EPISODE559HEIGHT549;
EPISODE559ON555 -> EPISODE559ON556;
EPISODE559ON556 -> EPISODE559BLOCK545;
EPISODE559ON556 -> EPISODE559X546;
EPISODE559ON556 -> EPISODE559Y547;
EPISODE559ON556 -> EPISODE559LEN548;
EPISODE559ON556 -> EPISODE559HEIGHT549;
EPISODE559ON556 -> EPISODE559BLOCK550;
EPISODE559ON556 -> EPISODE559X551;
EPISODE559ON556 -> EPISODE559Y552;
EPISODE559ON556 -> EPISODE559LEN553;
EPISODE559ON556 -> EPISODE559HEIGHT554;
EPISODE559BLOCK545 -> EPISODE559X546;
EPISODE559BLOCK545 -> EPISODE559Y547;
EPISODE559BLOCK545 -> EPISODE559LEN548;
EPISODE559BLOCK545 -> EPISODE559HEIGHT549;
EPISODE559BLOCK550 -> EPISODE559X551;
EPISODE559BLOCK550 -> EPISODE559Y552;
EPISODE559BLOCK550 -> EPISODE559LEN553;
EPISODE559BLOCK550 -> EPISODE559HEIGHT554;
}
559[shape=point style=invis]
}
649 -> 559 [ltail=cluster_649 lhead=cluster_559];
subgraph cluster_625 {label = EPISODE625count1
subgraph cluster_STATE652 {
label = State_1;
EPISODE625CLEAR623[label="CLEAR",shape=oval,color=blue];
EPISODE625CLEAR624[label="CLEAR",shape=oval,color=blue];
EPISODE625ON621[label="ON",shape=oval,color=blue];
EPISODE625ON622[label="ON",shape=oval,color=blue];
EPISODE625BLOCK611[label="BLOCK",shape=oval,color=blue];
EPISODE625X612[label="X",shape=oval,color=blue];
EPISODE625Y613[label="Y",shape=oval,color=blue];
EPISODE625LEN614[label="LEN",shape=oval,color=blue];
EPISODE625HEIGHT615[label="HEIGHT",shape=oval,color=blue];
EPISODE625BLOCK616[label="BLOCK",shape=oval,color=blue];
EPISODE625X617[label="X",shape=oval,color=blue];
EPISODE625Y618[label="Y",shape=oval,color=blue];
EPISODE625LEN619[label="LEN",shape=oval,color=blue];
EPISODE625HEIGHT620[label="HEIGHT",shape=oval,color=blue];
EPISODE625CLEAR623 -> EPISODE625CLEAR624;
EPISODE625CLEAR624 -> EPISODE625BLOCK611;
EPISODE625CLEAR624 -> EPISODE625X612;
EPISODE625CLEAR624 -> EPISODE625Y613;
EPISODE625CLEAR624 -> EPISODE625LEN614;
EPISODE625CLEAR624 -> EPISODE625HEIGHT615;
EPISODE625ON621 -> EPISODE625ON622;
EPISODE625ON622 -> EPISODE625BLOCK611;
EPISODE625ON622 -> EPISODE625X612;
EPISODE625ON622 -> EPISODE625Y613;
EPISODE625ON622 -> EPISODE625LEN614;
EPISODE625ON622 -> EPISODE625HEIGHT615;
EPISODE625ON622 -> EPISODE625BLOCK616;
EPISODE625ON622 -> EPISODE625X617;
EPISODE625ON622 -> EPISODE625Y618;
EPISODE625ON622 -> EPISODE625LEN619;
EPISODE625ON622 -> EPISODE625HEIGHT620;
EPISODE625BLOCK611 -> EPISODE625X612;
EPISODE625BLOCK611 -> EPISODE625Y613;
EPISODE625BLOCK611 -> EPISODE625LEN614;
EPISODE625BLOCK611 -> EPISODE625HEIGHT615;
EPISODE625BLOCK616 -> EPISODE625X617;
EPISODE625BLOCK616 -> EPISODE625Y618;
EPISODE625BLOCK616 -> EPISODE625LEN619;
EPISODE625BLOCK616 -> EPISODE625HEIGHT620;
}
625[shape=point style=invis]
}
649 -> 625 [ltail=cluster_649 lhead=cluster_625];
subgraph cluster_648 {label = EPISODE648count1
subgraph cluster_STATE653 {
label = State_1;
EPISODE648CLEAR646[label="CLEAR",shape=oval,color=blue];
EPISODE648CLEAR647[label="CLEAR",shape=oval,color=blue];
EPISODE648ON644[label="ON",shape=oval,color=blue];
EPISODE648ON645[label="ON",shape=oval,color=blue];
EPISODE648TRIANGLE634[label="TRIANGLE",shape=oval,color=blue];
EPISODE648X635[label="X",shape=oval,color=blue];
EPISODE648Y636[label="Y",shape=oval,color=blue];
EPISODE648LEN637[label="LEN",shape=oval,color=blue];
EPISODE648HEIGHT638[label="HEIGHT",shape=oval,color=blue];
EPISODE648BLOCK639[label="BLOCK",shape=oval,color=blue];
EPISODE648X640[label="X",shape=oval,color=blue];
EPISODE648Y641[label="Y",shape=oval,color=blue];
EPISODE648LEN642[label="LEN",shape=oval,color=blue];
EPISODE648HEIGHT643[label="HEIGHT",shape=oval,color=blue];
EPISODE648CLEAR646 -> EPISODE648CLEAR647;
EPISODE648CLEAR647 -> EPISODE648TRIANGLE634;
EPISODE648CLEAR647 -> EPISODE648X635;
EPISODE648CLEAR647 -> EPISODE648Y636;
EPISODE648CLEAR647 -> EPISODE648LEN637;
EPISODE648CLEAR647 -> EPISODE648HEIGHT638;
EPISODE648ON644 -> EPISODE648ON645;
EPISODE648ON645 -> EPISODE648TRIANGLE634;
EPISODE648ON645 -> EPISODE648X635;
EPISODE648ON645 -> EPISODE648Y636;
EPISODE648ON645 -> EPISODE648LEN637;
EPISODE648ON645 -> EPISODE648HEIGHT638;
EPISODE648ON645 -> EPISODE648BLOCK639;
EPISODE648ON645 -> EPISODE648X640;
EPISODE648ON645 -> EPISODE648Y641;
EPISODE648ON645 -> EPISODE648LEN642;
EPISODE648ON645 -> EPISODE648HEIGHT643;
EPISODE648TRIANGLE634 -> EPISODE648X635;
EPISODE648TRIANGLE634 -> EPISODE648Y636;
EPISODE648TRIANGLE634 -> EPISODE648LEN637;
EPISODE648TRIANGLE634 -> EPISODE648HEIGHT638;
EPISODE648BLOCK639 -> EPISODE648X640;
EPISODE648BLOCK639 -> EPISODE648Y641;
EPISODE648BLOCK639 -> EPISODE648LEN642;
EPISODE648BLOCK639 -> EPISODE648HEIGHT643;
}
648[shape=point style=invis]
}
649 -> 648 [ltail=cluster_649 lhead=cluster_648];
}

观察到为了在群集之间绘制边缘,我在每个群集中创建了不可见节点,例如:625[shape=point style=invis]并连接了两个不可见节点(如果两个群集之间存在父/子关系),像:649 -> 625 [ltail=cluster_649 lhead=cluster_625];

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

您看不见的节点是一个好主意,但是您被的(未写的?)规则所吸引,该规则要求所有节点都应处于同一等级,除非有命令“强制”新的排名。如果将“ 不可见”更改为“ 点缀”,您将看到这些节点发生了什么。
我试图找到一种简单的方法来使与这些额外的节点很好地协作,但是失败了。
最终,我使用了一些现有节点来实现我认为的目标。 我将这些边缘保持可见,因此您可以轻松看到我的更改。
我还添加了外围设备和边距属性。
程序的简化版本:

digraph G {
  compound = true 
  // a dummy cluster to pad the left side
  subgraph cluster_dummy{
      label="" ; peripheries=0;node[style=invis]; {rank=same _a; _b }
  }

  peripheries=0

  subgraph cluster_649 {
    label = EPISODE649count3 

    subgraph cluster_STATE650 {
    graph [ margin=30]
      label = State_1;
      // unmodified nodes go here
    }
  } 


  subgraph cluster_559 {
    label = EPISODE559count1 

    subgraph cluster_STATE651 {
    graph [ margin=30]
      label = State_1;
      // unmodified nodes go here
    } 
   }

  subgraph cluster_625 {

    label = EPISODE625count1 
    subgraph cluster_STATE652 {
      graph [ margin=30]
      label = State_1;
      // unmodified nodes go here
      } 
     }

  subgraph cluster_648 {

    label = EPISODE648count1
    subgraph cluster_STATE653 {
      graph [ margin=30]
      label = State_1;
      // unmodified nodes go here
      }
    }

  EPISODE649HEIGHT638 -> EPISODE559ON555  [weight=0 style=dotted]
  EPISODE649HEIGHT638 -> EPISODE625ON621  [weight=0 style=dotted]
  EPISODE649HEIGHT638 -> EPISODE648ON644  [weight=0 style=dotted]
}  

enter image description here