1

I am using pythontex to read in a large python list from disk into my .tex file; I wish to use the \foreach command from the tikz package to do some typesetting for each of the items in the list.

MWE is as follows:

\documentclass{article}

\usepackage{pythontex}
\usepackage{tikz}

\begin{document}

\begin{pycode}
some_letters = ['A', 'B', 'C']
\end{pycode}

normal for-loop:\\
\foreach \letter in {a, b, c} {letter=\letter\\}

for-loop with \texttt{pythontex}:\\
\foreach \letter in {\py{some_letters}} {letter=\letter\\}

\end{document}

and is typeset as follows:

    normal for-loop:
letter=a
letter=b
letter=c

    for-loop with pythontex:
letter=['A', 'B', 'C']

The first for-loop displays correctly. The second for-loop is where I attempt to read the python list. \py{} returns the python object and what I want are comma separated values like in the first for-loop. I have unsuccessfully tried the following instead of \py{some_letters}:

\py{*some_letters}  % attempt to explode the python list
\py{','.join(some_letters)}  % manually separate with commas
% and defining a generator function to yield one value at a time

Does anyone know how I can use the \foreach command with a python iterable? The desired output is as follows:

    normal for-loop:
letter=a
letter=b
letter=c

    for-loop with pythontex:
letter=A
letter=B
letter=C

update 1

The following is what I am using the after getting help from @whatisit

\documentclass{article}

\usepackage{pythontex}
\usepackage{tikz}

\begin{document}

\begin{pycode}
some_letters = ['A', 'B', 'C']
\end{pycode}

\newcommand{\dosomething}{letter=\letter\\}

normal for-loop:\\
\foreach \letter in {a, b, c} {\dosomething}

for-loop with \texttt{pythontex}:\\
\pyc{print('\\foreach \\letter in {{{}}} {{\\dosomething}}'.format(','.join(some_letters)))}
\end{document}

The \pyc{} command is the inline version of the pycode environment so it should work the same for these purposes. I defined the for-loop contents in \dosomething{} so that I can take advantage of my LaTeX IDE syntax highlighting.

update 2

The following uses the \pys{} command which is the inline version of the pysub environment to substitute anything inside !{python_code}. Otherwise everything else inside the \pys{} command can be left as normal latex source code.

\documentclass{article}

\usepackage{pythontex}
\usepackage{tikz}

\begin{document}

\pyc{some_letters = ['A', 'B', 'C']}

normal for-loop:\\
\foreach \letter in {a, b, c} {letter=\letter\\}

for-loop with \texttt{pythontex}:\\
\pys{\foreach \letter in {!{','.join(some_letters)}} {letter=\letter\\}}
\end{document}
  • Here's what you want to do (almost...) \py{print("\\foreach \\letter in {"+','.join(some_letters)+"} {letter=\\letter\\\\}")} Basically, rather than printing just that list, you want to print the entire line of LaTeX so that everything is processed at the correct time. The only issue with this is that printing the list results in something creating None...I'm not immediately sure what the problem is. – whatisit Jan 9 at 1:26
2

There are three versions that you can use. I would recommend the first, personally, which uses \pyc. The second uses \py, but prints something strange out which gets interpreted as None in LaTeX (hence requiring ending the line with %). The last method involves wrapping it in a pycode environment.

\documentclass{article}

\usepackage{pythontex}
\usepackage{tikz}

\begin{document}

\begin{pycode}
import sys
some_letters = ['A', 'B', 'C']
\end{pycode}

normal for-loop:\\
\foreach \letter in {a, b, c} {letter=\letter\\}

for-loop with \texttt{pythontex}:\\
Version 1:\\
\pyc{print("\\foreach \\letter in {"+','.join(some_letters)+"} {letter=\\letter\\\\}",file=sys.stdout, flush=True)}

\noindent
Version 2:\\
\py{print("\\foreach \\letter in {"+','.join(some_letters)+"} {letter=\\letter\\\\}",end='%', flush=True)}

\noindent
Version 3:\\
\begin{pycode}
print("\\foreach \\letter in {"+','.join(some_letters)+"} {letter=\\letter\\\\}")
\end{pycode}

\end{document}

Fixes for printing in pythontex and tikz loop

Caution! As I was struggling to figure out why the \py{...} version wasn't working, I realized that you need to have a LaTeX comment (using %) at the end of the line. Apparently, some special character is getting printed out at the end of the line and interpreted as an extra iteration through the loop...ultimately producing None. Make sure to either have % at the end of your print(...) contents OR use the print() option end='%'. (This issue is not present when using \pyc)

EDIT

I came across a post by G.Poore which explained the issue with \py. Turns out that it prints a string of whatever it is given (but does not expand anything). That's why the print() function acts funny there. Here is a version 2.2 which fixes the issue:

\noindent
Version 2.2:\\
\py{"\\foreach \\letter in {"+','.join(some_letters)+"} {letter=\\letter\\\\}"}

(Personally, I like the print() because it makes me feel like I'm within the Python environment. So, I tend to prefer the \pyc approach. But, hopefully this helps someone!)

  • 1
    Thanks @whatisit for your help! I actually find version 1 more intuitive. I will update the question with what I am going to use now that I know what to do. – jeschwar Jan 9 at 17:11
  • 1
    @jeschwar quick update! I found a comment to this answer to an unrelated question which explains the issue with \py. Turns out, you shouldn't use print() there. It's actually the most concise version, if that's what you prefer. – whatisit Jan 9 at 19:21
  • Thanks again @whatisit. Your previous comment prompted me to read the pythontex manual where I learned about the \pys{} command and corresponding pysub environment. I will provide another update in the question showing the use of these. – jeschwar Jan 9 at 20:01

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.