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

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 - 编程语言绑定 — 使用编程语言动态生成图形。