Every paper contains a number that was computed somewhere else — a script, a notebook, a spreadsheet — and then typed into the text by hand; edit the script, and the number in the paper quietly becomes a lie. PythonTeX closes that gap: it runs the Python you wrote inside your LaTeX source while the document is being typeset, and sets whatever comes back. It is the work of Geoffrey M. Poore, and despite the name it also drives Ruby, Julia, R, Octave, Bash, Rust, Perl and JavaScript. This page walks from \usepackage{pythontex} through the \py family of commands, the three-step build that catches everybody once, and the one situation where you should reach for something else.
Typesetting code versus running it: PythonTeX against listings and minted
Both listings and minted typeset code exactly as it looks and never execute a line of it. PythonTeX differs in that it runs the code and sets the string that comes back. Write \py{2**10} in your text and what appears is not the characters 2**10 but the result, 1024. Loading it takes one line, \usepackage{pythontex}; running it requires Python itself installed alongside your TeX distribution, plus Pygments for the syntax highlighting.
\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}This document sets “A circle of radius 2.5 has area 19.63.”, followed by 2¹⁰ = 1024 and √(3²+4²) = 5.0. The point is that the figure 19.63 appears nowhere in the source. Change radius to 3.0, rebuild, and both the radius and the area in the prose follow along. With hand-typed numbers there is always one you forget to update; here there is nothing to forget. Few other techniques buy you the guarantee that the numbers in a paper cannot disagree with the code behind them at anything like this price.
The idea itself is not new. WEB, the tool Donald Knuth built in 1984 for what he called literate programming, let you write prose inside a Pascal program: tangle extracted the Pascal, weave extracted the TeX. PythonTeX turns that inside out. The master document stays LaTeX, and the program moves in with it. Either way round, the motivation is identical — keep the explanation and the implementation in separate files and sooner or later they will disagree.
\py, \pyc, pycode, pyblock: choosing by suffix
You do not memorise these names; two questions decide them. Does this code get executed? Does it get shown on the page? The combination of those two answers is the suffix. Take the base name py: bare, it sets the value of an expression; c (code) runs it only; v (verb) typesets it only; b (block) does both. Inline you use the command form (\pyc{…}), and for several lines the identically-named environment (pycode).
| Command | Matching environment | Runs / typesets |
|---|---|---|
\py | — | runs an expression and sets only its string form |
\pyc | pycode | runs but typesets nothing; print output is brought in automatically |
\pyv | pyverbatim | does not run; typesets the code verbatim |
\pyb | pyblock | runs and typesets; print output is not brought in automatically |
\pys | pysub | replaces each !{expr} with its value, then reads the result as LaTeX |
\pycon | pyconsole | emulates the interactive console, setting >>> with input and output together |
The argument of an inline command works like \verb: it need not be braces at all. Any matched pair of identical characters will do, so \py{2**10}, \py#2**10# and \py@2**10@ all mean the same thing — a useful escape hatch when the code itself contains braces. There is exactly one restriction to respect: \py inserts a value, so it cannot take an assignment. The manual rules \py{a=1} invalid outright, on the grounds that an assignment has no string representation. Creating variables is the job of pycode; \py{a} only fetches them.
How print is handled flips depending on whether the code is shown, as the table implies. Where the code stays hidden — pycode, \pyc — the package option autoprint (on by default) drops the printed output in place. Where the code is shown — pyblock, \pyb — automatic insertion stops, on the reasoning that you rarely want output pasted directly under the listing that produced it. Put \printpythontex (or \stdoutpythontex) wherever you do want it. You can also stash it under a name with \saveprintpythontex{name} and recall it far away with \useprintpythontex{name}.
Teaching material and technical writing constantly need a reproduced interactive session. The pyconsole environment treats its contents as if typed into an interpreter, using Python's own code module to interleave input with output. The example below sets as three lines — >>> a = 1, >>> a + 3, 4 — and that 4 is not something you wrote; it was computed during the build. When you enter a multi-line construct such as a function definition, a blank line after the last line may be required. The same family also offers \pyconv / pyconverbatim, which typeset a pasted session without running it, and \pyconc / pyconcode, which run without typesetting.
\begin{pyconsole}
a = 1
a + 3
\end{pyconsole}
% typeset result:
% >>> a = 1
% >>> a + 3
% 4The three-step build, and why PythonTeX does not need -shell-escape
A PythonTeX document is built by running LaTeX, then pythontex, then LaTeX again. The first LaTeX pass does not execute anything; it merely extracts the code into an external file called <jobname>.pytxcode. The pythontex program then runs that code and saves the results, and the second LaTeX pass picks them up and makes the PDF. Run the engine only once and the values you carefully wrote simply do not appear — that is the classic first stumble.
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 documentHere is the fact that surprises people who know minted: PythonTeX does not need -shell-escape. minted launches an external program from inside the typesetting run, which is why it halts with ! Package minted Error: You must invoke LaTeX with the -shell-escape flag. (see “Code listings”). PythonTeX, by contrast, has its code executed not by LaTeX but by a separate program that sits between the two LaTeX runs. LaTeX only writes .pytxcode and later reads the results back. pythontex.sty does not contain a single use of \write18.
That “in between” design has one more pleasant side effect. The .pytxcode file records not only each chunk of code but also which line of the .tex file it came from. So when Python falls over, pythontex reports the line number in your manuscript rather than in the generated .py. Use an undefined name inside a pycode block and you get * PythonTeX stderr - error on line 8: followed by NameError: name 'nosuchname' is not defined — and that 8 is line 8 of the .tex. No opening the generated file and counting lines by hand.
Typing three commands every time is not realistic, so in practice you hand the job to latexmk. The configuration the manual gives registers the extracted-code file .pytxcode as a dependency and runs pythontex whenever it changes; when pythontex rewrites its output files, latexmk notices and recompiles on its own. Shell escape does not enter into it here either — latexmk simply calls pythontex as an ordinary external command.
# run pythontex whenever the extracted code changes
add_cus_dep('pytxcode', 'tex', 0, 'pythontex');
sub pythontex { return system("pythontex \"$_[0]\""); }The engine does not matter. Swap pdflatex for lualatex or xelatex, or for platex in a Japanese document, and the three-step shape is unchanged. Non-ASCII characters inside the code do require setting the document up, and the manual is specific: under pdfLaTeX, \usepackage[T1]{fontenc} with \usepackage[utf8]{inputenc}; under LuaLaTeX, \usepackage{fontspec}; under XeLaTeX, the same plus \defaultfontfeatures{Ligatures=TeX}. One XeLaTeX-only trap: if your code contains tabs, compile with -8bit, or the tabs get written out as the character sequence ^^I.
Why rebuilds stay fast: the cache, sessions, and --rerun
Code that has not changed is not executed. This is what turns the apparently reckless idea of embedding heavy computation in a document into something usable. pythontex saves its results under pythontex-files-<jobname>/ — the cache itself lives in pythontex_data.pkl — and on the next run it only executes the chunks that changed. Fixing a typo in one paragraph will not set your thirty-second simulation going again.
What counts as “changed” is tunable through --rerun, which has an equivalent package option, \usepackage[rerun=…]{pythontex}. The default is errors: everything modified, plus anything that produced an error last time. That is why a failing block is retried while you debug, without your having to touch it. The thresholds form a scale.
never— execute nothing; merely warn if there is modified code.modified— execute only chunks that changed (or whose dependencies changed).errors— the default. Everything modified, plus anything that errored last run.warnings— additionally re-execute anything that produced a warning last run.always— execute everything, every time. Essentially the same as--runall.
The cache's weak spot is code that has not changed but reads data that has. Declare it from the Python side with pytex.add_dependencies('data.csv') and the block is re-executed exactly when that file is updated — by modification time by default, or by hash with --hashdependencies. Files you create can be registered with pytex.add_created() so they are cleaned up later. Note too that sessions run in parallel: blocks split with \begin{pycode}[sessionname] become separate processes, and the number running at once defaults to the CPU core count (--jobs overrides it). If things still stop adding up, the manual's own last resort is to delete pythontex-files-<jobname>/ outright and rebuild.
Getting a matplotlib figure and SymPy algebra into the document
Making figures is refreshingly direct: have matplotlib savefig inside a pycode block, then include the file with \includegraphics. By default it is written next to the .tex, so there is no path to think about (\setpythontexworkingdir changes that if you want). The interesting part comes next. Write \setpythontexcontext{textwidth=\the\textwidth} and LaTeX's own dimensions cross over to Python, readable as pytex.context.textwidth; convert with pytex.pt_to_in() and you can build a figure exactly as wide as the text block. Because nothing is scaled afterwards, the labels inside the figure come out at the same size as the surrounding text.
\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}And here is the pothole that the first build nearly always hits. When the first LaTeX pass runs, wave.pdf does not exist yet, so you are told ! Package pdftex.def Error: File 'wave.pdf' not found: using draft setting. Nothing is broken — the figure is created by the second stage, pythontex, so once you run all three steps the second LaTeX pass finds it. Not turning back at that one line, convinced you have misconfigured something, is the first trick worth knowing.
For mathematics there are purpose-built families. Swap the base name py for another and you get exactly the same lineup again: \sympy, sympycode, sympyblock and \pylab, pylabcode, pylabblock. What differs is the initial import, and how the result is presented.
- The sympy family — loads the symbolic-algebra library SymPy with
from sympy import *. An expression inserted with\sympygoes through SymPy'sLatexPrinter, which formats it as LaTeX appropriate to the context (inline versus displayed). This is what makes tricks like generating an entire table of derivatives and integrals possible. - The pylab family — loads matplotlib's
pylabmodule withfrom pylab import *, putting plotting and NumPy in one namespace. If you prefer to write your own imports, as in the example above, the plainpyfamily is all you need.
When the journal cannot build it: depythontex and the security caveat
This is PythonTeX's real constraint. A processing chain that only runs a LaTeX engine will never finish this document. What is missing is not permission for shell escape but the intervening pythontex run itself. The manual admits as much: documents using PythonTeX are less suitable than plain LaTeX ones for journal submission, sharing, and conversion to other formats. depythontex exists for exactly this. Build with \usepackage[depythontex]{pythontex} and an auxiliary file <jobname>.depytx appears; the depythontex script reconciles it with the original source and writes out a second .tex in which every PythonTeX command and environment has been replaced by the typeset code and its output — ordinary LaTeX, results baked in, with no dependence on PythonTeX at all.
# 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 quietly pulls its weight. It lets you choose how code is displayed in the static version — verbatim, fancyvrb, listings, minted or pythontex — so a submission guideline demanding listings is no obstacle (see “Code listings”). There is a lighter option too: the manual notes that if you merely need to hand the document to a co-author, you can ship pythontex.sty together with the output directory. The recipient can then edit everything that is not Python as an ordinary LaTeX document, without ever running Python.
Finally, the point the manual sets in a warning box. Compiling a document that uses PythonTeX means actually running Python — and potentially other programs — on your machine. So compile only documents whose source you trust. That PythonTeX needs no -shell-escape does not make it safer: the code is executed just the same, only from outside LaTeX rather than inside it.