ill-identified diary

所属組織の見解などとは一切関係なく小難しい話しかしません

おまえはもうRのグラフの日本語表示に悩まない (各OS対応)

この記事は最終更新日から3年以上が経過しています

2021/9/10 追記: 改めて更新された話を統合して整理して書き直しました. 以降はこちらを参考にしてください: ill-identified.hatenablog.com

2021/1/15 追記: RStudio 1.4 がリリースされたのでなるべくアップデートしましょう

2020/12/06 追記: Japan.R で今回の話の要約+新情報を『Mac でも Windows でも, PNG でも PDF でもRのグラフに好きなフォントで日本語を表示したい (2020年最終版)/Display-CJK-Font-in-Any-Gpraphic-Device-and-Platform-2020 - Speaker Deck』として発表した. ハイライトは「近々出るRStudio 1.4 があれば fontregisterer はほぼいらなくなる」

2020/10/31 追記: geom_text(), geom_label() 関数などのフォント設定についての補足説明追加

覚えるべきこと

  1. Japan1GothicBBB とか Japan1Ryumin とかのじゅもんは忘れろ. 自分のPCに入ってるフォントを使え
  2. おまえが使えるフォントファミリ名を知れ. わからなかったら systemfontsfontregistererを使え.
  3. WINDOWSMACはフォントの登録で確実にフォントを表示させろ, fontregistererを使うと楽だ
  4. なるべくggplot2を使え. デフォルトの作図デバイスPNGファイルに使えるフォントには制約が多い
  5. PDF 保存にはなるべく cairo_pdf を使え. どのOSでも殆どのことはよけいなパッケージをインストールしなくてもできる・・・ fontregistererですら例外ではない.

今回おしえないこと:

  • 一部のOSでは特定のフォントがうまく表示できない, だが標準フォントは問題ない
  • MACでの書体変更, イタリック体の存在しない日本語フォントをイタリック体/スラント体にすることはできない
  • 無からドリトスを生み出す方法
  • 逆噴射文体について

目次

初めに

よくきたな. おれは ill-identified だ. 俺は毎日すごい数のエラーを R に吐かせているが, そのすべてをおまえに見せる気はない.

データ分析に使えるときいてRを触り始めて間もないおまえは, 散布図とかヒストグラムとかを理解し, ggplot2の使い方も覚えつつある. きをよくしたおまえは次にグラフを保存して宿題のレポートや会社の報告資料やブロゴとかに貼り付けようとする. それまでなら何時間もかかっていた作業が一瞬で終わり, テキーラを一杯ひっかける時間ができる.

だがなんかよくわからないエラーとか渓谷とかが大量でたり, 「さっき画面に写ってたのと保存したので違う!」となるだろう.

R Studio のエクスポート機能には “Save as PDF” と言う項目もある.めざといおまえはとっくにそれに気づいて試しているかもしれないが, おまえは既に大量のうろんな警告メッセージを眼にしているだろう (もしかすると全部EIGOのメセージかもしれない).

In grid.Call(C_textBounds, as.graphicsAnnot(x$label),  ... :
   ポストスクリプトフォントのデータベースにフォントファミリ 'XXXXX' が見付かりません
警告メッセージ: 
1: In grid.Call(C_stringMetric, as.graphicsAnnot(x$label)) :
  Windows のフォントデータベースにフォントファミリが見付かりません 
2: In grid.Call(C_stringMetric, as.graphicsAnnot(x$label)) :

R は歴史があるのでINTERNETには古い情報や新しい情報や, WindowsMac限定の情報があちこちに残っている. おれがここで教えるのはR・L・A・N・Gとの関係を取り戻す方法だ. つまり2020年現在で, おまえがどんなOSを使っていようが確実に, そしてなるべく簡単に日本語表示し, さまざまなファイル形式で保存する方法だ. なんかレガシーなプログラムで画像を吐き出してるやつをメンテナンスしたいときとか, どうしても特定の方法で日本語を表示することにこだわりたいやつには必ずしも役に立たないかもしれない.

具体的には Linux (Ubuntu 18), Windows 10, Mac OS (Mojave) だ. Windosw 8 とかは持ってないので試していない. あとなるべく RStudioを使え. もしWindows8とか少し古いOSでは事情が違うということを知っていればあとでこっそりおれに教えてくれ.

どのOSでもだいたい同じようにできる方法

今回の話も長いが, とにかく確実に日本語表示する方法を知りたいならこのセクションだけは読め.

今回教える方法で最低限必要なパッケージは tidyverse, ggplot2, systemfonts, そして今回のためにおれがつくったfontregistererだ. こいつらがなければインストールしろ.

install.packages("tidyverse")
install.packages("systemfonts")
remotes::install_github("Gedevan-Aleksizde/fontregisterer", repos = NULL, type = "source")
require(tidyverse)
require(systemfonts)
data(mtcars)
mtcars <- as_tibble(mtcars, rownames = "model") %>% mutate(cyl = as.character(cyl))

それ以外にも, 例として ggthemes, grid, gridExtra, patchwork を使っている. こいつらも便利だからまだ持ってなかったらインストールしろ.

OS別の下準備

おれが今回おしえる方法はほとんどどのオペレーティングSYSTEMでも使えるが, どのOSでも使える方法を実行するにはOSごとに異なる準備が必要だ. おれはOSごとに異なる準備の量を最低限に抑えたが, おまえはサボテンの陰に隠れたダニートレホを警戒するようにちゅういぶかく自分のOSをみきわめなければならない.

おまえがWINDOWSユーザなら特別な準備が必要ない. しいていうなら游書体とかOS標準のフォントがじゃあくなハッカーによって削除されていないか確認することだ. 終わったら次の「使えるフォントを登録する」セクションを読め.

MACユーザーは特別な準備が必要だ*1. Rで以下の関数を実行し必要なライブラリがインストールされているか確認しろ.

capabilities()[c("cairo", "X11")]

CAIROとX11どちらもTRUEなら次に進め. ないならインストールしろ(最近のMACX11だけないことが多いはずだ). たとえばターミナルで以下のように入力しろ.

# Cairo
brew install cairo
# X11
brew install --cask xquartz

注意: xquartz のほうはSU権限が必要かもしれない. だが brew でsudoを使ったり使わなかったりするのはBADなプラクティスなので, おれは代わりに公式サイトdmgファイルをダウンロードしてインストールしている.

Linux系もCAIROが必要だが, だいたい最初から入ってると思う. なければやはりインストールしろ. あとUBUNTU以外を使っているならNotoフォントを入れておけ. VLフォントとかでもたぶんなんとかなるがNotoはカバレッジに優れるので便利だ.

もし UBUNTUでもはいってなかったら, こんなかんじにしてインストールしろ

sudo apt install fonts-noto-cjk fonts-noto-cjk-extra

使えるフォントを登録する

OS別の準備を終えたおまえはさらに, インストールされてるフォントを全て登録するとゆうHARD WORKしなければならない. おまえは "Japan1" とか "Japan1HeiMin" とかそんな感じの呪文を書けという言い伝えを聞いたかもしれないが, それは忘れろ.

実は日本語表示の方法もOSや保存方法ごとに対応が違う. 実際のところおまえが普段使うフォントは決まっているだろうが, おれは今回汎用性の高いやり方としてインストールされているフォントを全て登録する方法を教える. おまえはいろいろなフォントを使えるようになる. 登録すべきフォント名を知るために, なんか fc-listだかfc-matchだか実行しろだとか, フォントのカタログ的なアイコンをクリックしろだとかおまえは教わったかもしれない. だがそれよりも systemfonts パッケージを使ったほうがかんたんだ. だがフォントを調べたら次にフォント登録待っている. なんかquartzFonts()だとかwindowsFontsだとか使い分けろというらしい. だがおれはこんなはなしをいちいち説明する時間が惜しいと考えた. 冒頭で要件に挙げた, おれがこのために作った fontregisterer は読み込むだけでこういった準備を勝手にやってくれる.

require(fontregisterer)

おまえがWINDOWSMACをつかっているなら読み込み時に登録されたフォントファミリ名の一覧を表示する. おれはおまえにIPAフォントのインストールとかも有料フォントの押し売りとかも要求しない. あとLINUXユーザーはここはやらなくてもいい.

あまつさえ毎回実行するのすらめんどくさかったら .Renviron とかなんかそんな感じのファイルに入れて初期化時に実行されるようにしろ. 初期化時コマンドのなんかは『R環境設定』で調べられる.

おれはこれ以降のサンプルプログラムで, 指定するフォントファミリ名を family_sans/family_serif という変数に与えている. どのフォントを使うかか無関心なら以下を実行しろ. おまえのOSがWINDOWSなら游書体, MACならヒラギノ, それ以外ならNotoフォントが選ばれる. もしおまえが古いWindowsを使っていたらMSゴシック/明朝になるはずだ. もしおまえが他のLINUXを使っていてNotoが入っていないのなら, 適宜変えろ. おまえが使えるフォントを知る方法はすでにおしえたとうりだ. 以下と同じ処理をする関数もfontregisterer::get_standard_font() 関数としておれが用意した.

if(Sys.info()["sysname"] == "Windows"){
  if(as.integer(str_extract(Sys.info()["release"], "^[0-9]+")) >=8){
    family_sans <- "Yu Gothic"
    family_serif <- "Yu Mincho"
    } else {
    family_sans <- "MS Gothic"
    family_serif <- "MS Mincho"
    }
  } else if(Sys.info()["sysname"] == "Linux") {
    family_sans <- "Noto Sans CJK JP"
    family_serif <- "Noto Serif CJK JP"
  } else if(Sys.info()["sysname"] == "Darwin"){
    family_serif <- "Hiragino Mincho ProN"
    family_sans <- "Hiragino Sans"
  } else {
    # インストールすればとりあえず動く
    family_sans <- "Noto Sans CJK JP"
    family_serif <- "Noto Serif CJK JP"
}


GGPLOT2でグラフを保存する

おまえは自分のPCにインストールーされているフォント名を手に入れた. これはおまえにとって銃(GUN)と同じくらい頼れる武器だ. だがまだお前は銃の引き金の引き方がわかっただけで, 狙いの付け方とかがわかってない.

おれはグラフをいつもggplot2で描く. ggplot2は真の男である Hadley Wickham が考案したGRAMMARオブGPAPHICSとゆう理念に基づいて作られているので, 後から色とかフォントとかデザインをいろいろ変えたりするのを + で足すだけで簡単にできる・・・もしおまえが ggplot2を知らないのなら,『ggplot2をつかってみよう』や『ggplot2再入門(2015年バージョン)』でどんなものかだいたいわかるはずだ. 参考になるもっと詳しいサイトも紹介されている. ただし画像の保存方法だけはおれが今回おしえる方法にすることをすすめる. 最近は 特殊なグラフを簡単に描くためのパッケージも多く作られ, それらは ggplot2 を使って作られることも多いので便利になった*2. だから少しづつデザインの違うグラフをいくつも作るのも A PIECEオブCAKE だ. おれは奮発して2種類のフォントと4種類の書体をどうじに表示するグラフを描いた:

g <- ggplot(mtcars, aes(x = mpg, y = wt, color = cyl)) +
  geom_text(aes(label = model), family = family_sans, fontface = "plain") +
  labs(x =paste(family_serif, "ボールドを使用"), y = paste(family_serif, "イタリックを使用"),
       title = paste(family_serif, "ボールドイタリックを使用")) +
  annotate("text", x = 10, y = 2, label = paste(family_sans, "標準書体を使用"), hjust = 0) +
  theme(
    text = element_text(family = family_serif, face = "plain"),
    title = element_text(face = "bold.italic"),
    axis.title = element_text(face = "italic"),
    axis.title.x = element_text(face = "bold")
    )
g
f:id:ill-identified:20201003195306p:plain
日本語フォントを異なる書体で表示

だがこのボールドイタリックのようにたまにうまくいかないこともある. 日本語フォントにはもともとイタリックがないからだ. CAIROを使えばわりとなんとかなるが, PNGではうまくいったりいかなかったりだ. おれはあきらめた.

ggplot2 でもフォントの指定は必要だ. 一番簡単なのはテーマ関数で一括していすることだ*3. 上記はデフォルトの theme_grey() を使っているが, よりシンプルな theme_classic() だろうが ggthemes パッケージから持ってきたものだろうが, base_family = があるやつならなんでもいい. グラフを何度も書くたびにテーマ関数を書くのがいやなら, theme_set() でデフォルトを決められる. ggthemes のテーマとも併用できる.

theme_set(
  theme_pander(base_family = family_serif) + theme(
    axis.title.y = element_text(face = "italic"),
    axis.title.x = element_text(face = "bold"))
  )
ggplot(mtcars, aes(x = mpg, y = wt, color = cyl)) +
  geom_text(aes(label = model), family = family_sans) +
  labs(x ="燃費 (miles/US gallon)", y = "重量 (1000ポンド)",
       title = "mtcars") +
  scale_color_colorblind(name = "シリンダ数")
f:id:ill-identified:20201003195241p:plain
テーマを適用した場合

ggplot2 で作成した画像は gg とか ggplot とかそんな感じの名前のオブジェクトに保存され, これは ggsave() 関数だけで一発で保存できる. デフォルトでは直前のプロットを保存するが, グラフをオブジェクトとして保存しておけば plot= で後からでも保存するグラフを指定できる. つまり画面表示用と保存用で違うデザインにすることもできるとゆうわけだ. ドリトスとコロナビール, どちらが欠けてもいけないように R の荒野の中で2つの選択肢はお前の心wを潤してくれる.

つまりこの場合は, 以下どちらでも保存できる.

g
ggsave(filename = "test1.png")
ggsave(filename = "test2.png", plot = g)

おまえは今度こそ単純な割に工程が複雑な作業をせずに仕事を早上がりし, バーでテキーラを一杯呷る時間ができるとゆうわけだ.

GGPLOT2でPDFを保存する

もし, PDF は一切不要で PNG でしか保存する気がないというのなら問題はこれで解決しとてもシンプルになる. 基本的に RStdio で日本語が表示されれば保存もうまくいくので, あとは解像度にちゅういするだけだ. だがここまで読み進めたおまえはきっと, PDFにフォントが埋め込まれずに困っているのだろう. 「画面に日本語が表示されてるのに保存したら消えた!」これはタルサ・ドゥームの罠だ.

答えは簡単だ. PDFで保存する時には device = cairo_pdf を指定しろ.

ggsave("ggplot_cairo.pdf", device = cairo_pdf)

なお, Rで描いたグラフを描画したり, 画像ファイルとして保存したりするための関数をグラフィックデバイス関数と呼ぶ. cairo_pdf() はグラフィックデバイス関数だ. ggsave() はデフォルトでは png() を呼び出すから, 最初は省略していた.

“Plots” ペーンに表示されたグラフを, “Export” から “Save as PDF” を選ぶことで保存できる. おまえはめざとくこれを見つけているかもしれない. しかしこれはフォント埋め込みをしないとゆう危険なわなが仕組まれているからつかうな.

f:id:ill-identified:20201005160719p:plain
RStudioのエクスポート画面

PNGならフォント埋め込みがないからSAVEアズIMAGEはつかってもいい.

もっと変わったフォントでも可能だ. おまえは「青柳隷書しも」というフォントをDAWNROADできる. このフォントもINSTALLすればRのグラフに使える. だがこいつは OpenTypeとTrueTypeでフォント名が微妙に違うから気をつけろ.

g2 <- ggplot(mtcars, aes(x = mpg, y = wt, color = cyl)) +
  geom_text(aes(label = model), family = "aoyagireisyo2") +
  labs( x = "カラット数", y = "価格") +
  scale_color_colorblind(name = "クラリティ") + 
  theme_grey(base_family = "aoyagireisyo2") +
  theme(legend.position = "bottom")
g2

f:id:ill-identified:20201003195833p:plain
「青柳隷書しも」で表示

さらにおれは持っている日本語フォントほぼ全てを埋め込んでみた

f:id:ill-identified:20201003200339p:plain
日本語フォントの比較
f:id:ill-identified:20201005163141p:plain
MACではフォントがないと書体変更はできない
f:id:ill-identified:20201005163358p:plain
WINDOWSではBIZ+UDフォントが正しく表示されない

もちろん日本語でなくとも, 変わったフォントでも表示できる

f:id:ill-identified:20201003192953p:plain
変わったフォントでどこかで見た凝った題字とかを作る

標準作図関数で描いたグラフを保存する.

ggplot2 はおまえにとって強力無比な銃 (GUN) となる. おれはグラフをぜんぶ ggplot2 で描けばいいと思うが, 真の男はこだわりを捨てなければならいこともある. LEGACYの話はしないと言ったが, たとえば randomForest::MDSplot とかなんか昔からあるやつは標準関数を使ってグラフを書く*4. メキシコのBARで標準グラフをいちいち ggplot2 で書き直そうものなら, すぐさまたむろする短気な悪党たちの銃弾やナイフをくらい1分と生きていられないだろう. こいつらに ggplot2 のお作法は通用しない.

plot() とかは標準の作図関数だ. 標準の作図関数は以下のようにして保存しろと書いてあることが多い.

png("plot.png")
plot(...)
dev.off()

だがこれだとグラフが画面に表示されなくて不便だ. おまえは dev.copy() を使うことができる. これでグラフを画面に表示しつつ保存できる.

plot(...)
dev.copy(png, file = "plot.png")
dev.off()
dev.copy(cairo_pdf, file =  "plot.pdf")
dev.off()

どっちも最後の dev.off() まで実行しないとファイルに画像が保存されない.

だがおまえもおれもたかが画像のほぞんに2行も書いていられるかと思うだろう. こいつも RStudio の “Plots” ペーンからも保存できる. だがPDFのフォントが埋め込まれないのはこちらも同じだ. だからおとなしく2行書け.

肝心のフォントは, それぞれの作図関数・・・text()その他もろもろでも個別に指定できるが, 最初にpar()関数で一括指定するのが楽だ

par(family = family_serif, font.axis = 2, font.lab = 3, font.main = 4, font.sub = 5)
with(mtcars, plot(mpg, wt, col = cyl, pch = "+", cex = 1.5,
     xlab = "X軸", ylab = "y軸", main = "日本語表示で広がるRの世界", sub = "subtitle"
     ))
f:id:ill-identified:20201004005158p:plain
標準グラフィックスでもフォント表示

family以降の数字は書体を指定している. 順に(1) 標準, (2) ボールド, (3) イタリック, (4) ボールドイタリック, (5) 記号だ. 最後は日本語と直接関係ないから省略する.

ここまでのまとめ

これでおまえはWINDOWSでもMACでもLINUXでも, PNGでもPDFでも, インストールされているほとんどのフォントをグラフに表示できるようになったはずだ. インストールされているフォントを適切に登録し, cairo_pdf を使うということを守ればPDFはフォントが埋め込まれ, PNG画像からも豆腐が消え去る. いわばお前はGUNの引き金の引き方も, 狙いの付け方とかも学んでRグラフィックスとゆう過酷なメキシコでサバイブする準備ができた状態だ.

ALL YOUR FONT ARE BELONG TO YOU...

補足

ggplot2 を使って膨大なグラフを作ったおまえは ggplot2 で何もかも解決できるわけではないと気づくだろう. たとえば ggplo2 にはドリトスを無限に生産する機能はない, あと異なるグラフを並べて1つの画像にする機能とかもない. そのへんの問題もついでに補足しとこう.

おれの作ったパッケージを使わない方法

おれのパッケージがうさんくさいから使いたくないだと?だがおまえの考えにも一理ある. かこくなメキシコには多くの困難が待ち構えている・・・ダニートレホや悪党どもの待ち伏せ・・・そして・・・タルサどもの罠・・・おまえがDO IT YOUSELFの精神をわすれないならおまえはきっと不測の事態からもサバイブできるだろう. 実際のところfontregistererそんなに複雑な処理をしていない. これまでの説明からもわかるように, fontregisterer はグラフィックエンジンを改造するとかだいそれたことはしてない. すべてRのデフォルトグラフィックスが用意しているオプション設定でできる範囲の操作を自動で書き換えているだけだ. 詳しくは後に書くとして, おれはまずWINDOWSMACでそれぞれフォントを登録する方法だけおしえることにする.

まずおまえがすべきなのは, systemfontssystem_fonts()関数の結果から, 使いたいフォント名を特定することだ. こいつの出力はtibbleだからdplyr::filter()とかが役に立つ. ここで注意すべきなのは, name列とfamilyの違いに気づくことだ. おまえがWINDOWSユーザなら, 必要なのはfamilyだけだ. これはフォントファミリ名という. たとえばおまえは游書体を使いたいとしよう. おまえはsystem_fonts()の結果から, Yu MinchoYu Gothicを見つけた. かしこいおまえはもうこれらが游明朝と游ゴシックを暗示するイコンだときづいているだろう. windowsFonts()windowsFont()を使い, 以下のようにして游明朝と游ゴシックを登録する.

windowsFonts(
  `Yu Mincho` = windowsFont("Yu Mincho"),
  `Yu Gothic` = windowsFont("Yu Gothic")
)

エクスプロ0ラーかなんかのフォント一覧では「游明朝」「游ゴシック」など日本語で表示されてるだろう. これでもRStudio上では表示できることもあるが, 画像を保存する際に正しいフォントが選ばれないことがあるのでsystem_fonts()の結果にある名前だけを使え.

おまえがMACユーザなら, さらにname列にも気を配る必要がある. MACの場合はファミリ名だけでなく, 書体 (STYLE) ごとに使うフォントを指定しなければならない. 家族すなわちFAMILY・・・複数の書体のフォントをまとめた単位がフォントファミリだからだ. MACで登録が必要なのは, 標準・ボールド・イタリック・ボールドイタリック体の4種類だ. しかし日本語ではイタリック体は普通使わないので, 標準フォントで代用することが多い. 実際ヒラギノフォントにはイタリックとかがない. ここでおまえに「ヒラギノ角ゴシック」と「ヒラギノ明朝ProN」を登録する例をみせてやる.

quartzFonts(
  `Hiragino Sans` = quartzFont(rep("HiraginoSans-W3", 4)),
  `Hiragino Mincho ProN` = quartzFont(rep("HiraMinProN-W3", 4))
)

この2つのフォントも日本語でのファミリ名がある. それはfc-listコマンドとかが照明している・・・ が, やはりsystem_fonts()に表示された結果を優先した. だがおまえだけにこっそりおしえてやるが, 実は違う名前で同じフォントを登録しても問題ない. そしてWINDOWSとの違いは, quartzFont()に4種類のフォント名を入力する必要があるということだ. しかしヒラギノフォントはどれも字幅しかバリエーションがないので, 全てにW3のフォントを指定している. おまえは字幅を自由に書き換えてもいいし, 丸ゴシックを登録することもできる.

geom_text() や geom_label() のフォント設定

すでにサンプルコードをちゅうい深くみたおまえは, theme() 関数と geom_text() でそれぞれフォントを指定していることに気づいているかも知れない. GGPLOT2のテーマ関数はグラフ全体のフォントとか色とかを一括指定できるが, geom_text(), geom_text()といった文字をプロットする関数には効果がない. これは「グラフのDATAと無関係な部分のデザインとデータをどう見せるかは切り離して考えるべきだ」とゆうggplot2の哲学に基づく仕様である*5. だが結果として日本語表示の手間が増えてしまいびみょうに厄介な仕様だ. テーマのデフォルト設定は theme_set()でできるという事実におまえは気づきつつあるかもしれないが, ついでに文字をプロットする関数のデフォルト設定方法をおしえてやる. それは update_geom_defaults()を使うことだ

theme_set(theme(text = element_text(family = family_sans)))

# 既にテーマに設定したフォントファミリをデフォルトに設定
update_geom_defaults("text", list(family = theme_get()$text$family))
update_geom_defaults("label", list(family = theme_get()$text$family))

あとたぶんおまえは文字をプロットするのにラベルを重ならないようにする ggrepelとかも使ってるだろう. これも該当パッケージを読み込んだ後に同じように設定できる.

update_geom_defaults("text_repel", list(family = theme_get()$text$family))
update_geom_defaults("label_repel", list(family = theme_get()$text$family))


GridExtra のタイトルのフォント

これは偶然にも数日前に R-Wakalang に投稿された質問だ. gridExtra::grid.arrange() は複数のグラフを並べて1つの画像にできる. top= でまとめて1つにした画像のtop/bottom/left/rightそれぞれにキャプションを指定できるが, フォントを指定する引数がない. grid::textGrob(), grid::gpar() でグラフィックすパラメータ付きのテキストを返す必要がある.

require(gridExtra)
require(grid)
g <- ggplot(data.frame(x = 0), aes(x = 0, y = 0)) + geom_point() +
  labs(x = "テスト", y = "Y軸", title = "タイトル") +
  theme(text = element_text(family = family_serif))
g_grid <- grid.arrange(
  g, g,
  top = textGrob("gridExtra上部のテキスト", gp = gpar(fontfamily = family_sans)),
  bottom = textGrob("下部のテキスト", gp = gpar(fontfamily = family_serif, fontface = "bold")),
  left = textGrob("左のテキスト", gp = gpar(fontfamily = family_serif, fontface = "italic")),
  right = textGrob("右のテキスト", gp = gpar(fontfamily = family_sans, fontface = "bold.italic"))
  )
ggsave("grid.png", plot  = g_grid)
ggsave("grid.pdf", plot = g_grid, device = cairo_pdf)
f:id:ill-identified:20201004012850p:plain
gridExtraの外側のキャプションにフォントとスタイルを指定

あと gridExtraで描画したグラフを1つのファイルにまとめるには plot =に指定する必要がある.

patchwork のキャプション

patchwork も同じように複数の画像を連結するためのパッケージだ. これも便利でおれはよく使っているが, plot_annotation() で指定したタイトルのフォント指定の方法がよくわからなかった. おれは ggsave() のほうに family = で指定したらうまくいったが, 今後どうなるかはわからないするには, theme 引数にテーマ関数を与える必要がある. theme_set()を使っているならそれが反映される

(g | g) + plot_annotation(title = "パッチワーク") + theme(text = element_text(family = family_serif))
f:id:ill-identified:20201004010630p:plain
patchworkのキャプションにフォント設定

ここで似たようなパッケージの比較がされているが, 全部は確認したくなかったのでしてない. 全部ggplot2ベースだからたぶんなんとかなるだろう.

R Markdown での扱い

以上で推奨するグラフィックデバイス関数は全て R Markdown でも使用可能だ. R Markdown では, plot()ggplot() の出力を一旦保存して後でHTMLとかPDFとかに貼り付けてくれる. チャンクオプションに dev = "cairo_pdf" などとグラフィックデバイスを指定できることが完全に照明されている. オプションも指定したいなら dev.args = に名前付きリストで書け. もっと具体的に言うと, “R Markdown Cookbook,” Ch. 11.15 High-quality graphicsに指定可能な一覧が載っている.

デフォルトは png だ この機能は knitr が担当しているので, 以下のようなプログラムを最初のチャンクに書けば全チャンクのデフォルトの設定を書き換えられる.

knitr::opts_chunk$set(
  dev = "cairo_pdf",
  dev.args = list(family = devfont)
)

もし HTMLとPDFでつかいわけたいならknitr::is_html_output()とかで場合分けしろ. おれがつくったrmdjaでは特に指定しなくても自動で切り替えるようにしている.

SVG での保存

HTML でベクタ画像を表示したい場合, SVG 形式にするという手もある. こちらも デフォルトに svg() があるが, svglite とかを使ったほうが良い. SVG 形式は, PNG や PDF と違い, 実装によってパフォーマンスに差がある. つまり変換が非効率で, ファイルサイズが大きくなり描画にも時間がかかることがある. これは『SVG画像』が参考になる. rsvg は残念ながらグラフィックデバイスとしては機能していないため, ggsave() とかで呼び出せるのは, svgsvglite かになる. diamonds のような数万件のデータの散布図の画像は 20MB 程度になるところ, svglite では なんとか8MB程度で済んだ. だがどちらにせよおまえのHTMLを見てくれるやつがストレスためることに違いはないので, なんでもベクタ画像にすれば良いとゆうわけでもない.

2020/11/29 追記: パワーポイント等にグラフをベクタ画像のまま貼り付けたい場合には, SVG で保存する必要がある*6. そしてここでもsvgliteを使ったほうが良いだろう. 上記の理由に加え, デフォルトの svg() はフォントをアウトライン化してしまい, 貼り付けるとテキストのコピーができなくなるため. 貼り付けた画像を「図形に変換」を選ぶと Office のオブジェクトとして扱えるため, 余白の調整やテキストの書き換えもできるようになる. exportパッケージ経由では最初から図形に変換した状態でコピーされるようだ.

factoextra での日本語表示

どこでかは忘れたが, 以前factoextraで日本語表示ができなかったのでshowtextを使って表示したというはなしをきいた. たしかにMACとかはデフォルトフォントが日本語グリフを持たないので何もしなければバイプロットのラベルとか文字化けする. だが当時の原因がなんなのかはしらないが, 遅くとも2017年の時点ではfont.familyでフォントを設定できるようになった. このパッケージのグラフは gridggplot2で描いているからフォントファミリが指定できるならおれのfontregistererで登録されたフォントはどれも使える. 例えばおれは去年の Japan.R の『三国志で学ぶデータ分析』とゆう発表でfactoextraを使用したが, 日本語はちゃんと表示されている*7. 後でくわしくおしえるようにおれはshowtextは現在ではメリットのある状況がほとんどないと思うからおすすめしない.

pca <- prcomp(df2 %>% as.data.frame %>% magrittr::set_rownames(., .$name) %>% select(where(is.numeric)), scale = T, center = T)
fviz_pca_ind(pca, font.family = family_sans)
f:id:ill-identified:20201003192951p:plain
factoextraのグラフの日本語表示

その他の保存形式

これは日本語フォント表示とは直接関係のない話だ.

その他に, 出力形式には Windows Metafile (WMF) として出力する win.metafile() や, XFIG形式に対応したグラフィックデバイスもあるが, 主に Windows で昔使われていた形式なので, 現在使うメリットはあまりない.

webp はまだ Chrome 系 OS しかまともに対応していないが, 必要になることもあるだろう. これはそのままの名前のwebp パッケージがやってくれる. めざといおまえは Linux 系は外部ライブラリのインストールも必要だと気づくだろう. しかしこいつは現時点では3次元配列を画像として読み書きする機能しかないので (1) 一度無劣化の画像形式で保存する (2) 再度読み込んで書き込み直す, しかない.

より細かい解説

おれがおしえる方法はいままでお前がどこかで見聞きした方法とだいぶ違うだろう. その疑問に応えるためにもう少し細かい解説をしておこう.

参考になる資料

Rのグラフ表示問題について, すでにまとまった日本語の情報はすくない. ほぼ奥村先生の書いたwebページしかない.

だがPDFのことが主だ. PNGとかも同時にやる方法はあまり書いてない.

こっちはデフォルトのデバイス限定だが, デバイスがどうフォントを取得するかについて書かれている (が, 日本語フォントでは不可能なことを書いていたり説明が少し不親切なところもある).

このデバイスというのはRがグラフを表示するための部分で, PDFとかに保存する際のフォント指定は別のプログラムへの指定なので別問題だ. これが日本語表示問題の混乱を招くポイントの1つに違いない.

日本語フォントが表示できないのは3つの問題が複合しているためわかりづらくなっている.

  1. RStudio 上のグラフに日本語が表示されない問題

  2. PDFのフォント埋め込み問題

  3. OSごとに対応方法が違う問題

ややこしい問題にややこしい問題をかけ, もう一度ややこしい問題をかけるから200倍のややこしさが生まれていることがすでに照明されつつある. (1) はシステムフォンとをどう認識させるかという問題だ. これはさらに厄介なことにOSによっては画面とPNGですら事情が変わることがある. (2) もOSに依存しやすいが cairo_pdf を使うことでどのOSもだいたい同じようにできるようになった. showtext とか extrafont とかも使わなくていい. (3) は (1) や (2) の違いすら覆しうる.

使えるフォント名を登録する

ここではfontsregistererで自動登録した処理についておしえる.

フォントを見つけるにはUNIX系(MACとかLINUXとかだ)はターミナルでfc-listを使うことが多い. デスクトッポのなんかフォントのカタログみたいなアイコンをクリックしてもいい. だが, WINDOWSではこれは使えない. だから今回はどのOSでも有効な systemfontsパッケージで探す. こいつはフォントのファイルパス, ファミリ名, Postscript名とかを全部表示してくれる.

こいつの system_fonts() 関数でフォント一覧を取得したら, それをもとにフォント登録する. LINUXは不要だが, WINDOWSMACはそれぞれ違う方法での登録が必要だ. WINDOWSwindowsFonts() だ. 簡単な登録方法は既に書いたとおりだ.

もちろん巷でいわれているように短い名前をつけなおすこともできる. おれも変数名にスペースとか入れたくないが, ここでは本来のファミリ名と一致させたほうが不測のエラーを防止できて便利だ.

おまえはMACをつかうのならWINDOWSユーザー同様にフォントを登録しなければならならい. それは quartzFonts() でできるが, こっちはファミリ名とPOSTSCRIPT名両方を指定する必要がある. これはWINDOWSユーザ以上のHARDWORKだ,

quartzFont() には順に標準書体, ボールド体, イタリック体, ボールドイタリック体の順でPOSTSCRIPT名を登録する. だが日本語フォントの多くにはイタリックとかないので標準のやつを登録するしかない. Cairoは標準フォントを勝手に書き換えて斜めにしてくれるが, MACではじつはバックエンドがX11になっている. これがMACで日本語の斜体ができない原因だ.

あとフォントファミリにはエイリアスがあるから ヒラギノ角ゴ ProN とかでもできるが, systemfonts に表示される名前にしたほうが無難だ. だがもし字の太さが気に入らないならそっちは適当に書き換えろ. register_all_fonts() はこの処理を自動でやっているだけだから後から自由に上書きできる. つまりこのパッケージ以下のような単純だが長たらしい処理を自動で実行しているだけだ.

get_styles <- function(data){
  data$style <- with(data, factor(tolower(style), c("normal", "regular", "medium", "bold italic", "W3")))
  normal <- filter(data, width == "normal", weight == "normal")
  if(NROW(normal) > 0){
    normal <- normal
  } else {
    normal <- data
  }
  if(NROW(filter(normal, style %in% c("regular", "normal", "medium", "bold italic", "W3"))) > 0){
    normal <- arrange(normal, style)$name[1]
  } else {
    normal <- normal$name[1]
  }
  bold <- filter(data, style == "bold")
  if(NROW(bold) > 0){
    bold <- bold$name[1]
  } else {
    bold <- normal
  }
  italic <- filter(data, style == "italic" | italic)
  if(NROW(italic) > 0){
    italic <- italic$name[1]
  } else {
    italic <- normal
  }
  bi <- filter(data, style == "bold italic")
  if(NROW(bi) > 0){
    bi <- bi$name[1]
  } else {
    bi <- italic
  }
  return(c(normal = normal, bold = bold, italic = italic, bolditalic = bi))
}
registerFonts <- function(){
  f <- system_fonts() %>% group_by(family, name) %>% summarise_all(~.x[1]) %>%
    group_by(family) %>% nest() %>% mutate(style = map(data, get_styles))
  if(Sys.info()["sysname"] == "Windows"){
    do.call(windowsFonts, setNames(lapply(f$family, windowsFont), f$family))
  }
  if(Sys.info()["sysname"] == "Darwin"){
    do.call(quartzFonts, setNames(lapply(f$style, quartzFont), f$family))
  }
}

registerFonts()

if(Sys.info()["sysname"] == "Windows"){
  names(windowsFonts())
}
if(Sys.info()["sysname"] == "Darwin"){
  names(quartzFonts())
}


たまにMacでは HiraMinProN とか書けというやつがいる.これはPOSTSCRIPT名と呼ばれる名称であり完全に誤りではないが制約のおおいやり方だ. 万全を期して上に書いたようなフォントファミリ名を正しく指定しろ.

上の例を見てもわかるように, 同じ游書体でもOSによって名前が違う. おまえはどのOSを使っているか油断なく目を光らせながらHARDWARKしなければならない.

標準グラフィックデバイスはPOSTSCRIPT名でもフォントファミリ名でも認識し, cairo_pdf はファミリ名でないと認識しないことが多い. たぶんそれぞれで判定方法が違うし, WINDOWSMACは登録しておかないと反応しないからOSごとに違う. よってPostscript名とファミリ名が大きく違うフォント, 例えばヒラギノ明朝ProN/HiraMinProN みたいなやつには注意が必要だ. 逆に IPAフォントとかは書体が1つしかなくファミリ名とPOSTSCRIPT名がほぼ同じなので適当に書いてもなんとかなる. あとファミリ名はエイリアスがあるのもややこしさを増している. だが systemfonts パッケージの結果を信じればだいたいうまくいく.

だから今回他のブロゴとか教科書であんまり言及されていない面倒なフォント登録を自動でやることで, 確実にフォント埋め込みできるような方法を紹介した. systemfonts パッケージはインストールされているフォントの一覧情報を取ってくるだけだが, この面倒なフォント登録をだいぶ簡単にしてくれる.

だが, このやり方で使えないフォントがいくつかある. おれの気づいた限りでは, Windows10に最近インストールされるようになった BIZ UD明朝/ゴシックフォントとかはイタリックやボールド体を指定すると文字化けする. MACなら既に描いたとうり原則として対応するフォントファイルがなければ無理だ

PDF で保存する利点

今回のような大掛かりな方法を採用した理由は画面表宇治・PNG・PDF保存を両立するためだ. なぜおれがここまでPDF保存にこだわっているのか, おまえは疑問におもってるかもしれない. PDFでの保存はグラフをベクタ画像で保存することを意味する. 高解像度の写真ではなく, ヒストグラムや棒グラフのような単純な図形であればベクタ画像のほうが基本的にファイルサイズが小さく, かつ拡大しても荒くならないという利点がある. 特に LaTeX などで PDF を作るなら, 画像も PDF 形式のほうがきれいに仕上がる*8. BMPPNG のようなラスタ画像(ビットマップ画像と呼ばれることも多いが, ファイル形式のほうの BMP と紛らわしいのでラスタ画像と呼ぶ), いわゆるドット絵では, DPI を大きく設定することである程度は拡大しても鮮明なままだが, 限界があるしファイルサイズも大きくなる. 文字も画像として描かれるため, 拡大すると文字も当然粗くなるし, 文字検索にもかからない. だがこれはおまえのブラウザのセキュリティがおまえをハッカーから守るためだったりオペレーティングシステムのなんかが関係していて表示できないこともおおいはずだ. Webページで公開する場合, PDF を表示できるかはユーザ側の設定に依存するので避けたほうがよいだろう. すでに書いたようにおれのつくったrmdjaではデフォルトでPDFとHTMLで画像のファイル形式を変えるようにしている. 一方で

ggsave もグラフィックデバイス関数なのか. おまえは考えるかもしれない. だが油断はきんもつだ. ggsave()PNGを保存するために標準関数のグラフを保存する時につかった png() を呼び出しているのだ. ggsave()device = に指定がない限りファイル拡張子から自動でデバイスを判定する.

pdf() の問題

いままでフォント埋め込みに悩んでいたおまえはきっとこうやって保存しろという噂話を鵜呑みにしたにちがいない.

pdf("plot.pdf", family = "Japan1")
plot(...)
dev.off()

あるいはggplot2ならこうかもしれない.

ggplot(...)
ggsave("ggplot.pdf", device = "pdf")

環境によってはこれでもなんとかなることもあるが, ならないことも多い. そんな運頼みの方法をおしえるつもりはない. 既にかいたように, pdf() が認識できるフォントはType1フォントとかいう古い形式のものだけだ. この規格に合わなければ windowsFonts() に登録したかどうかも関係ないし, 作図関数や par() にいくらフォント名を指定しても, pdfFonts()postscroptFonts() を使おうがフォントの埋め込みはされない. いや, あっていてもそもそも埋め込みがされない. pdf() で作成したPDFは常に embedFonts() で後からフォントを埋め込む必要がある. そしてこの埋め込み処理にはさらにGHOSTSCRIPTが必要になる. おれはそんな手間のかかる方法を薦めるつもりはない. cairo_pdf() はこの問題が解消されているというのが, cairo_pdf を薦める理由の1つだ.

cairo_pdf() の利点

おれが cairo_pdf を薦める理由は以下の3つだ.

  1. パッケージや外部プログラムの追加インストールが不要 (Mac のみ X11 が必要)

  2. 下準備がほとんどいらない

  3. (pdf と違い) Type 1 以外のフォントも埋め込んでくれる

そもそもpar()で指定できるフォントとかはいにしえの時代に作られたものなので, 前者は postscript を使用してコンバートするが, TrueType とか OpenType 的な現在主流のフォント規格に対応していない. つまり, 現在使われている日本語フォントの多くが使えない. これがPDFの日本語埋め込みに失敗する理由だ. そして cairo_pdf() は名前通り cairo という外部ライブラリを使用して画像変換している. これは複雑な設定なしに多くのフォントを使うことができるが, 一方で ヘルプに書いてあるように必ずしもベクタ画像化するとは限らず, ラスタ画像に変換することがある. しかしおれの経験上, 粗いと感じるレベルになったことがない.

cairo_pdf のすくない弱点は2つ. 1つはマッチするフォントがなくてもエラーや警告を出さないこと, 2つ目はデフォルトのフォントがOSの決めたものではなくHelveticaで固定されていることだ. つまり, cairo_pdf の認識できないフォントを使った場合, 勝手に Helvetica に置き換えられてしまう. そして Helvetica は当然日本語グリフが用意されてないし, プリインストールーされているのはMacだけだ.

また, たまに見かける quartzFonts()windowsFonts()serifsans に日本語フォントを上書きするという方法も ggplot2cairo_pdf では有効ではない. これはデフォルトフォントを書き換えることで特にフォント名を指定しなくても日本語グリフの用意されたフォントにフォールバックするとゆう仕組みだが, cairo_pdf のデフォルトフォントはこの方法で変更できないから無効だ. ヘルプではデフォルトフォントはHelveticaなので日本語グリフが用意されてない (と言いつつWINDOWSUbuntuはなんかしらんが日本語フォントにフォールバックしてしまうので文字化けしにくい). よって sans とかに日本語フォントを上書きするくらいなら最初からフォント名を指定したほうがどのグラフィックデバイスでもうまくいきやすい.

MAC特有の制約

他のセクションでも何度か書いたが, ここで改めてまとめてやる.

MACの場合, グラフィックデバイスquartzを指定すればいろいろな追加インストールが不要になる. こいつは type = "pdf"/type = "png" とか書くとファイル形式を指定できる. ちょうどこんな感じだ.

ggsave("...pdf", device = quartz, type = "pdf")

dev.copy(quartz, file = "...png", type = "png")
dev.off()

どっちを教えようかなやんだが, なるべくシンプルなはなしにしたかったのでこっちを後回しにした. だがおまえがMACしかつかわないならこっちの方法も有効だ.

あとMacはフォントをイタリックとかにしてくれない. Cairoは標準フォントから擬似的にイタリック体(斜体)を生成してくれるが, MACは実はCairoを使えずX11を使っている. 日本語フォントは普通イタリックとか用意されてないからMACでは日本語を斜体にできない.

ついでにMACWINDOWSLINUXと違い, フォントが見つからないと全部Helveticaにする. だからグラフを描く時にかならずフォントを指定しろ. それか保存時にオプションで指定しろ. UNIX系だからFontconfigが反映されるとおもったがなんかよくわからない. X11 のオプションも効果がない. たぶんX11が悪いかタルサ・ドゥームの罠だろう. おれはあきらめた.

バイスごとの細かい差異

同じファイル形式でも, 同じ関数で描いたグラフでも, 使用するOSやデバイスごとに出力が微妙に違う. typeCairo とか選べる. 細かいところに気づくやつは気づく.

例えばこのページではデバイスやOSごとの微妙な違いを比較している.

https://www.jumpingrivers.com/blog/r-graphics-cairo-png-pdf-saving/

さらに ragg とゆうパッケージがラスタ画像のグラフィックデバイスを提供する. インストールが少々大変だが, pngragg_png とかに置き換えるだけで使い方は同じだ. あとなんか早いらしい.

間違った方法, 使いにくい方法

おれがここで教えた方法以外にもやりかたはたくさんある. おれが教えた方法は, おまえが読んだ教科書やブロゴとかに載っている方法と違うかもしれない. それはだいたい間違ってたり, 間違ってなくてもとても使いにくい. もしお前が細かい違いにも注意深い真の男なら, 以降の解説が役に立つだろう.

"Japan1GothicBBB" とか "Japan1Ryumin" とかを使わない理由

古い情報では "Japan1GothicBBB" とか "Japan1Ryumin" とか指定しろと書いているが, おれやおまえのPCにそんなフォントが存在すると思ってのか*9. こいつらはそれぞれ「 中ゴシックBBB」「リュウミン」とゆうフォントで, このフォントを持ってるやつだけが指定すべきなのだ. たまたま運良く適当なフォントにFALL BACKすれば動くが, 動かないことのほうが多い.

Windowsだったら

windowsFonts(
  Japan1GothicBBB = windowsFont("Yu Gothic")
)

とか書き換えればかわりに游ゴシックが参照されるので動作するだろうが, sansとかを上書きするのと同じでメリットは特にない.

こいつらはモリサワとゆう企業が大昔から販売している日本語フォントだ. 大昔なのでType-1形式にも対応しているし, デファクトスタンダードな感じになっているらしい (詳しい話は Adobe-Japan1 とかでけんさくしろ). だからRに日本語表示させたいとゆう要望に答えて開発者が大昔に追加した(Murell and Ripley 2006). だが普通のPCには入っていない. 要は PDF() で保存した時にフォント名として参照してくれるとゆうだけでフォントの埋め込みとは一切関係ない. これはひとむかしまえのWORDをPDFにエクスポートしたときにFONTが埋め込まれずありもしないこいつらが指定された問題と似ている.

あるいは "Japan1" とか "Japan1Heimin" というじゅもんを挙げることもある. 前者は「小塚明朝Pro」で後者は「平成明朝」だ. こいつらも普通のPCには入っていない. 前者はAdobeReaderが表示に対応しているからそれで開けば表示できる, と言い張ってるだけだ. ハングルとか中国語とかも名称だけ用意されてるがたぶんおなじだろう.

重ねて言うが今は cairo_pdf を使ったほうが楽だ.

showtext は使わなくてもいい

日本語表示問題で showtext パッケージに言及されることがある. これは基本 pdf() とか基本グラフィックデバイスかんすうで日本語フォント (より正確には標準的な欧文フォント以外) を, 外部プログラム無しで表示するためのパッケージだ. だがすでに書いたように pdf() は普通の日本語フォントには対応していない. そこで苦肉の策として文字を画像として扱う (アウトライン化) ことで文字の表示を実現している. つまり, この方法では RStudio 上に表示できるかとは関係なく, PDF 形式でも文字を検索できない.

そもそも開発者がドキュメント(Qiu 2014, 2015)で書いている通り, showtextcairo_pdf が使えない時にPDFに文字を表示させたい場合に効果を発揮する. だが cairo が使えない場面は現在ほとんどないから推奨しない. それにこいつは最短でshowtext_auto()だけで日本語フォントを使えるようになるが, どのフォントかは指定できない. それにはいちいち font_add() で手動登録する必要がある. 手間がほぼ変わらずフォントを埋め込めるぶん, cairo_pdf のほうが便利だとおれは判断した. あとフォントのフォールバックとか, うまく読み込めないフォントがあったとかいろいろ使いづらかった. よって cairo_pdf より大きなメリットがあるとは言えない. すでに紹介した方法を実行すればshowtextを使わずともだいたいの場合でうまくいく.

extrafont も使わなくていい

extrafontも通常の方法ではRのグラフィックデバイスで読み込めないフォントを読み込んでグラフに表示させるためのパッケージだ. つまり showtext と違い, フォント情報が失われない (Windowsのみこれができないのでアウトライン化するらしいが試していない).

結論から言うと見出しの通りだがおれはようじん深いので一応簡単な使い方を書いておく.

公式のチュートリアルによれば, 次のような使い方になる. 初回や新たにフォントをインストールしたときは font_import() でフォントキャッシュを更新する. この操作はOS側が認識しているフォントを全て読み込み, R 側が認識していないもの (主に TrueType フォント) を ttp2tp1 というプログラムで, Rが扱いやすいType1 形式に変換している.

require(extrafont)
load_fonts()

使用する際は, extrafont パッケージを読み込み, load_fonts() でキャッシュを読み込む. これで pdf() に従来指定できなかったフォントも指定して保存できるようになるが, 保存されるのはフォントマップ情報のみなのでこの時点では埋め込まれない. 次に embed_fonts() で保存したPDFにフォントを埋め込む. この関数は Ghostscript を使ってPDFにフォントを埋め込んでいる*10.

しかし実際に動かしてみるとグリフ情報が正しく認識されず文字が重なったりしてうまく動かないことが多い. それになんか .ttc ファイルを一切読み込まなかったりするから取得するフォントにかなり漏れがある. もう既に cairo_pdf で簡単に埋め込む方法を確率したのでこれ以上は問題と原因を調べる気が起きない.

おまえが showtextextrafont を使うべきときは, 何らかの理由で cairo_pdf が使えないか, Cairo のレンダリングが気に入らない (わずかにフォントが太くなる傾向がある) かだろう. そしてこのようにこれら2つのパッケージは制約が多いから, 苦労に見合ったものになるかも気をつけるべきだ.

この違いがわかるか?

基本パッケージに含まれる grDevices::cairo_pdf() とは別に, cairoDevice::Cairo_pdf() というものが存在する. 同様に SVG と PS, そしてPNGとかにも対応する関数が存在する. もしもお前が先頭の大文字に気づかなければ, いつまでも意図した動作が得られないまま時間と体力だけを消耗し, やがてメキシコの砂漠で行き倒れになることだろう. どちらも名前通り Cairo という外部ライブラリを利用しているが, 後者はフォントを指定する引数が存在しない. このパッケージは『もうカツ丼はいいよな』 で10年以上前に紹介されているが, それ以降見向きもされていない. 実際おれの環境では便利なのだがMacWindowsとかでなんかうまくインストールできなかったりフォント指定が反映されなかったりしたので紹介しなかった. 原因が分かったら修正するかもしれない.

そしてさらに Cairo::cairoPDF() という関数も存在する (こいつも SVGPNG 版がある). こちらも Cairo_pdf と同様にフォントを自動選択してくれる, としているが, 実際には挙動が標準グラフィックデバイスに準拠しているため, 非欧文フォントはあんまり対応してない.そのため, 既に紹介したWINDOWSMACのフォント登録とは別にフォント登録が必要になる(そしてWINDOWSに至ってはggplot2に対応していない). つまり下準備がかなり面倒なため, 今回は選択肢から外した.

tikz を使う

日本語化よりもRの数式が気に入らない場合, tikzDevice で tikz を使い TeX ソースに変換することができる. よって, LaTeX でできる範囲ならどんなものも表示できる. R Markdown でも dev=tikz を設定するだけで使用できるが, 日本語表示と両立させるといろいろやることが多い. たとえばXeLaTeXで最短でやるならば最低限 engine="xetex", documentDeclaration="\\documentclass[xetex,ja=standard,jafont=noto]{bxjsarticle}\n" とかのオプションを書く必要がある.

TeXに慣れたやつだけが使うべきだろう.

いにしえのプロトコル

demo("Japanese") を実行するといにしえの日本語入力プロトコルを垣間見ることができる. もちろん現在使う必要はない.

参考文献

Murell, Paul, and Brian Ripley. 2006. “Non-Standard Fonts in Postscript and PDF Graphics.” R News 6 (2): 41–46. Retrieved from here.

Qiu, Yixuan. 2015. “Showtext: Using System Fonts in R Graphics.” The R Journal 7 (1): 99–108. DOI: 10.32614/RJ-2015-008.

———. 2014. “Using System Fonts in R Graphs.” Retrieved from here.


*1:どうしてもめんどうだったらMACは別の方法がある. 「MAC特有の制約」のくだりを読め.

*2:ggplot2 ベースのパッケージは例えば ggmap とか gghighlight とか bayesplot とか factorextra とか mlr3 とか, CRAN - Package ggplot2 をみればわかるようにとにかくあほみたいにたくさん作られている. だが作ったやつはあほでもこしぬけでもなく真の男なので役に立つことが照明されているのはゆうまでもない. 基盤が同じなので ggplot2 の基本的な使い方さえおぼえていれば習得しやすく, 自分でデザインの変更もやりやすい.

*3:geom_text(), geom_label() など, グラフの内部に文字をプロットするタイプの関数はこの限りではない. 関数ごとに family=に指定する必要がある. 詳しくはこの後の「補足」セクションを読め

*4:だがおれはその後, ggplot2 でほぼ同じグラフを描く関数を用意した 『[小ネタ] [R] randomForest::MDSplot() を ggplot2 で書き直す - ill-identified diary

*5:参考: https://github.com/tidyverse/ggplot2/issues/1859

*6:ただし古いバージョンでは対応していないかも知れない. 2017年ごろの更新で対応したという話もある. 自動更新される最近の Office ならおそらく同じことができると思われる. Windows 版 Home and Business Premium バージョン 2010/ Mac 版 365 サブスクリプション, バージョン 16.43 (20110804) で確認: https://r-wakalang.slack.com/archives/C088B7YSU/p1606569510095000?thread_ts=1606436666.093100&cid=C088B7YSU

*7:もっともおれはLINUXしか使わないからフォント登録は不要だ.

*8:なお EPS 画像という手もあるが, R と LaTeX を使うという今回のやり方ではあまりメリットがない. 詳しくは『LaTeX入門/図表』『2018年でもEPSファイルをTeXで使う』 に書いてあるように, PDF に EPS を挿入するには Ghostscript の処理を挟む必要があり, 最終的にPDFに貼り付けるなら完全に不要な処理である. さらに細かいことを言えば Purified EPS という規格であればなんかうまくいくので PDF に対して EPS はテキストデータなのでバージョン管理がしやすいという利点を活かせる. しかし R での使用に限って言えば, その画像を再現できる R プログラムを管理したほうが簡単だろう.

*9:誰とは言わないがなぜかこれで日本語を出力できると書く人間が跡を絶たない. 既に挙げた『Rでのフォントの扱い』にも書いてあるように実際にやってみればフォントは埋め込まれず, 他のPCで正しく表示されないことは一目瞭然だ. 10年前とかに書いたならまだしも, この記事の書かれた2017年以降になても Japan1BBBGothic とか Japan1HeiMin とかを使えとゆう記事が検索結果の上位に現れるとゆう有様だ. プログラーミングは意味のわからないじゅもんではない. なぜこんなじゅもんが流布してるのか俺にはわからない. PROGRAMMINGでいう「おまじない」はおしえるやつはりかいしているが, 重要でないわりにおしえるのが大変なので省略するとゆう意味で使われていた. だがこの件に関してはおしえるやつもタルサどもの罠にかけられたに違いない.

*10:実際の埋め込み処理はBaseの embedFonts() を使っているのでGhostscriptが必要になる.