在 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
}
主要问题是如上所述的布局。如果您希望获得进一步帮助,当前实施中还存在其他问题,如下所列:
- 将节点形状更改为圆角框
- 将节点格式化为在名称下方使用较小字体显示出生日期和死亡日期,并在节点右下角使用更小字体显示 ID
- Children边应该连接到节点的中心,使得点形节点和child之间的边是直线
- 减小点形状节点的宽度会显示线条不连续,而不是像我希望的那样显示连续的弯边
如有任何帮助,我们将不胜感激
如果您认为使用 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
}
使用了 clusters、group 属性和 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;
}
给予:
我正在尝试使用 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
}
主要问题是如上所述的布局。如果您希望获得进一步帮助,当前实施中还存在其他问题,如下所列:
- 将节点形状更改为圆角框
- 将节点格式化为在名称下方使用较小字体显示出生日期和死亡日期,并在节点右下角使用更小字体显示 ID
- Children边应该连接到节点的中心,使得点形节点和child之间的边是直线
- 减小点形状节点的宽度会显示线条不连续,而不是像我希望的那样显示连续的弯边
如有任何帮助,我们将不胜感激 如果您认为使用 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
}
使用了 clusters、group 属性和 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;
}
给予: