Graphviz 图形可视化教程 / 07 - 子图与集群
第 07 章 · 子图与集群
7.1 子图基础
子图(Subgraph)用于将节点和边分组,可以共享属性、约束排名、创建集群。
基本语法
digraph SubgraphBasic {
node [fontname="Microsoft YaHei" shape=box style=rounded]
// 子图定义
subgraph cluster_A {
label="子图 A"
a1 -> a2
}
subgraph cluster_B {
label="子图 B"
b1 -> b2
}
// 跨子图的边
a2 -> b1 [label="跨子图连接"]
}
子图的关键规则
| 规则 | 说明 |
|---|---|
名称以 cluster_ 开头 | 显示边框和标签 |
名称不以 cluster_ 开头 | 不显示边框,仅分组 |
| 子图中的节点继承属性 | 子图的 node 属性影响内部节点 |
| 子图可嵌套 | 支持多层嵌套 |
| 边可跨子图 | 子图之间的节点可连接 |
7.2 集群 (Cluster)
集群是名称以 cluster_ 开头的子图,Graphviz 会为其绘制边框。
基本集群
digraph ClusterBasic {
rankdir=TB
node [fontname="Microsoft YaHei" fontsize=11]
edge [fontname="Microsoft YaHei" fontsize=9 color="#666666"]
// 前端集群
subgraph cluster_frontend {
label="前端层"
style=filled
fillcolor="#E3F2FD"
color="#1976D2"
fontname="Microsoft YaHei"
WebApp [shape=box style="filled,rounded" fillcolor="#BBDEFB" label="Web 应用"]
MobileApp [shape=box style="filled,rounded" fillcolor="#BBDEFB" label="移动 App"]
}
// 后端集群
subgraph cluster_backend {
label="后端层"
style=filled
fillcolor="#E8F5E9"
color="#388E3C"
fontname="Microsoft YaHei"
API [shape=box style="filled,rounded" fillcolor="#C8E6C9" label="API 服务"]
Worker [shape=box style="filled,rounded" fillcolor="#C8E6C9" label="后台任务"]
}
// 数据集群
subgraph cluster_data {
label="数据层"
style=filled
fillcolor="#F3E5F5"
color="#7B1FA2"
fontname="Microsoft YaHei"
MySQL [shape=cylinder style=filled fillcolor="#E1BEE7" label="MySQL"]
Redis [shape=cylinder style=filled fillcolor="#E1BEE7" label="Redis"]
}
WebApp -> API [label="HTTP"]
MobileApp -> API [label="REST"]
API -> MySQL [label="查询"]
API -> Redis [label="缓存"]
API -> Worker [label="异步任务"]
Worker -> MySQL [label="写入"]
}
7.3 集群样式
边框样式
digraph ClusterStyles {
node [fontname="Microsoft YaHei" shape=box]
subgraph cluster_solid {
label="solid 实线"
style=solid
color="#1976D2"
s1 -> s2
}
subgraph cluster_dashed {
label="dashed 虚线"
style=dashed
color="#388E3C"
d1 -> d2
}
subgraph cluster_dotted {
label="dotted 点线"
style=dotted
color="#F44336"
t1 -> t2
}
subgraph cluster_filled {
label="filled 填充"
style=filled
fillcolor="#FFF3E0"
color="#FF9800"
f1 -> f2
}
subgraph cluster_rounded {
label="rounded 圆角"
style="filled,rounded"
fillcolor="#E8F5E9"
color="#388E3C"
r1 -> r2
}
}
集群属性
| 属性 | 说明 | 常用值 |
|---|---|---|
label | 集群标题 | 文本 |
style | 边框样式 | solid、dashed、dotted、filled、rounded |
color | 边框颜色 | 颜色值 |
fillcolor | 背景填充色 | 需 style=filled |
bgcolor | 背景色 | 同上 |
fontname | 标签字体 | 字体名 |
fontsize | 标签字号 | 数值 |
fontcolor | 标签颜色 | 颜色值 |
penwidth | 边框宽度 | 1、2、3 |
margin | 内边距 | 像素值 |
pencolor | 边框颜色(同 color) | 颜色值 |
tooltip | 鼠标提示 | 文本(SVG) |
7.4 嵌套子图
digraph NestedSubgraphs {
node [fontname="Microsoft YaHei" shape=box style=rounded]
edge [fontname="Microsoft YaHei" fontsize=9]
// 外层集群
subgraph cluster_system {
label="系统整体"
style=filled
fillcolor="#FAFAFA"
color="#9E9E9E"
pencolor="#9E9E9E"
fontname="Microsoft YaHei"
fontsize=14
// 内层集群 — 前端
subgraph cluster_fe {
label="前端"
style=filled
fillcolor="#E3F2FD"
color="#1976D2"
React [fillcolor="#BBDEFB" style="filled,rounded"]
Vue [fillcolor="#BBDEFB" style="filled,rounded"]
}
// 内层集群 — 后端
subgraph cluster_be {
label="后端"
style=filled
fillcolor="#E8F5E9"
color="#388E3C"
// 更深层嵌套
subgraph cluster_api {
label="API 层"
style="filled,rounded"
fillcolor="#C8E6C9"
color="#2E7D32"
REST [fillcolor="#A5D6A7" style="filled,rounded"]
GraphQL [fillcolor="#A5D6A7" style="filled,rounded"]
}
subgraph cluster_svc {
label="服务层"
style="filled,rounded"
fillcolor="#C8E6C9"
color="#2E7D32"
UserService [fillcolor="#A5D6A7" style="filled,rounded"]
OrderService [fillcolor="#A5D6A7" style="filled,rounded"]
}
}
// 内层集群 — 数据
subgraph cluster_db {
label="数据层"
style=filled
fillcolor="#F3E5F5"
color="#7B1FA2"
MySQL [shape=cylinder fillcolor="#E1BEE7" style=filled]
Redis [shape=cylinder fillcolor="#E1BEE7" style=filled]
}
}
React -> REST
Vue -> GraphQL
REST -> UserService
GraphQL -> OrderService
UserService -> MySQL
UserService -> Redis
OrderService -> MySQL
}
7.5 排名约束
rank=same
使同一子图中的节点在同一层级(仅 dot 引擎有效):
digraph RankSame {
rankdir=TB
node [fontname="Microsoft YaHei" shape=box style=rounded]
A -> B -> C
// D 和 E 与 B 同层
{
rank=same
D
E
}
A -> D
D -> C
E -> C
}
其他排名约束
| 约束 | 说明 |
|---|---|
rank=same | 同一层级 |
rank=min | 最小层级(顶层) |
rank=max | 最大层级(底层) |
rank=source | 源层级(比 min 稍低) |
rank=sink | 汇层级(比 max 稍高) |
digraph RankConstraints {
rankdir=TB
node [fontname="Microsoft YaHei" shape=box style=rounded]
// 源节点
{ rank=min; Start }
// 中间层
{ rank=same; A; B; C }
// 汇节点
{ rank=max; End }
Start -> {A B C}
A -> End
B -> End
C -> End
}
7.6 非集群子图
不以 cluster_ 开头的子图不会绘制边框,但可以共享属性:
digraph NonClusterSubgraph {
node [fontname="Microsoft YaHei" shape=box]
// 共享属性的子图
subgraph shared_red {
node [color="#F44336" fillcolor="#FFEBEE" style=filled]
R1 R2 R3
}
subgraph shared_blue {
node [color="#1976D2" fillcolor="#E3F2FD" style=filled]
B1 B2 B3
}
R1 -> R2 -> R3
B1 -> B2 -> B3
R2 -> B2
}
7.7 跨子图边
基本跨子图连接
digraph CrossSubgraphEdge {
rankdir=LR
node [fontname="Microsoft YaHei" shape=box style="filled,rounded"]
subgraph cluster_dev {
label="开发环境"
fillcolor="#E8F5E9"
style=filled
color="#388E3C"
Dev [fillcolor="#C8E6C9"]
}
subgraph cluster_staging {
label="预发布环境"
fillcolor="#FFF3E0"
style=filled
color="#FF9800"
Staging [fillcolor="#FFE0B2"]
}
subgraph cluster_prod {
label="生产环境"
fillcolor="#FFEBEE"
style=filled
color="#F44336"
Prod [fillcolor="#FFCDD2"]
}
Dev -> Staging [label="部署" penwidth=2]
Staging -> Prod [label="发布" penwidth=2 color="#F44336"]
}
7.8 业务场景
场景 1:微服务架构
digraph MicroservicesArch {
rankdir=TB
node [fontname="Microsoft YaHei"]
edge [fontname="Microsoft YaHei" fontsize=9 color="#666666"]
// 接入层
subgraph cluster_gateway {
label="网关层"
style="filled,rounded"
fillcolor="#E3F2FD"
color="#1976D2"
fontname="Microsoft YaHei"
Nginx [shape=box3d label="Nginx" style=filled fillcolor="#BBDEFB"]
Gateway [shape=box3d label="API Gateway" style=filled fillcolor="#BBDEFB"]
}
// 业务服务层
subgraph cluster_services {
label="业务服务"
style="filled,rounded"
fillcolor="#E8F5E9"
color="#388E3C"
fontname="Microsoft YaHei"
UserSvc [shape=component label="用户服务" style=filled fillcolor="#C8E6C9"]
OrderSvc [shape=component label="订单服务" style=filled fillcolor="#C8E6C9"]
PaySvc [shape=component label="支付服务" style=filled fillcolor="#C8E6C9"]
NotifySvc [shape=component label="通知服务" style=filled fillcolor="#C8E6C9"]
}
// 基础设施层
subgraph cluster_infra {
label="基础设施"
style="filled,rounded"
fillcolor="#F3E5F5"
color="#7B1FA2"
fontname="Microsoft YaHei"
MySQL [shape=cylinder label="MySQL" style=filled fillcolor="#E1BEE7"]
Redis [shape=cylinder label="Redis" style=filled fillcolor="#E1BEE7"]
MQ [shape=box3d label="消息队列" style=filled fillcolor="#E1BEE7"]
}
Nginx -> Gateway [label="负载均衡"]
Gateway -> UserSvc [label="用户相关"]
Gateway -> OrderSvc [label="订单相关"]
OrderSvc -> PaySvc [label="支付" color="#F44336"]
PaySvc -> NotifySvc [label="通知" style=dashed]
OrderSvc -> MQ -> NotifySvc [label="异步消息"]
UserSvc -> MySQL
UserSvc -> Redis [label="缓存"]
OrderSvc -> MySQL
}
场景 2:CI/CD 流水线
digraph CICDPipeline {
rankdir=LR
node [fontname="Microsoft YaHei" shape=box style="filled,rounded" fillcolor="#E3F2FD" color="#1976D2"]
edge [fontname="Microsoft YaHei" fontsize=9 color="#666666"]
// 代码阶段
subgraph cluster_code {
label="代码阶段"
style="filled,rounded"
fillcolor="#E8F5E9"
color="#388E3C"
fontname="Microsoft YaHei"
Checkout [label="代码检出"]
Lint [label="代码检查"]
Test [label="单元测试"]
}
// 构建阶段
subgraph cluster_build {
label="构建阶段"
style="filled,rounded"
fillcolor="#FFF3E0"
color="#FF9800"
fontname="Microsoft YaHei"
Build [label="构建镜像"]
Push [label="推送到仓库"]
}
// 部署阶段
subgraph cluster_deploy {
label="部署阶段"
style="filled,rounded"
fillcolor="#E3F2FD"
color="#1976D2"
fontname="Microsoft YaHei"
DeployDev [label="部署开发" fillcolor="#BBDEFB"]
DeployProd [label="部署生产" fillcolor="#FFCDD2" color="#C62828"]
}
Checkout -> Lint -> Test -> Build -> Push -> DeployDev -> DeployProd
}
7.9 子图与排名的交互
digraph SubgraphRanking {
rankdir=TB
node [fontname="Microsoft YaHei" shape=box]
// 使用子图定义排名
subgraph cluster_top {
rank=min
label="顶层"
style=dashed
Start [shape=circle]
}
subgraph cluster_middle {
rank=same
label="中间层"
style=dashed
A B
}
subgraph cluster_bottom {
rank=max
label="底层"
style=dashed
End [shape=doublecircle]
}
Start -> {A B}
{A B} -> End
}
注意事项
⚠️
cluster_前缀:必须以cluster_开头才能显示边框。大小写敏感。
⚠️ 子图属性继承:子图中的
node/edge设置只影响子图内部。
⚠️ 嵌套集群:过深的嵌套会导致布局混乱,建议不超过 3 层。
⚠️ rank=same 限制:只在
dot引擎中有效。
⚠️ 空子图:空的集群(无节点)不会绘制边框。
⚠️ 子图名唯一性:同一图中的子图名称不应重复。
扩展阅读
下一章:08 - 属性系统 — 深入理解 Graphviz 的属性系统。