本文へスキップ
からだにいいもの

Rのトピックスを中心に『まだ、まだ、知らない、役に立つ情報?』を発信します。

Rで解析:円グラフとドーナツグラフをプロットする

「ggpubr」パッケージは、項目ごとの数値から円グラフとドーナツグラフを作ることができます。渡すものは、項目名の列と数値の列を持つデータフレームです。ggplot2の上に乗る拡張なので、出来上がったものに色や文字をあとから足せます。この記事では、ggplot2だけで内訳を2重の輪にした円グラフと、月ごとの量を花びらの形で示すローズグラフを作る方法も合わせてまとめました。全体に対する割合を1枚で示したいときの、選択肢になるのではないかと考えます。

パッケージバージョンは1.0.0。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。

パッケージのインストール

下記コマンドを実行してください。

# パッケージのインストール
install.packages("ggpubr")
スポンサーリンク

コマンド例

詳細はコメント、パッケージのヘルプを確認してください。

略語=日本語の意味:
・aes:Aesthetic mappingの略で、データの列をプロットの見た目へ対応づける仕組み
・ha:ヘクタール。1haは10,000平方メートル
・ローズグラフ:同じ角度の扇を円周に並べ、扇の長さで量を示すプロット。鶏頭図とも呼ぶ

円グラフは、合計を360度に割り当て、項目の値の大きさを扇の角度に置き換えたものです。そのため元になるデータは、項目名の列と、集計済みの数値の列が1つずつあれば足ります。ドーナツグラフは同じものの中心を抜いた形で、抜いた場所に合計や表題を置けます。

まず、例で共通して使うデータを作ります。京都府和束町の茶園で、品種ごとの作付面積をまとめた想定の架空データです。

# パッケージの読み込み
library("ggplot2")
library("ggpubr")

# 和束町の茶園の品種別作付面積(ha)
ChaMenseki <- data.frame(
  Hinshu = c("やぶきた", "さみどり", "おくみどり", "ごこう", "その他"),
  Menseki = c(52.4, 23.1, 15.6, 9.8, 6.7)
)

# 扇の並び順を面積の多い順に固定
ChaMenseki$Hinshu <- factor(ChaMenseki$Hinshu, levels = ChaMenseki$Hinshu)

# 5つの区分に当てる色
Iro <- c("#2F5D2A", "#4E7A3A", "#6E9C4B", "#8FB86A", "#9E9E9E")

# 中身を確認
ChaMenseki
      Hinshu Menseki
1   やぶきた    52.4
2   さみどり    23.1
3 おくみどり    15.6
4     ごこう     9.8
5     その他     6.7

内訳を円グラフにする:ggpieコマンド

数値の列と、扇に添える文字の列を指定します。列名は文字列で渡します。fillオプションに列名を渡すと、その列の値ごとに扇を塗り分けます。

# 品種ごとの作付面積を円グラフにする
# 扇の角度に使う数値の列を指定:xオプション
# 扇に添える文字の列を指定:labelオプション
# 扇の塗り分けに使う列を指定:fillオプション
# 扇の境目の色を指定:colorオプション
# 塗り分けに使う色を指定:paletteオプション
# 凡例を消す:legendオプション
ggpie(ChaMenseki,
  x = "Menseki", label = "Hinshu",
  fill = "Hinshu", color = "white", palette = Iro,
  legend = "none"
)

品種ごとの作付面積を円グラフにする扇の角度に使う数値の列を指定:xオプション扇に添える文字の列を指定:labelオプション扇の塗り分けに使う列を指定:fillオプション扇の境目の色を指定:colorオプション塗り分けに使う色を指定:paletteオプション凡例を消す:legendオプション

ggpieコマンドは値をそのまま扇の角度にするだけで、割合の計算はしません。百分率を見せたいときは、自分で列を作ってlabelオプションに渡します。lab.posオプションを”in”にすると、文字が扇の中に入ります。

# 全体に対する割合(%)の文字を作る
ChaMenseki$Wariai <- paste0(
  round(ChaMenseki$Menseki / sum(ChaMenseki$Menseki) * 100, 1), "%"
)

# 割合を扇の中に入れる
# 文字の位置を扇の中にする:lab.posオプション
# 文字の大きさ・太さ・色を指定:lab.fontオプション
# 凡例の表題を指定:legend.titleオプション
ggpie(ChaMenseki,
  x = "Menseki", label = "Wariai",
  lab.pos = "in", lab.font = c(4, "bold", "white"),
  fill = "Hinshu", color = "white", palette = Iro,
  legend = "right", legend.title = "品種"
)

割合を扇の中に入れる文字の位置を扇の中にする:lab.posオプション文字の大きさ・太さ・色を指定:lab.fontオプション凡例の表題を指定:legend.titleオプション

オプション意味初期値
dataもとになるデータフレームなし
x扇の角度に使う数値が入った列の名前なし
label扇に添える文字が入った列の名前x
lab.pos文字を置く位置。”out”は扇の外、”in”は扇の中c(“out”, “in”)
lab.adjustlab.pos = “in”のときの文字の位置の微調整。増減させて効き方を確かめる0
lab.font文字の大きさ・字体・色をこの順で並べた長さ3のベクトル。字体は”plain”、”bold”、”italic”、”bold.italic”c(4, “plain”, “black”)
font.family文字に使うフォントの名前“”
color扇の輪郭の色“black”
fill扇の塗りつぶしの色、または塗り分けに使う列の名前“white”
palette塗り分けに使う色。”grey”、”RdBu”などのbrewerパレット、c(“blue”, “red”)のような自前の色、ggsciパッケージの”npg”、”aaas”、”lancet”、”jco”などが使えるNULL
size点と輪郭の太さNULL
ggtheme使うテーマ。NULLにするとggpubrのテーマを当てず、ggplot2の既定またはtheme_set()で決めたテーマのままになるtheme_pubr()
…ggparコマンドへ渡す、そのほかのオプションなし

中心を抜いてドーナツグラフにする:ggdonutchartコマンド

オプションの並びはggpieコマンドとほぼ同じで、label.repelオプションが1つ増えます。これをTRUEにすると、小さな扇の文字が重ならないよう外側へ散らし、引き出し線でつなぎます。

# 同じデータを中心の抜けた輪にする
# 文字を輪の外に置く:lab.posオプション
# 文字を散らして引き出し線でつなぐ:label.repelオプション
ggdonutchart(ChaMenseki,
  x = "Menseki", label = "Hinshu",
  lab.pos = "out", label.repel = TRUE,
  fill = "Hinshu", color = "white", palette = Iro
) +
  theme(legend.position = "none")

同じデータを中心の抜けた輪にする文字を輪の外に置く:lab.posオプション文字を散らして引き出し線でつなぐ:label.repelオプション

オプション意味初期値
dataもとになるデータフレームなし
x扇の角度に使う数値が入った列の名前なし
label扇に添える文字が入った列の名前x
lab.pos文字を置く位置。”out”は輪の外、”in”は輪の中c(“out”, “in”)
lab.adjustlab.pos = “in”のときの文字の位置の微調整。増減させて効き方を確かめる0
lab.font文字の大きさ・字体・色をこの順で並べた長さ3のベクトル。字体は”plain”、”bold”、”italic”、”bold.italic”c(4, “plain”, “black”)
label.repelTRUEにすると、扇の文字をggrepelパッケージのgeom_text_repelコマンドで輪の周りへ散らし、引き出し線でつなぐ。小さな扇が多いときに文字が重ならない。TRUEのときlab.posは効かないFALSE
font.family文字に使うフォントの名前“”
color扇の輪郭の色“black”
fill扇の塗りつぶしの色、または塗り分けに使う列の名前“white”
palette塗り分けに使う色。”grey”、”RdBu”などのbrewerパレット、c(“blue”, “red”)のような自前の色、ggsciパッケージの”npg”、”aaas”、”lancet”、”jco”などが使えるNULL
size点と輪郭の太さNULL
ggtheme使うテーマ。NULLにするとggpubrのテーマを当てず、ggplot2の既定またはtheme_set()で決めたテーマのままになるtheme_pubr()
…ggparコマンドへ渡す、そのほかのオプションなし

生のデータを数えて円グラフにする:tableコマンド

ggpieコマンドが受け取るのは集計済みの表です。1行が1件という形の記録から作るときは、先に件数を数えます。tableコマンドの結果をas.data.frameコマンドでデータフレームに直せば、そのまま渡せます。

# 乱数を固定
set.seed(731)

# 和束町の直売所で1日に売れたお茶の記録
Uriage <- data.frame(
  Shurui = sample(c("煎茶", "抹茶", "ほうじ茶", "玄米茶"),
    size = 120, replace = TRUE,
    prob = c(0.40, 0.25, 0.20, 0.15)
  )
)

# 種類ごとの件数を数えてデータフレームに直す
UriageShukei <- as.data.frame(table(Uriage$Shurui), stringsAsFactors = FALSE)
names(UriageShukei) <- c("Shurui", "Kensu")

# 件数の多い順に並べ替え、その順序を扇の並びに使う
UriageShukei <- UriageShukei[order(-UriageShukei$Kensu), ]
UriageShukei$Shurui <- factor(UriageShukei$Shurui, levels = UriageShukei$Shurui)

# 数えた結果を確認
UriageShukei
    Shurui Kensu
3     煎茶    50
1 ほうじ茶    31
4     抹茶    24
2   玄米茶    15

# 数えた結果をそのまま円グラフにする
ggpie(UriageShukei,
  x = "Kensu", label = "Shurui",
  fill = "Shurui", color = "white", palette = Iro[1:4],
  legend = "none"
)

数えた結果をそのまま円グラフにする

内訳を2重の輪にする:coord_polarコマンド

円グラフは、積み上げた棒を極座標に置き換えたものです。この仕組みを使うと、内側に大きな区分、外側にその内訳という2重の輪を作れます。ggplot2のcoord_polarコマンドは、直交座標のプロットを極座標に読み替えるもので、thetaオプションでどちらの軸を角度に対応させるかを決めます。

2つの輪をぴったり重ねるため、扇の始まりと終わりを累積和で自分で計算し、geom_rectコマンドで長方形として積みます。内側と外側で塗り分けの基準が違うので、区分名を1つの列にまとめて色を当てています。

# 3つの産地の品種別作付面積(ha)
SanchiHinshu <- data.frame(
  Sanchi = rep(c("和束町", "宇治田原町", "南山城村"), each = 3),
  Hinshu = rep(c("やぶきた", "さみどり", "おくみどり"), times = 3),
  Menseki = c(52.4, 23.1, 15.6, 28.7, 12.4, 9.5, 18.3, 7.9, 6.2)
)

# 産地の並び順を固定
SanchiHinshu$Sanchi <- factor(SanchiHinshu$Sanchi,
  levels = c("和束町", "宇治田原町", "南山城村")
)

# 内側の輪:産地ごとの合計から、扇の始まりと終わりを決める
Uchiwa <- aggregate(Menseki ~ Sanchi, data = SanchiHinshu, FUN = sum)
Uchiwa$Owari <- cumsum(Uchiwa$Menseki)
Uchiwa$Hajime <- c(0, head(Uchiwa$Owari, -1))
Uchiwa$Kubun <- as.character(Uchiwa$Sanchi)

# 外側の輪:産地と品種の組み合わせを、内側と同じ順に並べる
Sotowa <- SanchiHinshu[order(SanchiHinshu$Sanchi), ]
Sotowa$Owari <- cumsum(Sotowa$Menseki)
Sotowa$Hajime <- c(0, head(Sotowa$Owari, -1))
Sotowa$Kubun <- Sotowa$Hinshu

# 内側の3区分と外側の3区分に当てる色
IroKubun <- c(
  "和束町" = "#2F5D2A", "宇治田原町" = "#4E7A3A",
  "南山城村" = "#7FA95C", "やぶきた" = "#C7DCA7",
  "さみどり" = "#E2EBCE", "おくみどり" = "#F2F5E8"
)

# 長方形を2列に積み、極座標に置き換えて2重の輪にする
# 角度に対応させる軸を指定:thetaオプション
ggplot() +
  geom_rect(
    data = Uchiwa,
    aes(
      xmin = 0.5, xmax = 1.5, ymin = Hajime, ymax = Owari,
      fill = Kubun
    ),
    color = "white"
  ) +
  geom_rect(
    data = Sotowa,
    aes(
      xmin = 1.5, xmax = 2.5, ymin = Hajime, ymax = Owari,
      fill = Kubun
    ),
    color = "white"
  ) +
  coord_polar(theta = "y") +
  xlim(0, 2.5) +
  scale_fill_manual(values = IroKubun, breaks = names(IroKubun), name = NULL) +
  theme_void(base_size = 12)

長方形を2列に積み、極座標に置き換えて2重の輪にする角度に対応させる軸を指定:thetaオプション

オプション意味初期値
theta角度に対応させる軸。”x”または”y”“x”
start12時の位置から測った始点のずれ。単位はラジアンで、向きはdirectionに従う0
direction扇の進む向き。1は時計回り、-1は反時計回り1
clipプロット領域からはみ出した部分を切り取るかどうか。”on”は切り取る、”off”は切り取らない“on”

月ごとの量をローズグラフにする:geom_colコマンド

ローズグラフは、扇の角度をそろえ、長さで量を示すプロットです。円グラフと違って合計に対する割合ではなく量そのものを比べるので、月や方角のように一周して戻る値と相性がよい形です。棒グラフのx軸を角度に対応させると作れます。

# 和束町の直売所が1年で売った煎茶の月別出荷量(kg)
TsukibetsuShukka <- data.frame(
  Tsuki = factor(paste0(1:12, "月"), levels = paste0(1:12, "月")),
  Ryo = c(120, 95, 180, 640, 1480, 1120, 530, 410, 620, 880, 340, 210)
)

# 12本の棒を同じ角度で並べ、長さで量を示す
# 角度に月を対応させる:thetaオプション
# 棒を隙間なく並べる:widthオプション
ggplot(TsukibetsuShukka, aes(x = Tsuki, y = Ryo, fill = Ryo)) +
  geom_col(width = 1, color = "white") +
  coord_polar(theta = "x") +
  scale_fill_gradient(low = "#D7E3BC", high = "#2F5D2A", name = "出荷量(kg)") +
  labs(x = NULL, y = NULL) +
  theme_minimal(base_size = 12)

12本の棒を同じ角度で並べ、長さで量を示す角度に月を対応させる:thetaオプション棒を隙間なく並べる:widthオプション

ggpubrパッケージのほかのコマンドはRで解析:ggplot2を簡単に!「ggpubr」パッケージを参照してください。

他の円グラフの作成方法は、

・地図や散布図の上に小さな円グラフを並べたいときRで解析:複数の円グラフを簡単に作成可能!!「PieGlyph」パッケージとRで解析:円グラフの散布図を作成!「scatterpie」パッケージ

・マウスを乗せると値が出る円グラフはRで解析:インタラクティブな円グラフを作成「rd3pie」パッケージを確認してください。


この記事が誰かの役に立ちますように。

スポンサーリンク
価格および配送状況は変更される場合があります。購入時は商品ページをご確認ください。
当サイトに表示されている商品情報はAmazonから提供されたものであり、更新または削除される場合があります。
karada-goodはAmazonアソシエイトとして、適格販売により収入を得ています。