dot 入門指南

Basic Graph Drawing

dot 繪製定向圖形。它讀取屬性化的圖文本文件並描繪成圖像, 作爲圖形文件或圖形格式文件,如 GIF、PNG、SVG、PDF 或 PostScript。

dot 通過四種主要步驟畫圖。瞭解這一點有助於您瞭解 dot 佈局類型以及如何控制它們。dot 使用的佈局過程依賴於圖形是循環的(acyclic)。因此,第一步是通過反轉某些循環邊的內部方向來打破輸入圖中出現的任何循環。下一步將節點(nodes)分配給離散等級(ranks)或級別(levels)。在從上到下的圖形中,排名(rank)確定 Y 座標。跨越多個排名(rank)的邊被分解爲"虛擬"節點(virtual nodes)和單位長度邊的鏈。第三步在層級種安排節點以避免交叉。第四步將節點的 X 座標設置以保持邊短,最後一步路由邊樣線(edge splines)。這是相同的一般方法,大多數分層圖形繪製程序,基於 Warfield,Carpano 和 Sugiyama 的工作。我們將讀者推薦給 GKNV93,以便對 dot 算法有深入的瞭解。

dot 接受 DOT 語言的輸入(參見附錄 D)。此語言描述了三種主要對象類型:圖形(graphs)、節點(nodes)和邊(edges)。主(最外層)圖形可以是有向圖或無方向圖形。由於 dot 使定向圖形的佈局,因此以下所有示例都使用圖。(單獨的佈局實用程序 neato 繪製非定向圖形 [Nor92]。在主圖形中,子圖定義節點和邊的子集。

圖 1 是 DOT 語言中的示例圖。第 1 行提供圖形名稱和類型。後續的行創建節點、邊或子圖,並設置屬性。所有這些對象的名稱可以是 C 標識符、數字或引用的 C 字符串。引號保護標點符號和空白。

當節點的名稱首次出現在文件中時,將創建節點。當邊運算符 -> 加入節點時,將創建邊。在此示例中,第 2 行從 main 到 parse,從 parse 到 execute。用命令 dot 執行這個文件(將其稱爲 graph1.gv)產生圖 2 的圖形。命令行選項 -Tps 選擇 PostScript(EPSF)輸出。graph1.ps可以打印、由 PostScript 查看器顯示或嵌入到其他文檔中。

dot -Tps graph1.gv -o graph1.ps

在這裏插入圖片描述

調整佈局中節點和邊的表示或位置通常很有用。這是通過在輸入文件。屬性是字符串的名稱值對。圖 3 和圖 4 說明了一些佈局屬性。在圖 3 的列表中,第 2 行將圖形的大小設置爲 4,4(以英寸爲單位)。此屬性控制繪圖的大小;但是,此屬性控制圖形的大小。如果繪圖太大,則根據需要均勻縮放以適合。

節點或邊屬性以方括號設置。在第 3 行中,節點主分配形狀框。第 4 行的邊緣通過增加其權重(默認值爲 1)來拉直。第 6 行的邊緣以虛線繪製。第 8 行從執行邊製作字符串和 printf。在第 10 行中,默認邊緣顏色設置爲紅色。這會影響在文件中的此點之後創建的任何邊。第 11 行使粗體邊緣標記爲 100 次。在第 12 行中,節點make_string
多行標籤。第 13 行將默認節點更改爲一個填充藍色陰影的框。節點比較繼承這些值。

digraph G {
    size = "4,4";
    main [shape=box];
    main -> parse [weight=8];
    parse -> execute;
    main -> init [style=dotted];
    main -> cleanup;
    execute -> {make_string; printf};
    init -> make_string;
    edge [color=red];
    main -> prinf [style=bold, label= "100 times"];
    make_string [label = "make a \nstring"];
    node [shape=box,style=filled,color=".7 .3 1.0"];
    execute -> compare;
} 

在這裏插入圖片描述

2 Drawing Attributes

附錄A,B 和 C 中總結了影響圖形會值的主要屬性。關於更多的屬性,和屬性更完整的描述,你可以參考Graphviz 網站

www.graphviz.org/doc/info/attrs.html

2.1 Node Shapes

默認情況下,節點繪製的 shape=ellipse, width=.75, height=.5, 並由節點名稱標記。其他常見形狀包括框(box)、圓圈(circle)、記錄(record)和純文本(plaintext)。在附錄 H 中給出了主節點形狀的列表。 節點形狀純文本特別令人感興趣,因爲它繪製的節點沒有任何輪廓,這是某些圖表中的重要約定。在圖形結構是主要關注的情況下,特別是當圖形是中等的 點形狀較大,可減小節點以顯示最小內容。繪製時,節點的實際大小是請求的大小及其文本標籤所需的區域的較大,除非爲 fixedsize=true,在這種情況下,將強制執行寬度和高度值。

節點形狀分爲兩大類:基於面(polygon-based)和基於記錄(record-based)。除 record 和 Mrecord 之外的所有節點形狀都被視爲多邊形,並且按邊數(橢圓和圓形爲特殊情況)進行建模,以及其他幾個幾何屬性。其中一些屬性可以在圖形中指定。如果爲 regular=true,則節點將強制爲常規節點。參數 peripheries 設置繪製的邊界曲線數。例如,雙圓具有 peripheries=2。方向屬性指定以度爲單位的多邊形順時針旋轉。

形狀多邊形(polygon)公開所有多邊形參數,可用於創建許多未預定義的形狀。除了上面提到的參數 常規(regular)、外圍(peripheries)和方向(orientation)外,多邊形還按邊數(sides)、偏斜(skew)和失真(distortion)進行參數化。偏斜是浮動的點數(通常在 +1.0 和 1.0 之間),通過從上到下傾斜形狀來扭曲形狀,正值將多邊形的頂部向右移動。因此,傾斜可用於將框轉換爲平行四邊形。失真將多邊形從上到下縮小,負值導致底部大於頂部。變形將盒子變成梯形。圖 6 和圖 5 顯示了各種多邊形屬性。

基於記錄的節點構成其他類的節點形狀。其中包括形狀記錄和 Mrecord。兩者是相同的,除了後者有圓角。這些節點表示遞歸字段列表,這些字段繪製爲交替的水平和垂直行的框。遞歸結構爲由節點的標籤確定,該標籤具有以下架構:

rlabel -> field('|' field)*
field -> boxLabel| "rlabel"
boxLabel -> ['<' string '>'][string]

必須轉義文字大括號、垂直條和角括號。空格被解釋爲令牌之間的分隔符,因此,如果要在文本中字面顯示空格,則必須轉義它們。boxLabel 中的第一個字符串爲字段指定名稱,並用作框的端口名稱(參見第 3.1 節)。第二個字符串用作字段的標籤;它可能包含與多行標籤相同的轉義序列(參見第2.2節)。圖 7 和圖 8 的示例說明了記錄的使用和某些屬性。

2.2 Labels

如上所述,默認節點標籤是其名稱。默認情況下,邊緣未標記。可以使用標籤屬性顯式設置節點和邊標籤,如圖 4 所示。
儘管按名稱標記節點可能很方便,但在有些時候必須顯式設置標籤(labels)。例如,在繪製文件目錄樹時,一個目錄可能有多個名爲 src 的目錄,但每個目錄都必須具有唯一的節點標識符。

digraph G {
    a -> b -> c;
    b -> d;
    a [shape=polygon, sides=5, peripheries=3, color=lightblue, style=filled];
    c [shape=polygon, sides=4, skew=.4, label="hello world"]
    d [shape=invtriangle];
    e [shape=polygon, sides=4, distrotion=.7];
}

在這裏插入圖片描述

digraph structs {acyclic
    node [shape=record];
       struct1 [shape=record, label="<f0> left|<f1> mid\ndle|<f2> right"];
       struct2 [shape=record, label="<f0> one|<f1> two"];
       struct3 [shape=record, label="hello\nworld |{ b |{c|<here> d|e}| f}| g | h"];
       struct1 -> struct2;
       struct1 -> struct3;
}

在這裏插入圖片描述

inode 編號或完整路徑名稱是合適的唯一標識符。然後每個節點(node)的標籤(label)可以設置爲其目錄中的文件名。

可以使用轉義序列 \n, \l, \r 來終止居中或左或右對齊的行,從而創建多行標籤。

圖形和聚類子圖也可能具有標籤。默認情況下,圖形標註位於圖形下方。設置標籤 loc=t 將標籤居於圖形上方。羣集標籤顯示在右上角的封閉矩形內角落。值 labelloc=b 將標籤移動到矩形的底部。設置標籤 just=r 將標籤向右移動。

默認字體爲 14-point Times-Roman, black。可以使用屬性字體名稱(fontname)、字體大小(fontsize )和字體顏色(fontcolor)選擇其他字體系列(font families)、大小(sizes)和顏色(colors)。字體名稱應與目標解釋器兼容。最好只使用標準字體系列 Times、Helvetica、Courier 或 Symbol,因爲這些字體保證與任何目標圖形語言配合使用。例如,Times-Italic、Times-Italic 和 Times-Bold 是便攜式的;AvanteGardeDemiOblique 不是。

對於位圖(bitmap)輸出(如 GIF 或 JPG),點依賴於在佈局期間提供這些字體。Graphviz 的大多數預編譯安裝都使用字體配置用於將字體名稱與可用字體文件匹配的庫。字體配置附帶
用於顯示匹配和安裝字體的實用程序集。請參閱字體配置文檔或外部 Graphviz FontFAQ 或更多詳細信息。如果 Graphviz 是在沒有字體配置的情況下構建的(這通常意味着您從 源代碼,fontpath 屬性可以指定應搜索字體文件的目錄列表3。如果未設置,點將使用 DOTFONTPATH 環境變量,或者,如果未設置,GDFONTPATH 環境變量。如果未設置這些,dot 將使用內置列表。

Edge labels 位於邊緣(edge)中心附近。通常,要注意防止邊緣標籤重疊的邊緣(edges)和節點(nodes)。在複雜的圖形中,要確定標籤屬於哪個邊仍然很困難。如果裝飾(decorate)屬性設置爲 true,則繪製一條線,將標籤(label)連接到其邊緣(edge)。有時避免邊緣標籤和邊之間的衝突會強制繪圖大於預期。如果 labelfloat=true,點不會嘗試防止此類重疊,從而允許更緊湊的繪圖。

邊緣(edge)還可以使用頭標籤(headlabel)和尾號(taillabel)指定其他標籤,這些標籤放置在邊緣末端附近。這些標籤的特徵使用屬性標籤字體名稱(labelfontname)、標籤字體大小(;abe;fontsize)和標籤字體顏色(labelfontcolor)指定。這些標籤放置在邊緣(edge)和節點(node)的交點附近,因此可能會干擾它們。要調整圖形,用戶可以設置標註角度(labelangle)和標註距離(labeldistance)屬性。前者設置角度(以度)旋轉,標籤從邊緣(edge)與節點(node)發生事件的角度旋轉。後者設置一個多倍縮放因子來調整標籤(label)與節點(node)的距離。

####2.3 HTML-like Labels

爲了允許在更精細的粒度下更豐富的屬性集合,dot 使用 HTML 語法接受類似於 HTML 的標籤。這些字符串使用由 <…> 分隔的字符串而不是雙引號來指定。在這些分隔符中,字符串必須遵循 HTML 的詞法、引用和句法約定。

通過使用

元素,這些標籤可以被視爲 shape=record 的擴展和替換。有了這些,人們可以在框級別更改顏色和字體,幷包括圖像。
元素的 PORT 屬性爲單元格提供端口名稱(參見第 3.1 節)。

儘管類似 HTML 的標籤只是一種特殊類型的標籤屬性,但人們經常使用它們,就好像它們是類似於 records 的新類型的節點形狀一樣。因此,當使用這些值時,人們通常會看到 shape=none 和 margin=0。也請注意,作爲標籤(label),這些標籤(label)可用於邊(edges)和圖形(graphs)以及節點(nodes)。

圖 9 和圖 10 提供了使用類似 HTML 標籤的示例。

digraph html {
    abc [shape=none, margin=0, label=<
    <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
        <TR>
            <TD ROWSPAN="3"><FONT COLOR="red">hello</FONT><BR/>world</TD>
            <TD ROWSPAN="3" BGCOLOR="lightgrey">g</TD>
            <TD ROWSPAN="3">h</TD>
        </TR> 
        <TR>
            <TD>c</TD>
            <TD PORT="here">d</TD>
            <TD>e</TD>
        </TR>
        <TR>
            <TD COLSPAN="3">f</TD>
        </TR>
    </TABLE>>];
}

在這裏插入圖片描述

2.4 Graphics Styles

節點和邊可以指定顏色屬性,默認值爲黑色。這是用於繪製節點形狀或邊緣的顏色。顏色值可以是色相飽和-亮度三重(huesaturation-brightness triple)(在 0 和 1 之間三個浮點數字,用逗號分隔);附錄 J 中列出的顏色名稱之一(借用 X 窗口系統的某些版本);或紅綠藍 (RGB) 三重4
(在 00 和 FF 之間的三個十六進制數字,前面是字符"*")。因此,值"orchid",“0.8396,0.4862,0.8549"和”#DA70D6"是指定相同顏色的三種方法。對於自動生成顏色的腳本或工具,數字形式很方便。顏色名稱查找不區分大小寫,並且忽略非字母數字字符,因此 warmgrey 和 Warm=Grey 等效。

我們可以提供有關圖形圖形中顏色使用的一些提示。首先,避免使用太多明亮的顏色。"彩虹效應"令人困惑。最好選擇較窄的顏色範圍,或隨色調而變化飽和度。其次,當節點充滿深色或非常飽和的顏色時,標籤似乎更可讀 fontcolor=white 和 fontname=Helvetica。(我們還具有 PostScript functions 用於從普通字體(plain fonts)創建輪廓字體(outline fonts)。第三,在某些輸出格式中,您可以定義自己的顏色空間。例如,如果使用 PostScript 進行輸出,則可以重新定義節點顏色(nodecolor)、邊緣顏色(edgecolor)、或圖中圖色(graphcolor)。因此,要使用 RGB 顏色, 將以下一行放在 lib.ps 文件中。

/nodecolor {setrgbcolor} bind def

使用 -l 命令行選項加載這個文件。

dot -Tps -l lib.ps file.gv -o file.ps

style 屬性控制節點和邊的雜項圖形特徵。此屬性是具有可選參數列表的基元的逗號分隔列表。預定義的基元包括實心(solid)、虛線(dashed)、虛線(dotted)、粗體(bold)和 invis。前四條控制線繪製在節點邊界和邊上,具有明顯的意義。值 invis 會導致節點或邊未繪製。節點(node)的樣式(style)還可以包括填充(filled)、對角線(diagonals)和圓角(rounded)。使用顏色fillcolor 填充節點內的陰影。如果未設置此選項,則使用 color 的值。如果這也是未設置,則使用淺灰色(light grey) 作爲默認值。對角線樣式(diagonals style)會導致短對角線在頂點附近的邊對之間繪製。圓形樣式(rounded style)對多邊形角進行圓角。

用戶定義的樣式基元(primitives)可以作爲自定義 PostScript 過程(procedures)實現。此類基元在圖形(graph)、節點(node)、
或邊(edge),在繪製其任何標記之前。參數列表已轉換爲 PostScript notation 表示法。例如,具有 style="setlinewidth(8)"的節點繪製時採用粗輪廓繪製。此處,setlinewidth 是內置的 PostScript,但用戶定義的 PostScript 過程稱爲相同的方式。這些過程的定義可以在使用 -l 加載的庫文件中給出,如上所示。

Edges 具有用於設置箭頭的 dir 屬性。dir 可以是 forward(默認值)、back(後退)、both(兩者)或 none(無)。這僅指繪製箭頭的位置,並且不會更改基礎圖形。例如,設置 dir=back 會導致箭頭在尾部繪製,頭部無箭頭,但不會交換邊緣的端點。屬性 arrowhead(箭頭)和 arrowtail(箭尾)(如果有) 的樣式, 箭頭用於邊的頭部和尾端。允許的值是 normal, inv, dot, invdot, odot, invodot 和 none(參見附錄 I)。屬性箭頭大小(arrowsize)指定影響邊緣上繪製的任何箭頭大小的多倍因子。例如, arrowsize=2.0 使箭頭長兩倍,寬兩倍。

在樣式(style)和顏色(color)方面,羣集(clusters)的作用有點像大型框形節點,因爲羣集邊界是使用羣集的顏色屬性繪製的,在
一般,羣集的外觀會影響樣式 style, color 和 fillcolor 屬性。

如果 root graph 有指定 bgcolor 屬性,則此顏色用作整個繪圖的背景,並用作默認填充顏色。

2.5 Drawing Orientation,Size and Spacing

在確定 dot 繪圖大小時起重要作用的兩個屬性是節點(nodesep)和列塞(ranksep)。第一個指定同一列(same rank)的兩個相鄰節點(two adjacent nodes)之間的最小距離(以英寸爲單位)。第二個處理排列的間隔距離,即一個排名中節點底部和下一個排名中節點頂部之間的最小垂直空間。ranksep 屬性設置排名分隔(以英寸爲單位)。或者,一個可以有 ranksep=equally。這保證了所有等級的間距相等,從相鄰列上的節點中心測量。在這種情況下,兩個等級之間的排名分隔至少是默認的排名分隔。由於兩種用途是獨立的,因此可以同時設置兩種用途。例如,ranksep="1.0 equally"會導致排名間距相等,最小等級分隔爲 1 inch。

通常,使用默認節點大小和分離繪製的圖形對於目標打印機或文檔中圖形允許的空間來說太大。有幾種方法可以嘗試解決這個問題。首先,我們將回顧 dot 如何計算最終佈局大小。

佈局最初使用默認設置在內部以"natural"大小進行(除非設置了 ratio=compress(ratio=compress),如下所述)。繪圖的大小或縱橫比沒有綁定,因此,如果圖形很大,則佈局也很大。如果未指定大小或比率,則打印自然大小布局。

控制圖形輸出大小的最簡單方法是在圖形文件中(或使用 -G 在命令行上)size=“x,y”。這將確定最終佈局。例如,無論初始佈局有多大,size=“7.5,10” 都適合 8.5x11 頁(假設默認頁面方向)。

ratio 同樣影響佈局大小,如果繪圖已適合給定大小,則不會發生任何操作。否則,繪圖的減小程度足夠均勻,以使關鍵尺寸適合。

Case 1 沒有設置ratio, 如果繪圖滿足給定的 size 大小,不會發生什麼,否則,繪圖的減小程度足以使關鍵尺寸適合。

如果設置了 ratio, 有四個子案例。

Case 2a 如果 ratio=x, x 是一個浮點數,然後,在一個維度中放大繪圖,以達到以繪圖 height|width 表示的請求比率。

Case 2b 如果 ratio=fill, 並且設置了size=x,y, 然後,在一個維度中放大繪圖,以達到 y/x 的比例。然後,縮放執行,如案例 1。效果是,按大小給出的所有邊界框都已填充。

Case 2c 如果設置了 ratio=compress 和 size=x,y , 然後,初始佈局被壓縮,嘗試以將其放入給定的邊界框中。

Case 2d 如果 ratio=auto 和 page 屬性豆設置了,並且圖不能在一個頁面裏面畫下,那麼size屬性將被忽略,並且 dot 會計算一個適合的尺寸,特別是,給定維度中的大小將是該維度中頁面大小的最小整數倍數,該倍數至少是當前大小的一半。然後,兩個維度將獨立縮放到新大小。

如果設置了 rotate=90, 或者 orientation=landscape, 然後,繪圖旋轉 90 ° 進入橫向模式。佈局的 X 軸將沿每個頁的 Y 軸。這不會影響 dot 對大小(size)、比率(ratio)或 頁面(page)。

此時,如果未設置頁面,則最終佈局將生成爲一個頁面。
如果設置了 page=x,y, 然後,佈局被打印爲頁面序列,可以平鋪或組裝成馬賽克。常見設置是 page=“8.5,11” 或 page=“11,17”。這些值是指物理設備的完整大小;使用的實際面積將由邊距設置減小。(對於打印機輸出,默認值爲 0.5 英寸;對於位圖輸出(bitmap-output),X 和 Y 邊距分別爲 10 和 2 點。對於平鋪佈局,設置較小的邊距可能會有所幫助。這可以 使用邊距屬性完成。這可以採取單個數字,用於設置邊距,或兩個數字用逗號分隔,以分別設置 x 和 y 邊距。像往常一樣,單位是英寸。儘管可以設置 margin=0,但不幸的是,許多位圖打印機(bitmap printers)的內部硬件裕量無法覆蓋。

頁面的打印順序可以由 pagedir 屬性控制。輸出始終使用基於行或基於列的順序完成,並且 pagedir 設置爲兩個字母的代碼,指定主要方向和次要方向。例如,默認值爲 BL,指定從下到上 (B) 主要順序和從左到右 (L) 次要順序。因此,首先從左到右發出頁面的下排,然後向上發出第二行,從左到右,然後從左到右用上一行結束。從上到下的順序由 T 表示,從右到左的順序由 R 表示。

如果 center=true 和圖形可以在一頁上輸出,如果使用默認頁面大小 8.5 x 11 英寸(如果未設置頁面),則圖形將重新定位爲
居於該頁面。

一個常見的問題是,以小尺寸繪製的大圖形會產生不可讀的節點標籤。要製作更大的標籤,必須給予一些東西。限制可放入一頁上的可讀文本量。通常,在運行點之前,可以通過提取原始圖形的有趣部分來繪製較小的圖形。我們有一些工具,以幫助這一點。

sccmap 將圖形分解爲強連接的組件

tred 計算傳遞減少(去除傳遞性隱含的邊緣)

gvpr 圖形處理器選擇節點或邊,並收縮或刪除圖形的其餘部分

unflatten 通過驚人的葉邊長度改善樹木的縱橫比

考慮到這一點,下面是在給定圖形上嘗試的一些功能:

  1. 增加 node 的 fontsize.
  2. 使用更小的 ranksep 和 nodesep.
  3. 使用 ratio=auto.
  4. 使用 ratio=compress 和 給一個合理的 size.
  5. 無襯線字體(sans serif font)(如 Helvetica)在縮小時可能比 Times 更具可讀性。

2.6 Node and Edge Placement

dot中的屬性提供了許多方法來調整節點和邊的大規模佈局,以及微調繪圖以滿足用戶的需求和口味。本節討論這些屬性。

有時,從左到右而不是從上到下使邊指向是很自然的。如果頂層圖形中的 rankdir=LR,則以這種方式旋轉圖形。TB(從上到下)是默認值。模式 rankdir=BT 可用於繪製向上定向圖形。對於完整性,也可以具有 rankdir=RL。

在具有時間線的圖形中,或在強調源節點和接收器節點的圖形中,可能需要約束排名分配。子圖(subgraph)的排名(rank)可以設置爲相同(same)、最小(min)、源(source)、最大值(max)或接收器(sink)。值相同會導致子圖中的所有節點都在同一排(rank)上發生。如果設置爲最小(min),則子圖中的所有節點都保證在排名上至少與佈局中的任何其他節點一樣小。這可以通過設置 rank=source 進行嚴格規定,這強制子圖中的節點位於某些級別上,其級別嚴格小於任何其他節點的等級(min或source 子圖也指定的節點除外)。值 max 或 sink 對最大排名具有類似的作用。請注意,這些約束會導致節點的等效類。如果一個子圖將節點 A 和 B 強制位於同一級別上,而另一個子圖強制節點 C 和 B 共享一個排名,則兩個子圖中的所有節點都必須在同一個排名上繪製。圖 11 和圖 12 使用子圖進行控制排名分配。

在某些圖形中,節點的從左到右排序非常重要。如果子圖具有 ordering=out,則子圖中具有相同尾部的邊緣節點將按創建順序從左到右扇出。(另請注意,涉及頭節點的平面邊緣可能會干擾其排序。)

有許多方法可以微調節點和邊的佈局。例如,如果邊節點具有相同的 group 屬性,則 dot 會嘗試保持邊筆直,並避免其他邊穿過它。邊的重量提供了另一種保持邊直的方法。edge 的 weight 表明一定程度上衡量了邊緣的重要性;因此,weight 越大,其 nodes 之間的距離越近。dot 使較重的邊繪製得更短、更直。

當節點(nodes)被限制爲相同的排(rank)時,邊權重也會發揮作用。這些節點之間權重非零的邊儘可能以相同的方向(從左到右,或旋轉的圖形中從上到下)沿排名進行。這一事實可能利用來調整節點排序,將不可見邊(style=“invis”)在需要的地方。

可以使用 samehead 和 sametail 屬性約束與同一節點相鄰的邊的端點。具體而言,具有相同頭和相同頭的相同值的所有邊都受約束以在同一點。類似屬性適用於尾節點 sametail。

在排名分配期間,邊的頭部節點被限制爲比尾節點更高的等級。但是,如果邊具有 constraint=false,則不強制執行此要求。

在某些情況下,用戶可能希望邊緣的端點永遠不會太接近。這可以通過設置邊的 minlen 屬性來獲取。

digraph asde91 {
    ranksep=.75; size= "7.5, 7.5";
    {
        node [shape=plaintext, fontsize=16];
        /* the time-line graph */
        past -> 1978 -> 1980 -> 1982 -> 1983 -> 1985 -> 1986 -> 1987 -> 1988 -> 1989 -> 1990 -> "future";
        /* ancestor programs */
        "Bourne sh"; "make"; "SCCS"; "yacc"; "cron"; "Reiser cpp"; "Cshell"; "emacs"; "build"; "vi"; "<curses>"; "RCS"; "C*";
        
    }
    {
       rank=same;
       "Software IS"; "Configuration Mgt"; "Architecture & Libraries"; "Process";
    };
    
    node [shape=box];
    { rank = same; "past"; "SCCS"; "make"; "Bourne sh"; "yacc"; "cron";}
    { rank = same; 1978; "Reiser cpp"; "Cshell"; }
    { rank = same; 1980; "build"; "emacs"; "vi";}
    { rank = same; 1982; "RCS"; "<curses>"; "IMX"; "SYNED";}
    { rank = same; 1983; "ksh"; "IFS"; "TTU"; }
    { rank = same; 1985; "nmake"; "Peggy"; }
    { rank = same; 1986; "C*"; "ncpp"; "ksh-i"; "<curses-i>"; "PG2";}
    { rank = same; 1987; "Ansi cpp"; "nmake 2.0"; "3D File System"; "fdelta"; "DAG"; "CSAS";}
    { rank = same; 1988; "CIA"; "SBCS"; "ksh-88"; "PEGASUS/PML"; "PAX"; "backtalk";}
    { rank = same; 1989; "CIA++"; "APP"; "SHIP"; "DataShare"; "ryacc"; "Mosaic";}
    { rank = same; 1990; "libft"; "CoShell"; "DIA"; "IFS-i"; "kyacc"; "sfio"; "yeast"; "ML-X"; "DOT";}
    { rank = same; "future"; "Adv. Software Technology";}
    
    "PEGASUS/PML" -> "ML-X";
    "SCCS" -> "nmake";
    "SCCS" -> "3D File System";
    "SCCS" -> "RCS";
    "make" -> "nmake";
    "make" -> "build";
    "Bourne sh" -> "Cshell";
    "Bourne sh" -> "ksh";
    "Reiser cpp" -> "ncpp";
    "Cshell" -> "ksh";
    "build" -> "nmake 2.0";
    "vi" -> "<curses>";
    "vi" -> "ksh";
    "emacs" -> "ksh";
    "RCS" -> "SBCS";
    "RCS" -> "fdelta";
    "<curses>" -> "<curse-i>";
    "SYNED" -> "Peggy";
    "ksh" -> "nmake";
    "ksh" -> "ksh-i";
    "ksh" -> "ksh-88"
    "IFS" -> "<curses-i>";
    "IFS" -> "sfio";
    "IFS" -> "IFS-i";
    "nmake" -> "ncpp";
    "nmake" -> "3D File System";
    "nmake" -> "nmake 2.0";
    "Peggy" -> "PEGASUS/PML";
    ....
}

這定義了頭部和尾部之間的最小差值。例如,如果 minlen=2,則頭部和尾部之間始終至少有一箇中間排列。請注意,這與兩個節點之間的幾何距離無關。

應謹慎對待微調。dot 可以製作佈局時效果最佳,而不會在放置單個節點(nodes)和邊(edges)時受到太大的"幫助"或干擾。佈局可以通過增加某些邊的weight,或者通過使用 style=invis 創建不可見的邊(edges)或節點(nodes),有時甚至通過重新排列文件中的節點(nodes)和邊(edges)的順序來調整佈局。但是,這可能適得其反,因爲佈局不一定與輸入圖中的更改有關。最後一次調整會使所有以前的更改無效,並使繪圖非常糟糕。我們今後想到的項目是將 dot 的數學佈局技術與允許用戶定義的提示和約束的交互式前端相結合。

3 Advanced Features

3.1 Node Ports

節點端口是邊可以附加到節點的點。(當邊未附加到端口時,它針對節點的中心,邊緣在節點的邊界處剪切。

有兩種類型的端口。端口基於 8 個指南針點 “n”,“ne”,“e”,“se”,“s”,“sw”,“w"或"nw"可以爲任何節點指定。然後,邊的末端將針對節點上的該位置。因此,如果指定 se 端口,邊緣將連接到其東南"角”(southeast “corner”)處的節點。

此外,具有 record 形狀的節點可以使用記錄結構來定義端口,而具有表的類似 HTML 的標籤可以使用 元素的 PORT 屬性使任何單元格成爲端口。如果記錄框或表單元格定義端口名稱,則邊可以使用該端口名稱來指示該端口名稱應針對框的中心。(默認情況下,邊緣被剪切到框的邊界。)

還有兩種指定端口的方法。一種方法是使用邊緣的頭端口(headport)和尾端口(tailport)屬性,例如。

a -> b [tailport = se]

或者,端口名稱(portname)可用於使用語法 node_name:port_name 修改節點名稱作爲邊聲明的一部分。因此,處理上述示例的另一種方法是

a -> b:se

由於記錄框有自己的角,因此可以將指南針點端口添加到記錄名稱端口。因此,邊緣將附加到記錄節點 b 中的框的東南角,其端口名稱爲
f0.

a -> b:f0:se

圖 13 說明了在記錄節點中聲明和使用端口名稱, 如圖 14 所示的結果圖。

圖 15 和 16 提供了使用記錄節點和端口的另一個例子。這重複了圖 7 和圖 8 的示例,但現在使用端口作爲邊的連接器。請注意,如果記錄的輸入高度設置爲小值,則記錄有時看起來更好,因此文本標籤主導了實際大小,如圖 13 所示。否則,將假定默認節點大小 (.75 乘 .5),如圖 16 所示。圖 17 和圖 18 的示例在哈希表的佈局中使用從左到右的繪圖。

3.2 Clusters

cluster 是放置在佈局中自己不同矩形中的子圖(subgraph)。當子圖的名稱具有前綴 cluster 時,該子圖將識別爲 cluster。(如果頂級圖形具有 cluster=none,則關閉此特殊處理)。 標籤(Labels)、字體特徵(font characteristics)和 labelloc 屬性可以設置爲頂級圖形,但默認情況下,標籤(label)顯示在圖形上方。對於羣集(cluster),默認情況下標籤是左對齊的;對於羣集,標籤是左對齊的。如果標籤只是"r",標籤是正確的。顏色屬性指定封閉矩形的顏色。此外,羣集可能具有 style=“filled”,在這種情況下,矩形在繪製羣集之前用 fillcolor 填充。(如果未指定填充顏色,則使用羣集的顏色屬性。)

羣集由遞歸技術繪製,該技術計算羣集內節點的排名分配和內部排序。圖 19 到圖 21 是羣集佈局和相應的圖形文件。

digraph g {
 node [shape = record,height=.1];
 node0 [label = "<f0> |<f1> G|<f2> "];
 node1 [label = "<f0> |<f1> E|<f2> "];
 node2 [label = "<f0> |<f1> B|<f2> "];
 node3 [label = "<f0> |<f1> F|<f2> "];
 node4 [label = "<f0> |<f1> R|<f2> "];
 node5 [label = "<f0> |<f1> H|<f2> "];
 node6 [label = "<f0> |<f1> Y|<f2> "];
 node7 [label = "<f0> |<f1> A|<f2> "];
 node8 [label = "<f0> |<f1> C|<f2> "];
 "node0":f2 -> "node4":f1;
 "node0":f0 -> "node1":f1;
 "node1":f0 -> "node2":f1;
 "node1":f2 -> "node3":f1;
 "node2":f2 -> "node8":f1;
 "node2":f0 -> "node7":f1;
 "node4":f2 -> "node6":f1;
 "node4":f0 -> "node5":f1;
}

在這裏插入圖片描述

digraph structs {
node [shape=record];
    struct1 [shape=record,label="<f0> left|<f1> middle|<f2> right"];
    struct2 [shape=record,label="<f0> one|<f1> two"];
    struct3 [shape=record,label="hello\nworld |{ b |{c|<here> d|e}| f}| g | h"];
    struct1:f1 -> struct2:f0;
    struct1:f2 -> struct3:here;
}

在這裏插入圖片描述

digraph G {
    nodeseq=.05;
    rankdir=LR;
    node [shape=record,width=.1,height=.1];
    
    node0 [label = "<f0> |<f1> |<f2> |<f3> |<f4> |<f5> |<f6> | ",height=2.5];
    node [width = 1.5];
    node1 [label = "{<n> n14 | 718 |<p> }"];
    node2 [label = "{<n> a1  | 805 |<p> }"];
    node3 [label = "{<n> i9  | 718 |<p> }"];
    node4 [label = "{<n> e5  | 989 |<p> }"];
    node5 [label = "{<n> t20 | 959 |<p> }"];
    node6 [label = "{<n> o15 | 794 |<p> }"];
    node7 [label = "{<n> s19 | 659 |<p> }"];
   
    node0:f0 -> node1:n;
    node0:f1 -> node2:n;
    node0:f2 -> node3:n;
    node0:f5 -> node4:n;
    node0:f6 -> node5:n;
    node2:p  -> node6:n;
    node4:p  -> node7:n; 
}

在這裏插入圖片描述

digrah G {
    subgraph cluster0 {
        node [style=filled,color=white];
        style=filled;
        color=lightgrey;
        a0 -> a1 -> a2 -> a3;
        label = "process #1";
    }
    
    subgraph cluster1 {
        node [style=filled];
        b0 -> b1 -> b2 -> b3;
        label = "process #2";
        color=blue;
    }
    
    start -> a0;
    start -> b0;
    a1 -> b3;
    b2 -> a3;
    a3 -> a0;
    a3 -> end;
    b3 -> end;
    
    start [shape=Midamond];
    end [shape=Msquare];
}

在這裏插入圖片描述

如果頂層圖形的 compound(複合) 屬性設置爲 true,則 dot 將允許 edges 連接 nodes 和 clusters。這可以通過定義 lhead 或 ltail 屬性的 edge 來實現。這些屬性的值必須分別爲包含頭節點(lhead)或尾節點(ltail)的羣集的名稱。在這種情況下,edge 在 cluster 邊界處被剪切。所有其他邊緣屬性(如 arrowhead 或 dir)都應用於截斷的邊緣。例如,圖 22 顯示了使用 compound 屬性和生成的關係圖的圖形。

digraph G {
    compound=true;
    subgraph cluster0 {
        a -> b;
        a -> c;
        b -> d;
        c -> d;
    }
    subgraph clsuter1 {
        e -> g;
        e -> f;
    }
    b -> f [lhead=cluster1];
    d -> e;
    c -> g [ltail=cluster0, lhead=cluster1];
    c -> e [ltail=cluster0];
    d -> h;
}

在這裏插入圖片描述

3.3 Concentrators (集中器)

在頂層圖上設置 concentrate=true 可實現邊緣合併技術,以減少密集佈局中的雜亂。邊在並行運行時合併,具有公共終結點,長度大於 1。固定大小的佈局的一個有利副作用是,移除這些邊通常允許更大、更可讀的標籤。而濃縮器在點看起來有點像紐貝里的,它們通過搜索佈局中的邊緣而不是通過檢測基礎圖形中的完整雙部分圖形來找到。因此,dot 的方法運行得更快,但不像紐貝里的算法那樣摺疊。

4 Command Line Options

默認情況下,dot在篩選器模式下運行,從 stdin 讀取圖形,並在附加布局屬性的 DOT 格式的 stdout 上書寫圖形。點支持各種命令行選項:

-Tformat 設置輸出的格式。格式的允許值爲:

bmp Windows bitmap 格式

canon 漂亮的打印輸入;未完成佈局。

dot 已歸於 DOT。打印帶有佈局信息作爲屬性附加到的輸入,參見附錄 F。

fig FIG 輸出

gd DG 格式。這是 GD 圖形庫(GD Graphics Library)使用的內部格式。備用格式爲 gd2。

gif GIF 輸出

imap 爲服務器端圖像映射生成地圖文件。這可以與輸出的圖形形式結合使用,例如,在網頁中使用 -Tgif 或 -Tjpg 來附加指向節點和邊緣的鏈接。

cmapx 爲客戶端圖像映射生成 HTML 地圖文件。

pdf 通過開羅圖書館的 Adobe PDF。我們在嵌入到其他文檔中時就看到了問題。而是使用 -Tps2,如下所述。

plain 簡單、基於線的 ASCII 格式。附錄 E 描述了此輸出。備用格式爲純 ext,它提供邊頭和尾部節點上的端口名稱。

png PNG(便攜式網絡圖形)輸出。

ps PostScript(EPSF) 輸出。

ps2 帶 PDF 註釋的後期腳本 (EPSF) 輸出。此輸出應蒸餾到 PDF 中,例如 pdflatex,然後再包含在文檔中。 (使用 ps2pdf;epstopdf 不處理 %%綁定Box:(尾)。

svg SVG 輸出。備用窗體 svgz 生成壓縮 SVG。

vrml VRML 輸出

wbmp Wireless BitMap(WBMP) 格式。

digraph G {
    size="8,6"; ratio=fill; node[fontsize=24];
    
    ciafan->computefan; 
    fan->increment;
    computefan->fan;
    stringdup->fatal;
    main->exit;
    main->interp_err;
    main->ciafan;
    main->fatal;
    main->malloc;
    main->strcpy;
    main->getopt;
    main->init_index;
    main->fatal;
    main->malloc;
    main->strcpy;
    main->getopt;
    main->init_index;
    main->strlen;
    fan->fatal;
    fan->ref;
    fan->interp_err;
    ciafan->def;
    fan->free;
    computefan->stdprintf;
    computefan->get_sym_fields;
    fan->exit;
    fan->malloc;
    increment->strcmp;
    computefan->malloc;
    fan->stdsprintf;
    fan->strlen;
    computefan->strcmp;
    computefan->realloc;
    computefan-strlen;
    debug->sfprintf;
    debug-strcat;
    stringdup->malloc;
    fatal->sfprintf;
    stringdup->strcpy;
    stringdup->strlen;
    fatal->exit;
    
    subgraph "cluster_error.h" { label="error.h"; interp_err;}
    subpraph "cluster_sfio.h" { label="sfip.h"; sfprintf;}
    subgraph "cluster_ciafan.c" { label="ciafan.c"; ciafan; computefan; increment;}
    subgraph "cluster_util.c" { label="util.c"; stringdup; fatal; debug; }
    subgraph "cluster_query.h" { label="query.h"; ref; def;}
    subgraph "cluster_field.h" { get_sym_fields;}
    subgraph "cluster_stdio.h" { label="stdio.h"; stdprintf; stdspirntf;}
    subgraph "cluster_<libc.a>" {getopt;}
    subgraph "cluster_stdlib.h" {label="stdlib.h"; exit; malloc; free; realloc;}
    subgraph "cluster_main.c" {main;}
    subgraph "cluster_index.h" {init_index;}
    subgraph "cluster_string.h" { label="string.h"; strcpy; strlen; strcmp; strcat;}
}

-Gname=value 設置圖形屬性默認值。通常,在命令行(而不是在圖形文件中)設置大小、分值和相關值很方便。類似的標誌 -N 或 -E 設置默認節點或邊屬性。請注意,文件內容重寫命令行參數。

-llibfile 指定與設備相關的圖形庫文件。可以提供多個庫。這些名稱在輸出開始時傳遞給代碼生成器。

-ooutfile 將輸出寫到 outfile 文件中

-v 請求詳細輸出。在處請求詳細輸出。在處理大型佈局時,詳細消息可能會對dot的process進行一些估計。

-V 打印版本號和退出。

5 Miscellaneous

在頂層圖形標題中,可以聲明圖形爲嚴格二圖或嚴格圖形。這禁止創建多邊,即在定向情況下,最多只能有一個帶有給定尾節點和頭節點的邊。對於無方向圖形,最多只能有一個邊連接到同一兩個節點。使用同一兩個節點的後續邊語句將標識邊緣與以前定義的一個,並應用邊緣語句中給出的任何屬性。

節點(nodes)、邊(edges)和圖形(graphs)可能具有 URL 屬性。在某些輸出格式(ps2、imap、cmapx 或 svg 中),此信息集成在輸出中,以便在使用適當的顯示時節點(nodes)、邊(edges)和羣集(clusters)變爲活動鏈接工具。通常,附加到頂級圖形的 URL 用作基本 URL,支持組件上的相對 URL。當輸出格式爲 imap 或 cmapx 時,頭URL 和 tailURL 屬性也發生類似的處理。

對於某些格式(ps, fig or svg), comment 屬性可用於在輸出中嵌入人類可讀符號。

6 Conclusions 結論

點產生令人愉悅的分層圖形,可以應用於許多設置。由於點的基本算法工作良好,因此,我們有很好的基礎來深入研究繪製大圖和在線(動畫)圖形繪製的方法等問題。

7 Acknowledgments 感謝

我們感謝 Phong Vo 關於圖形繪製算法和編程的建議。圖形庫使用 Phong 的 splay tree dictionary library。此外,用戶 dag, dot 的前身,給了我們許多好的建議。蓋伊·雅各布森(Guy Jacobson)和蘭迪·哈克巴特(Randy Hackbarth)審閱了本手冊的早期草稿,埃姆登(Emden)爲當前的修訂做出了重大貢獻。約翰·埃爾森(John Ellson)寫了廣義多邊形形狀和花了相當大的努力,使其強大和高效。他還編寫了 GIF 和 ISMAP 生成器和其他工具,將 Graphviz 帶到 Web 上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章