# Macro sequence generalization (with bashful)

I'm trying to take a script-based approach to my standing question Automatic calculation of error in pgfplots, and I have something of a workable solution.

Using Python, I transform a given dataset and 'digest' it to something that is meaningful to my friend's field. If you're interesting in the script, it is reproduced below. I'm able to acceptably simplify its use within LaTeX using a series of commands that, ideally, I'd like to turn into a macro itself using \newcommand or similar macro. Unfortunately, I'm getting errors that I can neither explain nor solve. I'm using packages tikz,pgfplots, and bashful. bashful is the one giving me problems.

error.py (works perfectly)

def sqrt(n):
return n**.5

def avg(nums):
return sum(nums)/len(nums)

def stddev(nums):
s = sum(nums)
a = avg(nums)
s2 = sum([(n - a)**2 for n in nums])
return sqrt(s2/len(nums))

def stderr(nums):
return stddev(nums)/sqrt(len(nums))

lines = list()

import sys

with open(sys.argv[1],'r') as f:

data = list()

for i in range(len(lines)):
if lines[i][0].isdigit():
toks = lines[i].split()
data.append(map(int,toks))

data = [(data[0][i], [l[i] for l in data[1:]])                 for i in range(len(data[0]))]
for (val, nums) in data:
print val, avg(map(float,nums)), stderr(map(float,nums))


Manual commands

\bash[stdoutFile=plots/mydata.table.digest]
python error.py plots/mydata.table
\END

\newsavebox{\myplot}
\savebox{\myplot}{%
\begin{tikzpicture}
\begin{axis}[grid=major]
error bars/.cd,
y dir=both,
y explicit]
table[x index=0,
y index=1,
y error index=2]
{plots/mydata.table.digest};
\end{axis}
\end{tikzpicture}
}

\newcommand{\plotmyplot}{\usebox{\myplot}}

\begin{document}
stuff2 \plotmyplot
\end{document}


Attempt at generalization

\newcommand{\prepareplot}[2]{
\bash[stdoutFile=#2.digest]
python error.py #2
\END

\expandafter\newsavebox\csname #1\endcsname
\expandafter\savebox\csname #1\endcsname{%
\begin{tikzpicture}
\begin{axis}[grid=major]
error bars/.cd,
y dir=both,
y explicit]
table[x index=0,
y index=1,
y error index=2]
{#2.digest};
\end{axis}
\end{tikzpicture}}
\expandafter\newcommand\csname plot#1\endcsname\expandafter\usebox\csname #1\endcsname}


Error

! Use of \bashIII doesn't match its definition.
\prepareplot #1#2-> \bash [stdoutFile=#2.digest]
python error.py #2 \END \pa...
l.27 \prepareplot{myplotB}{plots/mydata.table}

?
! Emergency stop.
\prepareplot #1#2-> \bash [stdoutFile=#2.digest]
python error.py #2 \END \pa...
l.27 \prepareplot{myplotB}{plots/mydata.table}

!  ==> Fatal error occurred, no output PDF file produced!
Transcript written on plots.log.


Full MWE (requires python 2.7 and error.py)

\documentclass{article}
\usepackage{pgfplots,tikz,bashful}

\newcommand{\prepareplot}[2]{
\bash[stdoutFile=#2.digest]
python error.py #2 | \preparedplotname.digest
\END

\expandafter\newsavebox\csname #1\endcsname
\expandafter\savebox\csname #1\endcsname{%
\begin{tikzpicture}
\begin{axis}[grid=major]
error bars/.cd,
y dir=both,
y explicit]
table[x index=0,
y index=1,
y error index=2]
{#2.digest};
\end{axis}
\end{tikzpicture}}
\expandafter\newcommand\csname plot#1\endcsname\expandafter\usebox\csname #1\endcsname}

\pgfplotsset{compat=1.7}

\prepareplot{myplotB}{plots/mydata.table}

\bash[stdoutFile=plots/mydata.table.digest]
python error.py plots/mydata.table
\END

\newsavebox{\myplot}
\savebox{\myplot}{%
\begin{tikzpicture}
\begin{axis}[grid=major]
error bars/.cd,
y dir=both,
y explicit]
table[x index=0,
y index=1,
y error index=2]
{plots/mydata.table.digest};
\end{axis}
\end{tikzpicture}
}

\newcommand{\plotmyplot}{\usebox{\myplot}}

\begin{document}
stuff2 \plotmyplotB
\end{document}

• Can you add a real MWE and instructions about what it's needed to run it? Mar 18 '13 at 20:55
• @egreg, I apologize for the awful question; I'm thinking about ditching bashful altogether and just using \write18 (which I'm having separate problems with) since I don't need bashful's actual featureset. Mar 18 '13 at 21:00
• I can't test the script, because Python 2.7 refuses to install on my machine. However, the problem is that \bash can't go in the argument to other commands because it does category code changes (similarly to \verb). Mar 18 '13 at 23:25
• @egreg Hmmm... That makes a lot of sense. 'Fixing' it would probably break other things down the line, then. Mar 19 '13 at 9:46

The \bash command changes category codes, in order to come with multiline scripts, so it can't be used in the argument of other commands.

For one liners, however, there's no need of the full power of \bash, so the following should work:

\makeatletter
\newcommand{\rbash}[2][]{%
\begingroup
\setKeys@BL{#1}%
\begingroup\edef\x{\endgroup
\noexpand\bashIV{\detokenize{#2}}%
\noexpand\bashV{\detokenize{#2}}\logBL{bashV: Done!}%
}\x
\endgroup}
\makeatother

\rbash[stdoutFile=myls.digest]{ls -l 2>&1 > myls.digest}


I added a command just to test it.

Your command might then be defined by

\newcommand{\prepareplot}[2]{%
\rbash[stdoutFile=#2.digest]{python error.py #2 | \preparedplotname.digest}
\expandafter\newsavebox\csname #1box\endcsname
\expandafter\sbox\csname #1box\endcsname{%
\begin{tikzpicture}
\begin{axis}[grid=major]