Plots.jlはJuliaにおいてグラフをプロットするためのパッケージで、バックエンドエンジンを切り替えることでさまざまな形式の出力に対応できる。私は普段tex形式で出力可能なPGFPlotsX.jlをバックエンドとして走らせている。
が、こうするとラベル名、凡例名、タイトル名に日本語を含んだ場合、少々厄介な問題が浮上する。それについて今のところ私が試してみた限りのことを書く。
問題の所在
バックエンドでPGFPlotsXを走らせながらPlotsを使うには、次のようにする。
using Plots using LaTeXStrings pgfplotsx() # 二次関数 function f(x) return x^2 end plt1 = plot(-2:0.01:4, f, label="二次関数", xlabel="横軸", ylabel="縦軸") savefig(plt1, "figname.tex")
ここでは、凡例名に二次関数、x軸名に横軸、y軸名に縦軸なる名前を指定している*1。
このままJuliaを実行すると、困った事態が生じる。これらの日本語の軸名がLaTeXの数式として解釈され、しかも一文字一文字が独立した数式として$で囲まれるのである。生成されたfigname.texの中身を見てみると次の通り(三点リーダーは省略を意味する)。
︙ \begin{axis}[ ︙ xlabel={$横$$軸$}, ︙ ylabel={$縦$$軸$}, ︙ ] ︙ \addlegendentry {$二$$次$$関$$数$} \end{axis} ︙
xlabelやylabelの値ならびに\addlegendentryの引数がひどいことになっていることがわかる。ぶっちゃけ日本語フォントの場合は数式化しても見た目がほとんど変わらないのでこれでも良いのかもしれないが、あまり望ましい状態ではない。
解決策を探る
この解消のために思いつく策がいくつかある。第一にJuliaのraw"…"文字列を使うことである。第二にLaTeXStringsパッケージのL"…"文字列を使うことである。両者ともなんかよく見る解決策である。
第一の策を取ってみる。文字列をraw"…"に置き換える
plt1 = plot(-2:0.01:4, f, label=raw"二次関数", xlabel=raw"横軸", ylabel=raw"縦軸") savefig(plt1, "figname.tex")
が、この策は何の効果もない。結果は以下。
︙ \begin{axis}[ ︙ xlabel={$横$$軸$}, ︙ ylabel={$縦$$軸$}, ︙ ] ︙ \addlegendentry {$二$$次$$関$$数$} \end{axis} ︙
気を取り直して第二の策を取る。文字列をL"…"に置き換える。
plt1 = plot(-2:0.01:4, f, label=L"二次関数", xlabel=L"横軸", ylabel=L"縦軸") savefig(plt1, "figname.tex")
この結果は以下の通り。
︙ \begin{axis}[ ︙ xlabel={$横軸$}, ︙ ylabel={$縦軸$}, ︙ ] ︙ \addlegendentry {$二次関数$} \end{axis} ︙
一文字一文字が$で分断されるという馬鹿げた状態は回避できた。しかしながら依然として日本語が数式扱いになっている。これをどうにかする手段はないものだろうか。
LaTeXStringsパッケージ
LaTeXStringsというパッケージにおけるL"…"文字列は、主として次の2つの特徴を持つ(と理解している)。
LaTeXStringsパッケージを使ってもなお数式扱いになるのは2.の効果が作用しているからではないか?という粗雑な推論を立てる。
LaTeXStringsパッケージのREADME.mdには次のようなことが書いてある。
Finally, you can use the lowest-level constructor
LaTeXString(s). The only advantage of this is that it does not automatically put$at the beginning and end of the string. So, if for some reason you want to usetext/latexdisplay of ordinary text (with no equations or formatting), you can use this constructor. (Note that IJulia only formats LaTeX equations; other LaTeX text-formatting commands like\emphare ignored.)最後に、最低階層のコンストラクタ
LaTeXString(s)を使うことができる。これの唯一の利点は文字列のはじめと終わりに自動的に$を挿入しないことである。そのため、何らかの理由で(数式化やフォーマットされていない)通常のテキストのtext/latex表示を使いたい場合にはこのコンストラクタを使うことができる。(IJuliaはLaTeX数式のみをフォーマットすることに注意。\emphといった他のLaTeXのテキストフォーマットコマンドは無視される。)
つまり、LaTeXStringコンストラクタはL"…"から2. の機能を落としているということっぽい。というわけで、早速LaTeXString()を使ってみる。引数は文字列らしいので、LaTeXString("…")となる。
plt1 = plot(-2:0.01:4, f, label=LaTeXString("二次関数"), xlabel=LaTeXString("横軸"), ylabel=LaTeXString("縦軸")) savefig(plt1, "figname.tex")
これを実行すると以下の通り。
︙ \begin{axis}[ ︙ xlabel={横軸}, ︙ ylabel={縦軸}, ︙ ] ︙ \addlegendentry {二次関数} \end{axis} ︙
これでうまく行った。
結論としては、LaTeXString("…")で囲えばうまくいくということになりそうである。なお、文字列内に制御綴を含む場合(例えば\bfseriesなど)は制御綴の\を適宜\を使ってエスケープする必要があるっぽい*2。
日本語と数式環境が混在する場合
今まではラベル名に日本語のテキストだけが存在する状態であった。日本語と数式が混在する状況ではどうなるのだろうか。
結論としては、この場合はLaTeXString()を使わずにL"…"文字列を使い、数式部分は$で囲めば問題なさそうである。L"…"文字列内に$が含まれているので前後の$自動挿入がなされないからということなのだろうか。
# うまくいく例 plt1 = plot(-2:0.01:4, f, label=L"二次関数$y=x^2$", xlabel=L"横軸$x$", ylabel=L"縦軸$y$") savefig(plt1, "figname.tex")
結果は以下のようになる。
︙ \begin{axis}[ ︙ xlabel={横軸$x$}, ︙ ylabel={縦軸$y$}, ︙ ] ︙ \addlegendentry {二次関数$y=x^2$} \end{axis} ︙
ただし、L"…"を使わずに通常の文字列"…"を使い、$を\でエスケープする方式はうまくいかない。
# うまくいかない例 plt1 = plot(-2:0.01:4, f, label="二次関数\$y=x^2\$", xlabel="横軸\$x\$", ylabel="縦軸\$y\$") savefig(plt1, "figname.tex")
日本語が一文字一文字分裂して数式扱いされるうえに、\$がそのまま吐き出されるという最悪な結果になる。結果は以下の通り。
︙ \begin{axis}[ ︙ xlabel={$横$$軸$\$x\$}, ︙ ylabel={$縦$$軸$\$y\$}, ︙ ] ︙ \addlegendentry {$二$$次$$関$$数$\$y=x^2\$} \end{axis} ︙
しかしながら先述のLaTeXString()はこの点でも強く、これを使えば"…"でもうまくいく。
# うまくいく例 plt1 = plot(-2:0.01:4, f, label=LaTeXString("二次関数\$y=f(x)\$"), xlabel=LaTeXString("横軸\$x\$"), ylabel=LaTeXString("縦軸\$y\$")) savefig(plt1, "figname.tex")
LaTeXString()の引数にL"…"を取ることも可能。
# うまくいく例 plt1 = plot(-2:0.01:4, f, label=LaTeXString(L"二次関数$y=f(x)$"), xlabel=LaTeXString(L"横軸$x$"), ylabel=LaTeXString(L"縦軸$y$")) savefig(plt1, "figname.tex")
いずれも以下のような結果になる。
︙ \begin{axis}[ ︙ xlabel={横軸$x$}, ︙ ylabel={縦軸$y$}, ︙ ] ︙ \addlegendentry {二次関数$y=x^2$} \end{axis} ︙
結論
これらをまとめると次のようになる。
1. ラベル名に日本語を含み、数式を含まない場合
LaTeXString("…")を使う。文字列内に(La)TeXの制御綴を含む場合は適宜\によるエスケープが必要。
label = LaTeXString("二次関数")
2. ラベル名に日本語と数式を含む場合
L"…"を使い数式部分は$で囲む。エスケープは必要ない。
label = L"二次関数$y=f(x)$"
あるいは、LaTeXString("…")を使い数式部分は\$で囲む。(La)TeXの制御綴なども適宜\によるエスケープが必要。
label = LaTeXString("二次関数\$y=f(x)\$")
おまけ:ラベル名に日本語を含まない場合
ラベル名に日本語(非ASCII文字?)が含まれない場合は楽である。以下のようにすればいい。
1. テキストだけの場合
通常の文字列"…"を使う。
xlabel = "quadratic function"
2. テキスト+数式の場合
通常の文字列"…"を使い数式環境は\$で囲む(適宜\によるエスケープが必要)。もしくはLaTeXStringsのL"…"文字列を使い数式環境は$で囲む(エスケープの必要なし)。
xlabel = "quadratic function\$y=x^2\$"
xlabel = L"quadratic function$y=x^2$"
3. 数式だけの場合
通常の文字列"…"を使い前後を\$で囲む(適宜\によるエスケープが必要)。もしくはLaTeXStringsのL"…"文字列を使う(前後の$は必要なし、エスケープの必要なし)。
xlabel = "\$y=x^2\$"
xlabel = L"y=x^2"
感想
日本語文字列を含むと途端に取り扱いが面倒になる。なぜかはわからないが、まあそういうものなのだろう。なおバックエンドによっても挙動は違っていたので、やはりわからないことだらけである。
ここで書かれているやり方は「こうやったらなんかしらんけどうまくいった」程度のものであるから、あまり鵜呑みにしないほうがいい。PGFPlotsX側の記法で指定した場合はこういう問題は起きなかったので、おそらくPlotsに問題があるのだろうと推測している。