最近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)
そして、通常であれば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は非常に使いやすく嬉しいパッケージである。
未体験の方はぜひ使ってみてほしい。
どうかな