使用Python和Graphviz绘制家谱图时实现配偶同层级显示的问题
使用Python和Graphviz绘制家谱图时实现配偶同层级显示的问题
我完全懂你的困扰——想用Graphviz画出家谱图,却没法让配偶们处在同一层级,试了rank="same"也没起效对吧?其实问题出在Graphviz的布局逻辑上:默认会根据节点间的连接关系自动分配层级,而你的原始代码里配偶是作为当前节点的后续节点添加的,自然就跑到下一层去了。咱们调整下代码逻辑,用**子图(subgraph)**来强制配偶组同层级,就能解决这个问题。
关键修改思路
- 用子图分组配偶:创建一个
rank="same"的子图,把当前人物和他的所有配偶都放进这个子图里,强制他们处于同一层级。 - 避免重复节点:添加一个集合跟踪已创建的节点,防止同一个人物被多次添加(比如Eddy既是Alice的配偶,又是Dave等孩子的父亲,容易重复创建)。
- 理顺连接关系:配偶之间用虚线连接,亲子关系从父母(包括所有配偶)分别连到孩子,确保层级传递正确。
修改后的完整代码
from graphviz import Digraph class Person: def __init__(self, name, gender): self.name = name self.gender = gender self.partners = [] self.children = [] # Example family tree alice = Person("Alice", "Female") eddy = Person("Eddy", "Male") bob = Person("Bob", "Male") charlie = Person("Charlie", "Male") dave = Person("Dave", "Male") eve = Person("Eve", "Female") frank = Person("Frank", "Male") fp = Person("fictional Partner", "Female") fjr = Person("fjr", "Female") fjr2 = Person("fjr2", "Male") alice.partners.append(eddy) alice.children.append(bob) alice.children.append(charlie) eddy.children.append(dave) eddy.children.append(eve) eddy.children.append(frank) alice.partners.append(fp) frank.children.append(fjr) frank.children.append(fjr2) def build_family_tree(person, graph, added_nodes=None): # 初始化已添加节点集合,避免重复创建节点 if added_nodes is None: added_nodes = set() # 如果当前人物已在图中,直接返回 if person.name in added_nodes: return # 创建子图,强制当前人物和配偶同层级 with graph.subgraph() as spouse_subgraph: spouse_subgraph.attr(rank="same") # 添加当前人物节点 spouse_subgraph.node(person.name, shape="none", label=person.name) added_nodes.add(person.name) # 处理所有配偶:添加节点+虚线连接 for partner in person.partners: if partner.name not in added_nodes: spouse_subgraph.node(partner.name, shape="none", label=partner.name) added_nodes.add(partner.name) # 配偶间用虚线连接 graph.edge(person.name, partner.name, style="dashed") # 处理当前人物的孩子:连接+递归 for child in person.children: graph.edge(person.name, child.name, arrowhead="none") build_family_tree(child, graph, added_nodes) # 处理配偶的孩子:确保孩子和配偶的连接 for partner in person.partners: for child in partner.children: if child.name not in added_nodes: graph.edge(partner.name, child.name, arrowhead="none") build_family_tree(child, graph, added_nodes) # 创建图谱并生成 family_tree_graph = Digraph() build_family_tree(alice, family_tree_graph) family_tree_graph.render('family_tree', format='png', view=True)
效果说明
修改后,Alice、Eddy和fictional Partner会被强制放在同一层级,他们的孩子(Bob、Charlie、Dave等)自动排列在下一层,Frank的孩子fjr和fjr2则在更下一层,完美符合家谱的层级逻辑。
备注:内容来源于stack exchange,提问作者Jahlove
相关产品推荐
相关产品推荐

