SAS

SASのクソな部分をぶった切る!(3)作図環境

SASのクソな部分シリーズはなぜかアクセスされるようなので、第3回目を投稿します。

このブログは一応GTLに関する記事も投稿しているので、SASの作図環境について言及したいと思います。

正直いってSASの作図環境はクソです。Rやpythonと比べるとどうしても見劣りします。

これでも機能拡張は度々実施されて現在は一般的な統計グラフであれば簡単に作図できるようになってきていますが、それ以前はかなり独特な仕様なうえに使える機能も少なかったのでなかなか大変だったようです。

その独特な仕様というのがannotation datasetという特殊なデータセットです。

annotation dataset

annotation datasetとは

annotation datasetとはSAS/GRAPHで用意されているステートメント以外の作図を実施するために用意されたデータセットです。このデータセットはグラフ描画設定や座標といった任意のグラフオブジェクトを描画するための情報が格納されています。

ポイントは作図したいオブジェクトの座標だけでなく、グラフの作図命令もデータセットに格納するという点です。この特徴はおそらくRやpythonにはない独特な仕様です。

Rまたはpythonですと作図命令とその設定はメゾッドと引数で設定します。例えばpythonのSeabornで散布図を作図するメゾッドは以下のようになります。

sns.scatterplot(x="var1", y="var2")

snsはseabornのことです。scatterplotというメゾッドに引数となる2変数を指定することで散布図を作図することができます。ほかにも引数を指定することで体裁をカスタマイズすることができます。
Rの場合も大体このような形式です。

しかしSASのannotation datasetはこのような作図メゾッドと引数をプログラム上に記述するのではなく、データセットの中に格納します。はっきりいってプログラムに直打ちできたほうがずっと楽です。
一応annotation macroというannotation作成用マクロもあるのですが、これの使い方もマスターしないといけないのでめんどくさいことには変わりありません。

第一SASは変数の長さを必ず指定しないといけない仕様なので、作図するためにメゾッドと引数を格納した変数の設定を必ず実施する必要があります。非常にめんどくさい。
散布図や棒グラフのような一般的なグラフはステートメントがあるので、使用変数はそこで指定できるのですが、ステートメントにはない設定や任意の図形を描画するためにはannotation datasetが必要になります。

使用例

SAS公式の使用例をご紹介します。積み上げ棒グラフ自体はproc gchartというプロシジャがあるのでこれを使うのですが、各棒のラベルをannotation datasetで指定し、作図します。

goptions reset=all border; 
data sold; 
length type $ 10; 
input city $ units type $ ; 
datalines; 
Atlanta 99 Printers 
Atlanta 105 Plotters 
Atlanta 85 Terminals 
Paris 182 Printers 
Paris 150 Plotters 
Paris 157 Terminals 
Sydney 111 Printers 
Sydney 136 Plotters 
Sydney 100 Terminals 
; 
run; 

data barlabel; 
length color style $ 8; 
retain color "white" 
       when "a" 
       style "arial" 
       xsys ysys "2" 
       position "E" 
       size 4 
       hsys "3"; 
set sold; 
midpoint=city; subgroup=type; text=left(put(units,5.)); 
run; 


title "Orders Received"; 
footnote j=r "GANVBAR"; 
axis1 label=none major=none minor=none style=0 value=none; 
axis2 label=none; proc gchart data=sold; 

proc gchart data=sold;
vbar city / type=sum 
          sumvar=units 
        subgroup=type 
           width=17 
           raxis=axis1 
           maxis=axis2 
        annotate=barlabel; 
run; 
quit;
実行結果

gchartのvbarステートメントで棒グラフの作図指定をしていますが、このときannotationオプションでannotation datasetを指定すると、指定したデータセットに格納されて作図命令を実行できます。

annotation dataset (barlabel)の中身の一部は以下の通りです。

変数名説明
color文字色
whenオブジェクト同士が重なり合った時の設定 a=前面(after) b=背面(before)
styleラベルフォント
xsysX座標系
ysysY座標系
hsyssize変数の単位タイプ
positionラベルの配置
sizeラベルサイズ
textラベルテキスト

最悪なのはプロシジャのステートメントとannotation datasetのお作法の両方を理解しなければならないという点です。つーか座標系なんていちいち指定するのかよ。

両者の仕様は全然違う上に、annotation datasetの変数名や格納する定数をプログラマーが完全に把握していない使いこなせません。すべて覚えていなくてもマニュアルがあればよいのですが、ドキュメントは多いし公式はこっそ読み込み遅いしすべて英語なので大変です。入力補完なんて便利なものは使えないのでマンパワーで何とかしないといけません。またグラフの定義内容がプロシジャとannotation datasetに分かれて保存されるため、プログラム修正の時に苦労することになるかもしれません。

他の言語はメゾットと引数のルールが大体統一されているのでリファレンスを見ながらであればすぐ使いこなせるでしょうし、開発環境次第では入力補完があります。ユーザー数が多い分日本語の文献も入手しやすいですしどちらが楽かは明らかでしょう。

現在はgplot, gchartの上位互換であるsgplotがあるので、annotation datasetを覚える必要はほぼないのですが、ベテラン勢はまだannotation使っているので彼らが書いたコードに遭遇すると苦労するかもしれません。

時代によって作図言語設計が大幅に異なるというのもSASのクソポイントです。

またこれは私の所感なのですが、sgplotやGTLよりもgplotとannotation datasetの組み合わせのほうが低速です。

というのもannotation datasetで作図命令を記述するとこれをデータセットとして読み込んだ後にコンパイルする必要があるため、すでにステートメントとしてコンパイルされているsgplotやGTLよりもコンパイルの処理が入る分遅くなってしまうようです。グラフを1枚だけ出力する場合はあまり問題はないですが、出力枚数が多いと処理時間にかなり差が出てくると思います。

2022/05/08追記

現在のSASは、SAS StudioであればsgplotおよびGTLは完全ではないですが入力補完が使えるようです。しかしannotation datasetはデータステップで作成するため作図命令に関する入力補完は期待できません。
作図命令を変数名とその値で指定するので当然です。

この点だけでもannotation datasetはクソだといえるでしょう。

GTLだとこうなる

上記のグラフをgtlで作図するとこうなります。完全に同じというわけではありませんが、等価なグラフはannotation datasetなしで作成できます。annotationで頑張って指定していた箇所はsegmentlabelというオプションだけで実現できます。ラベル位置が棒の中心に表示されますが、もしannotationを使った場合と同様の位置に表示したい場合はtextplotステートメントを併用すれば良いです。anntation datasetで指定していた作図命令はすべてステートメントのオプションとして置き換えられるため、作図の定義内容がテンプレート内に集約されて見やすくなっています。

proc template; 
define statgraph test; 
begingraph; 
entrytitle "Ordered received" / textattrs=(size=14 weight=bold family="MS PGothic"); 

discreteattrmap name="map"; value "Plotter" / fillattrs=GraphData1; 
   value "Printer" / fillattrs=GraphData2; 
   value "Terminals" / fillattrs=GraphData3; 
enddiscreteattrmap; 

discreteattrvar attrmap="map" attrvar=_grp var=type; 

layout overlay /yaxisopts=(display=none) walldisplay=none; 

   barchartparm category=city response=units / 
      group=_grp 
      groupdisplay=stack 
      segmentlabeltype=auto 
      segmentlabelattrs=(color=white size=12 weight=bold family="MS PGothic") 
      name="bar"; 
   discretelegend "bar" / autoalign=(bottom bottomright); 
endlayout; 
endgraph; 
end; 
run; 

*作図順序を修正; 
proc sort data=sold; by city type;
run; 

proc sgrender data=sold template=test; 
run;
実行結果

乱立するプロシジャ

統計作図プロシジャもgplot gchart sgplot sgpanel sgpieなど、やたら乱立しています。pythonなどのオープンソースのソフトは開発者がたくさんいるので、パッケージがたくさん存在するのはまだわかるのですがSASの開発者はSAS社のみです。なんで乱立するのでしょうね?すべてGTLで統一してくれればよかったのに。

プロシジャがたくさんあるのにも関わらず作図機能はSASやRに及びません。前回作成したバイオリンプロットはもちろん、フォレストプロットやレーダーチャート、パス図などは作成するステートメントがないため自力で何とかするしかありません。(レーダーチャートは一応作図プロシジャがあるのですが、sg系のプロシジャとは別枠扱い)

もし他言語での解析ができる環境があるのであれば上記のグラフはSAS以外のソフトを使ったほうが得策かもしれませんね。別にできなくはないですが工数うなぎのぼりになるだけで大した成果がでないもん。