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

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

## Katexとは

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

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

## 実装

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

```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](https://qiita-image-store.s3.amazonaws.com/0/35118/5f6c9b20-05da-a9ff-c24b-63f8426dcc93.png)

## 解説

### mathjaxの解除

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

### Katexの読み込み

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

- [Khan/KaTeX: Fast math typesetting for the web.](https://github.com/Khan/KaTeX)
- [Auto-render extension](https://github.com/Khan/KaTeX/blob/master/contrib/auto-render/README.md)

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

### Katexの設定

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

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

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

- [はてなブログでKaTeXを使う - kivantium活動日記](http://kivantium.hateblo.jp/entry/2016/11/18/142840)

## 留意事項

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

### 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!**