どの論文にも、どこか別の場所——スクリプト、ノートブック、表計算——で計算されて、そのあと手で本文に打ち込まれた数値が入っています。スクリプトを直すと、本文の数値は静かに嘘になります。PythonTeX はこの隙間を塞ぐパッケージで、LaTeX のソースの中に書いた Python を組版の途中で実行し、返ってきた値をその場に組みます。作者は Geoffrey M. Poore。名前に反して Ruby・Julia・R・Octave・Bash・Rust・Perl・JavaScript も動かせます。このページでは \usepackage{pythontex} から \py 系のコマンド、誰もが最初に一度つまずく 3 ステップのビルド、そして「使ってはいけない場面」までを順に見ていきます。
コードを「見せる」listings と、コードを「動かす」PythonTeX
listings と minted はコードを 見た目どおりに組版する だけで、一行たりとも実行しません。PythonTeX が違うのは、コードを 実行して、返ってきた文字列を本文に組む ところです。本文に \py{2**10} と書けば、そこに組まれるのは 2**10 という文字列ではなく 1024 という計算結果です。読み込みは \usepackage{pythontex} の一行で、動かすには TeX 環境と並んで Python 本体 と、コードの色分けに使う Pygments が入っている必要があります。
\documentclass{article}
\usepackage{pythontex}
\begin{document}
% executed, but nothing is typeset from this block itself
\begin{pycode}
from math import sqrt
radius = 2.5
area = 3.14159 * radius**2
\end{pycode}
A circle of radius \py{radius} has area \py{round(area, 2)}.
\[ 2^{10} = \py{2**10}, \qquad \sqrt{3^2+4^2} = \py{sqrt(3**2 + 4**2)} \]
\end{document}この文書は「A circle of radius 2.5 has area 19.63.」と組まれ、数式には 2¹⁰ = 1024 と √(3²+4²) = 5.0 が入ります。ここで重要なのは 19.63 という数字がどこにも書かれていないことです。radius を 3.0 に変えてビルドし直せば、本文の半径も面積も勝手に追随します。手で打った数値なら片方だけ直し忘れる余地がありますが、この書き方には そもそも忘れる相手がいません。「論文の数値がコードと食い違わない」ことをここまで安く保証できる手段は、そう多くありません。
この発想自体はまったく新しいものではありません。ドナルド・クヌースが 1984 年に提唱した 文芸的プログラミング(literate programming) の道具 WEB は、Pascal のプログラムの中に説明文を書き、tangle がそこから Pascal を、weave が TeX を取り出す仕組みでした。PythonTeX がやっているのはその 裏返し です。主人となる文書は LaTeX のままで、その中にプログラムのほうが同居する。どちら向きであれ、動機はまったく同じ——説明と実装を別々のファイルに置けば、いつか必ずずれる、ということです。
\py・\pyc・pycode・pyblock の使い分け
命令の名前は覚えるものではなく、二つの質問に答えると決まる ものです。「そのコードを実行するか」「そのコードを紙面に見せるか」——この二択の組み合わせがそのまま接尾辞になっています。基底名 py に何も付けなければ式の値を組み、c(code)なら実行だけ、v(verb)なら組版だけ、b(block)なら両方。行内はコマンド(\pyc{…})、複数行は同じ意味の環境(pycode)という対応です。
| コマンド | 対応する環境 | 実行と組版 |
|---|---|---|
\py | — | 式を実行し、その文字列表現だけを組む |
\pyc | pycode | 実行するが組版しない。print の出力は自動で入る |
\pyv | pyverbatim | 実行せず、コードをそのまま組む |
\pyb | pyblock | 実行も組版もする。print の出力は自動では入らない |
\pys | pysub | !{式} を評価結果で置き換え、結果を LaTeX として解釈する |
\pycon | pyconsole | 対話コンソールを再現し、>>> と入力・出力をそろえて組む |
行内コマンドの引数は \verb と同じで、波括弧でなくてもかまいません。同じ文字を一対そろえればよいので、\py{2**10}・\py#2**10#・\py@2**10@ はすべて同じ意味です。コードに波括弧が入るときはこの逃げ道が効きます。ひとつだけ守るべき制限があって、\py は値を差し込む命令なので 代入が書けません。マニュアルは \py{a=1} を明示的に無効としており、理由は「代入は文字列にならないから」。変数を作るのは pycode の側の仕事で、\py{a} はそれを呼び出すだけ、と役割が分かれています。
print の扱いは、上の表のとおり コードを見せるかどうかで反転します。pycode や \pyc のようにコードを隠す側では、パッケージオプション autoprint(既定で有効)が働いて print の出力がその場に流し込まれます。ところが pyblock や \pyb のようにコードを見せる側では、コードのすぐ下に出力が続くのは通常望ましくないという判断から自動挿入は止まります。出力を出したい位置に \printpythontex(または \stdoutpythontex)を置いて明示的に取り込んでください。\saveprintpythontex{名前} で名前を付けて保存し、離れた場所で \useprintpythontex{名前} として使うこともできます。
教材や技術記事でよく要るのが 対話セッションの再現 です。pyconsole 環境は中身を対話インタプリタに打ち込んだかのように扱い、Python の code モジュールを使って入力と出力を交互に並べます。下の例は >>> a = 1、>>> a + 3、4 の三行として組まれます——出力の 4 は、あなたが書いたのではなくビルド中に計算されたものです。関数定義のような複数行の入力を置くときは、最後の行のあとに空行が必要になることがあります。同じ系列には、貼り付けたセッションを実行せず組むだけの \pyconv/pyconverbatim と、実行して何も組まない \pyconc/pyconcode もあります。
\begin{pyconsole}
a = 1
a + 3
\end{pyconsole}
% typeset result:
% >>> a = 1
% >>> a + 3
% 43 ステップのビルドと、-shell-escape が要らない理由
PythonTeX の文書は LaTeX → pythontex → LaTeX の 3 回 で組み上がります。一度目の LaTeX は本文中のコードを実行せず、〈ジョブ名〉.pytxcode という外部ファイルに 抜き出す だけ。次に走る pythontex プログラムがそれを実行して結果を保存し、二度目の LaTeX が保存された結果を 拾い上げて PDF にします。一度しか回さないと、書いたはずの値がどこにも出ない、というのが最初につまずく典型です。
pdflatex document.tex # 1) LaTeX extracts the code to document.pytxcode
pythontex document.tex # 2) a separate program runs it and caches the results
pdflatex document.tex # 3) LaTeX pulls the results back into the documentここで、minted を知っている人ほど意外に感じる事実があります。PythonTeX に -shell-escape は要りません。 minted は組版のさなかに LaTeX 自身が外部プログラムを起動するので、! Package minted Error: You must invoke LaTeX with the -shell-escape flag. で止まる(→「ソースコード掲載」)。対して PythonTeX でコードを実行するのは LaTeX ではなく、二回の LaTeX のあいだに挟まる独立したプログラム です。LaTeX 側は .pytxcode を書いて、後で結果を読むだけ。実際 pythontex.sty には \write18 を使う箇所が一つもありません。
この「間に挟まる」設計には、もうひとつ気持ちのよい副作用があります。.pytxcode にはコードの断片だけでなく、その断片が .tex ファイルの何行目にあったか も一緒に書き出されています。おかげで Python 側が転んだとき、pythontex は生成された .py の行番号ではなく、あなたの原稿の行番号で報告してくれます。実際 pycode の中で未定義の名前を使うと * PythonTeX stderr - error on line 8: と出て、続けて NameError: name 'nosuchname' is not defined が並びます。この 8 は .tex の 8 行目です。生成されたファイルを開いて行数を数え直す作業は要りません。
毎回 3 コマンドを手で打つのは現実的ではないので、実務では latexmk に任せます。マニュアルが挙げている構成は、抽出されたコードのファイル .pytxcode を依存関係として登録し、それが変わったら pythontex を走らせる、というものです。pythontex が結果ファイルを書き換えると latexmk はそれを検知して自動で再コンパイルします。ここでもシェルエスケープは登場しません——latexmk は普通の外部コマンドとして pythontex を呼ぶだけだからです。
# run pythontex whenever the extracted code changes
add_cus_dep('pytxcode', 'tex', 0, 'pythontex');
sub pythontex { return system("pythontex \"$_[0]\""); }エンジンは選びません。pdflatex を lualatex や xelatex に、日本語なら platex に置き換えても、3 ステップの形はそのままです。ただしコードに非 ASCII 文字を含めるなら文書側の設定が要ります——マニュアルの指定は、pdfLaTeX なら \usepackage[T1]{fontenc} と \usepackage[utf8]{inputenc}、LuaLaTeX なら \usepackage{fontspec}、XeLaTeX ならそれに加えて \defaultfontfeatures{Ligatures=TeX}。XeLaTeX でコード中にタブを使う場合だけは注意が必要で、-8bit を付けないとタブが ^^I という文字列として書き出されてしまいます。
再ビルドが速い理由——キャッシュ、セッション、--rerun
変わっていないコードは実行されません。 これが「重い計算を文書に埋め込む」という一見無謀な発想を実用に落としている核心です。pythontex は結果を pythontex-files-〈ジョブ名〉/ の下(キャッシュ本体は pythontex_data.pkl)に保存し、次の実行では変更のあった断片だけを回します。段落をひとつ直しただけで 30 秒かかるシミュレーションが走り直す、ということは起きません。
「変わった」の判定基準は --rerun で調整できます(\usepackage[rerun=…]{pythontex} と同義のパッケージオプションもあります)。既定は errors——変更された断片に加えて、前回エラーを出した断片も実行します。デバッグのときにいちいち編集しなくても再試行されるのはこのためです。しきい値は段階的に選べます。
never— 何も実行しない。変更されたコードがあれば警告だけ出す。modified— 変更された断片(および依存先が変わった断片)だけ実行する。errors— 既定値。 変更されたものに加え、前回エラーになったものを実行する。warnings— さらに、前回警告を出したものも実行する。always— 常に全部実行する。コマンドラインの--runallとほぼ同義。
キャッシュの弱点は「コードは変わっていないが、読んでいるデータが変わった」場合です。ここは Python 側から pytex.add_dependencies('data.csv') と宣言しておけば、そのファイルが更新されたときだけ自動で再実行されます(既定では更新時刻で判定し、--hashdependencies でハッシュに切り替えられます)。逆に生成したファイルは pytex.add_created() で登録しておくと後片付けの対象になります。なお セッションは並列に走ります。\begin{pycode}[session名] で分けたセッションは別プロセスになり、同時実行数は既定で CPU コア数(--jobs で変更可)。それでも辻褄が合わなくなったら、マニュアル自身が勧める最終手段は pythontex-files-〈ジョブ名〉/ を丸ごと消して組み直すことです。
matplotlib の図と SymPy の数式を文書に流し込む
図の作り方はごく素直で、pycode の中で matplotlib に savefig させ、あとは \includegraphics で貼るだけです。保存先は既定で .tex と同じディレクトリなので、パスを考える必要はありません(変えたければ \setpythontexworkingdir があります)。面白いのはここから先で、\setpythontexcontext{textwidth=\the\textwidth} と書いておくと LaTeX 側の寸法が Python 側に渡り、pytex.context.textwidth として読めます。pytex.pt_to_in() でインチに直せば、版面の幅にぴったり一致する図 を Python 側で作れます。あとから拡大縮小しないので、図の中の文字が本文の文字と同じ大きさで出ます。
\documentclass{article}
\usepackage{graphicx}
\usepackage{pythontex}
\setpythontexcontext{textwidth=\the\textwidth}
\begin{document}
\begin{pycode}
import matplotlib
matplotlib.use('pgf')
import matplotlib.pyplot as plt
import numpy as np
width = pytex.pt_to_in(pytex.context.textwidth)
x = np.linspace(0, 2*np.pi, 200)
fig, ax = plt.subplots(figsize=(width, 0.4*width))
ax.plot(x, np.sin(x))
fig.savefig('wave.pdf', bbox_inches='tight')
\end{pycode}
\includegraphics{wave.pdf}
\end{document}ここに、初回ビルドでほぼ必ず出る落とし穴があります。一度目の LaTeX が走る時点で wave.pdf はまだ存在しないので、! Package pdftex.def Error: File 'wave.pdf' not found: using draft setting. と言われます。壊れているわけではありません——図を作るのは二段階目の pythontex なので、3 ステップを最後まで回せば二度目の LaTeX でちゃんと入ります。この一行を見て「設定を間違えた」と引き返さないことが、最初のコツです。
数式のほうには専用のファミリーが用意されています。py を別の基底名に差し替えるだけで、\sympy・sympycode・sympyblock と \pylab・pylabcode・pylabblock という同じ顔ぶれが手に入ります。中身が違うのは最初の import と、結果の見せ方です。
- sympy 系 — 記号計算ライブラリ SymPy を
from sympy import *で読み込みます。\sympyで差し込んだ式は SymPy のLatexPrinterを通り、行内か別行立てかといった文脈に応じた LaTeX 表記に整えられます。導関数と積分の表を丸ごと自動生成する、といった芸当ができます。 - pylab 系 —
from pylab import *で matplotlib のpylabモジュールを読み込み、作図と NumPy を一つの名前空間にまとめます。上の例のようにimportを自分で書くならpy系のままで十分です。
投稿先でビルドできないとき——depythontex と安全性
PythonTeX の最大の制約はここです。LaTeX エンジンしか回さない処理系では、この文書は完成しません。 足りないのはシェルエスケープの許可ではなく、途中に挟まるはずの pythontex の実行そのものです。マニュアル自身が「PythonTeX を使った文書は、投稿・共有・他形式への変換において、素の LaTeX 文書より扱いにくい」と認めています。そのために用意されているのが depythontex です。\usepackage[depythontex]{pythontex} としてビルドすると 〈ジョブ名〉.depytx という補助ファイルが作られ、depythontex スクリプトがそれと元原稿を突き合わせて、すべての PythonTeX のコマンドと環境を、組版済みのコードとその出力で置き換えた 別の .tex を書き出します。結果が焼き込まれた、PythonTeX に依存しない普通の LaTeX です。
# 1) run the usual three steps, with the depythontex package option on
pdflatex document.tex
pythontex document.tex
pdflatex document.tex
# 2) write the static, PythonTeX-free copy
depythontex -o document-plain.tex document.tex
# code display in the output can be switched to another package
depythontex --listing minted -o document-plain.tex document.tex--listing は地味に効きます。静的版でコードをどう見せるかを verbatim・fancyvrb・listings・minted・pythontex から選べるので、「投稿規定が listings を要求している」といった事情にもそのまま合わせられます(→「ソースコード掲載」)。もっと軽い手もあって、マニュアルは 共著者に渡すだけ なら pythontex.sty と出力ディレクトリを一緒に配ればよい、と書いています。受け取った側は Python を一度も動かさずに、Python 以外の部分を普通の LaTeX 文書として編集できます。
最後に、マニュアルが警告の枠で明記している一点を。PythonTeX を含む文書をコンパイルするということは、あなたの計算機の上で Python(場合によっては他のプログラムも)を実際に走らせる ということです。したがってコンパイルしてよいのは 出所を信頼できる文書だけ です。-shell-escape が要らないことは、危険が小さいことを意味しません——実行するのは同じで、実行するのが LaTeX の外だというだけです。