業務フロー図ライブラリ Q Business Process Management

Q-BPM:プロセスダイアグラム画像の書き方

出典: Q-BPM

q-BPM.orgにおけるBPMN記法に基づくプロセスダイアグラム画像の多くは、Graphvizエクステンションによって生成されている。ここではGraphvizを用いたBPMN図の作成方法について記述する。

目次

Graphvizの概要

OSSライセンスの種類
BSD系
制約少。著作権者と無保証の表示を守れば追加開発ソースコードの公開義務はない。Apache、PostgreSQLなど
CPL系
制約中。追加機能やリンク部分の開発についてはソースコード公開義務がない。Firefox、Eclipseなど
GPL系
制約多。原則ソースコードの再公開義務がある(LGPLの動的リンク除く)。Linux、MySQLなど

Graphvizは「グラフ」を描画するためのオープンソースソフトウェア(OSS)で、AT&T Researchにより公開されている(CPL1.0ライセンス)。グラフ表記言語DOTによる記述を解読し、画像ファイルを生成する。DOTの[公式マニュアル]に記載されているサンプルは以下の通り。

Graphvizのツール群

Graphvizは、有向グラフ、無向グラフ、放射状グラフ、循環グラフなどを描画できる。(ここでは「BPMN記法を用いたBPDを定義する事」に主眼を置くため、有向グラフの作成を前提に記述する)

グラフとは

そもそも「グラフ」とは、「グラフ理論(Graph Theory)」分野における専門用語で「ノードとエッジによって表現できるもの」を指す。ビジネスプロセスダイアグラム(BPD)の様な流れ図に限らず、依存関係、データ構造、地図情報など様々な情報を模式化する為に広く利用される。

流れ図であるBPDを描くとき、そのエッジには向きが定義されるが、グラフ理論において、その様なグラフを特に「有向グラフ(Directed Graph)」と呼ぶ。その逆にエッジに向きが無いものを「無向グラフ(Undirected Graph)」、またエッジ交差がなく表記できるものを「平面グラフ(Plane Graph)」、すべてのエッジが水平垂直方向のみの直線で表現できるものを「直交グラフ(Orthogonal Graph)」と呼ぶ。

公式サンプルA

<DOT表記>
digraph test123 {
a -> b -> c;
a -> {x y};
b [shape=box];
c [label="hello\nworld",color=blue,fontsize=24,fontname="Palatino-Italic",fontcolor=red,style=filled];
a -> z [label="hi", weight=100];
x -> z [label="multi-line\nlabel"];
edge [style=dashed,color=red];
b -> x;
{rank=same; b x}
}

公式サンプルB

<DOT表記>
graph test123 {
a -- b -- c;
a -- {x y};
x -- c [w=10.0];
x -- y [w=5.0,len=3];
}

BPMN記法の例

Graphvizは、BPMN記法におけるオブジェクトやマーカの全てを表現できるものではなく、また厳密に表現できるものでもない。しかしながらテキスト情報を元に画像を自動的に生成するため、BPD画像作成やBPD画像翻訳の効率を高められる。 当サイトでは以下の書式を推奨する。

グラフの全体属性

有向グラフを描くために「digraph」、流れる方向を左から右へとする(デフォルトは上から下)ために「rankdir=LR;」を指定する必要がある。

シーケンスフロー

接続オブジェクト

image:connecting-objects.png

非制御フロー
アクティビティ「A1」が完了すれば、後続の「A2」「A3」が共に同時に実行される(AND-Split)。特別なエッジ属性を指定する必要はない。
制御フロー
単一選択分岐(XOR-Split)等で利用される。「A2」完了時、条件「x>100」が真であれば「A4」が実行される。エッジ属性として「arrowtail=odiamond」を指定する。また条件文は「label」「headlabel」「taillabel」の値として指定する。
デフォルトフロー
制御フローと組み合わせて使用され、全ての制御フローの条件が満たされない場合に選択される。エッジ属性として「arrowtail=rcrowlvee」を指定する。(バックスラッシュの向きを逆転させたい場合には「arrowtail=lcrowrvee」)
<DOT表記>
digraph G {
 rankdir=LR;
 A1 -> {A2 A3};
 A2 -> A4 [arrowtail=odiamond, label="X>100"];
 A2 -> A5 [arrowtail=rcrowlvee];
}

アクティビティ

フローオブジェクト

image:Objectoo.png

角が丸い長方形を表現するため、ノード属性「shape=box, style=rounded」を指定する。ラベルを変更する場合には「label」の値として指定する。

<DOT表記>
digraph G {
 rankdir=LR;

 A1 [shape=box, style=rounded];
 A2 [shape=box, style=rounded, label=""];
 A3 [shape=box, style=rounded, label="申請"];

 A1 -> A2 -> A3 ;
}

全ノードのデフォルト値を変更する場合は、予約語「node」により設定する。

<DOT表記>
digraph G {
 rankdir=LR;
 node [shape=box, style=rounded];

 A1 ;
 A2 [label=""];
 A3 [label="申請"];

 A1 -> A2 -> A3 ;
}

イベント

「ラベルの無い小さめの円」を表現するため、ノード属性を「label="", shape=circle, width=0.3」と指定する(デフォルトのwidthは0.75)。終了イベントは太線円にするため、加えて「style=bold」を指定する。

<DOT表記>
digraph G {
 rankdir=LR;
 node [shape=box, style=rounded];

 AS [label="", shape=circle, width="0.3"];
 AE [label="", shape=circle, width="0.3", syle=bold];

 A1 ;
 A2 [label=""];
 A3 [label="申請"];

 AS -> A1 -> A2 -> A3 -> AE;
}

スイムレーン

グラフの中にスイムレーン(サブグラフ)を作るために「subgraph clusterXXX」を記述する。(subgraphの名前の最初にclusterが付く。サブグラフのクラスタ機能と言う)。またスイムレーンのパーティシパント(参加者/関与システム)を記述すべく「label="marketing@company.com";」、また左寄せにすべく「labeljust=l;」を指定する。

<DOT表記>
digraph G {
 rankdir=LR;
 node [shape=box, style=rounded];

 subgraph clusterA {
  labeljust=l;
  label="marketing@company.com";

  AS [label="", shape=circle, width="0.3"];
  AE [label="", shape=circle, width="0.3", style=bold];
  A1 [label="A1:文書作成"];
  A2 [label="A2:修正確認"];

  AS -> A1;
  A1 -> A2 [style=invis]; // 不可視のエッジを定義し、AS、A1、A2、AEが水平に並ぶようにする
  A2 -> AE;
 }

 subgraph clusterB {
  labeljust=l;
  label="marketing-leader@company.com";

  B1 [label="B1:文書確認"];
  B2 [label="B2:コメント"];

  B1 -> B2;
 }

A1 -> B1; // スイムレーンをまたぐシーケンスフローはクラスタ定義の外に書く
B2 -> A2;

}

なお、sytle、color、fillcolor等の値を設定する事で「クラスタの外見」を変更する事も出来る。更にトップレベルグラフでcompound属性をtrue に設定し、アクティビティ(ノード)とスイムレーン(クラスタ)を結ぶメッセージフロー(エッジ)を描くこともできる。(詳細は参考文献)

Tips

位置を揃える(invisエッジの追加)

原則としてアクティビティの配置は、左から右へ並べられる。しかし上記の例においては、A1とB1を同じX座標(同じランク)にしたいと思う。A1とB2の間に「張力を与える」事で、A1とB1を同じランクにする事ができる。 なお、同じグラフ内(クラスタ内)のアクティビティであれば、「{rank=same; A1 A2}」と言う様な指定が出来る(「ランクの指定」参照)

<DOT表記>
digraph G01 {
 rankdir=LR; node [shape=box, style=rounded];

 subgraph clusterA {
  labeljust=l; label="marketing@company.com";

  AS [label="", shape=circle, width="0.3"];
  AE [label="", shape=circle, width="0.3", style=bold];
  A1 [label="A1:文書作成"];
  A2 [label="A2:修正確認"];

  AS -> A1;
  A1 -> A2 [style=invis];
  A2 -> AE;
 }

 subgraph clusterB {
  labeljust=l; label="marketing-leader@company.com";

  B1 [label="B1:文書確認"];
  B2 [label="B2:コメント"];

  B1 -> B2;
 }

A1 -> B1;
B2 -> A2;
A1 -> B2 [style=invis]; // ★不可視のエッジにより、A1とB2を近づける★

}

位置を揃える(張力の指定)

特定のアクティビティ「A1」「A2」「A3」を直線的に並べたい場合、分岐部分で“本線”たる「A1->A2」に「weight=10」の張力(重み)を指定する。

<DOT表記>
digraph G02 {
 rankdir=LR; node [shape=box, style=rounded];

 subgraph clusterA {
  labeljust=l; label="person@company.com";

  AS [label="", shape=circle, width="0.3"];
  AE1 [label="", shape=circle, width="0.3", style=bold];
  AE2 [label="", shape=circle, width="0.3", style=bold];
  A1 [label="A1:activity"];
  A2 [label="A2:activity"];
  A3 [label="A3:activity"];
  Ae [label="Ae:activity"];

  AS -> A1;
  A1 -> Ae [arrowtail=odiamond, label="NG"];
  Ae -> AE1;
  A1 -> A2 [arrowtail=rcrowlvee, weight=10]; //★張力「weight=10」により「A1->Ae」より「A1->A2」が直線的になる★
  A2 -> A3 [style=invis];
  A3 -> AE2 ;
 }

 subgraph clusterB {
  labeljust=l; label="section-leader@company.com";

  B1 [label="B1:activity"];
  B2 [label="B2:activity"];

  B1 -> B2;
 }

A2 -> B1;
B2 -> A3;
A2->B2 [style=invis];
}

位置を揃える(ランクの指定)

サブグラフ「clusterA」内で、「Ae」と「A3」のX座標(ランク)を合わせるために「{rank=same Ae A3};」を指定する。

<DOT表記>
digraph G03 {
 rankdir=LR; node [shape=box, style=rounded];

 subgraph clusterA {
  labeljust=l; label="person@company.com";

  AS [label="", shape=circle, width="0.3"];
  AE1 [label="", shape=circle, width="0.3", style=bold];
  AE2 [label="", shape=circle, width="0.3", style=bold];
  A1 [label="A1:activity"];
  A2 [label="A2:activity"];
  A3 [label="A3:activity"];
  Ae [label="Ae:activity"];

  AS -> A1;
  A1 -> Ae [arrowtail=odiamond, label="NG"];
  Ae -> AE1;
  A1 -> A2 [arrowtail=rcrowlvee, weight=10]; 
  A2 -> A3 [style=invis];
  A3 -> AE2 ;

 {rank=same Ae A3}; // ★「Ae」と「A3」のランクを合わせる★
 }

 subgraph clusterB {
  labeljust=l; label="section-leader@company.com";

  B1 [label="B1:activity"];
  B2 [label="B2:activity"];

  B1 -> B2;
 }

A2 -> B1;
B2 -> A3;
A2->B2 [style=invis];
}

位置を揃える(最低距離の指定)

「Ae」から「終了イベント」に伸びるシーケンスフローに「minlen=2」を指定する事で、“ランク”を挿入する事ができる。二つある終了イベントを並べる事ができる。(※二つの終了イベントに対して「ランクを揃える」を実行しても結果は同様)

<DOT表記>
digraph G04 {
 rankdir=LR; node [shape=box, style=rounded];

 subgraph clusterA {
  labeljust=l; label="person@company.com";

  AS [label="", shape=circle, width="0.3"];
  AE1 [label="", shape=circle, width="0.3", style=bold];
  AE2 [label="", shape=circle, width="0.3", style=bold];
  A1 [label="A1:activity"];
  A2 [label="A2:activity"];
  A3 [label="A3:activity"];
  Ae [label="Ae:activity"];

  AS -> A1;
  A1 -> Ae [arrowtail=odiamond, label="NG"];
  Ae -> AE1 [minlen=2]; //★「minlen=2」(inch)により「AE1」と「Ae」の間に一定の距離が置かれる★
  A1 -> A2 [arrowtail=rcrowlvee, weight=10]; 
  A2 -> A3 [style=invis];
  A3 -> AE2 ;
 }

 subgraph clusterB {
  labeljust=l; label="section-leader@company.com";

  B1 [label="B1:activity"];
  B2 [label="B2:activity"];

  B1 -> B2;
 }

A2 -> B1;
B2 -> A3;
A2->B2 [style=invis];
}

フローの重なりを回避する(ポートの指定)

「A1」と「B1」が同じX座標にあって、かつ「A1→B1」と「B1→A1」の様な往復するシーケンスフローを書きたい場合、重なりを排除するために、どちらかのシーケンスフローのポート位置を「[tailport=sw,headport=nw];」(矢先が南西、矢尻が北西)の様に指定する必要がある(「n、nw、w、sw、s、se、e、ne」デフォルトは「center」)。(ただしランクをずらす方が綺麗に見える)

<DOT表記>
digraph G05 { rankdir=LR; node [shape=box, style=rounded];

 subgraph clusterA { labeljust=l; label="any-section@company.com";
  AS [label="", shape=circle, width="0.3"];
  AE [label="", shape=circle, width="0.3", style=bold];
  A1 [label="A1: Daily\nReport"];
  A2 [label="A2: Memo"];

  AS -> A1;
  A2 -> AE;
  A1 -> A2 [style=invis];
 }

 subgraph clusterB { labeljust=l; label="section-leader@company.com";
  B1 [label="B1: Review"];
 }

A1 -> B1 [tailport=sw,headport=nw]; // ★テールとヘッドについてポート位置を指定する★
B1 -> A1 [arrowtail=odiamond, label="NG"];
B1 -> A2 [arrowtail=rcrowlvee];
}

ランクをずらした例 (「不可視のエッジ(B1 -> AE [style=invis, weight=10];)」を追加)

フローを逆行させる(dir属性の変更)

原則として、アクティビティやイベント(ノード)は、シーケンスフローが全て右向きになる様に配置される。あえて左向きのシーケンスフローを描きたい場合には「[dir=back]」を指定する。(以下の例では、[labelfloat=true]を設定し、シーケンスフローとラベルの重なりを許可している)

<DOT表記>
digraph G06 { rankdir=LR; node [shape=box, style=rounded];  edge [labelfloat=true];

 subgraph clusterA { labeljust=l; label="any-section@company.com";
  AS [label="", shape=circle, width="0.3"];
  AE [label="", shape=circle, width="0.3", style=bold];
  A1 [label="A1: Daily\nReport"];
  A2 [label="A2: Confirm\n& Memo"];

  AS -> A1;
  A1 -> AE [arrowtail=rcrowlvee];
  AE -> A2 [dir=back]; //★フローの逆行指定★
 }

 subgraph clusterB { labeljust=l; label="section-leader@company.com";
  B1 [label="B1: Review"];
 }

A1 -> B1 [arrowtail=odiamond, label="Review Flag"];
B1 -> A1 [arrowtail=odiamond, taillabel="NG", tailport=w, headport=s];
B1 -> A2 [arrowtail=rcrowlvee];
}

グラフ全体のサイズを指定する

プロセスダイアグラムは横方向に長くなりがちであるが、画面の都合上、5~7ランク程度に収めたい。(文字列も改行「\n」を多用し横方向に長くならない様に努めたい)。やむを得ずダイアグラムが大きくなる場合には「[size="10,5"]」の様にグラフサイズの最大値を指定し、全体を縮尺する事が出来る。(横方向の最大値は10インチを推奨する)。以下、サイズ制限をしたケースと、していないケースを例示する。

<DOT表記>
digraph G07 { graph [size="10,5", rankdir=LR]; node [shape=box, style=rounded]; edge [labelfloat=true];

 subgraph clusterA { labeljust=l; label="marketing@company.com";
  MS [label="", shape=circle, width="0.3"];
  ME [label="", shape=circle, width="0.3", style=bold];
  M1 [label="M1:step1"];
  M2 [label="M2:step2"];
  M3 [label="M3:step3"];
  M4 [label="M4:step4"];
  M5 [label="M5:step5"];
  M6 [label="M6:step6"];
  M7 [label="M7:step7"];

  MS -> M1;
  M1 -> M2 -> M3 -> M4 -> M5 -> M6 -> M7 [style=invis];
  M7 -> ME;
 }

 subgraph clusterB { labeljust=l; label="development@company.com";
  D1 [label="D1:step1"];
  D2 [label="D2:step2"];
  D3 [label="D3:step3"];
  D4 [label="D4:step4"];
  D5 [label="D5:step5"];
  D6 [label="D6:step6"];

  D1 -> D2 -> D3 -> D4 -> D5 -> D6 [style=invis];
 }

M1 -> D1 -> M2 -> D2 -> M3 -> D3 -> M4 -> D4 -> M5 -> D5 -> M6 -> D6 -> M7;
}

作図雛型

描画方法の例が多用されている雛型。(BPMN図としては成立していない)

<graphviz>
digraph TMPG { graph [size="10,5", rankdir=LR]; node [shape=box, style=rounded]; edge [labelfloat=true];

 subgraph clusterA { labeljust=l; label="sectionA@company.com";
  AS [label="", shape=circle, width="0.3"];
  AE [label="", shape=circle, width="0.3", style=bold];
  A1 [label="A1:step1"];
  A2 [label="A2:step2"];
  A3 [label="A3:step3"];
  A4 [label="A4:step4"];
  Ae [label="Ae:error\ncase"];
  A5 [label="A5:step5\nLong Name"];

  AS -> A1;
  A5 -> AE [weight=10];
  A1 -> A2 -> A3 -> A4 -> A5 [style=invis,weight=10];
  A4 -> Ae;
  Ae -> AE;
  {rank=same Ae A5};
 }

 subgraph clusterB { labeljust=l; label="sectionB@company.com";
  B1 [label="B1:step1"];
  B2 [label="B2:step2"];
  B3 [label="B3:step3"];
  B4 [label="B4:step4", style="rounded,filled" fillcolor=red];
  B5 [label="B5:step5", style="rounded,filled" fillcolor=green];

  B1 -> B2 -> B3 -> B4 -> B5 [style=invis];
 }

 subgraph clusterBL { labeljust=l; label="sectionB-leader@company.com";
  BL1 [label="BL1:step1"];
  BL2 [label="BL2:Message", shape=ellipse, style=dotted];
  BL3 [label="BL3:TEXT", shape=none];

  BL1 -> BL2 [style=invis];
  BL2 -> BL3 [minlen=2];
 }

A1 -> B1 [arrowtail=odiamond, label="X>100"];
B1 -> BL1 [arrowtail=rcrowlvee];
B2 -> A4 [tailport=ne,headport=w];
B2 -> BL2 [arrowhead=onormal, style=dotted]

}
</graphviz>

参考文献

ツールボックス
リンク元
リンク先の更新状況
アップロード
特別ページ
印刷用バージョン
この版への固定リンク


カテゴリ
一般名詞 | 固有名詞 | 汎用業務プロセス | 基幹系業務プロセス | 支援管理系業務プロセス
Q-BPM Q-BPMでは企業内の業務フローについて、そのサンプルプロセスを幅広く例示し、業務フロー図の作成を支援します。 (※ 業務フロー図: 業務の流れ図/ビジネスダイアグラム/業務プロセス図) 当サイトは世界中の協力者を募るクラウドソース型情報発信サイトであり、サイトコンテンツは原則として「特定条件を満たせば転載可能」な「CC-By SA」と呼ばれるライセンスのもとに公開されます。 株式会社クエステトラ このサイトはBPMに興味があるが多数の書籍や文献、難しい用語の調査に膨大な時間を費やしている世界中のビジネスマンの為に株式会社クエステトラによって始められました。株式会社クエステトラはBPMに興味があるが多くの関連用語を調べたり文献を探したりする手間を減らして、BPMを理解したり、BPMを実際に活用したりする時間を世界中のビジネスマンに貢献したいと思っています。

Powered by MediaWiki CreativeCommons By SA