PlantUML 渲染引擎内幕:Graphviz/dot 算法的 7 个调优点
PlantUML 大多数图(组件、状态、对象、类)底层都走 Graphviz dot 布局算法。理解 dot 的工作机制能解释很多「图为什么自动排成这样」的疑问,以及怎么改才更好看。
dot 算法是什么
PlantUUM 渲染 component class state 时,先用内置解析器把 .puml 转成 Graphviz 的 dot 语言,再用 dot 引擎算布局。最终输出的 SVG 是 dot 算出来的位置 + PlantUML 自己的样式表。
这意味着:你能用 dot 的所有特性影响 PlantUML 图。PlantUML 把它们包装成 skinparam !pragma 等指令,但理解底层有助于诊断奇怪布局。
调优点 1:rankdir 改方向
1 | @startuml |
底层 dot:
1 | digraph { |
rankdir 可选值:LR(左到右)、TB(默认,上到下)、BT、RL。
何时用 left to right:
- 时序图横向太长 → 改
top to bottom(默认) - 部署图区域多 →
left to right把多个 zone 横排
调优点 2:nodesep / ranksep 控制间距
1 | @startuml |
nodesep:同一 rank(同一行/列)节点之间的间距。默认 40(像素)。节点太挤 → 加大。
ranksep:不同 rank(行/列)之间的间距。默认 60。节点层级不清楚 → 加大。
调优点 3:隐形节点控布局
1 | @startuml |
(hub) 是匿名节点,dot 把它当真实节点算 rank。把多个目标拉到同一 rank。
实战用法:架构图里多个 service 都连同一个 DB,DB 自然下沉一级——加隐形节点让 DB 居中:
1 | component "auth-svc" as auth |
调优点 4:hidden 边对齐
1 | @startuml |
-[hidden]- 是 dot 的特殊边类型,只用于布局,不影响图渲染——A 和 C 会被 dot 拉到同一 rank。
实战:组件图里两个 service 没有直接关系但要横排:
1 | component "Web App" as web |
Web App 和 Admin Tool 横排对齐。
调优点 5:子图分组(package / node)
1 | @startuml |
dot 把 package 当 subgraph 处理,自动绘制包围盒 + 内部节点紧凑布局。
注意:子图不影响连线方向,只是视觉分组。
调优点 6:cluster 嵌套
1 | @startuml |
嵌套 node 生成嵌套 cluster,AWS 架构图经典用法。
调优点 7:边的权重 weight
1 | @startuml |
dot 算法中边有「权重」——权重高的边优先直连(同 rank 内对齐),权重低的边绕路。weight 10 强制 A 和 C 同 rank 对齐。
实战:架构图里关键路径走直线,辅助路径绕路:
1 | component "User" as user |
User → API → DB 主路径走直线,API → Cache 支路径绕开。
怎么 debug 奇怪布局
方法 1:导出 dot 文件手动看
PlantUML CLI:
1 | plantuml -tlog diagram.puml |
更详细:
1 | plantuml -tdot diagram.puml |
对比 plantuml 输出和 dot 输出——如果 dot 自己布局怪,问题在 dot 算法不在 PlantUML。
方法 2:-stdlib 简化
1 | plantuml -tsvg -Sstdlib=true diagram.puml |
-Sstdlib=true 关掉 PlantUML 的 stdlib 主题,看默认 dot 布局什么样。
方法 3:加 !pragma layout 指令
1 | @startuml |
PlantUUM 1.2023+ 支持 elk 和 neato 引擎。elk(Eclipse Layout Kernel)对复杂图布局更好。
边标签位置:PlantUML 独有
1 | @startuml |
<<...>> 语法控制边标签位置,PlantUML 自己实现,dot 没有。
常用:
<<on left>><<on right>>:左右两侧<<top>><<bottom>>:上下方<<start>><<end>>:沿边起点/终点
dot 不擅长的场景
1. 节点太多(>100)
dot 的算法复杂度是 O(V log V + E),200+ 节点时布局明显变慢,布局结果经常乱。
修法:
- 用 elk 引擎:
!pragma layout elk - 拆成多张图
- 用 cluster 嵌套减少同一 layout level 的节点数
2. 连线交叉严重
dot 尽力最小化连线交叉,但不能保证全局最优。
修法:
- 调节点位置(隐形节点 / hidden 边)
- 改 rankdir 看哪种方向交叉少
- 拆图
3. 巨型时序图(50+ lifeline)
dot 在时序图表现一般——时序图用 PlantUML 自带的算法,不走 dot。
实战:让一个乱图变好看
1 | @startuml |
调优后:
1 | @startuml |
两个 ranksep 的间距清晰,A 居中、节点均匀分布。
总结
| 场景 | 调优点 |
|---|---|
| 图方向不对 | left to right direction |
| 节点太挤 | skinparam nodesep / ranksep |
| 多个目标要对齐 | 隐形节点 (hub) |
| 两个无关系组件要对齐 | -[hidden]- |
| 分组布局 | package node |
| 主路径要直连 | weight 10 |
| 调试怪图 | -tdot 导出 dot 文件 |
调 PlantUML 布局的核心思路:理解 dot 是底层引擎,PlantUML 是它的 DSL。用 skinparam 调皮肤,用 dot 概念(hidden、隐形节点、weight)调布局。
- 标题: PlantUML 渲染引擎内幕:Graphviz/dot 算法的 7 个调优点
- 作者: puml.online
- 创建于 : 2026-07-30 17:05:00
- 更新于 : 2026-08-14 21:34:29
- 链接: https://puml.online/blog/plantuml-graphviz-internals/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。