Rで解析:WordとPowerPointをコードで操作する「officer」パッケージの紹介
officerは、Microsoft Word(.docx)とPowerPoint(.pptx)をRだけで生成・編集できるパッケージです。ファイルの内部形式であるOffice Open XMLを直接操作するため、Microsoft Office本体はもちろん外部ソフトを一切必要とせず、Windows・macOS・Linuxのいずれでも同じコードが動きます。空の文書をゼロから作るだけでなく、既存ファイルを雛形として読み込み、見出し・段落・表・画像・グラフの追加から文字列の一括置換までをコードで完結できます。分析のたびに手作業で資料を作り直す必要がなくなるため、集計結果や定型レポートを毎回同じ体裁で自動生成したい場面で特に威力を発揮します。flextableやrvg、mschartと組み合わせれば、体裁の整った表やベクター画像、ネイティブなグラフの埋め込みも可能です。
パッケージバージョンは0.7.6。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。
<おすすめのRに関する書籍です>
パッケージのインストール
下記コマンドを実行してください。
# officerパッケージをインストールする(初回のみ実行すればよい)
install.packages("officer")
# インストール済みのパッケージを読み込み、関数を使えるようにする
library("officer")コマンド例
詳細はコメント、パッケージのヘルプを確認してください。
Word文書オブジェクトを新規作成する:read_docxコマンド
read_docxはWord文書の操作の起点となる関数です。引数pathを省略すると空の新規文書を、既存の.docxや雛形の.dotxを渡すとそのファイルを読み込んだ状態のオブジェクトを取得します。ここでは新規作成した文書に、見出しや本文(body_add_par)、書式付きの段落(body_add_fpar・fpar・ftext)、データフレームの表(body_add_table)、Rの作図結果(plot_instr・body_add_plot)を順に追加し、1つの読書記録レポートを作成する例を示します。保存先は作業フォルダでTest.docxが作成されます。
| オプション | 意味 | 初期値 |
|---|---|---|
| path | ドキュメントの基礎となるdotxファイルのパス | NULL |
# テキスト・書式付き段落・表・グラフをセクションごとに構成した
# 文書を作成する例
# read_docx()で新規のWord文書オブジェクトを作成する
# 以降はこのdocに要素を追加しながら文書を組み立てていく
doc <- read_docx()
## 文字を追加する:body_add_parコマンド
# 文書の先頭にメインタイトルを「heading 1」スタイルで追加する
doc <- body_add_par(doc, "読書記録レポート", style = "heading 1")
# fparとftextで、一部だけ色や太字にした書式付きの導入文を作る
# ftextで装飾したい語句を、fp_text_liteでその書式(太字・色など)を指定する
intro_text <- fpar(
"この文書は、今年の",
ftext(
"月別読書冊数の集計",
fp_text_lite(bold = TRUE, color = "#C32900")
),
"をまとめたものです。以下のセクションで詳細な傾向を紹介します。"
)
# 作成した書式付き段落をbody_add_fparで文書に追加する
doc <- body_add_fpar(doc, intro_text)
## セクション1:読書データ ----
# セクションの見出しを「heading 2」スタイルで追加する
doc <- body_add_par(doc, "月別読書冊数", style = "heading 2")
# 表の前に置く説明文を通常段落として追加する
doc <- body_add_par(
doc,
"下記の表はジャンルごとの読書冊数をまとめたものです。"
)
# 表の元になるデータフレームを作成する(月別の冊数・ページ数・前月比)
reading_data <- data.frame(
Month = c("4月", "5月", "6月", "7月"),
Books = c(3, 5, 4, 7),
Pages = c(620, 980, 750, 1240),
Growth = c("−", "58.1%", "-23.4%", "65.3%"),
stringsAsFactors = FALSE
)
# body_add_tableでデータフレームを表として追加する(styleで表の体裁を指定)
doc <- body_add_table(doc, value = reading_data, style = "table_template")
# 数値の一部を強調した補足コメントを書式付き段落で作成する
comment <- fpar(
"特筆すべき点:",
ftext(
"7月は最もページ数が多かった月",
fp_text_lite(bold = TRUE, font.size = 11)
),
"で、前月比",
ftext("65.3%増加", fp_text_lite(color = "#006699", bold = TRUE)),
"しました。"
)
doc <- body_add_fpar(doc, comment)
## セクション2:グラフ ----
# 2つ目のセクションの見出しを追加する
doc <- body_add_par(doc, "ページ数の推移", style = "heading 2")
# グラフの前に置く説明文を追加する
doc <- body_add_par(
doc,
"図1は月ごとのページ数の推移を示しています。"
)
# plot_instrの中にRの作図コードを書くと、その描画結果を図として取り込める
# ここでは月別ページ数の棒グラフを作成する
pages_plot <- plot_instr({
months <- c("4月", "5月", "6月", "7月")
pages <- c(620, 980, 750, 1240)
barplot(
pages,
names.arg = months,
col = "#4472C4",
border = NA,
main = "月別ページ数",
ylab = "ページ数",
xlab = "月",
ylim = c(0, 1500)
)
# 目盛りを見やすくする補助線(横線のみ)を引く
grid(nx = NA, ny = NULL, col = "gray90", lty = 1)
})
# 作成した棒グラフをbody_add_plotで文書に追加する(width・heightはインチ単位)
doc <- body_add_plot(doc, pages_plot, width = 6, height = 4)
## セクション3:分布図 ----
# 3つ目のセクションの見出しを追加する
doc <- body_add_par(doc, "1日あたりの読書時間の分布", style = "heading 2")
# 2つ目のグラフの説明文を書式付き段落で作成する
analysis_intro <- fpar(
"下記の分布図は、",
ftext("1日あたりの読書時間のばらつき", fp_text_lite(italic = TRUE)),
"を示しています。生活リズムの変化を把握するのに役立ちます。"
)
doc <- body_add_fpar(doc, analysis_intro)
# 1日あたりの読書時間の密度プロット(分布図)を作成する
duration_plot <- plot_instr({
# 説明用に、1日あたりの読書時間(分)の疑似データを生成する
# set.seedで乱数を固定し、毎回同じ結果になるようにする
set.seed(123)
daily_minutes <- c(
# 4〜6月:平均20分程度
rnorm(90, mean = 20, sd = 8),
# 7月:夏休みで増加傾向、平均35分程度
rnorm(30, mean = 35, sd = 10)
)
# densityで推定した分布を折れ線で描画する
plot(
density(daily_minutes),
main = "1日あたりの読書時間の分布",
xlab = "読書時間(分)",
ylab = "密度",
col = "#C32900",
lwd = 2
)
# 分布曲線の下側を半透明の色で塗りつぶす
polygon(density(daily_minutes), col = rgb(0.76, 0.16, 0, 0.2), border = NA)
# 平均値の位置に縦の破線を引く
abline(v = mean(daily_minutes), col = "#006699", lwd = 2, lty = 2)
# 平均値の破線の凡例を右上に表示する
legend("topright", legend = "平均値", col = "#006699", lty = 2, lwd = 2)
})
doc <- body_add_plot(doc, duration_plot, width = 6, height = 4)
## まとめ ----
# 最後に結び(まとめ)のセクションを追加する
doc <- body_add_par(doc, "まとめ", style = "heading 2")
conclusion <- fpar(
"全体を通して",
ftext("読書量の増加傾向", fp_text_lite(bold = TRUE, color = "#006699")),
"が見られ、特に7月は大きく伸びました。",
"夏休み期間に読書時間が増えたことが要因と考えられます。"
)
doc <- body_add_fpar(doc, conclusion)
# printのtargetに保存先パスを渡し、作業フォルダにTest.docxとして書き出す
print(doc, target = paste0(getwd(), "/","Test.docx"))
パワーポイントの特定のIDのプレースホルダーに文字を挿入する:ph_location_idコマンド
プレースホルダー(仮の文字や入力枠)をidで指定するための関数です。プレースホルダーのidは同一レイアウト内で一意に割り振られており、「layout_properties」や「plot_layout_properties」で確認できます。
| オプション | 意味 | 初期値 |
|---|---|---|
| id | プレースホルダーのID | |
| newlabel | プレースホルダーに関連付ける新しいラベル | NULL |
## ph_location_idを使う例:スライドの各枠にIDを指定して文字を入れる
# read_pptxで新規のPowerPointオブジェクトを作成する
doc <- read_pptx()
# add_slideで「Comparison(比較)」レイアウトのスライドを1枚追加する
doc <- add_slide(doc, "Comparison")
# plot_layout_propertiesでレイアウトを図示し、各枠のIDを確認する
# (各ボックスの右上にIDが表示される)
plot_layout_properties(doc, "Comparison")
# ph_location_id(id = 2)でID2の枠を指定し、ph_withでその枠に文字を入れる
doc <- ph_with(doc, "第2四半期の比較", location = ph_location_id(id = 2))
# ID3の枠に文字を入れる
doc <- ph_with(doc, "国内売上", location = ph_location_id(id = 3))
# ID4の枠に文字を入れる
doc <- ph_with(doc, "前年同期比 +8%", location = ph_location_id(id = 4))
# ID8の枠に文字を入れる
doc <- ph_with(doc, "社内資料", location = ph_location_id(id = 8))
# 作業フォルダにTest.pptxとして書き出す
print(doc, target = paste0(getwd(), "/","Test.pptx"))・レイアウトをプロットして確認

・作業フォルダにTest.pptxとして書き出す

<おすすめのRに関する書籍です>
複数のブロックを連結して新しい文書を作成:block_listコマンド
複数のブロックをまとめて操作したい場合に使用します。
# ブロックの部品を準備する
# R同梱のサンプル画像(Rロゴ)のパスを取得する
img.file <- file.path(R.home("doc"), "html", "logo.jpg")
# 青色・太字のテキスト書式を定義する
fpt_blue_bold <- fp_text(color = "#006699", bold = TRUE)
# 赤色・斜体のテキスト書式を定義する
fpt_red_italic <- fp_text(color = "#C32900", italic = TRUE)
## この例はWord文書の出力でのみ利用できます
## (pptxはテキストと画像を組み合わせた段落に対応していないため)
## (指定自体は可能ですが、pptx出力では画像は表示されません)
# block_listで複数のfpar(段落)をひとまとめのブロックにする
value <- block_list(
# 1段落目:青太字のあいさつ
fpar(ftext("おはようございます", fpt_blue_bold)),
# 2段落目:青太字と赤斜体を組み合わせた文
fpar(ftext("今日は", fpt_blue_bold), " ",
ftext("晴れです", fpt_red_italic)),
# 3段落目:赤斜体の文と画像を同じ段落に配置する
fpar(
ftext("良い一日を", fpt_red_italic),
external_img(
src = img.file, height = 1.06, width = 1.39)))
# 新規のWord文書を作成する
doc <- read_docx()
# body_addでブロックリストの内容をまとめて文書に追加する
doc <- body_add(doc, value)
# 作業フォルダにTest_2.docxとして書き出す
print(doc, target = paste0(getwd(), "/","Test_2.docx"))
セクションを区切るためのコマンド:block_sectionコマンド
| オプション | 意味 | 初期値 |
|---|---|---|
| property | prop_section()で定義したセクションプロパティ |
# prop_sectionでセクションのページ設定(向き・余白・種類)をまとめて定義する
prop_section(
# 用紙の向きを横向き(ランドスケープ)に指定する
page_size = page_size(orient = "landscape"),
# 上部の余白を2インチに設定する(page_marの単位はインチ)
page_margins = page_mar(top = 2),
# セクションの種類。"continuous"は改ページせず続ける設定
type = "continuous"
)
$type
[1] "continuous"
$page_size
$width
[1] 11.69306
$height
[1] 8.268056
$orient
[1] "landscape"
attr(,"class")
[1] "page_size"
$page_margins
$header
[1] 0.4916667
$bottom
[1] 0.9840278
$top
[1] 2
$right
[1] 0.9840278
$left
[1] 0.9840278
$footer
[1] 0.4916667
$gutter
[1] 0
attr(,"class")
[1] "page_mar"
attr(,"class")
[1] "prop_section" "prop" いろいろなコンテンツを文書に追加する:body_addコマンド
| オプション | 意味 | 初期値 |
|---|---|---|
| x | rdocxオブジェクト | |
| value | ドキュメントに追加するオブジェクト(文字列ベクトル、data.frame、グラフ、書式付き段落のブロックなど) | |
| style | 段落スタイル名 | NULL |
| format_fun | 値のフォーマットに使う関数 | formatC |
| header | 表のヘッダーを表示するかどうか | TRUE |
| tcf | 表の条件付き書式設定 | table_conditional_formatting() |
| alignment | 列の配置。列数と長さが一致する必要があり、値は「l」(左)「r」(右)「c」(中央)のいずれか | NULL |
| width | 画像サイズ(unit引数で指定する単位) | 6 |
| height | 画像サイズ(unit引数で指定する単位) | 5 |
| res | png画像の解像度(ppi) | 300 |
| scale | 乗算スケーリングファクター。ggsaveと同様 | 1 |
| unit | 長さの単位。「in」「cm」「mm」のいずれか | “in” |
# body_add()の汎用性を示す例
# 見出し・目次・改ページ・表・段落・図・セクション区切りを、すべてbody_addだけで追加する
# 新規のWord文書を作成する
doc <- read_docx()
# 目次ページ用の見出しを「heading 1」スタイルで追加する
doc <- body_add(doc, "目次", style = "heading 1")
# block_tocで自動目次を挿入する
# この時点では枠だけが入り、Wordで開いてフィールドを更新すると見出し一覧が表示される
doc <- body_add(doc, block_toc())
# run_pagebreakで改ページを挿入し、本文を次のページから始める
doc <- body_add(doc, run_pagebreak())
# 本文の大見出しを追加する
doc <- body_add(doc, "読書記録サンプル", style = "heading 1")
# 表として差し込むデータフレームを作成する
reading_data <- data.frame(
Month = c("4月", "5月", "6月", "7月"),
Books = c(3, 5, 4, 7),
Pages = c(620, 980, 750, 1240),
stringsAsFactors = FALSE
)
# データフレームを表として追加する
# head()は既定で先頭6行を返す関数で、行数の多いデータで表が長くなりすぎるのを防ぐ
# (この例のデータは4行のため、結果は全4行になる)
doc <- body_add(doc, head(reading_data), style = "table_template")
# 別の見出しを追加する
doc <- body_add(doc, "読書ジャンル一覧", style = "heading 1")
# 文字列ベクトルを段落として追加する
# body_addに長さ2以上のベクトルを渡すと、要素ごとに独立した段落が作られる
# (ここでは5つのジャンルがそれぞれ「Normal」スタイルの段落になる)
genres <- c("小説", "エッセイ", "ビジネス書", "技術書", "歴史書")
doc <- body_add(doc, genres, style = "Normal")
# block_sectionでセクション区切り(continuous)を挿入する
# 改ページせず同じページのまま、以降のセクション設定を切り替えられる
doc <- body_add(doc, block_section(prop_section(type = "continuous")))
# plot_instrに作図コードを渡し、Rの基本グラフィックスの図を追加する
xdoc <- body_add(doc, plot_instr(code = barplot(1:5, col = 2:6)))
# 以降のセクションを横向き(ランドスケープ)に切り替える
# ページの向きだけが異なる新しいセクションが作られる
doc <- body_add(doc,
block_section(prop_section(page_size = page_size(orient = "landscape"))))
# 作業フォルダにTest_3.docxとして書き出す
print(doc, target = paste0(getwd(), "/","Test_3.docx"))
<おすすめのRに関する書籍です>
特定の文字列を置き換えるコマンド:body_replace_all_textコマンド
指定されたテキストをドキュメント中で全て置き換えることができます。例えば、誤った情報を正しいものに更新する際に便利です。
| オプション | 意味 | 初期値 |
|---|---|---|
| x | 対象のdocxオブジェクト | |
| old_value | 置き換え対象の値 | |
| new_value | 置き換え後の値 | |
| only_at_cursor | 現在のカーソル位置でのみ検索置換するかどうか | FALSE |
| warn | 古い値が見つからない場合に警告するか | TRUE |
# 置換の動作を確認するため、仮の文書を用意する
doc <- read_docx()
doc <- body_add_par(doc, "仮タイトルその1")
doc <- body_add_par(doc, "仮タイトルその2")
# docx_show_chunkで現在のカーソル位置にあるテキストを表示する
# 直前に追加した段落が対象なので、出力結果は「仮タイトルその2」
docx_show_chunk(doc)
# カーソル位置のみを対象に、正規表現を無効(fixed = TRUE)にして単純置換する
doc <- body_replace_all_text(
doc,
old_value = "仮タイトル",
new_value = "本タイトル",
only_at_cursor = TRUE,
fixed = TRUE)
# カーソル位置の段落だけが置換され、出力結果は「本タイトルその2」
docx_show_chunk(doc)
# 大文字小文字を区別せず(ignore.case = TRUE)、文書全体を対象に同じ置換を行う
doc <- body_replace_all_text(
doc,
old_value = "仮タイトル",
new_value = "本タイトル",
only_at_cursor = FALSE,
ignore.case = TRUE)
# cursor_backwardでカーソルを1つ前の段落に戻す
doc <- cursor_backward(doc)
# 戻した先の段落を確認する。出力結果は「本タイトルその1」
docx_show_chunk(doc)
# 正規表現で、末尾の数字を丸括弧付きの番号に変換する(\\1は後方参照)
doc <- body_replace_all_text(doc, "([0-9])$", "(\\1)")
# 末尾の「1」が「(1)」になり、出力結果は「本タイトルその(1)」
docx_show_chunk(doc)# 置換の動作を確認するため、仮の文書を用意する
doc <- read_docx()
doc <- body_add_par(doc, "仮タイトルその1")
doc <- body_add_par(doc, "仮タイトルその2")
# docx_show_chunkで現在のカーソル位置にあるテキストを表示する
# 直前に追加した段落が対象なので、出力結果は「仮タイトルその2」
docx_show_chunk(doc)
# カーソル位置のみを対象に、正規表現を無効(fixed = TRUE)にして単純置換する
doc <- body_replace_all_text(
doc,
old_value = "仮タイトル",
new_value = "本タイトル",
only_at_cursor = TRUE,
fixed = TRUE)
# カーソル位置の段落だけが置換され、出力結果は「本タイトルその2」
docx_show_chunk(doc)
# 大文字小文字を区別せず(ignore.case = TRUE)、文書全体を対象に同じ置換を行う
doc <- body_replace_all_text(
doc,
old_value = "仮タイトル",
new_value = "本タイトル",
only_at_cursor = FALSE,
ignore.case = TRUE)
# cursor_backwardでカーソルを1つ前の段落に戻す
doc <- cursor_backward(doc)
# 戻した先の段落を確認する。出力結果は「本タイトルその1」
docx_show_chunk(doc)
# 正規表現で、末尾の数字を丸括弧付きの番号に変換する(\\1は後方参照)
doc <- body_replace_all_text(doc, "([0-9])$", "(\\1)")
# 末尾の「1」が「(1)」になり、出力結果は「本タイトルその(1)」
docx_show_chunk(doc)ggplotオブジェクトを文書に埋め込む:block_ggコマンド
| オプション | 意味 | 初期値 |
|---|---|---|
| value | ggplotオブジェクト | |
| fp_p | 段落書式設定プロパティ。fp_par()を参照 | fp_par() |
| width | 画像サイズ(unit引数で指定する単位) | 6 |
| height | 画像サイズ(unit引数で指定する単位) | 5 |
| res | png画像の解像度(ppi) | 300 |
| scale | 乗算スケーリングファクター。ggsaveと同様 | 1 |
| unit | 長さの単位。「in」「cm」「mm」のいずれか | “in” |
# ggplot2が使える場合のみ実行する
if (require("ggplot2")) {
# 乱数を固定し、毎回同じグラフになるようにする
set.seed(2)
# 新規のWord文書を作成する
doc <- read_docx()
# body_append_start_contextで、要素をまとめて追記するための作業コンテキストを開始する
z <- body_append_start_context(doc)
# 3枚分のグラフを繰り返し作成して追記する
for (i in seq_len(3)) {
# 気温と湿度の疑似観測データを生成する
df <- data.frame(
temperature = rnorm(10, mean = 25, sd = 3),
humidity = rnorm(10, mean = 60, sd = 10)
)
# 気温と湿度の散布図を作成する
gg <- ggplot(df, aes(x = temperature, y = humidity)) + geom_point()
# write_elements_to_contextで、block_ggにしたグラフをコンテキストに書き込む
write_elements_to_context(
context = z,
block_gg(
value = gg
)
)
}
# body_append_stop_contextで追記を確定し、文書オブジェクトに反映する
doc <- body_append_stop_context(z)
# 作業フォルダにTest_4.docxとして書き出す
print(doc, target = paste0(getwd(), "/","Test_4.docx"))
}
<おすすめのRに関する書籍です>
この記事が誰かの役に立ちますように。