4

I want to pass parameters to a TikZ picture. The computation of the parameters is lengthy and done with sage. So I want to use both TikZ and sageTeX. Either the compilation enters an endless loop or I get non explicit errors messages: "\XC@define@color has an extra }".

Error messages:

    \documentclass{article}
\usepackage{sagetex} 
    \usepackage{tikz}
\begin{document}

Begin sagesilent, \ldots
    \begin{sagesilent} 
    x=2.1 
    y=3.1 
    \end{sagesilent}

After sagesilent:

 print $\sage{x}$

 print $\sage{y}$

\def \xf{\sage{x}}
\def \yf{\sage{y}}

we get \xf \,  and  \, \yf. 
    \begin{tikzpicture} 
    \coordinate (P) at (\xf,\yf);   
    \fill[black] (P) circle [radius=10pt];  
    \end{tikzpicture}

\end{document}

endless loop:

\documentclass{article}
\usepackage{sagetex} 
    \usepackage{tikz}

\begin{document}

Begin sagesilent, \ldots 
    \begin{sagesilent}
    r=2.1 
    \end{sagesilent}

After sagesilent we print $\sage{r}$

\def \cr{\sage{r}}

and we get $r=\cr$. 
    \begin{tikzpicture} 
    \draw circle (\cr);  
    \end{tikzpicture}

\end{document} 

The results are the same if I define the variable in the TikZ environnement or if I use \newcommand. It is also the same if I use an integer, 2 instead of 2.1. The new command seems to work in the text environnement but not in the graphic one.

  • Please don't use minimal for examples. It isn't suitable. Will article or standalone work here? – cfr Sep 13 '16 at 23:07
  • Sorry, the result is the same with article. – c05772 Sep 14 '16 at 0:08
  • Best to avoid \def, I think. It gives you no warning when you overwrite TeX's definition of \cr, for example. – cfr Sep 14 '16 at 0:25
  • I agree but by laziness I use \def, shorter, anyhow it does not change the problem and \cr is for the mwe only. – c05772 Sep 14 '16 at 15:03
  • You will change your mind when you spend hours or days trying to track down a problem which is caused by redefining a primitive or low level macro. Redefining \cr is mad, frankly. And it will mess up a good many tikzpictures, apart from anything else. – cfr Sep 14 '16 at 16:47
3

One thing that might work is to pull the generation of the TikZ code into Sage, too:

\begin{sagesilent}
# code to compute x and y

def mytikz(x, y):
    ret = [r'\begin{tikzpicture}']
    # ret.append() more tikz code, some of which presumably uses x and y
    ret.append(r'\end{tikzpicture}')

    return '\n'.join(ret)
\end{sagesilent}

Then, when you want your picture:

\sagestr{mytikz(x, y)}

That might not work; TikZ does a lot of weird low-level TeX stuff and it doesn't always play nicely with LaTeX's \ref and \label system.

  • 1
    I think that this method works, in general. I've played around with sagetex and tikz and found that creating the string for your picture inside sagesilent, as @Dan Drake illustrates, plays best with tikz. See, for example, my answer to Plotting the Cantor function where I follow this basic approach. – DJP Sep 14 '16 at 13:54
  • This solution works after tweaking. I post the working code for the second mwe below. Note that the TikZ code, if printed, introduce redundant CR but it des not matter in LaTeX. Another way is to write only the \def lines in the sage code. It makes the code easier to read. – c05772 Sep 14 '16 at 16:23
2

Mixing TikZ with SageTeX and similar packages that allow code execution is tricky, due to the way TikZ handles command processing. It has usually been easiest to assemble all of the TikZ commands outside of LaTeX, only passing the fully assembled version to LaTeX.

The most recent version of PythonTeX (0.15) added a string interpolation/variable substitution environment for these sorts of cases, and also added Sage support, so it might be an option depending on what you need to do.

\documentclass{article}

\usepackage[usefamily=sage]{pythontex} 
\usepackage{tikz}

\begin{document}

Define variables \ldots
\begin{sagecode} 
x = 2.1 
y = 3.1 
\end{sagecode}

After sagecode we get \sage{x} and \sage{y}. 

\begin{sagesub}
\begin{tikzpicture} 
\coordinate (P) at (!{x},!{y});   
\fill[black] (P) circle [radius=10pt];  
\end{tikzpicture}
\end{sagesub}

\end{document}

This would be compiled with a sequence of commands like

pdflatex file.tex
pythontex file.tex
pdflatex file.tex

This assumes that sage is on your PATH; otherwise, you might need to use pythontex's --interpreter option to specify the location of the executable.

Substitution/interpolation fields in the sagesub environment are indicated with !{<variable or expression>}. The <variable or expression> can contain curly braces, as long as they occur in pairs no more than 5 levels deep. If you need unpaired curly braces, you can use a sequence of braces as delimiters, as long as the sequence is longer than the longest unpaired sequence and no longer than 6. For example, !{{{<variable or expression>}}} allows unpaired {, {{, }, or }}.

0

This is the working code for the solution using Dan Drake suggestion above. It solves the endless loop case.

\documentclass{article}
\usepackage{sagetex}
\usepackage{tikz}
\begin{document}
Begin sagesilent, \ldots

\begin{sagesilent}
reset()
var('rd')
def mytikz(rd):
    ret = [r'\begin{tikzpicture}']
    ret.append(r'\draw circle (') 
    ret.append(str(rd)) 
    ret.append(r');') 
    ret.append(r'\end{tikzpicture}')
    return '\n'.join(ret)
rd=2.1
#ret=mytikz(rd)
\end{sagesilent}

After sagesilent we print $\sage{rd}$

\sagestr{mytikz(rd)}

\end{document}

Of course the first compilation results in an error because rd is not known in the sage string given to TikZ. After running sagetex, the second compilation gives the result.

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.