Spaghetti plotは一見seriesplotステートメントを使えば簡単なように見えますが、いくつか工夫が必要です。
Spaghetti plotとは
スパゲッティプロット(Spaghetti plot)は多数の線グラフを一つのプロットエリアに同時に表示する作図手法です。臨床試験では時系列データを被験者別にプロットするのに使われます。
要約統計量をプロットする場合と異なり個々のデータを確認することができ、特に外れ値の確認には有効かと思います。ただし線の本数が多くなってくるとデータの視認性が悪くなります。臨床試験ではデータ数はそこまで多くはならないため問題にはならないケースが多いですが、データ数が多い場合は別のグラフと併用を考えたほうが良いでしょう。
作図方法
作図自体は簡単です。seriesplotステートメントとgroupオプションを併用するだけです。
seriesplot x=time y=response / group=usubjid;
今回は治験薬群(n=30)とプラセボ群(n=30)の時系列データをスパゲッティプロットで可視化してみます。
proc template;
define statgraph spaghetti;
begingraph;
layout overlay /
yaxisopts=(linearopts=(tickvaluesequence=(start=0 end=150 increment=25))
);
seriesplot x=date y=response /
group=usubjid
lineattrs=(pattern=solid);
endlayout;
endgraph;
end;
run;
proc sgrender data=profile template=spaghetti;
run;
groupオプションを指定するとgroupに指定した変数の値毎に線の属性が決定されます。したがって被験者毎にプロットするとすべての線の色や種類がバラバラになってしまいます。
作図自体は正しいですが、これでは被験薬とプラセボが区別できません。
群ごとに線の属性を設定する
seriesplotにはgroupオプションとは別に、linecolorgroupオプションがあります。これは線の色を識別する群変数を指定するオプションで、これを使えばgroupオプションとは別の群変数で色分けできます。ただし凡例には反映されないため、凡例を作成するにはlegenditemステートメントで凡例を定義する必要があります。
上記のデータを利用して被験薬とプラセボの色を分けて表示します。データの並び順によって色が変わらないようにするためattribute mapを併用します。
proc template;
define statgraph spaghetti;
begingraph; /* 線の色の設定 */
discreteattrmap name="grp" /discretelegendentrypolicy=attrmap;
value "Treat" / lineattrs=GraphData1(pattern=solid);
value "Placebo" / lineattrs=GraphData2(pattern=solid);
enddiscreteattrmap; discreteattrvar attrvar=_grp var=extrt attrmap="grp";
/* 凡例の作成 */
legenditem type=line name="t" / lineattrs=GraphData1(pattern=solid) label="Treat";
legenditem type=line name="p" / lineattrs=GraphData2(pattern=solid) label="Placebo";
layout overlay /
yaxisopts=(linearopts=(tickvaluesequence=(start=0 end=150 increment=25)));
seriesplot x=date y=response /
group=usubjid
lineattrs=(pattern=solid)
datatransparency=0.5
linecolorgroup=_grp;
discretelegend "t" "p";
endlayout;
endgraph;
end;
run;
proc sgrender data=profile template=spaghetti;
run;
被験薬とプラセボが色分けされてわかりやすくなりました。被験薬のほうがより早いresponseの上昇がみられます。
またlinepatterngroupオプションを使用すると線の種類を識別する変数を指定することができます。このオプションを使ってプラセボを点線で表現すると以下のようになります。
色で識別したほうがわかりやすいので、線の種類の変更は線の本数が少ないときだけにしたほうがよさそうです。
proc template;
define statgraph spaghetti;
begingraph;
/* 線の色の設定 */
discreteattrmap name="grp" /discretelegendentrypolicy=attrmap;
value "Treat" / lineattrs=GraphData1(pattern=solid);
value "Placebo" / lineattrs=GraphData2(pattern=shortdash);
enddiscreteattrmap;
discreteattrvar attrvar=_grp var=extrt attrmap="grp";
/* 凡例の作成 */
legenditem type=line name="t" / lineattrs=GraphData1(pattern=solid) label="Treat";
legenditem type=line name="p" / lineattrs=GraphData2(pattern=shortdash) label="Placebo";
layout overlay /
yaxisopts=(linearopts=(tickvaluesequence=(start=0 end=150 increment=25)));
seriesplot x=date y=response /
group=usubjid
lineattrs=(pattern=solid)
datatransparency=0.5
linecolorgroup=_grp
linepatterngroup=_grp;
discretelegend "t" "p";
endlayout;
endgraph;
end;
run;
proc sgrender data=profile template=spaghetti;
run;
平均値の推移を同時表示する
各被験者の時系列データと各群の平均値を同時にプロットします。
まず群および時点毎に応答変数の平均値をmeansプロシジャなどで算出し、個別データとマージします。この時平均値をプロットする変数として時点と群変数を新規作成します。(ここではdate2, extrt2が該当します)マージするときはbyステートメントでキー変数を指定しないことがポイントです。
次に上記のテンプレートに平均値の作図ステートメントとattribute map、凡例を追加します。個別データの透過度は高めに設定しておくと平均値のラインが見やすくなります。
proc template;
define statgraph spaghetti;
begingraph;
/* 線の色の設定 */
discreteattrmap name="grp" /discretelegendentrypolicy=attrmap;
value "Treat" / lineattrs=GraphData1(pattern=solid);
value "Placebo" / lineattrs=GraphData2(pattern=solid);
enddiscreteattrmap;
discreteattrmap name="grp_mean" /discretelegendentrypolicy=attrmap;
value "Treat" / lineattrs=(color=blue pattern=solid thickness=2);
value "Placebo" / lineattrs=(color=red pattern=solid thickness=2);
enddiscreteattrmap;
discreteattrvar attrvar=_grp var=extrt attrmap="grp";
discreteattrvar attrvar=_grp2 var=extrt2 attrmap="grp_mean";
/* 凡例(個別)の作成 */
legenditem type=line name="t" / lineattrs=GraphData1(pattern=solid) label="Treat(individual)";
legenditem type=line name="p" / lineattrs=GraphData2(pattern=solid) label="Placebo(individual)";
layout overlay /
yaxisopts=(linearopts=(tickvaluesequence=(start=0 end=150 increment=25)));
/* 個別データ */
seriesplot x=date y=response /
group=usubjid
lineattrs=(pattern=solid)
datatransparency=0.8
linecolorgroup=_grp;
/* 平均値 */
seriesplot x=date2 y=mean /
group=_grp2
name="mean";
discretelegend "mean" "t" "p" ;
endlayout;
endgraph;
end;
run;
proc sgrender data=profile template=spaghetti;
run;