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

Graphviz 图形可视化教程 / 09 - 高级特性

第 09 章 · 高级特性

9.1 HTML 表格标签

HTML 标签是 Graphviz 中创建复杂节点标签的最强大方式。

基本表格结构

digraph HTMLBasics {
    node [fontname="Microsoft YaHei" shape=plain]
    edge [fontname="Microsoft YaHei"]

    // 基本表格
    table [label=<
        <TABLE BORDER="1" CELLBORDER="0" CELLSPACING="2" CELLPADDING="8">
            <TR>
                <TD BGCOLOR="#1976D2"><FONT COLOR="white"><B>标题栏</B></FONT></TD>
            </TR>
            <TR>
                <TD>内容区域</TD>
            </TR>
        </TABLE>
    >]

    another [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
            <TR><TD>单元格 1</TD><TD>单元格 2</TD></TR>
            <TR><TD COLSPAN="2">合并列</TD></TR>
        </TABLE>
    >]

    table -> another
}

TABLE 属性

属性 说明 常用值
BORDER 外边框宽度 012
CELLBORDER 单元格边框宽度 01
CELLSPACING 单元格间距 024
CELLPADDING 单元格内边距 4812
BGCOLOR 表格背景色 颜色值
ALIGN 水平对齐 LEFTCENTERRIGHT
VALIGN 垂直对齐 TOPMIDDLEBOTTOM
FIXEDSIZE 固定尺寸 TRUEFALSE
WIDTH 宽度(像素) 数值
HEIGHT 高度(像素) 数值
ROWS 行优先布局 ROWROWSPAN
COLUMNS 列优先布局 COLCOLSPAN

TD 单元格属性

属性 说明 常用值
COLSPAN 合并列数 23
ROWSPAN 合并行数 23
ALIGN 水平对齐 LEFTCENTERRIGHT
VALIGN 垂直对齐 TOPMIDDLEBOTTOM
BGCOLOR 背景色 颜色值
WIDTH 宽度 像素值
HEIGHT 高度 像素值
PORT 端口名 字符串
SIDES 边框方向 LRTB(可组合)
HREF 超链接 URL
TARGET 链接目标 _blank_self
TOOLTIP 鼠标提示 文本
FIXEDSIZE 固定尺寸 TRUEFALSE

9.2 复杂表格示例

UML 类图

digraph UMLAdvanced {
    node [fontname="Microsoft YaHei" shape=plain]
    edge [fontname="Microsoft YaHei" fontsize=9]

    UserService [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="6">
            <TR>
                <TD COLSPAN="2" BGCOLOR="#1976D2">
                    <FONT COLOR="white" POINT-SIZE="13"><B>«interface» UserService</B></FONT>
                </TD>
            </TR>
            <TR>
                <TD COLSPAN="2" BGCOLOR="#E3F2FD" ALIGN="LEFT">
                    <FONT POINT-SIZE="10">
                        - repository: UserRepository<BR/>
                        - cache: RedisClient<BR/>
                    </FONT>
                </TD>
            </TR>
            <TR>
                <TD COLSPAN="2" BGCOLOR="#E8F5E9" ALIGN="LEFT">
                    <FONT POINT-SIZE="10">
                        + findById(id: Long): User<BR/>
                        + create(user: User): User<BR/>
                        + update(user: User): void<BR/>
                        + delete(id: Long): void<BR/>
                    </FONT>
                </TD>
            </TR>
        </TABLE>
    >]

    UserRepository [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="6">
            <TR>
                <TD COLSPAN="2" BGCOLOR="#388E3C">
                    <FONT COLOR="white" POINT-SIZE="13"><B>«interface» UserRepository</B></FONT>
                </TD>
            </TR>
            <TR>
                <TD COLSPAN="2" BGCOLOR="#E8F5E9" ALIGN="LEFT">
                    <FONT POINT-SIZE="10">
                        + findById(id: Long): User<BR/>
                        + save(user: User): User<BR/>
                        + findByEmail(email: String): User<BR/>
                    </FONT>
                </TD>
            </TR>
        </TABLE>
    >]

    UserService -> UserRepository [label="依赖" arrowhead=open style=dashed]
}

数据库表结构

digraph DBSchema {
    node [fontname="Microsoft YaHei" shape=plain]
    edge [fontname="Microsoft YaHei" fontsize=9]

    Users [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="6">
            <TR><TD COLSPAN="3" BGCOLOR="#1976D2"><FONT COLOR="white"><B>users</B></FONT></TD></TR>
            <TR>
                <TD BGCOLOR="#FFE0B2">🔑</TD>
                <TD ALIGN="LEFT">id</TD>
                <TD ALIGN="LEFT">BIGINT PK</TD>
            </TR>
            <TR>
                <TD></TD>
                <TD ALIGN="LEFT">username</TD>
                <TD ALIGN="LEFT">VARCHAR(50)</TD>
            </TR>
            <TR>
                <TD></TD>
                <TD ALIGN="LEFT">email</TD>
                <TD ALIGN="LEFT">VARCHAR(100)</TD>
            </TR>
            <TR>
                <TD></TD>
                <TD ALIGN="LEFT">created_at</TD>
                <TD ALIGN="LEFT">TIMESTAMP</TD>
            </TR>
        </TABLE>
    >]

    Orders [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="6">
            <TR><TD COLSPAN="3" BGCOLOR="#388E3C"><FONT COLOR="white"><B>orders</B></FONT></TD></TR>
            <TR>
                <TD BGCOLOR="#FFE0B2">🔑</TD>
                <TD ALIGN="LEFT">id</TD>
                <TD ALIGN="LEFT">BIGINT PK</TD>
            </TR>
            <TR>
                <TD BGCOLOR="#BBDEFB">🔗</TD>
                <TD ALIGN="LEFT">user_id</TD>
                <TD ALIGN="LEFT">BIGINT FK</TD>
            </TR>
            <TR>
                <TD></TD>
                <TD ALIGN="LEFT">amount</TD>
                <TD ALIGN="LEFT">DECIMAL(10,2)</TD>
            </TR>
            <TR>
                <TD></TD>
                <TD ALIGN="LEFT">status</TD>
                <TD ALIGN="LEFT">VARCHAR(20)</TD>
            </TR>
        </TABLE>
    >]

    Users -> Orders [label="1 : N" arrowhead=none arrowhead=crow]
}

服务器监控面板

digraph MonitorDashboard {
    node [fontname="Microsoft YaHei" shape=plain]
    edge [fontname="Microsoft YaHei" fontsize=9]

    Server [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="6" BGCOLOR="#FAFAFA">
            <TR>
                <TD COLSPAN="4" BGCOLOR="#1976D2">
                    <FONT COLOR="white" POINT-SIZE="14"><B>🖥 Web Server 01</B></FONT>
                </TD>
            </TR>
            <TR>
                <TD BGCOLOR="#E3F2FD"><B>指标</B></TD>
                <TD BGCOLOR="#E3F2FD"><B>当前值</B></TD>
                <TD BGCOLOR="#E3F2FD"><B>阈值</B></TD>
                <TD BGCOLOR="#E3F2FD"><B>状态</B></TD>
            </TR>
            <TR>
                <TD>CPU</TD>
                <TD ALIGN="RIGHT">72%</TD>
                <TD ALIGN="RIGHT">80%</TD>
                <TD BGCOLOR="#C8E6C9">正常</TD>
            </TR>
            <TR>
                <TD>内存</TD>
                <TD ALIGN="RIGHT">85%</TD>
                <TD ALIGN="RIGHT">90%</TD>
                <TD BGCOLOR="#FFE0B2">警告</TD>
            </TR>
            <TR>
                <TD>磁盘</TD>
                <TD ALIGN="RIGHT">95%</TD>
                <TD ALIGN="RIGHT">90%</TD>
                <TD BGCOLOR="#FFCDD2">危险</TD>
            </TR>
            <TR>
                <TD>连接数</TD>
                <TD ALIGN="RIGHT">1,234</TD>
                <TD ALIGN="RIGHT">5,000</TD>
                <TD BGCOLOR="#C8E6C9">正常</TD>
            </TR>
        </TABLE>
    >]
}

9.3 图片嵌入

使用 IMG 标签

在 HTML 标签中嵌入图片:

digraph ImageEmbed {
    node [fontname="Microsoft YaHei" shape=plain]

    logo [label=<
        <TABLE BORDER="0" CELLBORDER="0" CELLSPACING="4">
            <TR>
                <TD><IMG SRC="/image/logo.png" SCALE="TRUE" WIDTH="64" HEIGHT="64"/></TD>
            </TR>
            <TR>
                <TD><B>应用名称</B></TD>
            </TR>
        </TABLE>
    >]

    service [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
            <TR>
                <TD><IMG SRC="/image/icon.png" SCALE="TRUE" WIDTH="32" HEIGHT="32"/></TD>
                <TD>服务节点</TD>
            </TR>
        </TABLE>
    >]

    logo -> service
}

使用 image 属性

digraph ImageAttr {
    node [fontname="Microsoft YaHei"]

    // image 属性(节点形状必须是 none 或 plaintext)
    icon [shape=none label="" image="/image/icon.png" width=1 height=1]
    text [label="纯文本节点"]

    icon -> text
}

⚠️ 图片路径:图片路径相对于运行 dot 命令时的工作目录,或使用绝对路径/URL。


9.4 高级端口

HTML 端口

digraph HTMLPorts {
    node [fontname="Microsoft YaHei" shape=plain]

    router [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="6">
            <TR>
                <TD COLSPAN="3" BGCOLOR="#1976D2">
                    <FONT COLOR="white"><B>路由器</B></FONT>
                </TD>
            </TR>
            <TR>
                <TD PORT="eth0">ETH0</TD>
                <TD PORT="eth1">ETH1</TD>
                <TD PORT="eth2">ETH2</TD>
            </TR>
        </TABLE>
    >]

    sw1 [label="交换机 1" shape=box style=rounded]
    sw2 [label="交换机 2" shape=box style=rounded]
    sw3 [label="交换机 3" shape=box style=rounded]

    router:eth0 -> sw1 [label="端口 0"]
    router:eth1 -> sw2 [label="端口 1"]
    router:eth2 -> sw3 [label="端口 2"]
}

端口与 Record 对比

特性 Record 端口 HTML 端口
语法 <f0> PORT="name"
布局 垂直/水平 完全自由(表格)
样式 有限 丰富(字体、颜色等)
合并单元格 不支持 支持 COLSPAN/ROWSPAN
推荐程度 旧项目兼容 推荐

9.5 排名约束 (Rank)

rank=same 详解

digraph RankSameExample {
    rankdir=TB
    node [fontname="Microsoft YaHei" shape=box style="filled,rounded" fillcolor="#E3F2FD" color="#1976D2"]

    Start [shape=circle fillcolor="#C8E6C9" color="#388E3C"]

    // 这三个节点在同一层
    {
        rank=same
        A [label="步骤 A"]
        B [label="步骤 B"]
        C [label="步骤 C"]
    }

    End [shape=doublecircle fillcolor="#FFCDD2" color="#C62828"]

    Start -> {A B C}
    {A B C} -> End
}

rank=source / rank=sink

digraph RankSourceSink {
    rankdir=TB
    node [fontname="Microsoft YaHei" shape=box]

    // source — 尽可能靠近顶层
    {
        rank=source
        Input1
        Input2
    }

    // sink — 尽可能靠近底层
    {
        rank=sink
        Output1
        Output2
    }

    // 中间层
    Process1
    Process2

    Input1 -> Process1
    Input2 -> Process2
    Process1 -> Output1
    Process2 -> Output2
    Input1 -> Process2 [style=dashed]
}

强制层级间距

digraph RankSep {
    rankdir=TB
    node [fontname="Microsoft YaHei" shape=box style=rounded]

    // 不同层级使用不同的 ranksep
    ranksep=1.5

    L1 [label="第 1 层" fillcolor="#E3F2FD" style=filled]
    L2 [label="第 2 层" fillcolor="#E8F5E9" style=filled]
    L3 [label="第 3 层" fillcolor="#FFF3E0" style=filled]
    L4 [label="第 4 层" fillcolor="#F3E5F5" style=filled]

    L1 -> L2 -> L3 -> L4
}

9.6 边的约束与自由

constraint=false 的用法

digraph ConstraintDemo {
    rankdir=TB
    node [fontname="Microsoft YaHei" shape=box style="filled,rounded" fillcolor="#E3F2FD" color="#1976D2"]

    A -> B -> C -> D

    // 这条边不影响排名,但仍然绘制
    A -> D [constraint=false style=dashed color="#F44336" label="非约束边"]

    // B 和 D 同层(因为 A->D 不影响 D 的排名)
    // 实际布局中 C 和 D 可能同层
}

虚拟节点

通过不可见节点控制边的路径:

digraph VirtualNodes {
    rankdir=TB
    node [fontname="Microsoft YaHei"]

    A [shape=box label="A"]
    B [shape=box label="B"]
    C [shape=box label="C"]

    // 虚拟节点(不可见)
    V [shape=point width=0 style=invis label=""]

    A -> V [style=invis]
    V -> C [style=invis]

    // 绕过 B 的边
    A -> C [style=dashed color="#999" label="绕过"]
    A -> B -> C
}

9.7 集中边 (Concentrate)

digraph ConcentrateDemo {
    concentrate=true
    node [fontname="Microsoft YaHei" shape=box]

    A -> B
    A -> C
    A -> D
    A -> E

    // concentrate=true 会合并从同一节点出发的多条边
    // 使用共享路径减少视觉混乱
}

9.8 业务场景:API 文档图

digraph APIDoc {
    rankdir=TB
    node [fontname="Microsoft YaHei" shape=plain]
    edge [fontname="Microsoft YaHei" fontsize=9]

    // API 端点
    GetUser [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="6">
            <TR>
                <TD BGCOLOR="#4CAF50"><FONT COLOR="white"><B>GET /api/users/:id</B></FONT></TD>
            </TR>
            <TR>
                <TD ALIGN="LEFT">
                    <FONT POINT-SIZE="10">
                        <B>参数:</B><BR/>
                        - id: Long (路径参数)<BR/>
                        <B>响应:</B><BR/>
                        - 200: User 对象<BR/>
                        - 404: 用户未找到<BR/>
                    </FONT>
                </TD>
            </TR>
        </TABLE>
    >]

    CreateUser [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="6">
            <TR>
                <TD BGCOLOR="#2196F3"><FONT COLOR="white"><B>POST /api/users</B></FONT></TD>
            </TR>
            <TR>
                <TD ALIGN="LEFT">
                    <FONT POINT-SIZE="10">
                        <B>请求体:</B><BR/>
                        - username: String<BR/>
                        - email: String<BR/>
                        <B>响应:</B><BR/>
                        - 201: 创建成功<BR/>
                        - 400: 参数错误<BR/>
                    </FONT>
                </TD>
            </TR>
        </TABLE>
    >]

    GetUser -> CreateUser [label="关联" style=dashed]
}

注意事项

⚠️ HTML 标签不用引号label=<TABLE>...</TABLE> 而不是 label="<TABLE>...</TABLE>"

⚠️ 嵌套引号:HTML 属性值中的引号用单引号 '<FONT COLOR='red'>' 或双引号均可。

⚠️ IMG 路径:图片路径相对于 dot 命令的工作目录,不是相对于 DOT 文件。

⚠️ Record vs HTML:HTML 标签功能更强大,新项目推荐使用 HTML 标签替代 Record。

⚠️ rank=same 仅 dot 有效:在其他引擎中 rank 属性无效。

⚠️ 输出格式限制:HTML 标签中的 HREFTOOLTIP 等交互属性仅在 SVG 输出中有效。


扩展阅读


下一章10 - 编程语言绑定 — 使用编程语言动态生成图形。