TikZ を standalone でサブファイル化したい

# TikZ を standalone でサブファイル化したい

TikZ は LaTeX 上で描画する強力なツールです。一方で、TikZ コードが本文ファイル内にある場合、以下のような問題が生じます。

- TikZ・本文のいずれか一方を作成中に、他方もタイプセットに含まれるため、試験的なタイプセットが長くなってしまう
- TikZ コードと本文がファイル内に混在するため、ファイル全体が煩雑になる

これらの解決方法は簡単で、TikZ コード（tikzpicuture 環境）のみを抜き出し、別ファイルとして作成し、必要な段階で TikZ イメージを挿入できるようにしてしまえば良いのです。（サブファイル化）しかし、単にサブファイル化して `\input` しても、サブファイルは単独でタイプセットすることが出来ません。

このような TikZ 単体でタイプセットし、メインファイルに後から挿入する方法を実現するには、standalone パッケージが便利です。

https://ctan.org/pkg/standalone

[standalone]: https://ctan.org/pkg/standalone "standalone \- CTAN"

本記事では TeX ソースのまま挿入する方法を考えます。

実は、standalone によってサブファイル化された TikZ イメージの挿入は、PDF を `\includegraphics` する方法もあります。しかし、TeX ソースをそのまま挿入する方法は、記事としてあまり見かけることはありませんでした。本記事はそんなスキマを埋めるスキマ記事です。

## ■ 前提

本記事では、メインファイルと TikZ ソースのみのファイルを、以下のようなディレクトリ構造で作成していると想定します。また、tikz フォルダにある tikz1.tex や tikz2.tex は独立してタイプセットでき、これらで描画された TikZ イメージを main.tex に挿入します。

```directory-tree
.
├─ main.tex
└─ tikz/
    ├─ tikz1.tex
    ├─ tikz2.tex
    ├─ ...
    └─ tikzN.tex
```

TikZ コード部分を抜いた本文のあるファイルを “メインファイル” (main.tex)、TikZ を描画するためだけのファイルを “サブファイル” (tikz1.tex, tikz2.tex...) と呼ぶこととします。

## ■ standalone のきほん

:::note info
standalone には文書クラスとパッケージのそれぞれにオプションがあります。また、提供されるコマンドにもコマンドオプションがあります。

記事内では、
- 文書クラスオプション
- パッケージオプション
- コマンドオプション

と区別して呼称しますが、この違いに注意してください。
:::

standalone はパッケージと文書クラスの両方があるバンドルです。メインファイルでパッケージを `\usepackage`、サブファイルで文書クラスを `\documentclass` します。

standalone パッケージのデフォルトでは、**サブファイルのプリアンブル（以下、サブプリアンブル）は、メインファイルで読みません。**
多くの場合、サブファイルにもプリアンブルが存在するため、そのままではメインファイル内でサブファイルを含んでタイプセットすることは出来ません。

メインファイルに standalone 文書クラスで作成したサブファイルのプリアンブルを含めるには、**`subpreambles` パッケージオプションを有効にする** 必要があります。このオプションを有効にすると、サブプリアンブルが <samp>.st**a**</samp> (*sta*ndalone) ファイルに転記され、これが 2 回目以降の実行時に読み込まれます。

standalone を利用したサブファイルを含めたメインファイルのタイプセットには少なくとも 2 回の実行が必要になります。また、挿入するサブファイルが最大 N 回のタイプセットを必要とする場合、メインファイルのタイプセットは全体で N+1 回のタイプセットが必要になります。これは、1 回目のタイプセットは standalone パッケージがサブプリアンブルを読む処理に利用されるためです。このとき、サブファイルの TikZ コードは一切読んでいないようです。

## ■ サブファイル

サブファイルでは、standalone を文書クラスとして読み込みます。今回は、TikZ を作成することのみを考えているため、`tikz` 文書クラスオプションを有効にします。これによって、tikzpicture 環境内のみが 1 つをコンテンツとした PDF が作成されるようになります。

:::note warn
standalone はサブファイルのプリアンブルをメインファイルに持ち込むことが出来ますが、メインファイルでも同じパッケージを `\usepackage` すると良いです。（特に pgfplots パッケージが想定されます）

これは非自明なパッケージの衝突を、非意図的に生じさせることを避けるためです。もちろん、サブファイルだけで読み込んだパッケージによる衝突を解消する方法はありますが、煩雑になる可能性があります。
:::

これを踏まえると、サブファイルは次のように書かれます。

```latex
% tikz1.tex, tikz2.tex
\documentclass[tikz]{standalone}
\tikzlibrary{
  % TikZ で必要なライブラリ
}
\tikzset{
  % TikZ に関する設定
}
\begin{document}

\begin{tikzpicture}
  % ここに TikZ コードを記述する
\end{tikzpicture}

\end{document}
```

もしも、サブファイルで共通するプリアンブルを利用したい場合は、サブプリアンブル用の別ファイルを作成し、プリアンブル内で `\input` すれば良いでしょう。

:::note info
このサブファイルには、フォント関連のプリアンブルを含めると危険な場合があります。これは、メインファイルへ TeX 形式で挿入した場合、メインファイルのフォントも変更してしまうためです。

もしも、サブファイルではメインファイルと異なるフォントを利用したい場合は、Image 形式で挿入することをオススメします。
:::

ちなみに、ここで利用される文書クラスは article です。TikZ のみを利用する場合には、文書クラスで違いが出ることは無いでしょう。もしも変更したい場合は、`class` 文書クラスオプションを利用します。(e.g. `class=jlreq`)

## ■ メインファイル

メインファイルでは、`subpreambles` パッケージオプションを有効にした standalone パッケージを早い段階で導入します。また、ここでは詳細にしませんが、`sort` パッケージオプション（サブプリアンブルの適当な並び替え）も有効にしておくと便利です。

:::note warn
メインファイルには `\usepackage{tikz}` が必要です。

サブファイルで `tikz` 文書クラスオプションを利用していても、メインファイルに `\usepackage{tikz}` は読み込まれません。
:::

TikZ イメージを含めたい箇所で `\includestandalone` を書けば挿入されます。ファイルの拡張子は、`extension` オプションによって指定されるため、`\includestandalone` で明記する必要はありません。

```latex
% main.tex
\documentclass{jlreq}
\usepackage[subpreambles, sort]{standalone}
% include other packages
% Example: amsmath, mathtools, hyperref, graphicx, float ...etc.
\usepackage{tikz}
\begin{document}

% Main text...

% \begin{figure}[tbp]
%   \centering
  \includestandalone{tikz/tikz1}
%   \caption{Drawing image by TikZ}
%   \label{fig:tikz-image1}
% \end{figure}

% Main text...

% \begin{figure}[tbp]
%   \centering
  \includestandalone{tikz/tikz2}
%   \caption{Drawing image by TikZ}
%   \label{fig:tikz-image2}
% \end{figure}

% Main text...

\end{document}
```

文書クラスオプションはオプションを有効にする順序を気にします。そのため、前よりも後のオプションが優先されます。

### ▽ プリアンブルの衝突と回避

複数のサブファイルとメインファイルを統合する場合、プリアンブルで衝突が生じることがあります。

`subpreambles, sort` パッケージオプションでも、サブプリアンブルで衝突が生じる場合、`print` パッケージオプションを与えて、別ファイルにすべてのサブプリアンブルを書き出して、手動で回避する方法を考えましょう。

```latex
\usepackage[subpreambles, print, sort]{standalone}
```

これによって、サブファイルを挿入せずにタイプセットが終了し、<samp>.st**p**</samp> (*st*andalone, *p*rint) ファイルが生成されます。このファイルには、すべてのサブプリアンブルが転記されています。この後、次の手順に従います。

1. このファイルを編集して、プリアンブルが衝突しない順序に書き変える
1. メインファイルに書き変えたプリアンブルを追加する
1. `print` パッケージオプションを無効化する
1. メインファイルをタイプセット

もしも、コメントアウトされた部分も <samp>.stp</samp> ファイルに転記したい場合は、`comments` パッケージオプションを有効にします。

### ▽ 挿入する TikZ イメージの調整

挿入する TikZ イメージの大きさ等をコマンドオプションから調整することが出来ます。

`\includestandalone` は [graphicx][] パッケージの `\includegraphics` に類似したコマンドオプションを受け付けます。これは TeX 形式での挿入でも機能します。

[graphicx]: https://ctan.org/pkg/graphicx "graphicx \- CTAN"

頻繁に利用されるオプションは、次のようなものがあります。

| コマンドオプション | 説明                         |
| :----------------: | :--------------------------- |
| `width`・`height`  | 横幅・縦幅の指定             |
|      `scale`       | スケール調整                 |
|      `angle`       | 回転角度の指定               |
|      `draft`       | ドラフトモードへの切り替え   |
|       `page`       | ページ指定（Image 形式のみ） |

`\includegraphics` でも頻繁に利用しますが、`width` を `\textwidth`・`\linewidth` の比で指定すると簡便です。

```latex
\includestandalone[ width=.8\textwidth ]{tikz/tikz2}
```

### ▽ サブファイルの挿入形式

これまで、サブファイルの挿入形式はソースコードとして挿入することを考えてきました。しかし、実は Image 形式として挿入する方法もあります。ここでは、これら 2 つの挿入形式の指定方法を紹介します。

サブファイルを挿入する `\includestandalone` は以下の 2 つの形式を利用することが出来ます。

- TeX 形式（デフォルト）
- Image 形式（PDF あるいは EPS ファイル）
    - `extension` オプションで拡張子を指定
    - デフォルトでは、コンパイラのターゲット出力ファイルの拡張子によって規定されている
        - pdflatex、lualatex、xelatex：`.pdf`
        - latex、(u)platex：`.eps`

TeX 形式での挿入は standalone が行う最も基本的な動作であり、本記事の紹介したかった挿入方法です。しかし、この方法は必ずしも Image 形式での挿入よりもメリットがあるということではありません。

Image 形式でメリットとなる点は、以下の 2 点があります。

- プリアンブルの衝突が生じない
- メインファイルと異なるフォントを簡単に利用できる

特にプリアンブルの衝突は大きなストレスになるため、Image 形式を利用する最大の理由になります。

これらの形式を選択するには、`mode` によるパッケージ・コマンドオプションから指定が必要です。`mode` の採りうる値は以下の 3 つと `build` 系の 3 つの計 6 つがあります。

|         `mode` の値         | 挿入形式                           |
| :-------------------------: | :--------------------------------- |
|       `tex` (default)       | TeX                                |
|           `image`           | Image                              |
| <code>image&#124;tex</code> | Image が無い場合、TeX が指定される |

`\includestandalone[mode=image]` は `\includegraphics` と等価なものになります。`mode=image` を選ぶのであれば、`\includegraphics` を利用した方がこれまでの使用感で利用でき、精神的にも楽かもしれません。

一方で、`mode=image` にはデメリットもあります。

- Image 形式が作成されていないと、メインファイルのタイプセット時にコケる
- サブファイルを更新した場合、Image 形式も更新する必要がある

これらを解決するために、サブファイルの Image 形式をメインファイルのタイプセット時に生成する `mode` があります。（本記事では、これらを “`build` 系” と表現します）

|  `mode` の値   | サブファイルのタイプセット条件 |
| :------------: | :----------------------------- |
|    `build`     | 常にタイプセットする           |
| `buildmissing` | Image 形式が無いとき           |
|   `buildnew`   | サブファイルが更新されたとき   |

:::note warn
これらの `build` 系を指定した場合、`-shell-escape` が必要になります。

もしも `-shell-escape` 無しで実行した場合、デフォルトの `tex` が指定されます。また、タイプセット方法はメインファイルと同じタイプセット方法を採ります。
:::

`build` 系は、サブファイルを更新した場合であっても常に新しい Image 形式を取得することが出来ます。`image` では手動で更新しない限り最新のサブファイルを Image 形式として取得できません。

ただし、`buildnew`・`buildmissing` は少し曲者です。どちらも、サブファイルのタイプセット条件を満たさないときにはサブファイルをタイプセットしないので、多くとも 1 回しかタイプセットしません。
そのため、複数回のタイプセットが必要な場合は、期待した結果を得られない可能性があります。

## ■ (u)pLaTeX 利用時の注意

サブファイルでは、文書クラスで `dvipdfmx` の指定が必要になります。

```latex
\documentclass[dvipdfmx, tikz]{standalone}
```

もしも、`tikz` 文書クラスオプションが上手く機能しなかった場合、次のようにしてください。これは、`tikz` 文書クラスオプションと等価なものとなっています。

```latex
\documentclass[dvipdfmx, varwidth=false, multi=tikzpicture]{standalone}
\usepackage{tikz}
```

また、(u)pLaTeX では、サブファイルに複数コンテンツ（複数の tikzpicture 環境）がある場合、コンテンツを上手く切り出せない問題が生じます。そのため、1 つのファイルに 1 つのコンテンツを徹底する必要があります。

----------

メインファイル内で `mode=image` の下で `\includestandalone` とする場合、(u)pLaTeX のデフォルトでは EPS ファイルが対象になります。

そのため、`extension=.pdf` を指定する必要があります。このとき、`extension` オプションの値は `.` から始まることに注意してください。

```latex
\usepackage[mode=image, extension=.pdf]{standalone}
```
```latex
\includestandalone[mode=image, extension=.pdf]{tikz/tikz1}
```

もちろん、サブファイルの PDF から EPS を作成すれば `extension=.pdf` を指定しなくても良いです。しかし多くの場合、サブファイルは PDF で出力されていることでしょう。また、Image 形式であれば `\includegraphics` を利用する方が簡便かもしれません。

ちなみに、`build` 系を利用すると dvips を勝手に実行して EPS を作成してくれます。そのため手動では、サブファイルを TeX →(LaTeX)→ DVI →(dvips)→ EPS とするべき操作がすべて不要になります。これであれば、(u)pLaTeX でも EPS ファイルを簡単に挿入することが出来ます。（ただし、現在では EPS ファイルの挿入は避けるべきとされています）

## ■ テストファイル

以上の使い方を具体的に示してみたい。

メインファイルと合わせて、これらを以下のようなディレクトリに配置します。

```
.
├─ main.tex
└─ tikz/
    ├─ flowchart.tex
    └─ skip-connection.tex
```

```latex
% main.tex
\documentclass{jlreq}
\usepackage[left=25mm,right=25mm,top=30mm,bottom=30mm]{geometry}
\usepackage[
    subpreambles, sort
    % ,mode=build
  ]{standalone}
\usepackage{hyperref}
\usepackage{caption}
\usepackage{tikz}
\begin{document}

Hellow \LaTeX{}!!

\section{Flowchart}

\begin{center}
  \includestandalone[width=.8\textwidth]{tikz/flowchart}
  \captionof{figure}{\nolinkurl{https://tikz.net/flowchart/}}
\end{center}

\section{Skip Connection}

\begin{center}
  \includestandalone[width=.8\textwidth]{tikz/skip-connection}
  \captionof{figure}{\nolinkurl{https://tikz.net/skip-connection/}}
\end{center}

\end{document}
```

サブファイルで作成する TikZ はそれぞれ tikz.net から適当に引用します。

- https://tikz.net/flowchart/
- https://tikz.net/skip-connection/

今回、メインファイルのタイプセットは LuaLaTeX を用います。また、複数回のタイプセットが必要なため、latexmk (ver.4.80) を利用します。

```terminal
$ latexmk -lualatex (-shell-escape) main.tex
```

`mode=build` 下では `-shell-escape` が必要なため、適宜有効にします。

:::note info
*Q.* <ins> 挿入形式が TeX と Image では、メインファイルの成果物 (PDF) のファイルサイズはどのくらい変わるのか。</ins>
:::

|         挿入形式          | ファイルサイズ (byte) |
| :-----------------------: | :----------------------: |
|            TeX            |          52,851          |
| Image <br> (`mode=build`) |          69,901          |

Image 形式を利用して挿入した場合、TeX を利用して挿入した場合に比べて、少し大きくなりました。これは、挿入した PDF のヘッダー情報が含まれるためだとされています。

したがって、PDF にメインファイルに無いフォントが含まれる場合、より大きなファイルになる可能性があります。

:::note info
*Q.* <ins>挿入形式が TeX と `mode=build` では、メインファイルの生成にかかる時間はどのくらい変わるのか。</ins>

実行・計測は以下のようにします。

```terminal
$ powershell -C Measure-Command {latexmk -lualatex (-shell-escape) main.tex}
```
:::

|         挿入形式          |     秒     |
| :-----------------------: | :--------: |
|            TeX            | 23.8017767 |
| Image <br> (`mode=build`) | 52.224716  |


`mode=build` では、すべてのサブファイルを個々の PDF として生成する必要があるため、`mode=tex` よりも時間がかかってしまいます。今回は、倍程度の差が生じました。

具体的に `mode=build` はメインファイル 1 回のタイプセットで次の順でファイルを実行します。

1. メインファイル
1. サブファイル 1
1. サブファイル 2
1. ...
1. サブファイル N
1. メインファイル

ここで、メインファイルにはサブファイルが Image 形式で挿入されています。しかし、サブファイルは複数のタイプセットが必要になる場合があります。（※ この時点では、サブファイルは必要回数のタイプセットを実行されていません）

完成品としての最終タイプセットであれば、どれだけ長いタイプセットでも待てば良いだけなので、必ずしも `build` 系が悪いものにはならないでしょう。

# 余談

*Q.* <ins>standalone パッケージって、LaTeX で生成される数式とかを余白の無い PDF で出力するためのパッケージじゃないの？？</ins>

開発されたモチベーションは違います。（と言いつつ、`convert` オプションで PNG 出力までアプローチされていますが）

この記事で書いたような、「特定の部分を外部ファイルにして取り出し・挿入したい」がモチベーションになります。そのため、いくつかの競合パッケージが存在します。この点は次節で。

----------

サブファイルを TeX 形式で挿入する場合、中間ファイルに <samp>.sta</samp> ファイルが作成されます。そのため、メインファイルのタイプセット中にエラーが生じた場合、<samp>.sta</samp> ファイルも削除しましょう。latexmk や llmk などのビルドツールや LaTeX Workshop (VSCode) が対象とする削除ファイルには含まれていません。ここには注意が必要です。

----------

サブファイル化された TikZ を Image 形式として挿入している人は、graphicx パッケージを利用して挿入する方が多勢になっているかもしれませんが、実は standalone パッケージからでも挿入することが出来ます。また、`build` 系を利用すれば、サブファイル更新時に挿入される Image 形式が最新のものかどうか深く注意する必要がなくなります。

ただ、どこかに寄稿するなどで TeX ファイルを渡して他人にタイプセットを任せる場合には、サブファイルを Image 形式 (`mode=image`) にしておくべきでしょう。余計な問題を回避できる可能性があります。その人が `-shell-escape` してくれるかも分かりません。

## 他の方法との比較

> § 4.3 Similar packages and classes - The standalone Package

standalone の他にも類似パッケージが存在しています。standalone のガイドには、他の類似パッケージとの差別化点が記載されています。
- [docmute][] パッケージ
- [subfiles][] パッケージ
- external ライブラリ (TikZ)

[docmute]: https://ctan.org/pkg/docmute "docmute \- CTAN"
[subfiles]: https://ctan.org/pkg/subfiles "subfiles \- CTAN"

doumute・subfiles パッケージは、サブプリアンブルをメインファイルのプリアンブルに取り込むような機能がありません。standalone はこの点で優れています。しかしながら、非意図的なパッケージの衝突がメインファイルのタイプセット中に発生する可能性があります。

external ライブラリは、メインファイルにある TikZ コードを一時的に TikZ イメージだけの出力に変更するためのライブラリです。メインファイルが煩雑で散らかった状態であることに変わりはなく、その設定方法も少し難解なもののように思われます。（[参照][tikz-external]）

[tikz-external]: https://tikz.dev/library-external "§ 52 Externalization Library - Externalization Library - PGF/TikZ Manual"