SAS

vlineステートメントを使うと目盛に存在するデータしか表示できない問題について

他部署の人から折れ線グラフをsgplotで作図するとき、目盛に存在しないデータはデータセットに含まれていても勝手に除外するという話を聞きました。

一瞬「???」と思いましたが、試してみてみてようやくわかりました。

データが勝手にグラフから削除される

問題となったのはこんな感じのコードです。かなりいい加減ですが、問題は再現できているはず。xaxisステートメントで軸の値を指定しているところがポイント。

data ds1; 
do AVISIT=0 to 50 by 5; 
   aval=1;
   output; 
end; 
run; 

proc sgplot data=ds1; 
vline AVISIT/ response= aval markers; 

xaxis values=(0 to 50 by 10) 
   offsetmin=0.05 offsetmax=0.05 label="時点";

yaxis label="測定値";
run;

これを実行すると以下のグラフが出力されます。本当はこんなコードではないのですが、まあお試しなので。


実行結果(vlineステートメント)

読み込んだデータセットには時点=5,15,25,35,45があるはずなんですけど、すべて削除されています。

原因と対処

vlineステートメントのX軸は離散変数です。X軸にはxaxisステートメントで指定した値以外に値は存在しないためプロットできないのだと思います。

今回の例でいうと、X軸には0と10の値は存在しますが、その中間の値は存在しません。データセットにX=5のレコードが存在したとしても、軸に存在しないデータは表示できないため、X=5のレコードはグラフから削除されてしまいます。
離散変数ではなく連続変数を扱う線形軸であれば、目盛の中間の値であっても表示できます。

SASのreferenceをみても

vline category-variable <option>;

となっています。カテゴリ変数をX軸としているので、X軸は線形軸ではないですね。xaxisステートメントで軸タイプを変更することも無理っぽいです。

なので対処方法としては、

  • 線形軸に変更する
    * Vlineステートメントを重ねがけする

の2択でしょう。私は前者を選ぶかな。

(追記)
後で試したらvlineステートメントでも線形軸に変更できました!なのでvlineステートメントを重ねがけする必要もなかったですね。

修正例

私はSASで作図するときはGTLしか使わないので、sgplotは全然わかりません。なのでGTLで解決策を提案します。

proc template; 
define statgraph answer; 
begingraph; 
   layout overlay / 
      xaxisopts=( 
        linearopts=(
           tickvaluesequence=(
              start=0 end=50 increment=10)
           ) 
        offsetmin=0.05 offsetmax=0.05 
        label="時点"
      ) 
      yaxisopts=(
         offsetmin=0.05 offsetmax=0.05 
         label="測定値"
      ); 

      seriesplot x=avisit y=aval/ display=all;
   endlayout;
endgraph;
end;
run;

proc sgrender data=ds1 template=answer; 
run;

実行結果(seriesplotステートメント)

おそらく以前は棒グラフと一緒に表示するときにvlineステートメントでないと重ね書きできなかったから習慣的にvlineステートメントを使っていたのではないでしょうか。ですがいまは棒グラフでも線形軸を扱えるようになっているためseriesplot とbarchartを重ね書きできるようになっています。

なので時系列データを作図するときにvlineステートメントを使う意味はあまりないのではと思っています。

(追記)
vlineステートメントでも線形軸を使用することが可能でした。ただし軸設定を明示しないと勝手に離散軸扱いになるようです。したがってvlineステートメントであっても以下のコードであれば目盛に存在しないデータでもちゃんと表示されます。

proc sgplot data=ds1; 
vline AVISIT/ response= aval markers; 

xaxis values=(0 to 50 by 10) 
   type=linear
   offsetmin=0.05
   offsetmax=0.05
   label="時点"; 
yaxis label="測定値";
run;