SAS

SAS Plotterでサンキーダイアグラムを作図する

「SAS Plotter」はモダンなグラフを簡単に作成できるグラフマクロパッケージです。
このページではSAS Plotter Version 1.3でサンキーダイアグラムを作成する方法を解説します。

version 1.3からインストール方法が変更になりました。詳細は以下のページをご参照ください。

SAS Plotterの使用方法「SAS Plotter」はモダンなグラフを簡単に作成できるグラフマクロパッケージです。 このページではSAS Plotter Ver...
Contents
  1. サンキーダイアグラムとは
  2. Input data
  3. 文法
  4. パラメータ
  5. 作図例

サンキーダイアグラムとは

サンキーダイアグラムはネットワーク図の一種で、一般的にエネルギーや資金の流れを視覚化する際に用いられます。
流れは矢印などの図形で表現され、その太さで流量を表現することが一般的のようです。

疫学研究において、サンキーダイアグラムは使用薬剤や傷病の状態といった患者の状態変化を可視化する際に用いられています。

SASにおけるサンキーダイアグラムは過去に以下の作成例が報告されています。

それに対しSAS plotterのマクロは他のソフトと同様の体裁のものが作成できることに加え、
各オブジェクトの表示位置や体裁の調整を可能にし、特定のノードを強調表示させることが可能になっています。

性能面では他のソフトウェアと比べて低機能ではありますが、シンプルなサンキーダイアグラムであれば、他ソフトと併用しなくてもSAS BaseとSAS GRAPH環境のみで作成できます。
とはいえSASでなければだめというわけではないのであれば、素直にRやtableau等のソフトを使うことを推奨します。

またjavascriptライブラリとSASのputステートメントを併用して、SASからサンキーダイアグラムをHTML形式で出力する事例が紹介されています。
HTMLで問題なければこちらのほうが応用が利くでしょう。

本マクロにおいてサンキーダイアグラムは3つの要素で構成されています。

サンキーダイアグラムの構成要素

ドメイン

X軸に対応する変数です。例えば測定時点などが該当します。

ノード

各ドメインにおけるカテゴリを表現します。本マクロでは長方形として表現されています。例えば特定時点の患者の使用薬剤などがノードに相当します。ノードは各ドメインにいずれかに必ず属します。

リンク

ノード同士を接続します。本マクロではシグモイド曲線の帯として表現され、帯の太さがそのリンクに属する要素の量を表現します。
作図にもよりますが、リンクは基本的に方向が決まっており左から右へ接続されます。リンクの左側ノードは「ソースノード」、右側のノードは「ターゲットノード」と呼びます。

例えばday0ではDrugAを使用していた患者集団が30日後にDrugBに切り替えた場合、 day0ドメインのノード「Drug A」とday30ドメインのノード「DrugB」はリンクによって接続されます。
「DrugA」はソースノード、「DrugB」はターゲットノードです。このリンクに属する患者数が多いほどリンクの形状は太くなります。

Input data

任意のドメイン変数を用意します。ドメイン変数にはそのドメインに対応するノードカテゴリを格納します。必ず数値変数に設定してください。
ドメイン変数にはノードカテゴリのフォーマットを適用することを推奨します。

domain1domain2domain3
node Anode Bnode C
node Bnode Anode C
node Dnode Anode B

文法

 ods graphics / < graphics option > ;
 ods listing gpath=< output path >;

%macro sankey(
   data=,

   domain=,
   domainfmt=,
   domaintextattrs=(color=black size=11),
   gap=5,

   nodefmt=auto,
   nodewidth=0.2,
   nodeattrs=auto,
   nodename=true,
   nodetextattrs=(color=black size=9),

   linktext=true,
   linktext_offset=0.05,
   linkattrs=auto,
   linktextattrs=(color=black size=8),

   reverse=false,
   focus=None,
   endFollowup=None,
   stat=both,
   unit=,

   legend=false,
   palette=sns,
   note=,
   deletedata=true);

パラメータ

data : データセット(必須)

入力データセット。keep, renameおよびwhereオプションが利用可能です。

ドメインパラメータ

domain : 変数 (必須)

ドメイン変数を指定します。変数は任意の変数をリンクされる順番で指定してください。例えば「var1 var2 var3」と指定した場合、var1→var2→var3の順序でリンクされます

domainfmt : フォーマット (必須)

ドメイン変数に割り当てるフォーマットを指定します。フォーマットは必ずworkライブラリに保存し、コード値は数値にする必要があります。フォーマットで定義されたラベルが表示されます。

domaintextattrs : テキストの体裁 (オプション)

ドメインのテキストの体裁を指定します。GTLのtextattrsオプションと同様 の項目(size, color, weight, style)が指定可能です。デフォルトは(size=11 color=black)。

ノードパラメータ

gap : 数値 (オプション)

同一ドメイン内のノードの間隔を指定します。デフォルトは5。

nodefmt : フォーマット (オプション)

ノード名のフォーマットを指定します。”auto”に指定した場合は、フォーマットは入力データのドメイン変数から取得します。入力データに存在しないノードを凡例に表示させる場合や、異なるデータからそれぞれ作図する場合はフォーマットを指定したほうが良いでしょう。フォーマットはworkライブラリに保存する必要があります。デフォルトは”auto”.

nodewidth : 数値 (オプション)

ノードの図形の幅を指定します。数値を大きくするとノードの図形の幅が広がります。デフォルトは0.2。

nodewidth

nodeattrs : キーワードまたは塗りの体裁(オプション)

ノードの塗りを設定します。”auto”の場合はノードのカテゴリに応じて塗分けされます。GTLのfillattrsの同様の設定(color, transparency)を指定するとすべてのノードが同じ体裁に変更されます。
例えば以下のように設定するとすべてのノードは青色になります。デフォルトは”auto”

nodename : 真偽値(オプション)

ノード名(ノードカテゴリの名前)の表示を切り替えます。デフォルトは”Tuue”。

nodetextattrs :テキストの体裁 (オプション)

ノードのテキストの体裁を指定します。GTLのtextattrsオプションと同様 の項目(size, color, weight, style)が指定可能です。デフォルトは(size=9 color=black)。

リンクパラメータ

linkattrs : 塗の体裁 (オプション)

リンク図形の塗りを設定します。”auto”の場合はソースノードのノードカテゴリに応じて塗分けられます。GTLのfillattrsの同様の設定(color, transparency)を指定するとすべてのリンクが同じ体裁に変更されます。
デフォルトは”auto”。

linktext : 真偽値(オプション)

リンクテキスト(頻度および割合)の表示を切り替えます。リンクテキストはソースノードの近くに表示されます。デフォルトは”Tuue”。

linktext_offset : 数値 (オプション)

ノードとリンクテキストの間隔を指定します。デフォルトは0.5。

linktext_offset

linktextattrs : テキストの体裁 (オプション)

リンクのテキストの体裁を指定します。GTLのtextattrsオプションと同様 の項目(size, color, weight, style)が指定可能です。デフォルトは(size=8 color=black)。

その他のパラメータ

reverse: 真偽値(オプション)

Trueに設定するとy軸を反転させます。デフォルトは”false”。

focus : 条件式 (オプション)

強調表示するリンクを条件式で指定します。条件式は以下の変数が使用可能です。コード値は入力データまたはフォーマットオプションで指定したフォーマットのコード値です。

source_node=nodeのコード値 
target_node=nodeのコード値
domain=domainのコード値
next_domain=domainのコード値

条件式を指定すると、条件に合致しないノードをソースとするリンクはすべてグレー表示となり、リンクテキスト表示は無効化されます。
例えば2番目のドメインのうちコード値=1をソースノードとするリンクを強調したい場合は以下のように指定します。

focus=(source_node=1 and domain=2)

 

デフォルトはnone(強調表示はしない)。

EndFollowup : ノードのコード値(オプション)

フォローアップ終了を示すコード値を指定します。指定するとフォローアップ終了のノードはグレー表示となります。さらにドメイン毎のフォローアップ中の症例数とその割合をサンキーダイアグラムの下部に表示します。

stat : キーワード (オプション)

ノードとリンクに表示される統計情報の内容を指定します。キーワードは以下のものが利用可能です。デフォルトは”both”。
割合は入力データセットのオブザベーション数に対する割合となります。

  • FREQ: 頻度
  • PCT: 割合(小数第二位まで表示)
  • BOTH: 頻度と割合
  • NONE: 統計情報は表示しない

unit : テキスト(オプション)

頻度の表示を有効にした場合、頻度の単位(接尾辞)を指定します。例えば「例」を指定した場合は頻度表示は「123例」といった感じで表示されます。
デフォルトは””(欠損)。

legend : 真偽値(オプション)

Trueの場合は群の凡例を表示します。デフォルトはTrue。

pallete : キーワード (オプション)

塗り、ライン、マーカーのカラーパレット、以下のパレットが利用可能です。デフォルトはSNS(seabornのデフォルトパレット)

  •  SAS
  • SNS (Seaborn)
  • STATA
  • TABLEAU

note: ステートメント(オプション)

グラフテンプレートにentryステートメントを挿入し、グラフタイトルまたはフットノートを表示します。デフォルトは””(表示しない)

deletedata: 真偽値(オプション)

マクロが作成した一時データを削除します。デフォルトはTrue(一時データを削除する)。

作図例

作図例はgithubのexample内にsasプログラムを格納しています。filenameステートメントを使えばすぐに実行できます。

ods listing gpath=<your output path>; 
filename exam url "https://github.com/Superman-jp/SAS_Plotter/raw/main/example/sankey_example.sas" encoding="UTF-8"; 

%include exam;

 

基本的なサンキーダイアグラム

各症例の治療計画(Regimen A~Regimen I)の時間変化を可視化します。
起点日、起点日、30, 60日及び120日後の各症例の治療計画を記録したデータを使用します。

proc format;
value domainf
1="day0"
2="day30"
3="day60"
4="day120";

value nodef
0="Drug A"
1="Drug B"
2="Drug C"
3="Drug D"
4="Drug E"
;
run;
data raw;
usubjid+1;
input day0 day30 day60 day120;
format day0 day30 day60 day120 nodef.;
cards;
0 2 3 4
0 2 3 4
0 2 3 4
2 1 2 4
2 1 2 4
2 1 2 4
2 1 2 4
2 1 2 4
2 1 4 3
4 3 2 1
4 3 2 1
4 3 2 1
4 3 2 1
;
run;

 

このデータを本マクロを使用して作図すると以下のようになります。

ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_basic" noborder;
title "Bacic Sankey";

%sankey(
   data=raw,
   domain=day0 day30 day60 day120,
   domainfmt=domainf,
   note=%nrstr(entrytitle 'your title here';
            entryfootnote halign=left 'your footnote here';
            entryfootnote halign=left 'your footnote here 2';)
   );
基本的なサンキーダイアグラム

ドメイン間隔の調整

ドメインの間隔はドメイン変数に適用するフォーマットのコード値に依存します。コード値を調整することで特定のドメインの間隔を調整することが可能です。
例えばコード値を以下のように調整したうえで前項のプログラムを再実行すると、day60とday120の間隔を広げています。

proc format;
value domain2f
1="day0"
2="day30"
3="day60"
5="day120";
run;

ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_change_intervals" noborder;
title "Adjust the domain interval";
ods html;
%sankey(
   data=raw,
   domain=day0 day30 day60 day120,
   domainfmt=domain2f
);
ドメイン間隔の調整

ノードのフォーマットと凡例

以下は「基本的なサンキーダイアグラム」のプログラムを修正し、day0とday60のダイアグラムを出力した結果です。修正前と比較すると同じノードなのにも関わらずRegimen A以外の色が変わってしまっていることがわかります。デフォルトでは入力データセットに存在するカテゴリに対して順番に色を割り当てているため、同じノードカテゴリであってもデータセットを変更すると勝手に色が変更される可能性があります。
また判定に表示される要素も入力データセットに存在するカテゴリのみ表示されます。

proc format;
value domain3f
1="day0"
2="day60"
;
run;
ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_not_set_nodefmt" noborder;
title "not set nodefmt parameter";

%sankey(
   data=raw,
   domain=day0 day60,
   domainfmt=domain3f,
   legend=true
);
nodeフォーマットを設定しない場合

これを防ぐにはnodefmtオプションでノードカテゴリのフォーマットを指定すると良いでしょう。データセットを変更してもノードには一貫した色が割り当てられます。
また凡例にはフォーマットに登録されたすべての要素が表示されます。

nodefmtオプションを設定して再実行した結果は以下の通りです。ノードの色はデータに存在するノードの順ではなくフォーマットに存在する順に色が割り当てられます。さらに凡例もフォーマットに定義されたすべてのRegimenが表示されています。

ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_set_nodefmt" noborder;
title "set nodefmt parameter";

%sankey(
   data=raw,
   domain=day0 day60,
   domainfmt=domain3f,
   nodefmt=nodef,
   legend=true
);
nodeフォーマットを指定した場合

塗りの体裁調整

デフォルトではノードとリンクの色はノードカテゴリに基づいて決定されています。nodeattrsまたはlinkattrsを設定するとすべてのノードまたはリンクの塗りが同じものに統一されます。

ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_set_nodeattrs" noborder;
title "change_the_node color";
ods html;
%sankey(
   data=raw,
   domain=day0 day30 day60 day120,
   domainfmt=domainf,
   nodeattrs=(color=grey)
);
ノードの塗りを変更
ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_set_linkattrs" noborder;
title "change the link color";
ods html;
%sankey(
   data=raw,
   domain=day0 day30 day60 day120,
   domainfmt=domainf,
   linkattrs=(color=skyblue transparency=0.7)
);
リンクの塗りを変更

テキストの体裁調整

domaintextattrs、nodetextattrsおよびlinktextattrsパラメータはドメイン、ノード、リンクのテキストの体裁を変更するのに便利です。
GTLのtextattrsオプションと同じ指定が可能です。

ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_set_textattrs" noborder;
title "change the text appearance";
ods html;
%sankey(
   data=raw,
   domain=day0 day30 day60 day120,
   domainfmt=domainf,
   domaintextattrs=(color=red size=12),
   nodetextattrs=(color=blue size=12),
   linktext_offset=0.05,
   linktextattrs=(color=green size=8)
);
テキストの体裁を変更

focusパラメータ

focusパラメータは特定のノードに着目したい場合に便利です。focusパラメータの条件式に合致しないノードをソースとするリンクはすべてグレー表示となり、リンクテキストが無効化されます。

以下の論文では特定のノードのみを強調表示した「focused sankey plot」が紹介されています。これと同じ作図をSAS plotterで作成してみます。

まずは入力データセットを作成します。

proc format;

value druglist
1="Drug A"
2="Drug B"
3="Drug C"
4="Drug D"
99="Lost to follow-up";

value timef
1="Day 0"
2="Day 30"
3="Day 60"
4="day 90"
;
run;

data drug_switch;
length usubjid $10 Day0 Day30 Day60 Day90 8;
format Day0 Day30 Day60 Day90 druglist.;
input usubjid $ Day0 Day30 Day60 Day90;
datalines;
A001 1 1 1 3
A002 1 1 1 4
A003 1 1 1 4
A004 1 1 1 4
A005 1 2 1 4
A006 1 3 1 4
A007 1 3 1 4
A008 1 4 1 99
A009 1 4 1 99
A010 1 1 2 2
A011 1 1 2 3
A012 1 1 2 3
A013 1 1 2 3
A014 1 2 2 4
A015 1 2 2 4
A016 1 3 2 4
A017 1 1 3 1
A018 1 1 3 2
A019 1 2 3 4
A020 1 2 3 4
A021 1 2 3 4
A022 1 3 3 4
A023 1 3 3 99
A024 2 4 2 4
A025 2 1 3 3
A026 2 1 3 3
A027 2 1 4 1
A028 2 1 4 2
A029 2 2 4 3
A030 2 2 4 4
A031 2 2 4 4
A032 2 3 4 4
A033 2 3 4 4
A034 2 99 99 99
A035 2 99 99 99
A036 3 1 4 2
A037 3 2 4 4
A038 3 3 4 99
A039 3 1 99 99
A040 3 1 99 99
A041 3 99 99 99
A042 4 4 3 99
A043 4 1 99 99
A044 4 2 99 99
;
run;

入力データセットからサンキーダイアグラムを作成してましょう。

focusパラメータに強調表示したいソースノードを条件式に設定します。条件式はsource_node, target_node, domain, next_domainの4つの変数を用いて定義します。またDrug AからDrug Dを上から配置するため、reverseオプションでY軸を反転させています。

例1:Drug Aをソースノードとするリンク

ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_focus1" noborder;
title "focus parameter example 1";
%sankey(
   data=drug_switch,
   domain=day0 day30 day60 day90,
   domainfmt=timef,
   focus=(source_node=1),
   gap=1,
   reverse=true,
   nodewidth=0.1,
   nodename=false,
   stat=freq,
   legend=true,
   linktext_offset=0.03,
   palette=sns
);
薬剤Aをsource_nodeとするリンクを強調表示

例2:Lost to followupをターゲットノードとするリンク

ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_focus2" noborder;
title "focus parameter example 2";
%sankey(
   data=drug_switch,
   domain=day0 day30 day60 day90,
   domainfmt=timef,
   focus=(target_node=99),
   gap=1,
   reverse=true,
   nodewidth=0.1,
   nodename=false,
   stat=freq,
   legend=true,
   linktext_offset=0.03,
   palette=sns);
フォローアップ終了をtarget_nodeとするリンクを強調表示

例3:ドメイン2(day 30)のノードをソースとするリンク

ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_focus3" noborder;
title "focus parameter example 3";

%sankey(
   data=drug_switch,
   domain=day0 day30 day60 day90,
   domainfmt=timef,
   focus=(domain=2),
   gap=1,
   reverse=true,
   nodewidth=0.1,
   nodename=false,
   stat=freq,
   legend=true,
   linktext_offset=0.03,
   palette=sns);
day30のリンクを強調表示

例4:複数条件を適用

ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_focus4" noborder;
title "focus parameter example 4";
%sankey(
   data=drug_switch,
   domain=day0 day30 day60 day90,
   domainfmt=timef,
   focus=((domain=1 and source_node=2) or (next_domain=4 and target_node=99)),
   gap=1,
   reverse=true,
   nodewidth=0.1,
   nodename=false,
   stat=freq,
   legend=true,
   linktext_offset=0.03,
   palette=sns);
複数条件を設定

endFollowupパラメータ

endFollowupパラメータにフォローアップ終了を示すノードのコード値を指定すると、指定したノードはグレーに表示されます。各ドメインのフォローアップ中の症例数と割合をサンキーダイアグラムの下部に表示します。

フォローアップ終了した症例数は、各ドメイン毎のendFollowupパラメータで指定したコード値のノードに該当するレコード数となります。

割合は以下の数式で算出されます。

% followup = (入力データセットのレコード数 – endFollowupパラメータで指定したコード値のノードに該当するレコード数) / 入力データセットのレコード数 * 100

ods graphics / height=15cm width=20cm imagefmt=png imagename="sankey_endfollowup" noborder;
title "percentage of Followup";
%sankey(
   data=drug_switch,
   domain=day0 day30 day60 day90,
   domainfmt=timef,
   gap=1,
   reverse=true,
   nodewidth=0.1,
   nodename=false,
   endfollowup=99,
   stat=freq,
   legend=true,

   note=%nrstr(entrytitle 'your title here';
               entryfootnote halign=left 'your footnote here';
            entryfootnote halign=left 'your footnote here 2';)
);
フォローアップ症例数とその割合を同時表示