Graphviz是一個強大的圖形可視化工具,
而其中rank
屬性是控制節點垂直佈局的關鍵參數之一。
本文將深入介紹rank='sink'
的使用方法和實際應用場景。
什麼是rank=’sink’?
在Graphviz中,rank
屬性用於指定子圖在垂直方向的位置層級。
而rank='sink'
特別表示將節點或子圖放置在圖的最底部,
不管其他節點的位置如何。
常見的rank值包括:rank='source'
– 放置在最頂部
rank='sink'
– 放置在最底部
rank='same'
– 與其他同級節點保持在同一水平線
rank='min'
– 優先放在頂部
rank='max'
– 優先放在底部
rank=’sink’ 的正確使用方法
要使用rank='sink'
,應該在子圖中設置此屬性,
而不是直接在節點上設置。
以下是正確的實現方式:
from graphviz import Digraph
g = Digraph()
# 主圖中的節點
g.node('A', 'Node A')
g.node('B', 'Node B')
g.node('C', 'Node C')
g.edges([("A", "B"), ("B", "C")])
# 正確:在子圖中使用rank='sink'
with g.subgraph() as s:
s.attr(rank='sink') # 設置子圖為sink
s.node('Logo', 'Company Logo')
# Logo節點會被放在最底部
#子圖只有一個節點(node)
g.render('correct_sink', format='png', view=True)
輸出結果:

注意:在上面的例子中,
我們創建了一個子圖,設置其rank='sink'
,
然後在這個子圖中添加了Logo節點。
這確保Logo節點被放在圖的最底部。
常見錯誤:直接在節點上設置rank
以下代碼展示了一個常見錯誤:嘗試直接在節點上設置rank
屬性:
from graphviz import Digraph
g = Digraph()
# 主圖中的節點
g.node('A', 'Node A')
g.node('B', 'Node B')
g.node('C', 'Node C')
g.edges([("A", "B"), ("B", "C")])
# 錯誤:直接在節點上設置rank
g.node('Logo', 'Company Logo', rank='sink') # 這不會按預期工作
g.render('incorrect_sink',
format='png', view=True)
輸出結果:

這種方法作用不如預期,
因為在Python的Graphviz接口中,rank
不是節點屬性,而是子圖屬性
不論有無 rank=’sink’ 圖形都是這樣排列。
多個層級的進階使用
我們可以使用多個子圖來創建多個具有不同rank值的節點組:
from graphviz import Digraph
g = Digraph()
# 設置一些常規節點
g.node('A', 'Process Start')
g.node('B', 'Process Middle')
g.node('C', 'Process End')
g.edges([("A", "B"), ("B", "C")])
# 創建頂部標題子圖
with g.subgraph() as s:
s.attr(rank='source') # 放在最頂部
s.node('Title', 'PROCESS FLOW CHART')
# 創建底部註腳子圖
with g.subgraph() as s:
s.attr(rank='sink') # 放在最底部
s.node('Footer', 'Copyright © 2025')
s.node('Logo', 'Company Logo')
# 連接標題和註腳(不影響rank)
g.edge('Title', 'A', style='invis') # 不可見邊,僅用於佈局
g.edge('C', 'Footer', style='invis') # 不可見邊,僅用於佈局
g.render('multi_level_ranks', format='png', view=True)
輸出結果:

rank=’sink’ 的實際應用場景
- 添加頁腳或標識:將公司標識、版權信息或文檔頁腳放在圖表底部。
- 流程終點標記:在流程圖中標記最終狀態或終點。
- 圖例位置控制:確保圖例始終出現在圖表的底部。
- 分層架構圖:在系統架構圖中,明確表示底層組件。
小結:rank=’sink’ 的關鍵要點
- 使用方式:必須在子圖中使用,而不是直接在節點上設置。
- 作用:將節點或一組節點放置在圖的最底部。
- 搭配使用:可與其他rank值如’source’、’same’等結合使用,創建層次分明的圖表。
- 實用場景:適用於添加頁腳、圖例或終點標記等需要固定在底部的元素。
透過正確使用rank='sink'
及其他rank值,
您可以精確控制Graphviz圖的垂直布局,
創建出層次分明、結構清晰的可視化圖表。
推薦hahow線上學習python: https://igrape.net/30afN
部分code:
# 添加流程底部的輔助節點
g.node('BottomAnchor', '', shape='point',
style='invis', width='0', height='0')
# 使用rank=sink確保輔助節點在最底部
with g.subgraph() as s:
s.attr(rank='sink')
s.node('BottomAnchor')
# 添加從Repair6到ICT的大弧線連接
# 使用隱形輔助邊引導弧線路徑
g.edge('Repair6', 'BottomAnchor',
style='invis', constraint='true')
g.edge('ICT', 'BottomAnchor',
style='invis', constraint='true')
# 添加從Repair6到ICT的大弧線,使用特殊設置
g.edge('Repair6', 'ICT', label="OK",
constraint='false', tailport='s', headport='s')
#, minlen='4' #這個參數無影響
也可沉在最底部,
作為隱形的子圖(僅有一個node)
Repair6 (最右方最底下的Repair, label為空字串)
Repair 6 & ICT 都與 BottomAnchor子圖
使用隱形的線連接起來 (constraint=“true”)
Repair 6 的南邊 -> ICT 的南邊 再連接 (constraint=“false”),
可以讓Repair6 -> ICT 使用弧狀的線連接

推薦hahow線上學習python: https://igrape.net/30afN
rank=’sink’ 不可與
g.attr(newrank=’true’)
#子圖同高度
一起使用
code:
from graphviz import Digraph
# 创建图表并设置newrank=true
g = Digraph('Manufacturing_test_flow',
filename='manufacturing_test_flow.gv',
format='png', engine='dot')
g.attr(rankdir='TB') # 从上到下的布局
g.attr(newrank='true') # 启用newrank
# 左侧流程
g.node('L1', 'Left Top', shape='box')
g.node('L2', 'Left Middle', shape='box')
g.node('L3', 'Left Bottom', shape='box')
g.edge('L1', 'L2')
g.edge('L2', 'L3')
# 右侧流程
g.node('R1', 'Right Top', shape='box')
g.node('R2', 'Right Middle', shape='box')
g.node('R3', 'Right Bottom', shape='box')
g.edge('R1', 'R2')
g.edge('R2', 'R3')
# # 确保上层节点在同一水平线上
# with g.subgraph() as s:
# s.attr(rank='same')
# s.node('L1')
# s.node('R1')
# # 确保中间节点在同一水平线上
# with g.subgraph() as s:
# s.attr(rank='same')
# s.node('L2')
# s.node('R2')
# # 确保底层节点在同一水平线上
# with g.subgraph() as s:
# s.attr(rank='same')
# s.node('L3')
# s.node('R3')
# 添加sink节点到最底部
with g.subgraph() as s:
s.attr(rank='sink')
s.node('LeftSink', 'Left Sink Node',
shape='box', style='filled',
fillcolor='lightblue')
s.node('RightSink', 'Right Sink Node',
shape='box', style='filled',
fillcolor='lightblue')
# # 连接到sink节点
# g.edge('L3', 'LeftSink')
# g.edge('R3', 'RightSink')
# 渲染图形
g.render(view=True)
輸出結果:

LeftSink 與 RightSink
未因為rank=’sink’的設定
而沉在最底下
註解掉這一行程式碼
# g.attr(newrank=’true’) # 启用newrank
rank=’sink’ 的設定
就如預期般地作用

推薦hahow線上學習python: https://igrape.net/30afN
近期留言