Dot/Graphviz 家谱可视化中的节点放置

Node placement in family tree visualization with Dot/Graphviz

我正在尝试使用 Dot/Graphviz 从数据库生成家谱可视化。第一个结果看起来很有希望,但有一个布局问题我还没有解决。

当我使用下面列出的代码时,它会产生

我对此非常满意。但是一旦我尝试在家族 F4/M4/M5 和 F2/M2 之间添加另一个节点,这可以通过取消注释下面代码中的两行来完成,它将给我

Male2 现在离Female2 很远,在Female4 和Male4 之间。于是F2/M2和F4/M4/M5一家就彻底撕裂了。我试图增加家庭联系的权重(值为 100)以确保家庭 F2/M2 和 F4/M4/M5 放在一起,但这不起作用。到目前为止,更改节点或连接的顺序也无济于事。最好的解决方案是,如果 family F4/M4/M5 可以放在左边,MaleX 放在中间,family F2/M2 放在右边。

有人有什么建议吗?我宁愿不更改节点和连接在代码中定义的顺序,因为这是由脚本完成的,并且是由数据库结构预定义的。

graph Test {

rankdir = BT;
splines = ortho;
center = true;

{
rank = same;
NodeFemale1 [label = Female1];
NodeMale1 [label = Male1];
ConnectionFemale1Male1 [shape = box, label = "", height = 0, width = 1, margin = 0, penwidth = 1];
NodeFemale1 -- ConnectionFemale1Male1 -- NodeMale1 [weight = 100, penwidth = 2];
}

ConnectionChildren11 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
ConnectionFemale1Male1 -- ConnectionChildren11 [penwidth = 2];

{
rank = same;
NodeFemale2 [label = Female2];
NodeMale2 [label = Male2];
ConnectionFemale2Male2 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
NodeFemale2 -- ConnectionFemale2Male2 -- NodeMale2 [weight = 100, penwidth = 2];
}

ConnectionChildren11 -- NodeMale2 [penwidth = 2];

ConnectionChildren22 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
ConnectionFemale2Male2 -- ConnectionChildren22 [penwidth = 2];

NodeMale3 [label = Male3];
ConnectionChildren22 -- NodeMale3 [weight = 10, penwidth = 2];

NodeFemale3 [label = Female3];
ConnectionChildren22 -- NodeFemale3 [penwidth = 2];

// NodeMaleX [label = MaleX];
// ConnectionChildren11 -- NodeMaleX [weight = 10, penwidth = 2];

{
rank = same;
NodeFemale4 [label = Female4];
NodeMale4 [label = Male4];
NodeMale5 [label = Male5];
ConnectionFemale4Male4 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
NodeFemale4 -- ConnectionFemale4Male4 -- NodeMale4 [weight = 100, penwidth = 2];
ConnectionMale4Male5 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
NodeMale4 -- ConnectionMale4Male5 -- NodeMale5 [weight = 100, penwidth = 2];
}

ConnectionChildren11 -- NodeFemale4 [penwidth = 2];

ConnectionChildren44 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
ConnectionFemale4Male4 -- ConnectionChildren44 [penwidth = 2];

NodeFemale6 [label = Female6];
ConnectionChildren44 -- NodeFemale6 [weight = 10, penwidth = 2];

NodeFemale7 [label = Female7];
ConnectionChildren44 -- NodeFemale7 [penwidth = 2];

ConnectionChildren45 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
ConnectionMale4Male5 -- ConnectionChildren45 [penwidth = 2];

NodeFemale8 [label = Female8];
ConnectionChildren45 -- NodeFemale8 [penwidth = 2];

}

我认为不诉诸 subgraph 就无法按照自己的方式进行控制。这在为您提供节点和边缘的脚本和数据库的上下文中可能有用,也可能没有帮助,但我已经尝试了一些希望接近您想要的东西:

graph Test 
{
/* layout / format */
    rankdir = BT;               // bottoms to top
    splines = ortho;            // edges orthogonal
    center = true;              // page center
    edge [ penwidth = 2 ];      // edge thickness
    node [ width = 1.1 ];       // conistent node size

/* node and edge definitions as produced by the script (?) */
    NodeFemale1 [label = Female1];
    NodeMale1 [label = Male1];
    ConnectionFemale1Male1 [shape = box, label = "", height = 0, width = 1, margin = 0, penwidth = 1];
    // 1 NodeFemale1 -- ConnectionFemale1Male1 -- NodeMale1 [weight = 100, penwidth = 2];
    ConnectionChildren11 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
    // 2 ConnectionFemale1Male1 -- ConnectionChildren11 [penwidth = 2];
    NodeFemale2 [label = Female2];
    NodeMale2 [label = Male2];
    ConnectionFemale2Male2 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
    // 3 NodeFemale2 -- ConnectionFemale2Male2 -- NodeMale2 [weight = 100, penwidth = 2];
    // 4 ConnectionChildren11 -- NodeMale2 [penwidth = 2];
    ConnectionChildren22 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
    // 5 ConnectionFemale2Male2 -- ConnectionChildren22 [penwidth = 2];
    NodeMale3 [label = Male3];
    // 6 ConnectionChildren22 -- NodeMale3 [weight = 10, penwidth = 2];
    NodeFemale3 [label = Female3];
    // 7 ConnectionChildren22 -- NodeFemale3 [penwidth = 2];
    NodeMaleX [label = MaleX];
    // 8 ConnectionChildren11 -- NodeMaleX [weight = 10, penwidth = 2];
    NodeFemale4 [label = Female4];
    NodeMale4 [label = Male4];
    NodeMale5 [label = Male5];
    ConnectionFemale4Male4 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
    // 9 NodeFemale4 -- ConnectionFemale4Male4 -- NodeMale4 [weight = 100, penwidth = 2];
    ConnectionMale4Male5 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
    // 10 NodeMale4 -- ConnectionMale4Male5 -- NodeMale5 [weight = 100, penwidth = 2];
    // 11 ConnectionChildren11 -- NodeFemale4 [penwidth = 2];
    ConnectionChildren44 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
    // 12 ConnectionFemale4Male4 -- ConnectionChildren44 [penwidth = 2];
    NodeFemale6 [label = Female6];
    // 13 ConnectionChildren44 -- NodeFemale6 [weight = 10, penwidth = 2];
    NodeFemale7 [label = Female7];
    // 14 ConnectionChildren44 -- NodeFemale7 [penwidth = 2];
    ConnectionChildren45 [shape = box, label = "", height = 0, width = 0, margin = 0, penwidth = 1];
    // 15 ConnectionMale4Male5 -- ConnectionChildren45 [penwidth = 2];
    NodeFemale8 [label = Female8];
    // 16 ConnectionChildren45 -- NodeFemale8 [penwidth = 2];

/* family / generation subgraphs */
    subgraph cluster0
    {
        style = filled;
        fillcolor = lightgrey;
        color = white;
        { rank = same; NodeFemale1; ConnectionFemale1Male1; NodeMale1 }
        NodeFemale1 -- ConnectionFemale1Male1 -- NodeMale1;
    }

    ConnectionFemale1Male1 -- ConnectionChildren11;

    subgraph cluster1
    {
        { rank = same; NodeMale2; ConnectionFemale2Male2; NodeFemale2 }
        NodeFemale2 -- ConnectionFemale2Male2 -- NodeMale2;
    }

    ConnectionChildren11 -- NodeMale2;

    subgraph cluster2
    {
        NodeMaleX;
    }

    ConnectionChildren11 -- NodeMaleX;

    subgraph cluster3
    {
        { rank = same; NodeFemale4; NodeMale4; NodeMale5; ConnectionFemale4Male4; ConnectionMale4Male5 }
        NodeFemale4 -- ConnectionFemale4Male4 -- NodeMale4 -- ConnectionMale4Male5 -- NodeMale5;
    }

    ConnectionChildren11 -- NodeFemale4;

    subgraph cluster4
    {
        color = white;
        { rank = same; NodeMale3; NodeFemale3 }
    }

    ConnectionFemale2Male2 --ConnectionChildren22;
    ConnectionChildren22 -- { NodeMale3 NodeFemale3 };

    subgraph cluster5
    {
        color = white;
        { rank = same; NodeFemale6; NodeFemale7 }
    }

    ConnectionFemale4Male4 --ConnectionChildren44;
    ConnectionChildren44 -- { NodeFemale6 NodeFemale7 };

    subgraph cluster6
    {
        color = white;
        NodeFemale8;
    }

    ConnectionMale4Male5 --ConnectionChildren45;
    ConnectionChildren45 -- NodeFemale8;
}

集群可以自定义,如父级别所示。如果你只是设置 color = white 它们变成 "invisible",如孙子一代所示。