在 Graphviz 中实现家谱可视化

Implement family tree visualization in Graphviz

我正在尝试使用 Python Graphviz 构建多代家谱。我创建了函数来简化使用他们的关系添加人员(添加已婚夫妇,添加 children)。不过,我遇到了 Graphviz 布局的问题,即在添加 marriage 和 children 时边缘与节点重叠。已婚人士节点似乎并没有紧密地靠在一起,如下所示:

如图所示,一对没有children的情况是完美的,但是当添加children时,布局似乎很混乱。

这里是没有二代的排版,排版好像没问题

我用来生成的代码

import graphviz

def add_marriage_node(tree, id1, name1, id2, name2):
    with tree.subgraph() as sub_tree:
        sub_tree.attr(rank='same')
        sub_tree.node(str(id1), name1)
        sub_tree.node(str(id2), name2)
        sub_tree.node('N' + str(id1) + '_' + str(id2),
            shape='point',
            **{'width':str(0.08)})
    tree.edge(str(id1), 'N' + str(id1) + '_' + str(id2))
    tree.edge('N' + str(id1) + '_' + str(id2), str(id2))


# Children= [{'id': 1, 'name': 'ChildA'}, {'id': 2, 'name': 'ChildB'}]
def add_children_nodes(tree, father_id, mother_id, children):
    # Add parent_children point nodes
    with tree.subgraph() as sub_tree:
        sub_tree.attr(rank='same')
        for child in children:
            parent_node = 'N' + str(father_id) + '_' + str(mother_id)
            parent_child_node = 'N' + str(father_id) + '_' + str(mother_id) + '_' + str(child['id'])
            sub_tree.node(parent_child_node,
                shape='point',
                **{'width':str(0.08)})
        if len(children) % 2 == 0:
            center_node = 'N' + str(father_id) + '_' + str(mother_id) + 'B'
            sub_tree.node(center_node,
                    shape='point',
                    **{'width':str(0.08)})

    # Connect parent node to the middle parent_children point or a new center point
    if len(children) % 2 == 0:
        tree.edge(str(parent_node), str(center_node))
    else:
        middle_child = children[len(children) // 2]
        parent_child_node = 'N' + str(father_id) + '_' + str(mother_id) + '_' + str(middle_child['id'])
        tree.node(str(middle_child['id']), str(middle_child['name']))
        tree.edge(str(parent_node), str(parent_child_node))

    # Connect the parent_children nodes horizontally
    i = 0
    while i < len(children)-1:
        parent_child_node1 = 'N' + str(father_id) + '_' + str(mother_id) + '_' + str(children[i]['id'])
        parent_child_node2 = 'N' + str(father_id) + '_' + str(mother_id) + '_' + str(children[i+1]['id'])
        if len(children) % 2 == 0 and i == len(children)/2 - 1:
            tree.edge(parent_child_node1, center_node)
            tree.edge(center_node, parent_child_node2)
        else:
            tree.edge(parent_child_node1, parent_child_node2)
        i += 1

    # Add children nodes and connect them to their respective parent_children node
    for i in range(len(children)):
        parent_child_node = 'N' + str(father_id) + '_' + str(mother_id) + '_' + str(children[i]['id'])
        tree.node(str(children[i]['id']), str(children[i]['name']))
        tree.edge(parent_child_node, str(children[i]['id']))


tree = graphviz.Graph(  engine='dot',
                        graph_attr={
                                    'splines': 'false',
                                    'nodesep':'0.2',
                                    'ranksep': '0.125',
                                    'overlap':'false',
                                    'concentrate': 'false',
                                    'rankdir': 'TB'  # [TB, BT, LR, RL]
                        },
                        node_attr={'style': 'filled', 'shape': 'box'},
                        edge_attr={'dir': 'none', 'arrowhead': 'none'},
                        encoding='utf8',
                        filename='family_tree',
                        format='pdf')


add_marriage_node(tree, 1, 'Grand Father', 2, 'Grand Mother')

add_children_nodes(tree, 1, 2, [
    {'id': 3, 'name': 'Father'},
    {'id': 4, 'name': 'Uncle'},
    {'id': 5, 'name': 'Aunt'},
    ])

add_marriage_node(tree, 3, 'Father', 6, 'Mother')
add_marriage_node(tree, 4, 'Uncle', 7, 'His Wife')
add_marriage_node(tree, 5, 'Aunt', 8, 'Her Husband')

add_children_nodes(tree, 3, 6, [
    {'id': 9, 'name': 'Me'},
    {'id': 10, 'name': 'Brother'},
    {'id': 11, 'name': 'Sister'},
    ])

add_marriage_node(tree, 9, 'Me', 12, 'My Wife')
add_children_nodes(tree, 9, 12, [
    {'id': 13, 'name': 'My Son'}
    ])

tree.view()

上一个脚本生成的点文件:

graph {
    graph [concentrate=false nodesep=0.2 overlap=false rankdir=TB ranksep=0.125 splines=false]
    node [shape=box style=filled]
    edge [arrowhead=none dir=none]
    {
        rank=same
        1 [label="Grand Father"]
        2 [label="Grand Mother"]
        N1_2 [shape=point width=0.08]
    }
    1 -- N1_2
    N1_2 -- 2
    {
        rank=same
        N1_2_3 [shape=point width=0.08]
        N1_2_4 [shape=point width=0.08]
        N1_2_5 [shape=point width=0.08]
    }
    4 [label=Uncle]
    N1_2 -- N1_2_4
    N1_2_3 -- N1_2_4
    N1_2_4 -- N1_2_5
    3 [label=Father]
    N1_2_3 -- 3
    4 [label=Uncle]
    N1_2_4 -- 4
    5 [label=Aunt]
    N1_2_5 -- 5
    {
        rank=same
        3 [label=Father]
        6 [label=Mother]
        N3_6 [shape=point width=0.08]
    }
    3 -- N3_6
    N3_6 -- 6
    {
        rank=same
        4 [label=Uncle]
        7 [label="His Wife"]
        N4_7 [shape=point width=0.08]
    }
    4 -- N4_7
    N4_7 -- 7
    {
        rank=same
        5 [label=Aunt]
        8 [label="Her Husband"]
        N5_8 [shape=point width=0.08]
    }
    5 -- N5_8
    N5_8 -- 8
    {
        rank=same
        N3_6_9 [shape=point width=0.08]
        N3_6_10 [shape=point width=0.08]
        N3_6_11 [shape=point width=0.08]
    }
    10 [label=Brother]
    N3_6 -- N3_6_10
    N3_6_9 -- N3_6_10
    N3_6_10 -- N3_6_11
    9 [label=Me]
    N3_6_9 -- 9
    10 [label=Brother]
    N3_6_10 -- 10
    11 [label=Sister]
    N3_6_11 -- 11
    {
        rank=same
        9 [label=Me]
        12 [label="My Wife"]
        N9_12 [shape=point width=0.08]
    }
    9 -- N9_12
    N9_12 -- 12
    {
        rank=same
        N9_12_13 [shape=point width=0.08]
    }
    13 [label="My Son"]
    N9_12 -- N9_12_13
    13 [label="My Son"]
    N9_12_13 -- 13
}

主要问题是如上所述的布局。如果您希望获得进一步帮助,当前实施中还存在其他问题,如下所列:

如有任何帮助,我们将不胜感激 如果您认为使用 Graphviz 构建家谱不是一个好主意,请推荐其他库

----更新----

即使在添加集群和组之后,仍然发现可扩展性有问题。添加堂兄弟时,布局再次变得混乱,如下图所示:

下面是从 python 包装器生成的点:

graph {
    graph [concentrate=false newrank=true ranksep=0.1 splines=false]
    node [shape=box style="filled, rounded"]
    edge [arrowhead=none dir=none]
    subgraph cluster_1_2 {
        graph [concentrate=false newrank=true peripheries=0 ranksep=0.1 splines=false]
        node [shape=box style="filled, rounded"]
        edge [arrowhead=none dir=none]
        rank=same
        1 [label=<
                    Grand Father
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    1
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED"]
        2 [label=<
                    Grand Mother
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    2
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#F4C2C2"]
        N_1_2 [shape=point width=0.08]
    }
    1 -- N_1_2
    N_1_2 -- 2
    {
        graph [concentrate=false newrank=true ranksep=0.1 splines=false]
        node [shape=box style="filled, rounded"]
        edge [arrowhead=none dir=none]
        rank=same
        N_1_2_3 [group=G_3 shape=point width=0.08]
        N_1_2_4 [group=G_4 shape=point width=0.08]
        N_1_2_5 [group=G_5 shape=point width=0.08]
    }
    4 [label=<
                    Aunt
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    4
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#F4C2C2" group=G_4]
    N_1_2 -- N_1_2_4
    N_1_2_3 -- N_1_2_4
    N_1_2_4 -- N_1_2_5
    3 [label=<
                    Father
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    3
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED" group=G_3]
    N_1_2_3 -- 3
    4 [label=<
                    Aunt
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    4
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#F4C2C2" group=G_4]
    N_1_2_4 -- 4
    5 [label=<
                    Uncle
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    5
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED" group=G_5]
    N_1_2_5 -- 5
    subgraph cluster_3_6 {
        graph [concentrate=false newrank=true peripheries=0 ranksep=0.1 splines=false]
        node [shape=box style="filled, rounded"]
        edge [arrowhead=none dir=none]
        rank=same
        3 [label=<
                    Father
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    3
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED"]
        6 [label=<
                    Mother
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    6
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#F4C2C2"]
        N_3_6 [shape=point width=0.08]
    }
    3 -- N_3_6
    N_3_6 -- 6
    subgraph cluster_5_8 {
        graph [concentrate=false newrank=true peripheries=0 ranksep=0.1 splines=false]
        node [shape=box style="filled, rounded"]
        edge [arrowhead=none dir=none]
        rank=same
        5 [label=<
                    Uncle
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    5
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED"]
        8 [label=<
                    His Wife
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    8
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#F4C2C2"]
        N_5_8 [shape=point width=0.08]
    }
    5 -- N_5_8
    N_5_8 -- 8
    subgraph cluster_4_7 {
        graph [concentrate=false newrank=true peripheries=0 ranksep=0.1 splines=false]
        node [shape=box style="filled, rounded"]
        edge [arrowhead=none dir=none]
        rank=same
        4 [label=<
                    Aunt
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    4
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#F4C2C2"]
        7 [label=<
                    Her Husband
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    7
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED"]
        N_4_7 [shape=point width=0.08]
    }
    4 -- N_4_7
    N_4_7 -- 7
    {
        graph [concentrate=false newrank=true ranksep=0.1 splines=false]
        node [shape=box style="filled, rounded"]
        edge [arrowhead=none dir=none]
        rank=same
        N_3_6_9 [group=G_9 shape=point width=0.08]
        N_3_6_10 [group=G_10 shape=point width=0.08]
        N_3_6_11 [group=G_11 shape=point width=0.08]
    }
    10 [label=<
                    Sister
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    10
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#F4C2C2" group=G_10]
    N_3_6 -- N_3_6_10
    N_3_6_9 -- N_3_6_10
    N_3_6_10 -- N_3_6_11
    9 [label=<
                    Me
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    9
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED" group=G_9]
    N_3_6_9 -- 9
    10 [label=<
                    Sister
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    10
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#F4C2C2" group=G_10]
    N_3_6_10 -- 10
    11 [label=<
                    Brother
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    11
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED" group=G_11]
    N_3_6_11 -- 11
    {
        graph [concentrate=false newrank=true ranksep=0.1 splines=false]
        node [shape=box style="filled, rounded"]
        edge [arrowhead=none dir=none]
        rank=same
        N_4_7_14 [group=G_14 shape=point width=0.08]
        N_4_7_15 [group=G_15 shape=point width=0.08]
        N4_7B [shape=point width=0.08]
    }
    N_4_7 -- N4_7B
    N_4_7_14 -- N4_7B
    N4_7B -- N_4_7_15
    14 [label=<
                    Cousin 1
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    14
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#F4C2C2" group=G_14]
    N_4_7_14 -- 14
    15 [label=<
                    Cousin 2
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    15
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED" group=G_15]
    N_4_7_15 -- 15
    {
        graph [concentrate=false newrank=true ranksep=0.1 splines=false]
        node [shape=box style="filled, rounded"]
        edge [arrowhead=none dir=none]
        rank=same
        N_5_8_16 [group=G_16 shape=point width=0.08]
        N_5_8_17 [group=G_17 shape=point width=0.08]
        N5_8B [shape=point width=0.08]
    }
    N_5_8 -- N5_8B
    N_5_8_16 -- N5_8B
    N5_8B -- N_5_8_17
    16 [label=<
                    Cousin 3
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    16
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#F4C2C2" group=G_16]
    N_5_8_16 -- 16
    17 [label=<
                    Cousin 4
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    17
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED" group=G_17]
    N_5_8_17 -- 17
    subgraph cluster_9_12 {
        graph [concentrate=false newrank=true peripheries=0 ranksep=0.1 splines=false]
        node [shape=box style="filled, rounded"]
        edge [arrowhead=none dir=none]
        rank=same
        9 [label=<
                    Me
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    9
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED"]
        12 [label=<
                    My Wife
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    12
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#F4C2C2"]
        N_9_12 [shape=point width=0.08]
    }
    9 -- N_9_12
    N_9_12 -- 12
    {
        graph [concentrate=false newrank=true ranksep=0.1 splines=false]
        node [shape=box style="filled, rounded"]
        edge [arrowhead=none dir=none]
        rank=same
        N_9_12_13 [group=G_13 shape=point width=0.08]
    }
    13 [label=<
                    My Son
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    13
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED" group=G_13]
    N_9_12 -- N_9_12_13
    13 [label=<
                    My Son
                    <BR/>
                    <FONT POINT-SIZE="9">
                    1900 - 1950
                    </FONT>
                    <BR/>
                    <FONT POINT-SIZE="8">
                    13
                    </FONT>
                    <BR ALIGN="RIGHT"/>
                    > fillcolor="#C2EBED" group=G_13]
    N_9_12_13 -- 13
}

使用了 clustersgroup 属性和 html-like 标签。如果需要,外围可以设置为 0(参见示例)

graph {
    graph [concentrate=false nodesep=0.2 overlap=false rankdir=TB ranksep=0.125 splines=false]
    node [shape=box style="filled,rounded"]  // added rounded
    edge [arrowhead=none dir=none]
    // added clusters to group couples
    // used group attribute (to nodes) to make connector edges vertical
    {
        rank=same
    // example of mult-line & justified, same fontsize
        1 [label="Grand Father\n1/2/1610-1/3/1810\nabc\r"]
    // example using "html-like" label
    //   see:   https://graphviz.org/doc/info/shapes.html#html
        2 [label=<Grand Mother<BR/><FONT POINT-SIZE="9">1/2/1610-1/3/1810</FONT><BR/><FONT POINT-SIZE="7">read me</FONT><BR ALIGN="RIGHT"/>>]
        N1_2 [shape=point width=0.08]
    }
    1 -- N1_2
    N1_2 -- 2
    {
        rank=same
        N1_2_3 [shape=point width=0.08 group=F]
        N1_2_4 [shape=point width=0.08]
        N1_2_5 [shape=point width=0.08 group=A]
    }
    4 [label=Uncle]
    N1_2 -- N1_2_4
    N1_2_3 -- N1_2_4
    N1_2_4 -- N1_2_5
    3 [label=Father]
    N1_2_3 -- 3 
    4 [label=Uncle]
    N1_2_4 -- 4
    5 [label=Aunt group=A]
    N1_2_5 -- 5
    subgraph cluster1{
      graph [peripheries=0]  // no surrounding rectangle
      {
        rank=same
        3 [label=Father group=F]
        6 [label=Mother]
        N3_6 [shape=point width=0.08]
      }
    }
    3 -- N3_6
    N3_6 -- 6
    subgraph clusterU{
      {
        rank=same
        4 [label=Uncle]
        7 [label="His Wife"]
        N4_7 [shape=point width=0.08]
      }
    }
    4 -- N4_7
    N4_7 -- 7
    subgraph clusteraeiou {
      {
        rank=same
        5 [label=Aunt]
        8 [label="Her Husband"]
        N5_8 [shape=point width=0.08]
      }
    }
    5 -- N5_8
    N5_8 -- 8
    {
        rank=same
        N3_6_9 [shape=point width=0.08 group=g9]
        N3_6_10 [shape=point width=0.08]
        N3_6_11 [shape=point width=0.08 group=g10]  // group: try to make N3_6_11 -- 11  vertical
    }
    10 [label=Brother]
    N3_6 -- N3_6_10
    N3_6_9 -- N3_6_10
    N3_6_10 -- N3_6_11
    9 [label=Me]
    N3_6_9 -- 9
    10 [label=Brother]
    N3_6_10 -- 10
    11 [label=Sister group=g10]  // group: try to make N3_6_11 -- 11  vertical
    N3_6_11 -- 11
    subgraph cluster0{
      {
        rank=same
        9 [label=Me  group=g9]
        12 [label="My Wife"]
        N9_12 [shape=point width=0.08]
      }
    }
    9 -- N9_12
    N9_12 -- 12
    {
        rank=same
        N9_12_13 [shape=point width=0.08]
    }
    13 [label="My Son"]
    N9_12 -- N9_12_13
    13 [label="My Son"]
    N9_12_13 -- 13
}

给出:

您的标签文本中有很多前导空格。产生的节点宽度导致(?)奇数放置。这是您的图表,其中删除了空格,但名称已填充到可信的长度:

graph {
    graph [concentrate=false,
        newrank=true,
        ranksep=0.1,
        splines=false
    ];
    node [label="\N",
        shape=box,
        style="filled, rounded"
    ];
    edge [arrowhead=none,
        dir=none
    ];
    {
        graph [concentrate=false,
            newrank=true,
            rank=same,
            ranksep=0.1,
            splines=false
        ];
        node [shape=box,
            style="filled, rounded"
        ];
        edge [arrowhead=none,
            dir=none
        ];
        N_1_2_3 [group=G_3,
            shape=point,
            width=0.08];
        N_1_2_4 [group=G_4,
            shape=point,
            width=0.08];
        N_1_2_5 [group=G_5,
            shape=point,
            width=0.08];
    }
    {
        graph [concentrate=false,
            newrank=true,
            rank=same,
            ranksep=0.1,
            splines=false
        ];
        node [shape=box,
            style="filled, rounded"
        ];
        edge [arrowhead=none,
            dir=none
        ];
        N_3_6_9 [group=G_9,
            shape=point,
            width=0.08];
        N_3_6_10    [group=G_10,
            shape=point,
            width=0.08];
        N_3_6_11    [group=G_11,
            shape=point,
            width=0.08];
    }
    {
        graph [concentrate=false,
            newrank=true,
            rank=same,
            ranksep=0.1,
            splines=false
        ];
        node [shape=box,
            style="filled, rounded"
        ];
        edge [arrowhead=none,
            dir=none
        ];
        N_4_7_14    [group=G_14,
            shape=point,
            width=0.08];
        N_4_7_15    [group=G_15,
            shape=point,
            width=0.08];
        N4_7B   [shape=point,
            width=0.08];
    }
    {
        graph [concentrate=false,
            newrank=true,
            rank=same,
            ranksep=0.1,
            splines=false
        ];
        node [shape=box,
            style="filled, rounded"
        ];
        edge [arrowhead=none,
            dir=none
        ];
        N_5_8_16    [group=G_16,
            shape=point,
            width=0.08];
        N_5_8_17    [group=G_17,
            shape=point,
            width=0.08];
        N5_8B   [shape=point,
            width=0.08];
    }
    {
        graph [concentrate=false,
            newrank=true,
            rank=same,
            ranksep=0.1,
            splines=false
        ];
        node [shape=box,
            style="filled, rounded"
        ];
        edge [arrowhead=none,
            dir=none
        ];
        N_9_12_13   [group=G_13,
            shape=point,
            width=0.08];
    }
    subgraph cluster_1_2 {
        graph [concentrate=false,
            newrank=true,
            peripheries=0,
            rank=same,
            ranksep=0.1,
            splines=false
        ];
        node [shape=box,
            style="filled, rounded"
        ];
        edge [arrowhead=none,
            dir=none
        ];
        1   [fillcolor="#C2EBED",
    label=<Grand Father<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">1</FONT><BR ALIGN="RIGHT"/>>]
        N_1_2   [shape=point,
            width=0.08];
        1 -- N_1_2;
        2   [fillcolor="#F4C2C2",
    label=<Grand Mother<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">2</FONT><BR ALIGN="RIGHT"/>>]
        N_1_2 -- 2;
    }
    subgraph cluster_3_6 {
        graph [concentrate=false,
            newrank=true,
            peripheries=0,
            rank=same,
            ranksep=0.1,
            splines=false
        ];
        node [shape=box,
            style="filled, rounded"
        ];
        edge [arrowhead=none,
            dir=none
        ];
        3   [fillcolor="#C2EBED",
            group=G_3,
    label=<Father Father<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">3</FONT><BR ALIGN="RIGHT"/>>]
        N_3_6   [shape=point,
            width=0.08];
        3 -- N_3_6;
        6   [fillcolor="#F4C2C2",
    label=<Mother Mother<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">6</FONT><BR ALIGN="RIGHT"/>>]
        N_3_6 -- 6;
    }
    subgraph cluster_5_8 {
        graph [concentrate=false,
            newrank=true,
            peripheries=0,
            rank=same,
            ranksep=0.1,
            splines=false
        ];
        node [shape=box,
            style="filled, rounded"
        ];
        edge [arrowhead=none,
            dir=none
        ];
        5   [fillcolor="#C2EBED",
            group=G_5,
    label=<Uncle Uncleeeee<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">5</FONT><BR ALIGN="RIGHT"/>>]
        N_5_8   [shape=point,
            width=0.08];
        5 -- N_5_8;
        8   [fillcolor="#F4C2C2",
    label=<His Wife Wife<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">8</FONT><BR ALIGN="RIGHT"/>>]
        N_5_8 -- 8;
    }
    subgraph cluster_4_7 {
        graph [concentrate=false,
            newrank=true,
            peripheries=0,
            rank=same,
            ranksep=0.1,
            splines=false
        ];
        node [shape=box,
            style="filled, rounded"
        ];
        edge [arrowhead=none,
            dir=none
        ];
        4   [fillcolor="#F4C2C2",
            group=G_4,
    label=<Auntie Auntie<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">4</FONT><BR ALIGN="RIGHT"/>>]
        N_4_7   [shape=point,
            width=0.08];
        4 -- N_4_7;
        7   [fillcolor="#C2EBED",
    label=<Her Husband Husband<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">7</FONT><BR ALIGN="RIGHT"/>>]
        N_4_7 -- 7;
    }
    subgraph cluster_9_12 {
        graph [concentrate=false,
            newrank=true,
            peripheries=0,
            rank=same,
            ranksep=0.1,
            splines=false
        ];
        node [shape=box,
            style="filled, rounded"
        ];
        edge [arrowhead=none,
            dir=none
        ];
        9   [fillcolor="#C2EBED",
            group=G_9,
    label=<Call Me Ishmael<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">9</FONT><BR ALIGN="RIGHT"/>>]
        N_9_12  [shape=point,
            width=0.08];
        9 -- N_9_12;
        12  [fillcolor="#F4C2C2",
    label=<My Wife Wife<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">12</FONT><BR ALIGN="RIGHT"/>>]
        N_9_12 -- 12;
    }
    N_1_2 -- N_1_2_4;
    N_1_2_3 -- N_1_2_4;
    N_1_2_3 -- 3;
    N_1_2_4 -- N_1_2_5;
    N_1_2_4 -- 4;
    N_1_2_5 -- 5;
    N_3_6 -- N_3_6_10;
    N_5_8 -- N5_8B;
    N_4_7 -- N4_7B;
    N_3_6_9 -- N_3_6_10;
    N_3_6_9 -- 9;
    N_3_6_10 -- N_3_6_11;
    10  [fillcolor="#F4C2C2",
        group=G_10,
    label=<Sister Sister<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">10</FONT><BR ALIGN="RIGHT"/>>]
    N_3_6_10 -- 10;
    11  [fillcolor="#C2EBED",
        group=G_11,
    label=<Brother Brother<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">11</FONT><BR ALIGN="RIGHT"/>>]
    N_3_6_11 -- 11;
    N_4_7_14 -- N4_7B;
    14  [fillcolor="#F4C2C2",
        group=G_14,
    label=<Cousin 1 Cousin<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">14</FONT><BR ALIGN="RIGHT"/>>]
    N_4_7_14 -- 14;
    15  [fillcolor="#C2EBED",
        group=G_15,
    label=<Cousin 2 Cousin<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">15</FONT><BR ALIGN="RIGHT"/>>]
    N_4_7_15 -- 15;
    N4_7B -- N_4_7_15;
    N_5_8_16 -- N5_8B;
    16  [fillcolor="#F4C2C2",
        group=G_16,
    label=<Cousin 3 Cousin<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">16</FONT><BR ALIGN="RIGHT"/>>]
    N_5_8_16 -- 16;
    17  [fillcolor="#C2EBED",
        group=G_17,
    label=<Cousin 4 Cousin<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">17</FONT><BR ALIGN="RIGHT"/>>]
    N_5_8_17 -- 17;
    N5_8B -- N_5_8_17;
    N_9_12 -- N_9_12_13;
    13  [fillcolor="#C2EBED",
        group=G_13,
    label=<My Son the Kid<BR/><FONT POINT-SIZE="9">1900 - 1950</FONT><BR/><FONT POINT-SIZE="8">13</FONT><BR ALIGN="RIGHT"/>>]
    N_9_12_13 -- 13;
}

给予: