You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Graphviz Python中让箭头从左侧进入注释节点?

解决Graphviz Python中注释节点的箭头接入方向问题

需求说明

我用Graphviz的Python库绘图,有个特定需求:标记在annotations列表里的半矩形样式注释节点,需要让箭头从左侧进入,而非默认的底部。

代码背景

  • model对象包含edge对象,每个edge有source和target节点(本质是字符串)
  • 维护annotations列表,用来标记需要设置为半矩形样式的节点
  • 核心目标:让这类节点的入箭头改为从左侧接入

原代码

g = Digraph('G', filename='./output/model_' + str(mi), format='png', strict=True)
g.graph_attr.update(rankdir='BT')
g.attr('node', shape='note')
sources = list()
targets = list()
annotations = list()
PossibleModel.MAX_DEPTH = 3

"""Let us first see what the possible inputs are"""
"""  
for edge in model.get_edges():
    sources.append(str(edge.source))
    targets.append(str(edge.target))
"""  
for edge in model.get_edges():
    sources.append(edge.source.small_string2())
    targets.append(edge.target.small_string2())
  
difference = list(set(sources) - set(targets))
print('difference', difference)

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.edge(edge.source.small_string2(), edge.target.small_string2(), label=str(edge.weight), color='red')
        g.edge(edge.source.small_string2(), edge.source.small_string3(), color='black', arrowhead='none', style='dashed')
        g.edge(edge.target.small_string2(), edge.target.small_string3(), color='black', arrowhead='none', style='dashed')
        annotations.append(edge.source.small_string3())
        annotations.append(edge.target.small_string3())
    else:
        g.attr('edge', color='blue')
        g.edge(str(edge.source), str(edge.target), label=edge_contained)

for node in difference:
    g.node(node, style='rounded', shape='ellipse')

for node in targets:
    g.node(node, shape='box')
    
for node in annotations:
    g.node(node, color='transparent', image='test.png', fontsize='11')

解决方案

要实现箭头从左侧接入注释节点,核心是利用Graphviz的**端口(port)**特性,指定边连接到节点的左侧端口(west)。具体修改如下:

  1. 修改指向注释节点的边:在创建指向annotations列表中节点的边时,把目标节点格式改为{节点名}:west,强制箭头连接到节点左侧。
  2. (可选)调整节点锚点:如果使用自定义图片作为节点样式,可以设置imagepos="ml"(middle left),让图片的左侧作为端口锚点,确保箭头位置准确。

修改后的关键代码片段

# 原代码中创建指向注释节点的边部分,替换为:
g.edge(edge.source.small_string2(), f"{edge.source.small_string3()}:west", color='black', arrowhead='none', style='dashed')
g.edge(edge.target.small_string2(), f"{edge.target.small_string3()}:west", color='black', arrowhead='none', style='dashed')

# 注释节点的设置可添加imagepos属性(如果需要):
for node in annotations:
    g.node(node, color='transparent', image='test.png', fontsize='11', imagepos="ml")

完整修改后的代码

g = Digraph('G', filename='./output/model_' + str(mi), format='png', strict=True)
g.graph_attr.update(rankdir='BT')
g.attr('node', shape='note')
sources = list()
targets = list()
annotations = list()
PossibleModel.MAX_DEPTH = 3

"""Let us first see what the possible inputs are"""
"""  
for edge in model.get_edges():
    sources.append(str(edge.source))
    targets.append(str(edge.target))
"""  
for edge in model.get_edges():
    sources.append(edge.source.small_string2())
    targets.append(edge.target.small_string2())
  
difference = list(set(sources) - set(targets))
print('difference', difference)

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.edge(edge.source.small_string2(), edge.target.small_string2(), label=str(edge.weight), color='red')
        # 修改这里,指定目标节点的west端口
        g.edge(edge.source.small_string2(), f"{edge.source.small_string3()}:west", color='black', arrowhead='none', style='dashed')
        g.edge(edge.target.small_string2(), f"{edge.target.small_string3()}:west", color='black', arrowhead='none', style='dashed')
        annotations.append(edge.source.small_string3())
        annotations.append(edge.target.small_string3())
    else:
        g.attr('edge', color='blue')
        g.edge(str(edge.source), str(edge.target), label=edge_contained)

for node in difference:
    g.node(node, style='rounded', shape='ellipse')

for node in targets:
    g.node(node, shape='box')
    
# 可选:添加imagepos确保图片锚点在左侧
for node in annotations:
    g.node(node, color='transparent', image='test.png', fontsize='11', imagepos="ml")

原理说明

Graphviz的节点支持通过:方向格式指定连接端口,常用的方向包括:

  • west:左侧
  • east:右侧
  • north:顶部
  • south:底部

因为你的图设置了rankdir='BT'(从下到上布局),默认箭头会沿着布局方向从底部接入节点,指定:west后,强制边连接到节点的左侧,满足需求。

内容的提问来源于stack exchange,提问作者Alexandre Goossens

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 12:35:24