R
RMarkdown
Katex

R MarkdownでKatexを使って数式表示

More than 1 year has passed since last update.

タイトルのまんまです。気が向いたのでやってみた。

Katexとは

Katexとはtexライクな数式コードをブラウザ上でレンダリングするためのJavaScriptライブラリです。同様のJavaScriptとしてはmathjaxが筆頭としてよく利用されており,R Markdownでも標準でmathjaxを利用するようになっています。

ただ最近「mathjaxよりKatexを使わないかい?」という意見を見るようになり,選択肢が多いほうがいいと思い実装してみました。

実装

まず以下のようなhtmlファイルを準備します:

include_katex.html
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.css" integrity="sha384-wITovz90syo1dJWVh32uuETPVEtGigN07tkttEqPv+uR2SE/mbQcG7ATL28aI9H0" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.js" integrity="sha384-/y1Nn9+QQAipbNQWU65krzJralCnuOasHncUFXGkdwntGeSvQicrYkiUBwsgUqc1" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/contrib/auto-render.min.js" integrity="sha384-dq1/gEHSxPZQ7DdrM82ID4YVol9BYyU7GbWlIwnwyPzotpoc57wDw/guX8EaYGPx" crossorigin="anonymous"></script>
<script>
  document.addEventListener("DOMContentLoaded", function() {
    renderMathInElement(document.body, {delimiters: [
      {left: "$$", right: "$$", display: true},
      {left: "$", right: "$", display: false}]
    });
  });
</script>

これをRmdのyaml-front-matter(冒頭のyaml部分)でin_headerにて読みこむように指定します:

---
title: "R MarkdownでKatexを使って数式表示"
output:
  html_document:
    includes:
      in_header: include_katex.html
    mathjax: NULL
    self_contained: false
---

以下テスト。

$$
f(x)= \sum_{k=0}^{\infty} \frac{ f^{(k)}(x_0)}{n!} \left( x-x_0 \right)^k 
$$

文中の数式$y = f(x)$のテスト。

これでOKです。以下のような感じになります:

3453333.png

解説

mathjaxの解除

katexを使うのでmathjaxを解除する必要があります。これは上述の例のようにyaml-front-matterでmathjax: NULLとすればOKです。

Katexの読み込み

要するにkatex.min.jskatex.min.cssのファイル,及びauto-renderのためのauto-render.min.jsをheadに読み込むような<script>タグを仕込めばいいだけです。これについては公式サイトを参照してもらえればと:

CDNへのパスについては,必ず公式サイトをチェックしてから,必要に応じて変更してください

Katexの設定

色々設定ポイントがあるのですが,詳しくは上記公式サイトを参照してください。今回はmathjaxからの移行とR Markdownでの利便性を考え,以下のように設定しました:

document.addEventListener("DOMContentLoaded", function() {
  renderMathInElement(document.body, {delimiters: [
    {left: "$$", right: "$$", display: true},
    {left: "$", right: "$", display: false}]
  });
});

これで$$で挟んだものはブロック要素として,$で挟んだものはインライン要素(行内)でレンダリングされるようになります。これについては以下のサイトを参考にさせていただきました:

留意事項

地雷というか気になる点がいくつかありました。

self_containedについて

上記例ではself_contained: falseと指定しています。つまりhtmlファイル内にbase64-encしないようにしてます。この場合オンラインでないと表示されません。ですがCDNで読み込むようにしているので速度は(回線が貧弱でなければ)十分でしょう。

なおself_contained: trueでも動作しますが,正直オススメしません。理由は以下の2点です:

rmarkdown::renderにかなり時間がかかる

katexをまるっとDLしてbase64encして差し込むので,その変換の分時間がかなりかかります。またファイルサイズがかなり大きくなります。これだとkatexを利用するメリットほぼなし,です。

CDN読み込みの<script>および<link>タグ内属性について

検証中に気付いたのですが,self_contained: trueにするなら以下のようにしないとうまく表示されませんでした:

  • CDNから読み込む(今回の)<script>タグ内属性はsrc属性のみ
  • CDNから読み込む(今回の)<link>タグ内属性はrel属性とhref属性のみ

公式サイトでは,CDNとの整合性チェックのためIntegrity属性を指定したコードが表示されています。これはセキュリティ上大切だと思うし,そうすべきだと思います。でもそれが入っているとどうも動作しません…。ダメダメです。

RStudio DesktopとRStudio Serverの違い

環境にもよるかもしれませんが,手元(Ubuntu)で検証したところViewerでの表示速度に大きな差がでます。おそらくRStudioに組み込まれているブラウザの問題で,Desktop版だとものすごく遅くなります(ビジーになる)。なおRStudio Serverでrenderすると瞬時に表示されます。「katex速い」が実感できるはずです。てことでできるだけRStudio Server版でやりましょう

Katexとmathjaxは完全互換ではない

大体のことは大丈夫なのですが,多少違います。この辺りは省略しますので,ご自身で調べてみてください。

結論

こうなりました:

  • in_headerでスクリプトを読み込ませる
  • self_contained: falseを超推奨
  • RStudio Server環境を推奨

これらが揃えば,きっとmathjaxにはない数式レンダリング速度を体験できるでしょう。

Enjoy!