如何修改Python中Graphviz digraph对象已有节点的标签与字体属性
Graphviz Python库修改已生成节点字体属性的解决方案
失效原因解释
g.attr('node', fontname='Arial')这类全局属性设置,仅对调用方法后新增的节点/元素生效,已经创建完成的节点属性是独立存储的,不会被后续的全局默认属性修改回溯覆盖,所以生成完所有节点再调用该方法不会生效。
解决方案
方案1:直接操作Digraph对象的body属性(推荐)
Digraph对象的body列表存储了所有图元素的定义行,你可以直接遍历修改指定节点或者全局节点的属性,无需导出重构。
全局修改所有节点的字体
import re for idx, line in enumerate(g.body): # 跳过边定义、注释等非节点/全局属性行 if not line.strip().startswith(('"', 'graph ', 'node ')): continue # 修改全局node默认属性,保证后续新增节点也生效 if line.strip().startswith('node '): if 'fontname' not in line: g.body[idx] = line.rstrip(']') + ' fontname="Arial"]' continue # 匹配已存在的单个节点定义 node_match = re.match(r'(\s*".+?"\s*\[)(.*)(\].*)', line) if node_match: prefix, old_attrs, suffix = node_match.groups() # 移除已存在的fontname定义避免冲突 cleaned_attrs = re.sub(r'fontname\s*=\s*["\']?[^"\'\s]+["\']?\s*', '', old_attrs) # 插入新的字体属性 new_line = f"{prefix}{cleaned_attrs.strip()} fontname=\"Arial\"{suffix}" g.body[idx] = new_line
修改单个指定节点的字体
比如要修改节点ID为other-bwd-other的字体:
import re target_node_id = "other-bwd-other" for idx, line in enumerate(g.body): if line.strip().startswith(f'"{target_node_id}"'): # 移除旧的fontname,加入新属性 updated_line = re.sub(r'fontname\s*=\s*["\']?[^"\'\s]+["\']?\s*', '', line) updated_line = re.sub(r'\]$', ' fontname="Arial"]', updated_line) g.body[idx] = updated_line break
方案2:导出dot源码正则替换后重建对象
如果不想操作原对象的内部结构,可以导出源码批量处理后重新加载:
import re from graphviz import Source # 导出原dot源码 raw_dot = g.source # 批量替换所有节点的fontname属性 processed_dot = re.sub( r'(\s*"[^"]+"\s*\[)([^\]]*)(\])', lambda m: f"{m.group(1)}{re.sub(r'fontname\\s*=\\s*[^ ]+', '', m.group(2))} fontname=\"Arial\"{m.group(3)}", raw_dot ) # 生成新的Digraph对象 new_g = Source(processed_dot)
两种方案修改完成后,直接调用render()等方法渲染即可,字体配置会生效。
内容的提问来源于stack exchange,提问作者gherkins
相关产品推荐
相关产品推荐

