强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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边框样式soliddasheddottedfilledrounded
color边框颜色颜色值
fillcolor背景填充色style=filled
bgcolor背景色同上
fontname标签字体字体名
fontsize标签字号数值
fontcolor标签颜色颜色值
penwidth边框宽度123
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 的属性系统。