ラベル プロシジャ: SGPLOT の投稿を表示しています。 すべての投稿を表示
ラベル プロシジャ: SGPLOT の投稿を表示しています。 すべての投稿を表示

2020年3月2日月曜日

[SGPLOT] 塗りつぶしパターンの設定




SGPLOTの棒グラフやポリゴンの描画などで「塗りつぶしパターン」を設定する方法を紹介。



まずは、塗りつぶしパターンとか気にしないで、普通に棒グラフを描画してみます。

proc sgplot data=sashelp.class;
    vbar age / stat=percent group=age;
run;





次に塗りつぶしパターンを設定してみます。

ods graphics / attrpriority=none;
proc sgplot data=sashelp.class;
    vbar age / stat=percent group=age fillpattern;
run;



  • PLOTステートメントで「FILLPATTERN」を指定すると、塗りつぶしパターンが追加されます。
  • ODS GRAPHICS / ATTRPRIORITY=NONE」は以下のリンク記事で詳細を解説しています。
  • https://sas-boubi.blogspot.com/2019/12/sg.html




さらに、もっと見やすくしてみます。

ods graphics / attrpriority=none;
proc sgplot data=sashelp.class;
    styleattrs datafillpatterns=(L3 X3 R3 L5 X5 R5);
    vbar age / stat=percent group=age fillpattern;
run;



  • STYLEATTRステートメント」で塗りつぶしパターンの種類を設定しています。
  • 塗りつぶしパターンには「L1~L5」「R1~R5」「X1~X5」が設定できます。




この塗りつぶしパターンを設定するメリットは、

  • カラーだけに依存していない。
  • 白黒印刷しても、塗りつぶしパターンからグループを区別することができる。
  • 色覚障害のかたによりAccessibilityな出力を提供できる。



2020年2月19日水曜日

【SGPLOT】POLYGONステートメントの描き方いろいろ





SGPLOT の POLYGONステートメント でポリゴンを描画できます。
今回はこのステートメントの色々な書き方を紹介していきたいと思います。





1. POLYGONステートメントの基本




以下の例をご覧ください。

/* 座標を定義 */
data test;
input segment x y;
cards;
1 1 1
1 5 1
1 5 5
1 1 5
;

/* ポリゴンを描画 */
proc sgplot data=test;
   polygon x=x y=y id=segment / fill outline;
   xaxis min=0 max=6;
   yaxis min=0 max=6;
run;




  • 最初にデータステップでx軸とy軸の座標を定義
  • SGPLOT の POLYGONステートメントで、座標間に順番に線を引いていって形をつくる(以下のようなイメージ)









2. 複数のポリゴンを描画する


/* 座標を定義 */
data test;
input segment x y;
cards;
1 1 1
1 2 1
1 2 2
1 1 2
2 3 3
2 4 3
2 4 4
2 3 4
;

/* ポリゴンを描画 */
proc sgplot data=test;
   polygon x=x y=y id=segment / fill outline;
   xaxis min=0 max=6;
   yaxis min=0 max=6;
run;


POLYGONステートメントで「id=segment」と指定しています。
この「ID=」に指定した変数の値ごとにポリゴンを別々に描画することが出来ます。
今回はSEGMENTという変数の値ごとに2つポリゴンを描画しています。




ちなみに、以下のようにポリゴンを重ねることも可能です。

/* 座標を定義 */
data test;
input segment x y;
cards;
1 1 1
1 5 1
1 5 5
1 1 5
2 3 3
2 6 3
2 6 6
2 3 6
;

/* ポリゴンを描画 */
proc sgplot data=test;
   polygon x=x y=y id=segment / fill outline;
   xaxis min=0 max=6;
   yaxis min=0 max=6;
run;





3. 穴を作る


/* 座標を定義 */
data test;
input segment x y;
cards;
1 1 1
1 5 1
1 5 5
1 1 5
1 . .
1 2 2
1 4 2
1 4 4
1 2 4
;

/* ポリゴンを描画 */
proc sgplot data=test;
   polygon x=x y=y id=segment / fill outline;
   xaxis min=0 max=6;
   yaxis min=0 max=6;
run;



上で作成したデータセットのように、

  • まず外側のポリゴンを定義した後、
  • x軸とy軸が欠損値の行を用意することで、そこから穴の始まりを示すことが出来る。
  • その後の定義は穴として描画される。





ちなみに、穴をちょっとずらして定義すると、以下のように面白い感じになる。

/* 座標を定義 */
data test;
input segment x y;
cards;
1 1 1
1 5 1
1 5 5
1 1 5
1 . .
1 3 3
1 6 3
1 6 6
1 3 6
;

/* ポリゴンを描画 */
proc sgplot data=test;
   polygon x=x y=y id=segment / fill outline;
   xaxis min=0 max=6;
   yaxis min=0 max=6;
run;




2019年11月28日木曜日

[SGPLOT] BY値ごとにグラフを作成する際、軸やシンボルなどをグラフ間で揃えたい






これは SGPLOT をよく使用する方なら一度は困るところではないでしょうか?
まずは、以下の失敗例をご覧ください。



失敗例

/* Sample Data */
proc sort data=sashelp.class (obs=5) out=class;
    by age;
run;

/* BY値ごとにグラフを作成 */
ods graphics / height=400 width=400;

proc sgplot data=class;
    scatter x=height y=weight / group=sex markerattrs=(symbol=circlefilled);
    by age;
run;




「BYステートメント」によって、変数「AGE」の値ごとにグラフを作成しています。
また「GROUP=オプション」によって、変数「SEX」の値ごとにシンボルカラーを変えています。



ここで気になるのが、、

  • X軸とY軸の目盛がグラフ間で異なっている。
  • シンボルの色がグラフ間で異なっている(SEX=Fのシンボルが、AGE=13の時は青、AGE=14の時は赤になっている)



そうなんですよ、、BY値ごとにグラフを作成すると、軸やシンボルはグラフ間で統一してくれません。
でも解決方法は簡単!



成功例

proc sgplot data=class uniform=all;
    scatter x=height y=weight / group=sex markerattrs=(symbol=circlefilled);
    by age;
run;




UNIFORM=オプション」を指定するだけ!
このオプションは「BY値ごとに作成したグラフのどこを統一させたいか」を設定します。
設定値には以下があります。



UNIFORM=

 設定値 設定内容 
SCALEX軸を統一 and Y軸を統一
XSCALEX軸を統一
YSCALEY軸を統一
GROUP「GROUP=オプションに指定した変数の値ごとにシンボルや線種などを統一
XSCALEGROUP「XSCALE」と「GROUP」の両方を設定
YSCALEGROUP「YSCALE」と「GROUP」の両方を設定
ALL上記のすべてを統一



2019年6月21日金曜日

「ODS RTF」+「SGPLOT」だと、TITLEステートメントの設定値がグラフのタイトルになってしまう





以下の例をご覧ください。

title "HEIGHT AND WEIGHT";

ods rtf file="出力パス\test.rtf";

    proc sgplot data=sashelp.class;
        scatter x=height y=weight;
    run;

ods rtf close;


TITLEステートメントの設定値がSGPLOTのグラフ内のタイトルにあてられました。



いやいや、「RTFのヘッダーにあててほしいんだけど」って場合は「NOGTITLE」というオプションを指定します。

title "HEIGHT AND WEIGHT";

ods rtf file="出力パス\test.rtf" nogtitle;

    proc sgplot data=sashelp.class;
        scatter x=height y=weight;
    run;

ods rtf close;



同様にFOOTNOTEステートメントが設定されてると、SGPLOTのグラフ内のフットノートに当てられます。
これも「NOGFOOTNOTE」というオプションを指定することで、RTFのフッターにあてることができます。



ちなみに「ODS RTF」だけじゃなくて、「ODS EXCEL」「ODS PDF」とかも共通する話です。
あと「SGPLOT」だけじゃなく、「GPLOT」も共通する話です。



2019年2月22日金曜日

グラフのマーカーや線などの属性をGROUP毎に設定する【Attribute Map Dataset 編】



「Attribute Map Dataset」を利用して、「SGPLOT」や「GTL」でマーカーや線などの属性を定義する方法を紹介します。




まず、以下の可愛らしいグラフをご覧ください。




年齢ごとに、マーカーの種類や色を変えて散布図を描いてます。
どうやってるか解説していきたいと思います。





Step1. 「Attribute Map Dataset」を作成する


まずグループ(年齢)毎にマーカーの種類や色を定義したデータセットを作ります。
(このデータセットを「Attribute Map Dataset」と呼びます)

data MYMAP;
input ID:$20. VALUE:$30. MARKERCOLOR:$30. MARKERSYMBOL:$30. MARKERSIZE:8.;
cards;
myid 11 blue CircleFilled 11
myid 12 red  StarFilled 11
myid 13 yellow TriangleFilled 11
myid 14 lightgreen DiamondFilled 11
myid 15 black SquareFilled 11
myid 16 skyblue TriangleDownFilled 11
;

proc sort data=MYMAP;
   by ID;
run;



たとえば1OBS目では以下を設定しています。
  • グループのIDを「myid」と設定
  • グループの値(今回は年齢)が「11」の時に、
  • マーカー色「blue」
  • マーカーの種類「CircleFilled」
  • マーカーサイズ「11」



データセットには以下のような変数を含めることが出来ます(一部抜粋)

変数設定内容備考
ID文字ID値PROC SORTでIDの順にソートする事をお勧めします。

例えば、各オブザベーションのID値の順番が "myid", "myid2", "myid" のように異なるID値が間に入ると正しく動作しません。

VALUE文字グループの値例えば年齢をグループにするのであれば年齢の値を指定

グループにする変数にFORMATが割り当てられている場合、FORMATを当てた後の値を指定する事。

例えば 11 = "11歳" のようにFORMATが当てられている場合、"11歳" の方を指定する。

・"_OTHER_" と "_MISSING_" はSAS内部での予約語なので注意。バージョン毎に予約語が増えるかも

FillColor文字塗りつぶしの色棒グラフの中の色など
MarkerColor 文字マーカーの色散布図のマーカーの色など
MarkerSize数値マーカーのサイズ散布図のマーカーのサイズなど
MarkerSymbol文字マーカーの種類散布図のマーカーの種類など
LineColor文字線の色折れ線グラフの線の色など
LinePattern数値/
文字
線の種類折れ線グラフの線の種類など
LineThickness数値線の太さ折れ線グラフの線の太さなど
…等々

(「ID」と「VALUE」は必ずデータセットに含める必要があり、それ以外は任意)





Step2. グラフを描画


Step1で作った「Attribute Map Dataset」をSGPLOTまたはGTLで参照してグラフを描くことが出来ます。


📝 注意

SAS9.4M3より前のバージョンでは、この機能 (Attribute Map Dataset) と一緒に、PLOTステートメント (SCATTERやSERIESなど) でも属性を定義している場合、結果のプロット部分と凡例部分の属性が一致しないおかしな状態になることがある?らしいので注意。

その他、気づいた範囲で注意点を以下例とともに記載しているので要確認です。


  • SGPLOTで描画
proc sgplot data=SASHELP.CLASS dattrmap=MYMAP;
   scatter x=HEIGHT y=WEIGHT / group=AGE grouporder=ascending attrid=myid;
run;

  • group=」でAGE毎に散布図を描いています。
  • dattrmap=」で参照する Attribute Map Dataset を指定。
  • attrid=」で参照する Attribute Map Dataset のID値を指定。
  • 以下のように同じグループ変数に異なるID値を割り当てるような事は出来ません(正しく動作しない&ログにWARNINGが出る)  

scatter x=XX1 y=YY1 / group=AGE attrid=myid;
scatter x=XX2 y=YY2 / group=AGE attrid=myid2;



  • GTLで描画
proc template ;
     define statgraph MYTEMP ;
     begingraph;

     layout overlay;
          scatterplot x=HEIGHT y=WEIGHT / group=AGE grouporder=ascending name="leg1";
          discretelegend "leg1" / title="Age";
     endlayout;

     endgraph;
     end;
run;

proc sgrender data=SASHELP.CLASS template=MYTEMP dattrmap=MYMAP;
     dattrvar AGE="myid";
run;

  • group=」でAGE毎に散布図を描いています。
  • dattrmap=」で参照する Attribute Map Dataset を指定。
  • dattrvar」でグループ変数AGEに対応づけるAttribute Map DatasetのID値を指定。
  •   以下のように同じグループ変数に異なるID値を割り当てるような事は出来ません(正しく動作しない)

dattrvar AGE="myid" AGE="myid2";



2019年2月6日水曜日

2軸グラフの描き方【SGPLOT編】




Y2AXISオプション」で、右側のY軸を使うことが出来ます。


これにより、以下例のように
  • 1つ目の折れ線のY軸のスケールを左側に示し
  • 2つ目の折れ線のY軸のスケールを右側に示す
という事が出来ます。




* 使用するデータの準備 ;
proc sort data=SASHELP.ELECTRIC  out=ELECTRIC;
    by YEAR;
    where CUSTOMER = "Residential";
run;

* 2軸グラフを描く ; 
proc sgplot data=ELECTRIC;
    series x=YEAR y=COAL               / lineattrs=(color=blue);
    series x=YEAR y=NATURALGAS / lineattrs=(color=red)  y2axis ;
    xaxis type=discrete;
run;



例では、2つの折れ線を書いて、X軸はYEARを用い、
  • 左側のY軸にCOALを設定
  • 右側のY軸にNATURALGASを設定
としています。


ちなみにX軸も「X2AXIS」と指定すれば、上側のX軸を使うことも出来ますよ。



2016年10月25日火曜日

グラフ描画時にデータセットが作れる



(注意:今回のテクニックにGPLOTは含まれません)



SGPLOTでグラフを書くときに「ODS TRACE ON/OFF」で囲って実行してみましょう。

ods trace on;
proc sgplot data=SASHELP.CLASS;
  vbar AGE;
run;
ods trace off;

ログ

ログを見ると「SGPlot」という出力オブジェクトが作成されている事が分かります。


この出力オブジェクトを以下のように「ODS OUTPUT」に指定してやると、、

ods output SGPlot=OUT1;
proc sgplot data=SASHELP.CLASS;
  vbar AGE;
run;
ods output close;

データセット:OUT1

なんとグラフ描画時に内部的に作られた?データセットを出力する事が出来ます。



役に立つ例

「ODS GRAPHICS ON;」とすると、一部の統計プロシジャで統計量と一緒にグラフも出力されるのをご存知ですか?
(出力先がLISTINGの場合は統計プロシジャの結果にグラフは含まれません)

これらのグラフも上記の方法でデータセット化出来ちゃいます。


例えば
「ODS GRAPHICS ON;」かつ出力先がHTMLになっている状態で、以下のようにPROC LIFETESTを実行すると生存曲線も出力されますが、、

ods trace on;
proc lifetest data=sashelp.bmt  ;
  time t * status(0);
  strata group;
run;
ods trace off;

ログ













結果ビューア



これもグラフ用データセットが出力できます。

ods output SurvivalPlot=OUT1 ;
proc lifetest data=SASHELP.BMT ;
  time T * STATUS(0);
  strata GROUP;
run;
ods output close;

データセット:OUT1



あとでSGPLOTやSGRENDERを使って自分好みの生存曲線を描く時にかなり使い勝手のいいデータセットです!(わりとそのまんま使える)

今まで生存曲線を描画するためのデータセットを作るのって結構面倒でしたが、上記の方法でだいぶ楽になると思います。


2016年7月1日金曜日

SGPLOTでTEMPLATEプロシジャのコードを自動生成する【TMPLOUT=オプション】





SGPLOTプロシジャに「TMPLOUT=オプション」をつけると、TEMPLATEプロシジャのコードを自動生成してくれます。


  • 自動生成されるコードの出力先を「TMPLOUT=」にtxt形式等でフルパスで指定する。
  • 生成されるコードの中身は環境によって少し異なる。あと後述しますが注意点あり

proc sgplot data=SASHELP.FISH  tmplout="出力先をフルパス指定" ;
      hbox WEIGHT / category=SPECIES;
run;


自動生成されたコード
proc template;
define statgraph sgplot;
dynamic _ticklist_;
begingraph / collation=binary;
layout overlay / yaxisopts=(labelFitPolicy=Split) y2axisopts=(labelFitPolicy=Split) yaxisopts=(discreteOpts=(sortOrder=ascendingFormatted)) yaxisopts=(type=Discrete reverse=true discreteOpts=(tickValueList=_ticklist_ tickValueListPolicy=Union)) y2axisopts=(discreteOpts=(sortOrder=ascendingFormatted)) y2axisopts=(type=Discrete reverse=true discreteOpts=(tickValueList=_ticklist_ tickValueListPolicy=Union));
   BoxPlot X='Species'n Y='Weight'n / primary=true orient=horizontal LegendLabel="Weight" NAME="HBOX";
endlayout;
endgraph;
end;
run;



💬 注意点

例えば、以下のSGPLOTからTEMPLATEプロシジャのコードを自動生成すると、、

proc sgplot data=SASHELP.CLASS  tmplout="出力先をフルパス指定" ;
      vbar SEX;
run;


自動生成されたコード
proc template;
define statgraph sgplot;
dynamic _NEGATIVE_;
dynamic _ticklist_;
begingraph / collation=binary;
layout overlay / yaxisopts=(labelFitPolicy=Split) y2axisopts=(labelFitPolicy=Split) xaxisopts=(type=Discrete discreteOpts=(tickValueList=_ticklist_ tickvaluefitpolicy=SplitRotate tickValueListPolicy=Union)) x2axisopts=(type=Discrete discreteOpts=(tickValueList=_ticklist_ tickvaluefitpolicy=SplitRotate tickValueListPolicy=Union)) yaxisopts=(linearopts=(Integer=true));
   BarChartParm X='Sex'n Y=_FREQUENCY_ / primary=true LegendLabel="度数" NAME="VBAR";
endlayout;
endgraph;
end;
run;


自動生成されたコードの青文字で示した部分に注目!
プロットに使用したデータセット「SASHELP.CLASS」には「_FREQUENCY_」なんて変数はないし、DYNAMICステートメントにも「_FREQUENCY_」なんていうDYNAMIC変数は定義されていません。
ナニコレ??

どうやら、グラフに含まれる要約値(今回の場合は度数)は、自分で計算しないといけない場合があるようです。



例えば今回の場合では、以下のような対応が必要
  • SEXごとの度数をPROC FREQとかで求めてデータセットに出力
  • 自動生成されたコードの「Y=_FREQUENCY_」の部分を「Y=自分で求めた度数が入った変数」に置き換える
  • SGRENDERでは上記で作成したデータセットを使用する



まとめ

SGPLOTでは不可能なカスタマイズをしたい場合にTEMPLATEプロシジャを使いますが、TMPLOUT=オプションでコードを自動生成してしまえば、自分で一から書くより楽な場合があります。

ただし、自動生成なので改行とかインデントつけたりして、見やすくする必要がありますし、
前述したとおり、想定外のコードが生成される場合があるので、ちゃんと中身を確認・理解したうえで適宜カスタマイズする必要があります。


2016年5月7日土曜日

箱ひげ図をかく 【SGPLOT編】




構文

箱ひげ図の向きによってステートメントが分かれます。


縦向き
  PROC SGPLOT DATA=対象データセット;
      VBOX  分析変数 / CATEGORY=カテゴリ  オプション ;
  RUN;


横向き
  PROC SGPLOT DATA=対象データセット;
      HBOX  分析変数 / CATEGORY=カテゴリ  オプション ;
  RUN;

  • デフォルトで「CATEGORY=」を指定した軸は離散軸になりますが、ユーザー側で線形軸等に変えると、挙動が変わってしまいます。詳細はリファレンスを要確認。



オプション
  設定内容  指定   詳細設定
  箱の幅

  BOXWIDTH  =  0~1

  
  箱の書式

  FILLATTRS  =  (詳細設定) 

  COLOR = 色

  ひげの書式

  WHISKERATTRS  =  (詳細設定) 

  COLOR = 色

  中央値の書式

  MEDIANATTRS  =  (詳細設定)

  COLOR = 色

  平均値の書式 

  MEANATTRS  =  (詳細設定)
  
  COLOR   = 色
  SYMBOL = 表示マーク  

  外れ値の書式 

  OUTLIERATTRS  =  (詳細設定)   

  SYMBOL = 表示マーク 
  

…etc ( 色々できるのでリファレンスを確認してみてください )



注意
  • オプションの組み合わせで挙動が変わる可能性あり。
  • デフォルトで出力される箱ひげ図のタイプ(箱、ひげ、外れ値等の定義)はリファレンスを要確認



1. 簡単な例


title "お魚の体重分布";
proc sgplot data=SASHELP.FISH;
   vbox WEIGHT / category=SPECIES;
run;




2.カスタマイズ

title "お魚の体重分布";
proc sgplot data=SASHELP.FISH;
   hbox WEIGHT / category=SPECIES
                         boxwidth = 0.3
                         meanattrs = (color=black symbol=plus)
                         fillattrs = (color=white)
                         whiskerattrs = (color=black)
                         medianattrs = (color=black)
                         outlierattrs = (symbol=circlefilled);
run;