[Tex/LaTex] PythonTex equivalent to \Sexpr{} in R

knitrliterate-programmingpythonsweave

I started to use the excellent PythonTex package to write reproducible reports but can't seem to get it to evaluate Python code inside a LaTeX command.

R has Sweave & knitr which provide the \Sexpr{} command that lets you access variables declared in R chunks inside a LaTeX command. This works in R with Sweave/knitr:

\documentclass{article}
\usepackage{siunitx}
\begin{document}
<<read, engine='R'>>=
y = 4
@
The value of y is $\SI{\Sexpr{y}}{\metre}$.
\end{document}

However, the following does not seem to work in PythonTex:

\documentclass{article}
\usepackage{siunitx}
\usepackage{pythontex}
\begin{document}
\pyc{y = 4}

The value of y is $\SI{\py{y}}{\metre}$.

\end{document}

Am I missing something? Is there a way to achieve \Sexpr{} functionality in PythonTex?

Thanks for your help!

Best Answer

You can do what you want, but the approach is a bit different from Sweave and knitr.

With Sweave and knitr, the file you create is a .Rnw, and the output is .tex. In the .tex, each \Sexpr{...} is replaced by its output. So in the final .tex file that is compiled, there are no \Sexpr{...}.

With PythonTeX, you create the .tex directly, so everything you do has to be valid .tex. Based on how \SI works, having \py inside it causes problems--\SI expects numbers, not commands.

There are a number of ways you could work around this. I've given two examples below. In the first approach, I've created a Python function SI() that takes a variable and a unit, and returns an \SI command. In the second approach, I've created a new LaTeX command \pySI that does the same thing, just using a more LaTeX-style interface. This last approach will have problems if you need to use the # and % characters in the arguments, but that shouldn't be an issue for this application.

\documentclass{article}
\usepackage{siunitx}
\usepackage{pythontex}

\begin{pycode}
def SI(var, unit):
    return '\\SI{' + str(var) + '}{' + unit + '}'
\end{pycode}

\newcommand{\pySI}[2]{\py{'\\SI{' + str(#1) + '}{#2}'}}

\begin{document}
\pyc{y = 4}

The value of y is \py{SI(y, r'\metre')}.

The value of y is \pySI{y}{\metre}.

\end{document}