Graphviz 如何获得3个不同级别的单个集群?

Graphviz 如何获得3个不同级别的单个集群?,graphviz,dot,Graphviz,Dot,这是我的点文件: digraph G { rankdir=TB; ranksep=1; subgraph cluster_application { subgraph cluster_module_core { init_a -> service_a; init_a -> service_b; init_a -> service_c; init_a -> servi

这是我的点文件:

digraph G {
   rankdir=TB;
   ranksep=1;

   subgraph cluster_application {

       subgraph cluster_module_core {
         init_a -> service_a;
         init_a -> service_b;
         init_a -> service_c;
         init_a -> service_d;
       }

       subgraph cluster_module_a {
         init_d -> service_c_1;
         init_d -> service_d_1;
       }

       subgraph cluster_module_b {
         init_b -> service_a_1;
         init_b -> service_b_1;
       }

       subgraph cluster_module_db {
         init_c -> db_service;
         db_service -> db;
       }
   }

   main -> init_a;
   main -> init_b;
   main -> init_c;
   main -> init_d;

   service_a -> service_a_1;
   service_b -> service_b_1;
   service_c -> service_c_1;
   service_d -> service_d_1;

   service_a_1 -> db_service;
   service_b_1 -> db_service;
   service_c_1 -> db_service;
   service_d_1 -> db_service;
}
如何获得如下所示的视觉效果:

                        Main
                         |
                         |
                   +------------+
                   |    core    |
                   +------------+
                    /  /     \  \
                   /  /       \  \
          +-----------+     +-----------+
          | Module A  |     |  Module B |
          +-----------+     +-----------+
                   \  \       /  /
                    \  \     /  /
                   +-------------+
                   | Module DB   |
                   +-------------+

所以我们可以清楚地看到ModuleA和ModuleB充当了中间产品?我试着将它们分组,但我仍然让它们在垂直轴上重叠,而不是在不同的层次上。我不介意行与框交叉,否则是不可能的

一旦您对graphviz在图形上定位节点的方式不满意,您将进入一个丑陋的世界,其中包含不可见的边、约束错误和权重

我为您的
main->init_c
边添加了
constraint=false
属性,并添加了一些不可见边(为了清晰起见,我临时将它们标记为红色)。如果要进一步调整节点和簇的位置,可以使用不同边的
weight
属性

digraph G {
   rankdir=TB;
   ranksep=1;

   subgraph cluster_application {

       subgraph cluster_module_core {
         init_a -> service_a;
         init_a -> service_b;
         init_a -> service_c;
         init_a -> service_d;
       }

       subgraph cluster_module_a {
         init_d -> service_c_1;
         init_d -> service_d_1;
       }

       subgraph cluster_module_b {
         init_b -> service_a_1;
         init_b -> service_b_1;
       }

       subgraph cluster_module_db {
         init_c -> db_service;
         db_service -> db;
       }
   }

   main -> init_a;
   main -> init_b;
   main -> init_c [constraint=false]
   main -> init_d;

   service_a -> service_a_1;
   service_b -> service_b_1;
   service_c -> service_c_1;
   service_d -> service_d_1;

   service_a_1 -> db_service;
   service_b_1 -> db_service;
   service_c_1 -> db_service;
   service_d_1 -> db_service;

   service_d -> init_d [color="red"] #[style=invis]
   service_d -> init_b [color="red"] #[style=invis]
   service_d_1 -> init_c [color="red"] #[style=invis]
   service_b_1 -> init_c [color="red"] #[style=invis]
}
结果:

谢谢,我想在选择哪些不可见边的背后有什么特殊的逻辑吗?从外观上看,逻辑似乎是以对称方式形成一条公共路径,边缘指向节点,而不改变内部节点的权重。所以init总是第一个。@LoïcFaure Lacroix没有特别的逻辑,我通常做的是绘制一个没有不可见边的图形,然后开始将它们添加到需要添加的部分。例如,在垂直图形中,如果B在图形上大约出现在a的下方,我会将a到B之间的边添加到图中。很难看的想法。