Rで解析:文字を枠に自動調整「ggfittext」パッケージ
ggplot2 で文字ラベルを描くとき、geom_text() では文字サイズを自分で指定するしかないため、文字が枠からはみ出したり、逆に広い余白の中で小さく間延びしたりと、体裁を整えるのに手間がかかります。
本パッケージは指定したボックスの大きさに合わせてテキストを自動で縮小・拡大・折り返しします。中心となる geom_fit_text() は、x/y による自動指定、幅と高さの明示、xmin・xmax・ymin・ymax による範囲指定という3通りの方法でボックスを定義でき、ボックス内9か所への配置、暗い塗り色に対する文字色の自動反転などにも対応します。
棒グラフ用の geom_bar_text() は、ラベルの配置位置や文字色を棒の形状に応じて自動で決めてくれます。テキストラベルの見栄え調整に悩んだときにおすすめのパッケージです。
パッケージバージョンは0.10.4。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。
<おすすめのRに関する書籍です>
パッケージのインストール
下記コマンドを実行してください。
# パッケージのインストール
install.packages("ggfittext")
# パッケージの読み込み
library("ggfittext")
# コマンド例で必要なパッケージ
# install.packages("ggplot2")
library("ggplot2")美的属性(aesthetics)
geom_fit_text() では、テキストとボックスを決めるために下記のaesへのオプション指定が必要です。
- label:描画する文字列(必須)
- xmin と xmax、または x:ボックスの横方向の範囲(必須)
- ymin と ymax、または y:ボックスの縦方向の範囲(必須)
- alpha、angle、colour、family、fill、fontface、lineheight、size:任意指定
x や y でボックスを指定した場合、幅と高さは軸上の値の間隔の0.9倍が使われます。そのため ggplot2::geom_tile() などで枠を描いて重ねる場合は、width や height に0.9を指定すると枠と文字のボックスがぴたりと揃います。なお size はポイント単位で、ミリメートル単位の ggplot2::geom_text() とは異なる点に注意してください。geom_bar_text() は x と y だけあれば動作し、label を省略した場合は棒の値がそのままラベルになります。
コマンド例
詳細はコメント、パッケージのヘルプを確認してください。
ボックス内に収まるよう文字サイズを自動調整:geom_fit_textコマンド
指定したボックスの中に収まるよう、テキストを自動で縮小・拡大・折り返しして配置します。
| オプション | 意味 | 初期値 |
|---|---|---|
| mapping | ボックスを指定する美的属性を含む ggplot2::aes() オブジェクト | NULL |
| data | このレイヤーで描画するデータ、NULL ではプロット全体のデータを継承し、データフレームや関数を渡すと上書きできる | NULL |
| stat | データに適用する統計変換、”identity” は変換しない | “identity” |
| position | データに適用する位置調整、”identity” は位置調整しない | “identity” |
| na.rm | FALSE では欠損値を警告付きで除去し、TRUE では警告なしで除去する | FALSE |
| show.legend | このレイヤーを凡例に含めるかどうか、NA では美的属性がマッピングされている場合のみ含める | NA |
| inherit.aes | FALSE では ggplot2::ggplot() で指定した既定の美的属性を継承せず上書きする | TRUE |
| padding.x | テキスト左右方向の余白、grid::unit() オブジェクトで指定する | grid::unit(1, “mm”) |
| padding.y | テキスト上下方向の余白、grid::unit() オブジェクトで指定する | grid::unit(1, “mm”) |
| min.size | 表示する最小フォントサイズ(ポイント)、これを下回るテキストは非表示になる | 4 |
| place | ボックス内のテキスト配置位置、centre、topleft、top、topright、right、bottomright、bottom、bottomleft、left の9か所を指定でき、center と middle は centre と同義 | “centre” |
| outside | TRUE では top、right、bottom、left の配置でボックスに収まらないテキストをボックスの外側に描画する | FALSE |
| grow | TRUE では縮小だけでなく拡大もおこない、テキストをボックスいっぱいに広げる | FALSE |
| reflow | TRUE ではテキストを折り返してボックス内に収める、既存の改行は維持される | FALSE |
| hjust | テキストの水平方向の揃え、既定は0.5で、左寄せ配置では0、右寄せ配置では1になる | NULL |
| vjust | テキストの垂直方向の揃え、既定は0.5 | NULL |
| fullheight | TRUE ではディセンダ(文字の下へ出る部分)をサイズ計算に含め、FALSE ではエックスハイトとアセンダのみで計算する、未指定では grow の値に応じて自動設定 | NULL |
| width | x 美的属性を使う場合のボックスの幅、grid::unit() オブジェクトか x 軸スケール上の数値で指定する | NULL |
| height | y 美的属性を使う場合のボックスの高さ、grid::unit() オブジェクトか y 軸スケール上の数値で指定する | NULL |
| formatter | 描画前にテキストへ適用する関数、要素ごとに逐次適用されるためベクトル化は不要 | NULL |
| contrast | TRUE では fill 美的属性と組み合わせて、暗い塗り色に対し文字色を反転させる | FALSE |
| flip | TRUE では極座標で上下反転したテキストを読みやすい向きに補正する | FALSE |
| rich | TRUE では gridtext::richtext_grob() による markdown と HTML の記法を有効にする、実験的機能で極座標では使用できない | FALSE |
| … | colour や fontface などレイヤー全体へ固定値として適用する美的属性を渡す | なし |
xmin と xmax で時間の範囲、y で会議室を指定したガントチャート風の予約表です。ボックスの位置は geom_tile() で描いた枠と一致させているので、枠のなかに予定名が収まる様子がそのまま確認できます。幅の広い枠では大きく、狭い枠では折り返して小さく描かれます。
# 架空の会議室予約データを作成
yoyaku <- data.frame(
room = c("第1会議室", "第1会議室", "第2会議室", "第2会議室", "第3会議室"),
start = c(9, 13, 10, 14, 9),
end = c(11, 15, 12, 15.5, 17),
plan = c("新製品キックオフ会議", "予算レビュー", "中途採用の一次面接",
"1on1面談", "データ分析ハンズオン研修"))
# 予約時間の範囲を横方向のボックス、会議室を縦軸にして予定名をプロット
ggplot(yoyaku, aes(xmin = start, xmax = end, y = room, label = plan)) +
# 予約枠を塗りと枠線で描いてボックスを可視化する、高さ0.9は geom_fit_text の既定と同じ
geom_tile(aes(x = (start + end) / 2, width = end - start),
height = 0.9, fill = "#eaf2f8", colour = "#2c7fb8") +
# 長い予定名は折り返し、それでも収まらない場合は縮小して枠内に収める
geom_fit_text(reflow = TRUE, padding.x = grid::unit(2, "mm")) +
# 横軸の目盛りを時刻表示にする
scale_x_continuous(breaks = 9:17, labels = paste0(9:17, ":00")) +
labs(x = NULL, y = NULL, title = "会議室予約表(架空データ)") +
theme_minimal(base_size = 12) +
# 予約枠を見やすくするため横方向のグリッド線を消す
theme(panel.grid.major.y = element_blank(),
panel.grid.minor.x = element_blank())
xmin・xmax・ymin・ymax でボックスの四辺を直接指定すると、任意の矩形にラベルを収められます。塗り色をaesに含めておけば、contrast = TRUE で濃い色の帯だけ文字色が反転します。なお幅の狭い帯ではラベルが min.size を下回って非表示になる場合があります。必ず表示したいときは min.size = 0 を指定します。
# 架空の社内アンケート結果を作成
kekka <- data.frame(
kaitou = factor(c("とても満足", "満足", "どちらでもない", "不満"),
levels = c("とても満足", "満足", "どちらでもない", "不満")),
ritsu = c(42, 31, 17, 10))
# 累積比率から各回答の帯の右端と左端を求める
kekka$xmax <- cumsum(kekka$ritsu)
kekka$xmin <- kekka$xmax - kekka$ritsu
# 回答と比率を改行でつないでラベルを作る
kekka$label <- paste0(kekka$kaitou, "\n", kekka$ritsu, "%")
# 帯の四辺をボックスとして指定し、内側にラベルを収める
ggplot(kekka, aes(xmin = xmin, xmax = xmax, ymin = 0, ymax = 1,
fill = kaitou, label = label)) +
# 100%積み上げ帯グラフの本体を描画する
geom_rect(colour = "white") +
# 暗い帯の上では文字色を自動で反転する
geom_fit_text(reflow = TRUE, contrast = TRUE) +
# 濃淡のはっきりした配色を手動で指定する
scale_fill_manual(values = c("#0b3d5c", "#3b7ea1", "#a9cfe3", "#e4eef5")) +
labs(x = "回答比率(%)", y = NULL, fill = "回答",
title = "社内アンケート結果(架空データ)") +
theme_minimal(base_size = 12) +
# 縦軸の目盛りとグリッド線を消す
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
panel.grid = element_blank())
棒グラフのラベル付けに特化:geom_bar_textコマンド
geom_fit_text() を棒グラフ向けに調整したコマンドです。ggplot2::geom_col() や ggplot2::geom_bar() でプロットした棒の範囲をボックスとし、配置位置・文字色・はみ出し時の外側描画を棒の範囲から自動で決めます。
| オプション | 意味 | 初期値 |
|---|---|---|
| mapping | ボックスを指定する美的属性を含む ggplot2::aes() オブジェクト | NULL |
| data | このレイヤーで描画するデータ、NULL ではプロット全体のデータを継承し、データフレームや関数を渡すと上書きできる | NULL |
| stat | データに適用する統計変換、”identity” は変換しない | “identity” |
| position | データに適用する位置調整、積み上げ棒に付けるラベルでは棒側と揃えて “stack” を指定する | “identity” |
| na.rm | FALSE では欠損値を警告付きで除去し、TRUE では警告なしで除去する | FALSE |
| show.legend | このレイヤーを凡例に含めるかどうか、NA では美的属性がマッピングされている場合のみ含める | NA |
| inherit.aes | FALSE では ggplot2::ggplot() で指定した既定の美的属性を継承せず上書きする | TRUE |
| padding.x | テキスト左右方向の余白、grid::unit() オブジェクトで指定する | grid::unit(1, “mm”) |
| padding.y | テキスト上下方向の余白、grid::unit() オブジェクトで指定する | grid::unit(1, “mm”) |
| min.size | 表示する最小フォントサイズ(ポイント)、geom_fit_text() の4ポイントより大きい8ポイントが既定 | 8 |
| place | ボックス内のテキスト配置位置、未指定では通常の向きの棒で top、横向きの棒で right となり、負の値では反対側になる | NULL |
| outside | 棒に収まらないテキストを外側に描画するかどうか、未指定では position = “identity” のとき TRUE、それ以外では FALSE になる | NULL |
| grow | TRUE では縮小だけでなく拡大もおこない、テキストをボックスいっぱいに広げる | FALSE |
| reflow | TRUE ではテキストを折り返してボックス内に収める、既存の改行は維持される | FALSE |
| hjust | テキストの水平方向の揃え、既定は0.5で、左寄せ配置では0、右寄せ配置では1になる | NULL |
| vjust | テキストの垂直方向の揃え、既定は0.5 | NULL |
| fullheight | TRUE ではディセンダ(文字の下へ出る部分)をサイズ計算に含め、FALSE ではエックスハイトとアセンダのみで計算する、未指定では grow の値に応じて自動設定 | NULL |
| width | x 美的属性を使う場合のボックスの幅、grid::unit() オブジェクトか x 軸スケール上の数値で指定する | NULL |
| height | y 美的属性を使う場合のボックスの高さ、grid::unit() オブジェクトか y 軸スケール上の数値で指定する | NULL |
| formatter | 描画前にテキストへ適用する関数、要素ごとに逐次適用されるため文字列を返す非ベクトル化関数でよい | NULL |
| contrast | fill 美的属性と組み合わせて暗い塗り色に対し文字色を反転させるかどうか、未指定では文字色が既定の黒のままなら TRUE になる | NULL |
| rich | TRUE では gridtext::richtext_grob() による markdown と HTML の記法を有効にする、実験的機能で極座標では使用できない | FALSE |
| … | colour や fontface などレイヤー全体へ固定値として適用する美的属性を渡す | なし |
label を指定しない場合は棒の値がそのままラベルになります。棒が短くて文字が入りきらない場合は、棒の外側に描画されます。
# 架空の店舗別売上データを作成
uriage <- data.frame(
shop = c("札幌本店", "旭川店", "函館店", "釧路店", "帯広店"),
sales = c(1280, 860, 540, 210, 95))
# 棒グラフに売上値のラベルを付ける
ggplot(uriage, aes(x = shop, y = sales)) +
# 棒グラフの本体を描画する
geom_col(fill = "#2c7fb8") +
# label 未指定なので y の値がラベルになり、短い棒では外側に描画される
geom_bar_text() +
labs(x = NULL, y = "売上(千円)", title = "店舗別売上(架空データ)") +
theme_minimal(base_size = 12)
積み上げ棒に付ける場合は、棒側と同じ position を指定します。formatter を使うと、元データを加工せずにラベルだけへ単位を付けられます。
# 架空の店舗別・商品カテゴリ別売上データを作成
uriage2 <- data.frame(
shop = rep(c("札幌本店", "旭川店", "函館店"), each = 3),
category = rep(c("書籍", "文房具", "雑貨"), times = 3),
sales = c(620, 410, 250, 380, 300, 180, 210, 190, 140))
# 積み上げ棒の各区画にラベルを収める
ggplot(uriage2, aes(x = shop, y = sales, fill = category, label = sales)) +
# 積み上げ棒グラフの本体を描画する
geom_col(position = "stack") +
# 棒と同じ position を指定し、formatter でラベルに単位を付ける
geom_bar_text(position = "stack", formatter = function(x) paste0(x, "千円"), contrast = TRUE) +
# 濃淡のはっきりした配色を指定
scale_fill_manual(values = c("#0b3d5c", "#3b7ea1", "#a9cfe3")) +
labs(x = NULL, y = "売上(千円)", fill = "カテゴリ", title = "店舗別・カテゴリ別売上(架空データ)") +
theme_minimal(base_size = 12)
<おすすめのRに関する書籍です>
この記事が誰かの役に立ちますように。