如何用Graphviz Python为仅含出边的节点设置椭圆形状?
解决Graphviz Python节点形状设置失效问题
需求
生成有向图时,仅包含出边的节点设为椭圆(ellipse),其余节点设为矩形(box)。已知两个目标椭圆节点:Place Order--Importance_shift-1--Object_Type--Customers 和 Place Order--Quantity_shift-1--Object_Type--Orders。
问题根源
原代码错误使用g.attr('node', attrs=...)来设置单个节点属性——g.attr是用来配置全局/默认属性的,无法针对单个节点生效;且在加边流程中重复设置节点属性,导致配置相互覆盖。生成的Dot文件里的node [attrs="xxx"]写法不符合Graphviz语法,自然不会生效。
修正方案
先单独定义所有节点的形状属性,再添加边,彻底避免重复操作导致的覆盖问题:
修正后的代码
from graphviz import Digraph g = Digraph('G', filename='./output/model_' + str(mi), format='png') g.graph_attr.update(rankdir='BT') # 初始化全局节点默认形状为矩形 g.attr('node', shape='box') sources = list() targets = list() PossibleModel.MAX_DEPTH = 3 # 收集所有边的源节点和目标节点 for edge in model.get_edges(): sources.append(str(edge.source)) targets.append(str(edge.target)) # 计算仅含出边的节点(只在sources中出现,不在targets中出现) difference = list(set(sources) - set(targets)) print('difference', difference) # 第一步:先定义所有节点的形状属性 # 获取所有唯一节点 all_nodes = list(set(sources + targets)) for node in all_nodes: if node in difference: # 仅出边节点设为椭圆 g.node(node, shape='ellipse') else: # 其余节点保持默认矩形(或显式设置) g.node(node, shape='box') # 第二步:添加所有边 for edge in model.get_edges(): edge_contained = '' for rule in br_rules: if str(edge.source) in rule or str(edge.target) in rule: edge_contained += rule + '\n' if edge_contained == '': g.attr('edge', color='red') g.edge(str(edge.source), str(edge.target), label=str(edge.weight)) else: g.attr('edge', color='blue') g.edge(str(edge.source), str(edge.target), label=edge_contained)
关键修正点
- 分离节点定义与边添加流程:先一次性定义所有节点的形状,避免在加边时重复设置导致覆盖
- 使用
g.node()指定单个节点属性:这是Graphviz Python API中针对单个节点设置属性的正确方式,替代原错误的g.attr('node', attrs=...)写法 - 避免重复操作:所有节点属性只定义一次,边的处理只关注边的颜色和标签
验证效果
修正后生成的Dot文件会出现类似如下的节点定义,符合Graphviz语法要求:
digraph G { graph [rankdir=BT] node [shape=box] "Place Order--Quantity_shift-1--Object_Type--Orders" [shape=ellipse] "Place Order--Importance_shift-1--Object_Type--Customers" [shape=ellipse] "Determine shipping method--Shipping Method_shift-1--Object_Type--Orders" [shape=box] "Calculate Order Value--Order Value_shift-1--Object_Type--Orders" [shape=box] edge [color=red] "Place Order--Quantity_shift-1--Object_Type--Orders" -> "Determine shipping method--Shipping Method_shift-1--Object_Type--Orders" [label=100] ... }
内容的提问来源于stack exchange,提问作者Alexandre Goossens
相关产品推荐
相关产品推荐

