Graphs in TikZ

TikZでグラフ(ネットワーク)を簡単に描く

Graph記法とは

TikZのgraphsライブラリには,グラフを簡単に描くための\graphがある.まずはプリアンブルで以下のようにgraphsライブラリを読み込む.

\usetikzlibrary{graphs}

\graph記法はTikZ環境内で使えるマクロで以下のように使う.

\begin{tikzpicture}
\graph{
    1 -- 2 -- 3 -- 4;
    1 -- 5;
};
\end{tikzpicture}

すると次のグラフができる.

グラフ1

\graph内に新しく現れた頂点には,新たにTikZのnodeが生成される. 他方,すでに現れた頂点と同じ名前には,同じnodeが使いまわされる. 上では,1は1行目で生成されるが,2行目では1行目で生成された1が使いまわされている.

Note

graph記法の内部で\foreach\onslide等を使うとバグることがある.あまり複雑なコードは書かないほうが良い.

以下では,tikzpicture環境は省略する.

デフォルトスタイルの設定

graph環境のオプションでスタイルを設定できる.通常のTikZのノードやパスと同じようにスタイルの指定が可能である.

\graph[nodes={<node style>}, edges={<edge style>}]{...};

グラフごとにいちいち指定するのは面倒なので,graphs/every graph/.styleを用いて,デフォルトスタイルを以下のように指定すると便利である.

\tikzset{mynodes/.style={circle,white,fill=UniBlue!90,text width=.8em,inner sep=0pt,text centered,font=\footnotesize}} % 頂点のスタイル
\tikzset{myedges/.style={thick}} % 枝のスタイル
\tikzset{graphs/every graph/.style={nodes={mynodes}, edges={myedges}}} % グラフのデフォルトスタイル
\tikzset{graphs/digraph/.style={edges={myedges,-latex}}} % 有向グラフのデフォルトスタイル
\tikzset{every loop/.style={looseness=30}} % ループのスタイル

上のスタイルを用いると,先の例のグラフは以下のようになる.

グラフ2

デフォルトでは頂点名がそのまま頂点内テキストとして描画される. 以下のオプションを追加でevery graph./styleに指定するとこれを変更できる.

オプション

説明

empty nodes

頂点内テキストを描画しない

math nodes

頂点内テキストを数式モード$...$として解釈

Graph記法いろいろ

\graph内では色々な略記法が使えるので,通常のTikZより楽である.

有向枝をひく

有向枝は->でひく.下の例のdigraphは上で定義した有向グラフのデフォルトスタイルである.

\graph[digraph]{
    1 -> 2 -> 3 -> 4;
    1 -> 5;
};

有向グラフの例

<->を使うと両向きの有向枝もひける.

ループ・多重辺

ループや多重辺は枝にオプションをつけることで実現できる.ループはTikZにあるloop aboveを用い,多重辺はbend left, bend rightで調整する.なお,ループの大きさはevery loop/.styleloosenessで調整できる.

\graph{
    1 --[loop above] 1;
    2 -- 3;
    2 --[bend left] 3;
    2 --[bend right] 3;
};

ループ・多重辺の例

まとめて枝をひく

{}で頂点をグループ化すると,まとめて枝をひくことができる.

\graph{
    1 -- {2, 3, 4} -- 5;
};

まとめて枝をひく例

2つのグループ間に枝をひくこともできる.complete bipartiteをつけると,その上の完全二部グラフが作れる.

\graph{
    {1, 2, 3} --[complete bipartite] {4, 5, 6};
};

complete bipartiteの例

既存のTikZノードを使う

\graph外で定義したTikZのノードを使うには,その座標を書く. 以下は,すでに定義されたTikZノードaと新しいグラフ頂点のノード1に枝を引く例.

\graph{
    (a) -- 1;
};

TikZノードを使う例

頂点に文字を書く

as={}を書くことで,頂点内のテキストを指定できる.

\graph{
    1[as={$s$}];
}

asを使う例

Graphs.standardライブラリとグラフマクロ

完全グラフやサイクルグラフなどのよく使うグラフは,グラフマクロとしてTikZ内に登録されている.これらを使うためには,graphs.standardを読み込む.

\usetikzlibrary{graphs.standard}

例えば,\(n\)頂点完全グラフ(\(K_n\))はK_nで作れる.n=で頂点数を指定できる.

\graph{subgraph K_n[n=5, clockwise]};

K_nの例

ここで,clockwiseは頂点を時計回りに配置するオプションである. デフォルトでは,ノード名は1, 2, …, nになる.

\(m\)頂点と\(n\)頂点をもつ完全二部グラフ(\(K_{nm}\))はK_nmを使う.

\graph{subgraph K_nm[n=5, m=3]};

デフォルトでは左側ノード名がV 1, V 2, …, V nとなり,右側ノード名がW 1, W 2, …, W mとなる.

K_nmの例

以下がgraphs.standardライブラリに定義されているグラフ一覧である.

グラフ

マクロ名

補足

完全グラフ(\(C_n\))

K_n

完全二部グラフ(\(K_{nm}\))

K_nm

サイクルグラフ(\(C_n\))

C_n

パスグラフ(\(P_n\))

P_n

独立集合

I_n

K_nの枝なし版

二部独立集合

I_nm

K_nmの枝なし版

グリッドグラフ

Grid_n

自作グラフマクロを登録する

デフォルトのグラフマクロは種類が少ないので,よく使うグラフは自作グラフマクロとして登録しておくと便利である.TikZのスタイル同様に \tikzgraphset{declare={<グラフ名>}{<中身>}} で登録できる.以下はPetersenグラフを自作マクロPetersenとして登録する例である.参考: Petersen graph with new tikz graph library

\tikzgraphsset{declare={Petersen}{%
    subgraph C_n [n=5, name=A, radius=1.5cm]; 
    subgraph I_n [n=5, name=B, radius=.8cm];
    \foreach \i [evaluate={\j=int(mod(\i+2,5)+1);}] in {1,...,5}{
        A \i -- B \i;
        B \i -- B \j;
}}}

登録後は以下のようにして簡単に呼び出せる.

\graph[clockwise]{Petersen};

Petersenグラフの例

配置の調整

デフォルトの配置規則

デフォルトでは,Cartesian placementという配置規則に従ってノードが配置される.これは,大雑把に言うと,パス内では左から右に頂点が配置され,パスどうしは上から下に配置される.オプションを指定すると方向を変えることもできる.grow *がパス内の頂点配置,branch *がパスどうしの配置を指定する.

オプション

効果

grow down , branch down

上から下

grow up , branch up

下から上

grow left , branch left

右から左

grow right, branch right

左から右

各オプションではgrow down=<値>のように,頂点の間隔を指定できる.デフォルトでは全て1である.

手動で座標を指定

Cartesian placementを無効にし,自分で座標を指定したい場合は,no placementを利用し,頂点ごとにat={}を用いて座標を指定する.atを指定しない頂点は原点に配置される.

\graph[no placement]{
    a;
    b[at={(1,0)}];
}

x=<値>, y=<値>を用いて,\(x\)座標と\(y\)座標を別々に指定することもできる.これをグループ{}を組み合わせると,座標指定が多少楽になる.

\graph[no placement]{
    a; % (0,0) に配置される
    {[x=1]
        b[y=0], c[y=-1] % (1,0), (1,-1) に配置される
    };
}

残念ながら,通常のTikZのleft=1cm of aのような他ノードからの相対的な位置の指定はできないようである.どうしても相対位置指定をしたい場合は,\graphの外でノードを作り,枝だけ\graph内で作ることになる.

Tips

枝を消す

\graphsimpleオプションを指定すると,同じ頂点対間に枝が複数回ひかれた場合には,最後にひいた枝のみが残る.これを応用すると,後から枝を消すことができる.例えば,\(K_5\)から1本だけ枝を削除したグラフは,いちいち枝を指定することなく以下のように簡潔に書ける.

\graph[simple]{
    subgraph K_n[n=5, clockwise];
    3 -!- 5;
};

-!-は空の枝をひく記法である.simpleがない場合は,-!-は何もしない.

枝を細分する

枝の細分(subdivision)も簡単に作れる.

\newcommand{\subdivision}[3]{%
    \path (#1) -- (#2)
    \foreach \i in {1,...,#3} {
        node[mynodes, text width=.5em, pos=\i/(#3+1)] {}
    };
}

使い方は,\subdivision{<始点>}{<終点>}{<細分した枝に追加される頂点数>}である.始点と終点にはノード名を指定する.

例: \(K_5\)の細分は以下のように作れる.Kuratowskiの定理を紹介するときに便利だと思う.

\graph{subgraph K_n[n=5,clockwise,radius=2cm]};
\subdivision{1}{2}{2};
\subdivision{2}{3}{4};
\subdivision{3}{4}{2};
\subdivision{4}{5}{1};
\subdivision{5}{1}{1};
\subdivision{5}{2}{3};

K_5の細分