ラベル ODSOUT の投稿を表示しています。 すべての投稿を表示
ラベル ODSOUT の投稿を表示しています。 すべての投稿を表示

2015年8月2日日曜日

RWIで迷路を作る



RWIを使って迷路を描画してみます。
(※ SAS9.4以降で動作します)



迷路作成の初期値を設定

%let n    = 37;
%let init = 1234;

n    ・・・ 迷路のマスの数。(必ず奇数を設定する事)
init  ・・・ 迷路の壁と床を決めるために生成する乱数のシード値

初期値を変えるたびに異なる迷路を作ることが出来ます。


迷路の壁と床を乱数で決める

data DT1;

  *** 全マス目分の配列を定義 ;
  array AR(&n, &n) ;

  *** 最初から壁にする部分を2に設定 ;
  do y=1 to &n;
      do x=1 to &n;
         if x in (1,&n) or y in (1,&n) or mod(x*y,2)=1 then AR(x,y)=2;
         else AR(x,y)=1;
      end;
  end;

  *** 乱数を生成して壁の位置を決める ;
  *** 壁の位置 1:上、2:下、3:右、4:左 ;
  call streaminit(&init);
  do y=3 to &n-2 by 2;
  do x=3 to &n-2 by 2;

     *** 1段目は上下左右の壁の乱数を生成 ;
     if y=3 then do;
         * 左のマスが壁だったら上下右のみの壁の乱数を生成 ;
         if AR(x-1,y)=2 then  RAND = ceil(rand('uniform')*3);
         else RAND = ceil(rand('uniform')*4);
     end;

     *** 2段目以降は下左右の壁の乱数を生成 ;
     if y^=3 then do;
         * 左のマスが壁だったら下右のみの壁の乱数を生成 ;
         if AR(x-1,y)=2 then  RAND = ceil(rand('uniform')*2)+1;
         else RAND = ceil(rand('uniform')*3)+1;
     end;

     if RAND=1 then AR(x,y-1)=2; * 上 ;
     if RAND=2 then AR(x,y+1)=2; * 下 ;
     if RAND=3 then AR(x+1,y)=2; * 右 ;
     if RAND=4 then AR(x-1,y)=2; * 左 ;
  end;
  end;
run;


RWIで迷路描画

data _NULL_;
  length VAR1 $5.;
  set DT1;
  array AR(&n, &n);
  dcl odsout ob();
  ob.table_start();

  do y=1 to &n;
      ob.row_start();

      do x=1 to &n;

         *** 壁と床を描画 ;
          VAR1="";
          if (x=2 and y=2) or (x=&n-1 and y=&n-1) then VAR1="☆";
          ob.format_cell(data:VAR1,  style_attr: "background=" || choosec(AR(x,y),"white","black") ||
                                                                  " height=0.4cm  width=0.4cm");
      end;

      ob.row_end();
  end;

  ob.table_end();
run;


2015年7月31日金曜日

RWIで集計表を作る



今回のゴールはRWIで以下の表をPDF形式で作成することです。
集計に使うデータセットは「SASHELP.CARS」の先頭80obsとします。

注意:
SAS9.4以降で動作します。
また、今回のプログラムには、HTML形式でサポートされていないオプションを使用しています。




ステップ①

  • まずFREQプロシジャで集計し、結果をデータセットに出力します。
  • 結果のデータセットを加工して、RWIで出力しやすい形にします。

*=== 集計 ===========================================;
proc freq data=SASHELP.CARS (obs=80) noprint;
     tables MAKE / out=OUT1;
     tables TYPE / out=OUT2;
run;

*=== 集計結果を出力の形に加工 =======================;
data OUT;
     length NO 8. ITEM1 ITEM2 COL1 COL2 $20.;

     set OUT1 (in=_IN1)
           OUT2 (in=_IN2)
     ;
     *** 項目No.、項目名の導出 ******************;
     NO    = whichn(1,of _IN:);
     ITEM1 = choosec(NO, "Make","Type");
     ITEM2 = coalescec(MAKE,TYPE);

     *** Nとパーセントを出力の形に **************;
     COL1 = cats(COUNT);
     COL2 = cats( "(", put(round(PERCENT,.1), 8.1) ,")" );
run;






ステップ②

  • 上で作ったデータセットをRWIで出力します。

*=== 出力開始 ===========================================;
options nodate;
ods pdf file="出力するファイルのパス\RWI_Sample2.pdf" style = printer;

data _NULL_;
     length LINE $5.;

     set OUT end=EOF;
     by NO ;

     if _N_=1 then do;
         dcl odsout ob();
         ob.title(data:'集計結果');
         ob.table_start();

         *** 項目名を出力 *************************;
         LINE = "LR";
         ob.head_start();
         ob.row_start();
             ob.format_cell(data:"因子", inhibit:LINE, style_attr:"background=white cellwidth=3cm just=l");
             ob.format_cell(data:""       , inhibit:LINE, style_attr:"background=white cellwidth=3cm just=l");
             ob.format_cell(data:"n"     , inhibit:LINE, style_attr:"background=white cellwidth=2cm just=r");
             ob.format_cell(data:"(%)"  , inhibit:LINE, style_attr:"background=white cellwidth=2cm just=l");
         ob.row_end();
         ob.head_end();
     
end;

     *** データの中身を出力 ***********************;
     * 各集計項目の先頭を1行あける。 ;
     if first.NO then do;
         ob.row_start();
         ob.format_cell( data:ITEM1 , inhibit:"BLR", column_span:4, style_attr:"just=l");
         ob.row_end();
     end;

     * データの中身を出力 ;
     * 変数LINEに、行毎の罫線の設定を格納 ;
     LINE = "TBLR";
     if EOF then LINE="TLR";

     ob.row_start();
         ob.format_cell( data:""        , inhibit:LINE, style_attr:"just=l");
         ob.format_cell( data:ITEM2 , inhibit:LINE, style_attr:"just=l");
         ob.format_cell( data:COL1  , inhibit:LINE, style_attr:"just=r");
         ob.format_cell( data:COL2  , inhibit:LINE, style_attr:"just=l");
     ob.row_end();

     * 最後に表作成を終了 ;
     if EOF then ob.table_end();
run;

ods pdf close;


出力結果

※ プログラム中の青字のパスを各時環境のパスに変更してください。



今回のポイントは format_cellメソッド内の「inhibitオプション」による罫線の細かい指定です。

構文
FORMAT_CELL( INHIBIT:'罫線を非表示にする位置 ' )

罫線を非表示にする位置
T ・・・ 上側
B ・・・ 下側
L ・・・ 左側
R ・・・ 右側

例 : 上下の罫線を非表示にする
FORMAT_CELL( INHIBIT : 'TB' ) ;

注意:現状、inhibitオプションはHTML形式ではサポートされていない


RWIについては、以下の入門シリーズにまとめています。
レポート作成インターフェイス(RWI)入門1


📝注意

記事の中で使用している「_N_」「END=オプション」「FIRST.BY変数」は「サブセット化IF」と一緒に使用すると正しく動かなくなりやすいです。


2015年5月12日火曜日

RWIでフォトブックをつくる



※ SAS9.4以降で動作します。
また、貼り付ける画像ファイルによっては、出来上がるファイル容量も馬鹿でかくなるので、PCの空き領域がない場合は、実行しない方がいいかも。


プログラムを実行する場合は、プログラム中の青字にしてるパスを各時環境のパスに変更してください。

プログラムで使う写真

   



プログラム
ods html close;
ods pdf file="出力するファイルのパス\photobook.pdf" notoc  dpi=150;

data _NULL_;
  dcl odsout ob();

  *** 1ページ目 ***************************;
  ob.layout_absolute();

    * 1枚目の写真 ;
    ob.region( x:'2cm',  y:'1cm',  width:'9cm' );
    ob.image( file:'写真を格納したパス\DSC_0614.JPG' );

    ob.region( x:'12cm',  y:'5cm',  width:'7cm' );
    ob.format_text( data:"夏の恒例「SASユーザー総会」",
                         style_attr:"fontsize=12pt" );

    * 2枚目の写真 ;  
    ob.region( x:'10cm',  y:'12cm',  width:'8cm');
    ob.image( file:'写真を格納したパス\DSC_0618.JPG' );

    ob.region( x:'2cm', y:'22cm', width:'8cm' );
    ob.format_text( data:"ユーザー総会限定の粗品",
                         style_attr:"fontsize=12pt" );
    
  ob.layout_end();

  ob.page();

  *** 2ページ目 ***************************;
  ob.layout_absolute();

    * 1枚目の写真 ;
    ob.region( x:'2cm', y:'1cm', width:'10cm' );
    ob.image( file:'写真を格納したパス\DSC_0489.JPG' );

    ob.region( x:'12.5cm', y:'5cm', width:'7cm' );
    ob.format_text( data:"堀切菖蒲園の菖蒲たち",
                         style_attr:"fontsize=12pt" );

    * 2枚目の写真 ;  
    ob.region( x:'2cm', y:'9cm', width:'10cm' );
    ob.image( file:'写真を格納したパス\DSC_0611.JPG' );

    ob.region( x:'12.5cm', y:'16cm', width:'7cm' );
    ob.format_text( data:"熱い将棋バトル、電王戦タッグマッチ2014",
                         style_attr:"fontsize=12pt" );
 
  ob.layout_end();

run;

ods pdf close;
ods html;


結果





写真の解像度が高いと、出来上がるPDFファイルの容量も大きくなってしまいます。

プログラム2行目の「ods pdf  ~ dpi=150;」で、解像度を設定してます。
デフォルトは 「dpi=150」なので、写真枚数が多い場合は、ファイル容量が恐ろしくやばくなるので、まずは「dpi=75」とかにして、様子を見たほうがいいかも。


今回使用してるRWIについては、以下の入門シリーズにまとめています。
レポート作成インターフェイス(RWI)入門1

2015年5月11日月曜日

レポート作成インターフェイス(RWI)入門8


RWIでテキストを配置するメソッドを紹介。

 FORMAT_TEXT( data: "テキスト)



このメソッドと、以前紹介したREGIONメソッドを組み合わせれば、好きな位置に好きなテキストを配置できます。


ods html close;
ods pdf file="出力するファイルのパス\TEST.pdf";

data _NULL_;
  dcl odsout ob();
  ob.layout_absolute();

     ob.region( x:'1cm',  y:'2cm',  width:'8cm');
     ob.format_text( data:"aaaaaaaaaaa" );

     ob.region( x:'5cm',  y:'3cm',  width:'8cm');
     ob.format_text( data:"bbbbbbbbbb" );

  ob.layout_end();

run;

ods pdf close;
ods html;

TEST.pdf


2015年1月5日月曜日

1年分のカレンダーを作るSASプログラム



本年も、どうぞよろしくお願い致します!!


年の始まりということで、以前紹介した「RWIでカレンダーを作ってみる。」を改良して、1年分のカレンダーを作るプログラムを2パターン作りました。
祝日を色分けする処理も加えてます。


ちなみにSAS9.4以降で動作します。
また、実行する場合は、最後のほうに書いた補足の通り、プログラムを直してください。


(2020/12/26 出力結果のタイトル文字を大きくするなど、プログラムを改良)


まずは、以下の通り、その年の祝日をデータセット化しておきます。
「祝日一覧」とか適当にググると調べられます。

*** 2015年の祝日をデータセット化 ;
data HOLIDAY;
input  i :yymmdd10. HOLIDAY :$30.;
cards;
2015/1/1 元日
2015/1/12 成人の日
2015/2/11 建国記念の日
2015/3/21 春分の日
2015/4/29 昭和の日
2015/5/3 憲法記念日
2015/5/4 みどりの日
2015/5/5 こどもの日
2015/5/6 振替休日
2015/7/20 海の日
2015/9/21 敬老の日
2015/9/22 国民の休日
2015/9/23 秋分の日
2015/10/12 体育の日
2015/11/3 文化の日
2015/11/23 勤労感謝の日
2015/12/23 天皇誕生日
;


カレンダーのパターン①



*** 年を指定 ;
%let YEAR = 2015;


*** 用紙の向きを横に ;
options orientation = landscape;


title height=20pt "SAS Calendar ( &YEAR )";
ods pdf file="出力するパス\calendar1.pdf" notoc;


*** RWIでカレンダーを作る ;
data _NULL_;

  * 祝日一覧をハッシュオブジェクトに格納 ;
  length HOLIDAY $20.;
  dcl hash hs( dataset:"HOLIDAY" );
  hs.definekey( "i" );
  hs.definedata( "HOLIDAY" );
  hs.definedone();


  * 月ごとにループ ;
  do MONTH = 1 to 12;

     * 月の開始日と終了日を取得 ;
     STDT = mdy(MONTH, 1, &YEAR);
     ENDT = intnx("month", STDT, 0, "end");

     * カレンダー作成開始 ;
     dcl odsout ob();
     ob.table_start();

         * 月を出力 ;
         ob.head_start();
         ob.row_start();

              ob.format_cell( data: put(STDT,monname20.), column_span:7,
                                     style_attr: "background=midnightblue  color=white
                                                      fontsize=10  fontweight=bold  just=left");
         ob.row_end();

         * 曜日を出力 ;
         ob.row_start();
              do i = 1 to 7;
                  ob.format_cell( data: char("SMTWTFS",i) ,
                                        style_attr: "background=skyblue color=white fontsize=5") ;
              end;
         ob.row_end();
         ob.head_end();

         * 日付を出力 ;
         ob.row_start();
              do i = STDT to ENDT;

                  * 初日が日曜以外であれば空白を埋める ;
                  if i=STDT then do i2=1 to weekday(STDT)-1;
                      ob.format_cell();
                  end;

                  * 日付を出力 (文字色も設定) ;
                  HOLIDAY="";

                  *--- 平日は黒 ;
                  COLOR="BLACK";

                  *--- 日曜と祝日は赤 ;
                  if weekday( i )=1 or hs.find()=0 then COLOR="RED";

                  *--- 土曜は青 ;
                  else if weekday( i )=7 then COLOR="BLUE";

                  ob.format_cell( data:cats( day( i ), "#", HOLIDAY ) ,split:"#",
                                         style_attr:"height=2.7cm width=3.5cm fontsize=5 color="||COLOR);


                  * 土曜日であれば折り返す ;
                  if weekday( i )=7 and i^=ENDT then do;
                       ob.row_end();
                       ob.row_start();
                  end;

              end;
         ob.row_end();

      ob.table_end();

      * 月ごとに改ページ ;
      if MONTH^=12 then ob.page();

  end;
run;


ods pdf close;




カレンダーのパターン②




*** 年を指定 ;
%let YEAR = 2015;


*** 用紙の向きを縦に ;
options orientation = portrait;


title height=20pt "SAS Calendar ( &YEAR )";
ods pdf file="出力するパス\calendar2.pdf" notoc;


*** RWIでカレンダーを作る ;
data _NULL_;

  * 祝日一覧をハッシュオブジェクトに格納 ;
  length HOLIDAY $20.;
  dcl hash hs( dataset:"HOLIDAY" );
  hs.definekey( "i" );
  hs.definedata( "HOLIDAY" );
  hs.definedone();

  * カレンダー作成開始 ;
  dcl odsout ob();
  ob.layout_gridded(columns:3,rows:4);

  * 月ごとにループ ;
  do MONTH = 1 to 12;

      * 月の開始日と終了日を取得 ;
      STDT = mdy(MONTH, 1, &YEAR);
      ENDT = intnx("month", STDT, 0, "end");

      ob.region();
      ob.table_start();

         * 月を出力 ;
         ob.head_start();
         ob.row_start();

              ob.format_cell( data: put(STDT,monname3.), column_span:7,
                                     style_attr:"background=midnightblue  color=white 
                                                     fontsize=3  fontweight=bold  just=left");
         ob.row_end();

         * 曜日を出力 ;
         ob.row_start();
              do i = 1 to 7;
                  ob.format_cell( data: char("SMTWTFS",i),
                                        style_attr: "background=lightsteelblue color=white");
              end;
         ob.row_end();
         ob.head_end();

         * 日付を出力 ;
         ob.row_start();
              do i = STDT to ENDT;

                  * 初日が日曜以外であれば空白を埋める ;
                  if i=STDT then do i2=1 to weekday(STDT)-1;
                      ob.format_cell();
                  end;


                  * 日付を出力 (文字色も設定) ;
                  HOLIDAY="";

                  *--- 平日は黒 ;
                  COLOR="BLACK";

                  *--- 日曜と祝日は赤 ;
                  if weekday( i )=1 or hs.find()=0 then COLOR="RED";

                  *--- 土曜は青 ;
                  else if weekday( i )=7 then COLOR="BLUE";

                  ob.format_cell( data: day( i ), style_attr:"color="||COLOR );


                  * 土曜日であれば折り返す ;
                  if weekday( i )=7 and i^=ENDT then do;
                       ob.row_end();
                       ob.row_start();
                  end;

             end;
         ob.row_end();
      ob.table_end();

  end;
  ob.layout_end();
run;


ods pdf close;




補足


・プログラムの最初らへんの「ods pdf」部分を、各自保存したいパスに変えてください。
ods pdf file="結果を保存するパス\ファイル名.pdf";


・ 出力する年を変えたい場合は、プログラム先頭の以下の箇所を変えてあげる。

*** 年月を指定 ;
%let YEAR = 2015;

また、その年の祝日にあわせてデータセットHOLIDAYを更新してください。



2014年12月17日水曜日

レポート作成インターフェイス(RWI)入門7


RWIで画像ファイルを配置するメソッドを紹介。

  IMAGE( file: "画像ファイルのフルパス)



簡単な例ですが、スマホで撮った写真を配置してみます。
(以降、HTMLへの出力が有効になっている前提)

data _NULL_;

  dcl odsout ob();
  ob.image( file: "画像ファイルのパス\flower.jpg" );

run;


結果



実務では、SASで作ったグラフを、画像ファイルとして保存しておき、それを配置するってことも出来ます。


ちなみに、写真の花は堀切菖蒲園というところで撮ったやつです。
花びらがクシャッと垂れた感じがかわいいですね。



2014年12月12日金曜日

レポート作成インターフェイス(RWI)入門6


RWIで改ページを設定するメソッド。

  PAGE()



プログラムと結果を見てみましょう。
(以降、HTMLへの出力が有効になっている前提)

data _NULL_;
  dcl odsout ob();

     *** 1ページ目 ;
     ob.table_start();
         ob.row_start();
            ob.format_cell( data:"aa" );
         ob.row_end();
     ob.table_end();

     ob.page();

     *** 2ページ目 ;
     ob.table_start();
         ob.row_start();
            ob.format_cell( data:"bb" );
         ob.row_end();
     ob.table_end();
run;

結果



レポートを作るうえで大事なメソッドです。

2014年12月8日月曜日

レポート作成インターフェイス(RWI)入門5



RWIで、複数の表を好きな位置に配置する方法を紹介。

ods html close;
ods pdf file="出力するファイルのパス\test.pdf";

data _NULL_;
  dcl odsout ob();

  * レイアウト設定開始 ;
  ob.layout_absolute();

     * 1個目の表を配置 ;
     ob.region( x:'1cm', y:'1cm' );
     ob.table_start();
         ob.row_start();
            ob.format_cell(data:"aa");
            ob.format_cell(data:"bb");
         ob.row_end();
     ob.table_end();

     * 2個目の表を配置 ;
     ob.region( x:'5cm', y:'2cm' );
     ob.table_start();
         ob.row_start();
            ob.format_cell(data:"cc");
           ob.format_cell(data:"dd");
         ob.row_end();
     ob.table_end();

  ob.layout_end();
run;

ods pdf close;
ods html;


結果




解説


今回使うlayout_absoluteメソッドは、マニュアルにPRINTER出力のみ対応してるよと書いてあります。
なので、HTML出力を閉じておき、PDFファイルに出力します。

  ods html close;
  ods pdf file="出力するPDFファイルのフルパス";


好きな位置に配置するためのレイアウトを開始。

  layout_absolute()


表を配置する前にregionメソッドで領域の出力位置を設定。
ただ、いまいち分からないのが、例えば位置を5cmと設定して、出力されたpdfを倍率100%にして見ても5cmのところに配置されてるわけでもなさそう?。。どういう基準で配置されてるのかよく分からないです。

  region( x : 'xの位置' ,  y : 'yの位置' )


レイアウト設定を終了させます。

  layout_end()


PDF出力を閉じて出力完了。あと最後にデフォルトの出力先をHTMLにしてます。

  ods pdf close;
  ods html;


イメージとしては、スクラップブックのように、いろんな表やグラフを好きな位置にペタペタ貼る感じです。


また別の記事で、応用例(遊び)を紹介したいと思います。



RWI入門記事一覧
1.基本構文
2.データセットの中身を出力する
4.複数の表を並べる
5.複数の表を好きな位置に配置する

2014年11月17日月曜日

レポート作成インターフェイス(RWI)入門4


RWIで複数の表を並べる方法を紹介します。
まずは以下のプログラムを実行して結果を見てみましょう。

(以降、HTMLへの出力が有効になっている前提)

data _NULL_;
   dcl odsout ob();

   * グリッドを設定する ;
   ob.layout_gridded( columns:2, rows:2 );

       * 1個目の表を配置 ;
       ob.region();
       ob.table_start();
          ob.row_start();
               ob.format_cell(data:"aa");
               ob.format_cell(data:"bb");
          ob.row_end();
       ob.table_end();

       * 2個目の表を配置 ;
       ob.region();
       ob.table_start();
          ob.row_start();
               ob.format_cell(data:"cc");
               ob.format_cell(data:"dd");
          ob.row_end();
       ob.table_end();

       * 3個目の表を配置 ;
       ob.region();
       ob.table_start();
          ob.row_start();
               ob.format_cell(data:"ee");
               ob.format_cell(data:"ff");
          ob.row_end();
       ob.table_end();

   ob.layout_end();
 run;

結果



解説


まずは、表を配置する列数と行数を設定。
  layout_gridded( columns:列数 , rows:行数  )


そしたら、表を配置する前に以下のメソッドを書くだけです。
  region()


最後にレイアウト設定を終了させます。
  layout_end()



例えば列2×行2のレイアウトを作って表を配置するイメージはこんな感じ。














regionメソッドを書く度、左から右、次の行の左から右に、、、と表をどんどん配置していきます。


ちなみに。。

長くなるので紹介は出来ませんでしたが、imageメソッドというのがあり、表だけじゃなくグラフなどのイメージも配置できちゃうので、色々遊べそうです。

2014年11月6日木曜日

RWIでカレンダーを作ってみる。



遊び回です。RWIでカレンダー作ってみました。

style_attrで細かい書式設定をしてるため、ごちゃごちゃして見えますが、そこを見なければプログラムとしてはシンプルな構造になってます。


※ SAS9.4以降で動作します。

*** 年月を指定 ;
%let YEAR = 2014;
%let MONTH = 11;


*** RWIでカレンダーを作る ;
data _NULL_;

  * 月の開始日と終了日を取得 ;
  STDT = mdy(&MONTH, 1, &YEAR);
  ENDT = intnx("month", STDT, 0, "end");

  * カレンダー作成開始 ;
  dcl odsout ob();
  ob.table_start();

     * 月を出力 ;
     ob.head_start();
     ob.row_start();
          ob.format_cell( data: put(STDT,monname20.), column_span:7,
                                 style_attr: "background=midnightblue  color=white
                                                  fontsize=10  fontweight=bold  just=left");
     ob.row_end();

     * 曜日を出力 ;
     ob.row_start();
          do i = 1 to 7;
              ob.format_cell( data: char("SMTWTFS",i) ,
                                    style_attr: "background=skyblue color=white fontsize=5") ;
          end;
     ob.row_end();
     ob.head_end();

      * 日付を出力 ;
     ob.row_start();
          do i = STDT to ENDT;

              * 1日が日曜以外であれば空白を埋める ;
              if i=STDT then do i2=1 to weekday(STDT)-1;
                  ob.format_cell();
              end;

              * 日付を出力 ;
              ob.format_cell( data:day( i ) ,  style_attr:"height=2cm width=2cm fontsize=5;");

              * 土曜日であれば折り返す ;
              if weekday( i )=7 and i^=ENDT then do;
                   ob.row_end();
                   ob.row_start();
              end;

          end;
     ob.row_end();

  ob.table_end();
run;

結果




補足

・大体以下で紹介した事をもとにしてます。
レポート作成インターフェイス(RWI)入門1
レポート作成インターフェイス(RWI)入門2
レポート作成インターフェイス(RWI)入門3


・出力する年月を変えたい場合は、プログラム先頭の以下の箇所を変えてください。

*** 年月を指定 ;
%let YEAR = 2014;
%let MONTH = 11;


・PDFなどに出力して印刷したい場合は、プログラムの先頭と最後に以下の文を挿入すればok。
 先頭: ods pdf file="結果を保存するパスを指定\SAS_Calendar.pdf";
 最後: ods pdf close;


2014年11月4日火曜日

レポート作成インターフェイス(RWI)入門3


今回はRWIで、セル結合する方法を紹介。
(以降、HTMLへの出力が有効になっている前提)


横結合する構文 :  format_cell( column_span: 結合する数 )

data _NULL_;

    dcl odsout ob();
    ob.table_start();

          * 1行目を出力 ;
          ob.row_start();
              ob.format_cell(data:"aa");
              ob.format_cell(data:"bb");
          ob.row_end();

          * 2行目を出力 ;
          ob.row_start();
              ob.format_cell(data:"cc", column_span:2);
          ob.row_end();

    ob.table_end();
run;

結果


縦結合する構文 :  format_cell( row_span: 結合する数 )

data _NULL_;

    dcl odsout ob();
    ob.table_start();

          * 1行目を出力 ;
           ob.row_start();
                ob.format_cell(data:"aa");
                ob.format_cell(data:"bb", row_span:2);
           ob.row_end();

          * 2行目を出力 ;
           ob.row_start();
                ob.format_cell(data:"cc");
           ob.row_end();

    ob.table_end();
run;

結果



実際の使用例

*** サンプルデータ ;
data DT1;
    A="001"; B="AA"; output;
    A="001"; B="BB"; output;
    A="002"; B="CC"; output;
    A="002"; B="DD"; output;
    A="002"; B="EE"; output;
run;

  A  
B
  001 
  AA   
  001
  BB
  002
  CC
  002 
  DD  
  002
  EE

上のサンプルから、RWIを使って以下のように出力してみます。
(Aの値が同じものをセル結合させる)



*** ① Aの値が同じもの同士の数を求める ;
proc sort data=DT1;
    by A;
run;

proc sql;
    create table DT2 as
    select A, count(*) as _COUNT
    from DT1
    group by A;
quit;

  A  
 _COUNT 
 001 
  2
 002
  3


*** ② RWIでセル結合した表を作る ;
data _NULL_;

    merge DT1 DT2 end=EOF;
    by A;

    *** データステップの最初だけ実行する部分 ;
    if _N_=1 then do;

        * RWIを使えるようにして表作成を開始 ;
        dcl odsout ob();
        ob.table_start();

        * 項目名を出力 ;
        ob.head_start();
        ob.row_start();
            ob.format_cell(data:"A");
            ob.format_cell(data:"B");
        ob.row_end();
        ob.head_end();
    end;

    *** データの中身を出力 ;
    ob.row_start();
        if  first.A then  ob.format_cell( data:A, row_span: _COUNT);
        ob.format_cell(data:B);
    ob.row_end();

    *** 最後に表作成を終了 ;
    if EOF then ob.table_end();
run;


ざっくり解説
① まずAの値が同じもの同士の数を求める。
方法はDATAステップでも何でもいいけど、とりあえずSQLで求めてます。

② 次にRWIで表を作ります。ポイントは以下。

if  first.A then  ob.format_cell( data:A, row_span: _COUNT);

BY変数Aの値が同じもの同士の先頭行で、format_cellメソッドを実行。
そこで先にSQLで求めた変数_COUNTをセル結合する数として指定してます。


📝注意


記事の中で使用している「_N_」「END=オプション」「FIRST.BY変数」は「サブセット化IF」と一緒に使用すると正しく動かなくなる事があります。


2014年10月24日金曜日

レポート作成インターフェイス(RWI)入門2




今回はデータセットの中身をRWIで出力する方法を紹介。

(以降、HTMLへの出力が有効になっている前提)


出力するデータ
data DT1;
   V1=1; V2="AAA"; output;
   V1=2; V2="BBB"; output;
   V1=3; V2="CCC"; output;
run;

 V1  
 V2  
  1
 AAA  
  2
 BBB
  3
 CCC


RWIを使って出力

data _NULL_;

   set DT1 end=EOF;

   *** データステップの最初だけ実行する部分 ;
   if _N_=1 then do;

       * RWIを使えるようにして表作成を開始 ;
       dcl odsout ob();
       ob.table_start();

       * 項目名を出力 ;
       ob.head_start();
       ob.row_start();
            ob.format_cell(data: "V1",  style_attr: "background=blue color=white");
            ob.format_cell(data: "V2",  style_attr: "background=blue color=white");
       ob.row_end();
       ob.head_end();

   end;


   *** データの中身を出力 ;
   ob.row_start();
        ob.format_cell(data: V1);
        ob.format_cell(data: V2);
   ob.row_end();

   *** 最後に表作成を終了 ;
   if EOF then ob.table_end();
run;

結果ビューア





処理の流れ


set DT1 end=EOF;

まず、出力するデータセットDT1を読み込む。
end=EOF」で最終オブザベーションを読み込むとき一時変数EOFに「1」が入る。(この一時変数は後で使う)

 ちなみに今回は一時変数名をEOFという名前にしているけど、任意の名前で指定可能。
 

*** データステップの最初だけ実行する部分 ;
if _N_=1 then do;

    * RWIを使えるようにして表作成を開始 ;

    dcl odsout ob();
    ob.table_start();

    * 項目名を出力 ;
    ob.head_start();
    ob.row_start();

         ob.format_cell(data: "V1",  style_attr: "background=blue color=white");
         ob.format_cell(data: "V2",  style_attr: "background=blue color=white");
    ob.row_end();
    ob.head_end();

end;

オブザベーションを読み込むたびに実行する必要がない箇所、
つまり最初の1回実行するだけでいい箇所を「if _N_=1 then do;」と「end;」で囲んであげる。

今回新たに登場した「head_start」「head_endメソッド」では、囲んだ範囲をヘッダーとして扱うことが出来ます。

また、「format_cellメソッド」の「style_attr」というのは、セルのスタイル属性を設定するオプションで、今回は背景色=青、文字色=白にしてます。

セルのスタイル設定
参照名.format_cell( data: "表示するテキスト",  style_attr: "スタイル属性")

使いたいスタイル属性は、SAS社の提供してるODSのリファレンスを参照ください。


*** データの中身を出力 ;
ob.row_start();
     ob.format_cell(data: V1);
     ob.format_cell(data: V2);
ob.row_end();

オブザベーション毎に変数値を出力


if EOF then ob.table_end();

一番最初に作った一時変数EOFを使って、最後に表作成を終了させる。




📝注意
記事の中で使用している「_N_」と「END=オプション」は「サブセット化IF」と一緒に使用すると正しく動かなくなりやすいです。

2014年10月22日水曜日

レポート作成インターフェイス(RWI)入門1


「Report Writing Interface」略してRWIと言われる機能がSAS9.4から追加されました。
SAS9.4より前のバージョンでも評価版として一部機能は使えます。


RWIを使うと、データステップ上で柔軟にレポートを作成することができます。
マニュアルには、出力先としてHTMLやPRINTERを選択できるよと書いてあります。


まずは簡単に、適当な表を作ってみましょう。
(以降、HTMLへの出力が有効になっている前提)


data _NULL_;

   *** ① RWIを使えるようにする **********;
   dcl  odsout ob() ;

   *** ② 表作成開始 *******************;
   ob.table_start();

      *** 1行目出力 ;
      ob.row_start() ;
          ob.format_cell( data: "1") ;
          ob.format_cell( data: "aaa") ;
      ob.row_end() ;

      *** 2行目出力 ;
      ob.row_start() ;
          ob.format_cell( data: "2") ;
          ob.format_cell( data: "bbb") ;
      ob.row_end() ;

  ob.table_end() ;

run;


結果



解説

① まず最初に「dcl odsout ob()」は「obって名前でRWIを使えるようにするよ」みたいな事をいってます。
ここはobじゃなくても好きな名前でok

② そのあとは「ob.メソッド()」で表を作る各メソッドを実行しています。
以下に各ステートメントやメソッドについてまとめました。

ステートメントとメソッドの説明
 dcl odsout 参照() 

 指定した参照名でRWIを使えるようにする 

 参照.table_start()

 表の作成開始

 参照.table_end()

 表の作成終了

 参照.row_start()

 行の作成開始

 参照.row_end() 

 行の作成終了

 参照.format_cell( data:"表示するテキスト")

 セルを作成


メソッドのざっくりしたイメージ。



























以上が、もっとも基本的な部分です。
HTMLで<table><tr><td>のようなタグを作るようなイメージに似てますね。



RWI入門記事一覧
1.基本構文
5.複数の表を好きな位置に配置する
6.改ページの設定
7.画像ファイルを配置する