はじめに

  • 特殊な事例かもしれませんが, 英数字 (シングルバイト文字) と日本語 (マルチバイ ト文字) のフォントを混在させて作図しなさい, という縛りを受けることがあります. ——例えばCPUE (/1000網)——の日本語フォント部はMS ゴシックで, 英数字 はArialで, みたいな感じです.
  • ggplot2では図タイトルや軸ラベル, 凡例ラベル等のそれぞれのフォントは, ggplot2::theme()等の引数を個別に指定することで容易に変更することができます. しかし, 一つの文字列内で複数のフォントを混在させるのは, かなりの手間です. 例えば, stack overflowに解決策の一例がありますが, 文字列が長くなるのと, htmlの知識が必要になります.
  • そこで, フォント混在作図問題を少しでも楽にするためにmixfonts()を作成しました.

使用例

library(frabento)  # このパッケージ
library(ggplot2)   # 作図
library(ggtext)    # element_markdown()などを使うため
library(patchwork) # ggplotを簡単, キレイにレイアウト 
library(ragg)      # マルチバイト文字のfallback
frabento::register_all_fonts() # system下のfontを登録. fontregistererより移植

mixfonts()では, デフォルトのASCII文字フォントをArial, マルチバイト文字フォントをMS Gothicにしています.

# ベースのthemeをsetしておく
theme_set(theme_linedraw(base_family = "MS Gothic") +
          theme(aspect.ratio = 1/1)) # アスペクト(縦横)比

例1: 軸タイトル axis.title

# 仮想データ作成
dat <- data.frame(cpue = rnorm(n = 30, mean = 500, sd = 35),
                  year = seq(1990, length.out = 30, by = 1))

# まずはmixfontsを使わない
g <- ggplot(data = dat, aes(x = year, y = cpue)) +
    geom_path() + geom_point() +
    labs(x = "年", y = "CPUE (/1000網)") +
    theme(axis.title.y = element_text(color = "blue"))

# mixfontsを使うと
gm <- g + labs(y = mixfonts("CPUE (/1000網)")) +
    theme(axis.title.y = ggtext::element_markdown(angle = 90, color = "blue"))

# use patchwork
g | gm

フォントを任意のものに変更

gm1 <- gm + labs(y = mixfonts("CPUE (/1000網)", asciifont = "Cambria"))
gm2 <- gm + labs(y = mixfonts("CPUE (/1000網)", mbytefont = "Meiryo"))
gm3 <- gm + labs(y = mixfonts("CPUE (/1000網)",
                              ascii = "Times New Roman",
                              mbyte = "HGSSoeiKakugothicUB"))

# patchwork
gm1 + gm2 + gm3 + plot_layout(ncol = 3)

折り返し, 上付き, 下付き

文字列の折り返しや上付き (superscript), 下付き (subscript) にも対応してます.
上付き・下付きいずれの場合も, 添字部分は中括弧 {} で囲んでください. 次のコードを参照.

# 折り返したい位置に改行記号 `\n` を挿入
gm4 <- gm + labs(y = mixfonts("A海区における\n大中型まき網漁業の\nCPUE (/1000網)"))

# 上付き, 下付き
gm5 <- gm + labs(y = mixfonts("A海区における産卵量\n(eggs_{a} 10^{12})",
                              mbyte = "HGSSoeiKakugothicUB"))

# mixfont() を使わなくても折り返しはできる (フォントの混在は不可).
g_  <- g + labs(y = "A海区における\n大中型まき網漁業の\nCPUE (/1000網)")

# フォントをASCII (シングルバイト文字) に変更すると日本語部分が豆腐化※.
# フォントが上書きされる.
# ※ GitHub Pages上では日本語部分が補完されて表示されているかもしれません.
g__ <- g_ + theme(axis.title.y = element_text(family = "Arial"))

# patchwork
gm4 + gm5 + g_ + g__ + plot_layout(ncol = 2, byrow = TRUE)

例2: 凡例 legend

# 仮想データ
d2 <- data.frame(cpue = c(rnorm(n = 30, mean = 300, sd = 25),
                          rnorm(n = 30, mean = 500, sd = 35)),
                 year = rep(seq(1990, length.out = 30, by = 1), times = 2),
                 age  = rep(c("0歳魚", "1歳魚+"), each = 30))

pbase <- ggplot(data = d2, aes(x = year, y = cpue, group = age)) +
    geom_path(aes(color = age))

p0 <- pbase +
    theme(legend.text = element_text(color = "blue")) +
    labs(title = "混在できない")

# mixfonts()を使う (値の指定が必要 => 値を変更できる利点も)
pm1 <- pbase +
    scale_color_discrete(labels = mixfonts(c("0歳魚", "1歳魚以上"))) +
    theme(legend.text = ggtext::element_markdown(color = "blue")) +
    labs(title = "混在 by mixfonts()")

# label_mixfonts()を使う (関数を返すので値の指定は不要. dataの値は変更できない)
pm2 <- pbase +
    scale_color_discrete(labels = label_mixfonts()) +
    theme(legend.text = ggtext::element_markdown(color = "blue")) +
    labs(title = "混在 by label_mixfonts()")

# patchwork
p0 + plot_spacer() + pm1 + pm2 + plot_layout(ncol = 2, byrow = TRUE)

例3: facetタイトル + パネル内テキスト strip.text & geom_richtext

パネル内テキストは元のデータ (ラベル部分) をmixfonts()で変換します.

intext <- data.frame(age = c("0歳魚", "1歳魚+"),
                     text = mixfonts(c("(1) 0歳魚", "(2) 1歳以上"),
                                     asciifont = "Arial Rounded MT Bold",
                                     mbytefont = "HGSSoeiKakugothicUB"))

prich <- 
    pbase + 
    facet_wrap(~ age, labeller = labeller(age = label_mixfonts())) + 
    theme(strip.text = element_markdown(size = 15)) +
    ggtext::geom_richtext(data = intext, aes(x = 1990, y = 400, label = text),
                          hjust = 0, label.size = 0, label.color = NA, fill = NA) +
    labs(title = "facetタイトル + パネル内")
    
prich

参考情報

  • raggの紹介ブログ: fallbackのフォントをどう指定したらよいかがわかりませんが, 指定できるのであれば これ以上のパッケージはないと思います. 今後の動向に注目です.
# 豆腐化した文字をfallback (最後の拠り所) で補完する
fallback_text <- "This is English, この文は日本語です 🚀"

ggplot() + theme(aspect.ratio = 1/2) +
    geom_text(aes(x = 0, y = 1, label = fallback_text, family = "Arial"),
              size = 3.5)

その他

  • 日本語フォント利用のためにfontregistererを読み込んでいましたが, 同パッケージの更新が2年前で止まっているため, R4.2.2以降??ではインストールできなくなった模様です. fontregistererについては, 作者のページ に情報があります.