SVG画像

[2022-09-09] 何年も放置していたので状況がかなり変わってきました。最新の R 4.2.1 でやり直しました。

はじめに

拡大してもジャギーが出ないベクトルグラフィックの SVG形式 が Web では広く用いられるようになりました。かつては、R で SVG を出力するには、R 標準(cairo)の svg() を使うか、RSVGTipsDevice パッケージの devSVGTips() を使うという選択肢がありました。2015年末に Hadley Wickham が新しい svglite というパッケージを作りました(アナウンス、GitHubの hadley/svglite)。一方、RSVGTipsDevice は CRAN から消えてアーカイブ入りしてしまいました。また、ggplot2 では ggsave() という関数で SVG を含むいろいろな形式で保存できるようになりました。

cairo 版では、文字も図形になり、ビューアに依存しないので安心ですが、日本語を使う場合は下の例のように日本語のフォント名を指定する必要があります。一方、svglite 版は文字は文字情報のまま入りますので、テキストエディタで文字列やフォント名を編集することができます。

比較のため、Mac で普通に画面に描いてスクリーンショットをとって PNG にしたものを最初に挙げておきます:

quartz(width=7, height=4)
par(mgp=c(2, 0.8, 0))
curve(dnorm(x), xlim=c(-3, 3), main="正規分布")
Quartzグラフィックの例

標準(cairo)の svg() を使って SVG 出力します(XQuartz のインストールが必要のはずです):

svg("dnorm-cairo.svg", family="Japan1GothicBBB", width=7, height=4)
par(mgp=c(2, 0.8, 0))
curve(dnorm(x), xlim=c(-3, 3), main="正規分布")
dev.off()
CairoのSVGの例

ファイルサイズは 29558 バイトです。

svglite の svglite() を使います:

library(svglite)
svglite("dnorm-svglite.svg", width=7, height=4)
par(mgp=c(2, 0.8, 0))
curve(dnorm(x), xlim=c(-3, 3), main="正規分布")
dev.off()
svgliteのSVGの例

ファイルサイズは 6442 バイトになりました。

フォント指定は Arial になるようです。「正規分布」という日本語の幅がちょっと微妙ですね。SVG ファイルを見ると、textLength='...' lengthAdjust='spacingAndGlyphs' のような記述がたくさんあるので、これらを一括削除してみました。[2022-09-15追記] ついでに font-family: "Arial";font-family: sans-serif; に一括置換しました。

svgliteのSVGの例(修正)

一括削除の方法はいろいろありそうですが、例えば sed なら次のようにします:

sed "s/ textLength='[^']*' lengthAdjust='spacingAndGlyphs'//g" dnorm-svglite.svg >dnorm-svglite-fixed.svg

こちらのほうがファイルサイズも 5652 バイト("Arial" を sans-serif に直して 5727 バイト)に減りますし、見かけ上も良さそうです。

rsvgによる変換

SVG は Web では最適ですが、論文など PDF で提出するものを LaTeX で作成する際には、図も PDF で用意することになるので、最初から PDF で出力するか、SVG を PDF に変換する必要があります。

SVG を PDF などに変換するには、GNOME プロジェクトの一環として開発された SVG ライブラリ librsvg が便利です。rsvg の頭の r は 開発者 Raph Levien の頭文字かと思ったら、"Resplendent SVG" の略だそうです(GNOME Wiki: Librsvg にそう書いてありますが、ほんとかな)。これを R から使えるようにしたのが rsvg パッケージです。これを使えば SVG 画像を PDF や任意解像度のビットマップ画像に変換できます。

前節の最後に書いたように修正した svglite 出力で試してみます:

library(rsvg)
rsvg_png("dnorm-svglite-fixed.svg", "dnorm-svglite-fixed.png")  # PNGに変換
rsvg_pdf("dnorm-svglite-fixed.svg", "dnorm-svglite-fixed.pdf")  # PDFに変換

変換した PDF はちゃんとフォントが埋め込まれています:

% pdffonts dnorm-svglite-fixed.pdf
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
SDIIYF+ArialMT                       TrueType          WinAnsi          yes yes yes      6  0
NLDWWV+ArialMT                       TrueType          WinAnsi          yes yes yes      7  0
GJXHML+HiraginoSans-W6               CID Type 0C       Identity-H       yes yes yes      8  0

なお、Mac では brew install librsvg、CentOS 7 では yum install librsvg2-tools で入る rsvg-convert コマンドを使えば、R を使わなくても SVG → PNG/PDF 変換ができます。ターミナルで例えば

rsvg-convert --format=pdf --output=hoge.pdf hoge.svg

のようにして使います。