最近officerパッケージでハマったこと3つ

Rひとりアドベントカレンダー26日目です。

Rのofficerパッケージは便利です。

パワーポイントでレポートが簡単に作れる。

こんな感じで会社用のテンプレートを読み込んで出力なんてことも簡単にできる。

library(officer)
read_pptx("会社のテンプレート.pptx") %>%
    add_slide(layout = "表紙", master = "hoxom") %>%
    ph_with(value = "サンプルレポート", location = ph_location_type(type = "ctrTitle")) %>% 
    ph_with(value = "株式会社ホクソエム", location = ph_location_type(type = "subTitle")) %>% 
    print(my_pres, target = "結果報告.pptx")

そしてShinyと組み合わせれば、データをアップロードして、分析を自動実行し、pptx形式でダウンロードみたいな仕組みも簡単に作れる。

が、いくつか混乱するポイントもあるので対応策を列挙したい。

officerパッケージで検索して出てくる事例は大抵古い

以前はPowerPoint上のスライドにテキストを挿入したい場合はph_with_text()、ggplot2で作ったプロットを挿入したい場合はph_with_gg()など関数を使い分けていたようである。

が、最近仕様が変わり、ph_with()がS3クラスの関数として実装されたので、渡されたオブジェクトによって、よしなに関数を使い分けてくれるようになった(S3ディスパッチ)。

そしてph_with_text()等の旧関数群は次のバージョンで廃止されるらしい。

(ph_with_textのヘルプより)
Description
add text into a new shape in a slide. This function will be deprecated in favor of  ph_with in the next release.

ということで、検索して出てくる事例は旧関数群を使っていることが多いので、コピペで済ませたい人は公式サイトを参照した方が良い。

https://davidgohel.github.io/officer/articles/offcran/powerpoint.html

明らかにggplot2で作ったプロットをggplot2で作ったプロットとして認識してくれない

生存時間分析のプロットをggplot2で実施してくれるsurvminerパッケージというものがある。

例えばこのパッケージのggsurvplot()にsurvfitクラスのオブジェクトを渡すとカプランマイヤー曲線をよしなに描画してくれる。

> library(survival)
> library(survminer)
> fit <- survfit(Surv(time, status) ~ sex, data = kidney)
> ggsurvplot(fit)

f:id:dichika:20191126204603p:plain

そして、通常であればggplot2で作ったプロットをph_with()に渡すとスライド上にそのまま描画してくれるので、このggsurvplot()で作ったオブジェクトを渡してみるとエラーになる。

> res_gg <- ggsurvplot(fit)
> my_pres <- my_pres %>% 
+     add_slide(layout = "タイトルとテキストとコンテンツ", master = "hoxom") %>% 
+     ph_with(value = res_gg, location = ph_location_type(type = "body", id = 2))
UseMethod("ph_with", value) でエラー: 
   'ph_with' をクラス "c('ggsurvplot', 'ggsurv', 'list')" のオブジェクトに適用できるようなメソッドがありません

実はggplot2に対応するph_with()のS3メソッドがph_with.gg()なのに対して、ggsurvplot()が返すオブジェクトはggクラスもggplotクラスも持たない。

とりあえずの応急処置としてはggsurvplot()で作ったオブジェクトにggクラスを付与すれば良い(長期的にはofficerかsurvminerにプルリクを出すべきだとは思うが面倒なのでやってない)。

> res_gg <- ggsurvplot(fit)
> class(res_gg)
[1] "ggsurvplot" "ggsurv"     "list" 
# とりあえずggを付与する
> class(res_gg) <- c(class(res_gg), "gg")

ggplot2に限らずph_with()にオブジェクトを渡して、期待した動作をしない場合はS3ディスパッチ周りを疑ってみてほしい。

ph_location_type()で指定するidはlayout_properties()で示されるidではない

スライドにコンテンツを挿入可能なオブジェクトが複数あり、そこにテキストや図表を挿入したい場合、これらを区別して指定する必要がある。

区別にはまずtypeで指定するという方法がある。

layout_properties()でマスタを指定すると、そのマスタに含まれるオブジェクトの一覧が表示される。

例えば「表紙」という名称のオブジェクトは以下のように示される(一部のみ示す)。

# layout_properties()で取得できる情報(一部)
> layout_properties(my_pres, "表紙")
   master_name name     type id 
1          hoxom 表紙     body  5      
2          hoxom 表紙     body  6      
3          hoxom 表紙     body 22 
19         hoxom 表紙 ctrTitle  2 
20         hoxom 表紙 subTitle  3 

ここでctrTitleとsubTitleのようにオブジェクトのtypeが異なる場合、それぞれのtypeを指定すれば良い。

しかしtypeが異なる場合、idで指定する必要がある。

ここでポイントなのが、ここで指定するidはlayout_properties()で表示されるidではなく、オブジェクトの作成順に対応した1から始まる連番である。

例えば、先のマスタの場合、typeが同じオブジェクトが3つあるのでidは1〜3のどれかとなり、ここで表示されている5,6,22ではない。

# これで表示されるidを指定するとエラーになる
> layout_properties(my_pres, "表紙")
   master_name name     type id 
1          hoxom 表紙     body  5      
2          hoxom 表紙     body  6      
3          hoxom 表紙     body 22 
19         hoxom 表紙 ctrTitle  2 
20         hoxom 表紙 subTitle  3 

オブジェクトの作成順を覚えていれば問題ないが、覚えていない場合、ここは試行錯誤することになる。

私は試行錯誤した。みんなも試行錯誤してほしい。

というわけで最近のofficerでハマったことを列挙した。

とはいえかつてPowerPoint VBAをいじっていた身としてはofficerは非常に使いやすく嬉しいパッケージである。

未体験の方はぜひ使ってみてほしい。

どうかな