Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I'm drawing a TikZ figure and am going to need a couple of constant that I could easily change between compilations, e.g. a main radius, a proportion, a number of lines, etc. What is the preferred way of defining these?

It's not just one \draw command, so I suppose I can't use let.

share|improve this question
    
I would use \newcommand*{\Name}{<value>} to declare it so that you can be sure it is not already been defined elsewhere. Definitely do not use \let -- it is not for this purpose. –  Peter Grill Mar 7 '12 at 21:17
    
Do you plan to adjust these from the command line for multiple runs? Or is this tikzpicture included in another document and if so, do you want to adjust them from that document? –  Peter Grill Mar 7 '12 at 21:24
    
@PeterGrill: Thanks. The tikzpicture is included from another document, but I only need to change the constants in the document containing the tikzpicture (the deepest document). –  Nazia Mar 7 '12 at 21:34
    
@PeterGrill: There is a let operation in TikZ, I guess the OP doesn’t mean TeX’s \let macro. –  Tobi Mar 7 '12 at 21:58
    
@Tobi: Ok, that's probably what the OP meant. And yes, the TeX \let is different than the TiKZ let. –  Peter Grill Mar 7 '12 at 22:00

2 Answers 2

up vote 14 down vote accepted

Using \newcommand and \pgfmathsetmacro:

Since you are only planning on changing the parameter within the deepest .tex file containing the tikzpicture, I would use \newcommand*{\Name}{}% to set the values and the just use \Name to access them.

However, if the value of some of the parameters are mathematically computed from another, then I would recommend using \pgfmathsetmacro{\NewName}{}. For example:

\newcommand*{\Diameter}{3.0}%
\pgfmathsetmacro{\Radius}{\Diameter/2}%
\pgfmathsetmacro{\Circumference}{2*pi*\Radius}%

This will be very useful when the calculation is a bit more complex.

However, should you want to consider the ability to change them from the parent document, you could instead use \providecommand{}{} in the tikzpicture document instead to set the parameter. This will then allow for the possibility that you could change the parameter in the parent document. One downside of this approach is that there is a risk that the value is defined somewhere else also no error will be triggered in the tikzpicture.

Using \pgfmathsetnewmacro:

As pointed out in the comments \pgfmathsetmacro uses a \def so no error is produced if you are overwriting an existing macro name. So, instead you could use \pgfmathsetnewmacro as defined below -- this issues a \newcommand to check that the macro does not already exist, before calling \pgfmathsetmacro:

\newcommand*{\pgfmathsetnewmacro}[2]{%
    \newcommand*{#1}{}% Error if already defined
    \pgfmathsetmacro{#1}{#2}%
}%

If you are defining the values within the tikzpicture and are not worried about overriding any previously defined ones, then you can use \def and \pgfmathsetmacro.

Update: Problems with using \def:

The comments suggest that if you define these constants within the tikzpicture environment, any case of accidentally overwriting an existing macro via a \def or \pgfmathsetmacro will not result in any problems outside of the tikzpicture as the re-definitions would only be local to the tikzpicture environment. This is NOT entirely accurate, as it can result in problems inside the tikzpicture environment, as I just discovered after several hours of debugging.

With the wrong thinking that there is no problems in using \def within a local scope, I decide to change the hard to read (and hard to modify if additional parameters are added at the beginning) macros such as:

\newcommand*{\DrawXAxis}[3][]{%
    \draw [ultra thick, #1] (#2,0) -- (#3,0)%
}%

to something like this:

\newcommand*{\DrawXAxisReadable}[3][]{%
    \def\XAxisStyle{#1}
    \def\XAxisMin{#2}
    \def\XAxisMax{#3}
    \draw [ultra thick, \XAxisStyle] (\XAxisMin,0) -- (\XAxisMax,0)%
}%

thinking that there is no problem if I overwrite \XAxisMin within this macro as I don't need what ever has been set previously and it will be restored anyway upon the end of this macro.

Well, this is ok in most cases -- but not ok if some parent macro had defined \XAxisMin and had passed it to this macro as a parameter. The code below illustrates this. It compiles just fine as is, but if you un comment the last tikzpicture then pdflatex seems to be stuck in an infinite loop.


Test Code:

\documentclass{standalone}
\usepackage{tikz}

%\def\Diameter{}% Error from \newcommand if this is uncommented
%\def\Radius{}% Error from \pgfmathsetnewmacro if this is uncommented
%\def\Circumference{}% Error from \pgfmathsetnewmacro if this is uncommented


% This bascially automates a \newcommand{<name>}{} to ensure
% that a command with the given <name> does not already exist
\newcommand*{\pgfmathsetnewmacro}[2]{%
    \newcommand*{#1}{}% Error if already defined
    \pgfmathsetmacro{#1}{#2}%
}%

\begin{document}
\newcommand*{\Diameter}{3.0}%

\pgfmathsetnewmacro{\Radius}{\Diameter/2}%
\pgfmathsetnewmacro{\Circumference}{2*pi*\Radius}%

\newcommand{\Origin}{(0,0)}%

\begin{tikzpicture}
    \draw \Origin circle (\Radius);
\end{tikzpicture}
\end{document}

Code: Problem in using \def within tikzpicture:

\documentclass{article}
\usepackage{tikz}

\newcommand*{\XAxisMin}{0}%
\newcommand*{\XAxisMax}{5}%

\newcommand*{\DrawXAxis}[3][]{%
    \draw [ultra thick, #1] (#2,0) -- (#3,0)%
}%

\newcommand*{\DrawXAxisReadable}[3][]{%
    \def\XAxisStyle{#1}
    \def\XAxisMin{#2}
    \def\XAxisMax{#3}
    \draw [ultra thick, \XAxisStyle] (\XAxisMin,0) -- (\XAxisMax,0)%
}%

\begin{document}
\begin{tikzpicture}
    \DrawXAxis[black]{\XAxisMin}{\XAxisMax};
\end{tikzpicture}

\begin{tikzpicture}
    \DrawXAxisReadable[blue]{0}{5};
\end{tikzpicture}

%%% Un comment this to see the problem
%\begin{tikzpicture}
%   \DrawXAxisReadable[red]{\XAxisMin}{\XAxisMax};
%\end{tikzpicture}
\end{document}
share|improve this answer
3  
I prefer the shorter \def\xx{2.0} which should harmless since I use it inside the tikzpicuture environment (group). The definition is only valid inside the group an won’t cause conflict outside. Certainly this will only work if one needs the parameters in one picture. –  Tobi Mar 7 '12 at 22:00
1  
@Tobi: Personal preference I guess. I often put my constant definitions outside the tikzpicture, so prefer \newcommand*{}{} as it is safer. And if there are many of these to define, copy-paste is faster anyway. –  Peter Grill Mar 7 '12 at 22:03
    
What are the safety issues with \def? –  Nazia Mar 7 '12 at 22:07
2  
@Nazia: \newcommand will produce an error if you attempt to redefine an existing name, \def will not. See What is the difference between \def and \newcommand? –  Peter Grill Mar 7 '12 at 22:09
    
@ Peter: Surly, this is my preference … :-) –  Tobi Mar 7 '12 at 22:17

Using \def

I normally prefer the shorter \def than \newcommand. The problem is, that \def doesn’t check wether the macro already exist, so it’s maybe overwritten. But I use the \definitions only inside {tikzpicture} and for a possible overwriting only exists in the current group of {tikzpicture}

\documentclass[border=1cm]{standalone}

\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
   \def\radius{1cm}
   \draw circle (\radius);
\end{tikzpicture}
\end{document}

In the above example \radius is only defined inside of {tikzpicture} and can only be used inside of it.

The next example shows that \def maybe produce an undesired result

\documentclass[border=1cm]{standalone}

\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
   \def\bfseries{1mm}
   \draw [line width=\bfseries] circle (2cm);
   \node {\bfseries That's the problem.};
\end{tikzpicture}
\end{document}

Using \newcommand

If I need a global variable I prefer \newcommand since it gives an error if I try to use an already existing macro name.

\documentclass[border=1cm]{standalone}

\usepackage{tikz}

\newcommand\radius{1cm}

\begin{document}
\begin{tikzpicture}
   \draw circle (\radius);
\end{tikzpicture}

\begin{tikzpicture}
   \draw [red] circle (\radius);
\end{tikzpicture}
\end{document}

The same example as the second one in “Using \def” but with \newcommand. If we now try to use an existing command (\bfseries) as TikZ variable we get the error message that \bfseries is already defined. So the user must decide wether to redefine it or use an other name which is the recommend way in this case.

\documentclass[border=1cm]{standalone}

\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
   \newcommand\bfseries{1mm}
   \draw [line width=\bfseries] circle (2cm);
   \node {\bfseries That's the problem.};
\end{tikzpicture}
\end{document}
share|improve this answer
    
@PeterGrill: This is my answer. What do you think about it? –  Tobi Mar 25 '12 at 9:20
    
I don't think your 2nd example shows a problem. One would do that if they did not know (or did not want) to use \bfseries, and hence the correct result was produced. –  Peter Grill Mar 25 '12 at 18:04
    
@PeterGrill: I guess I used the wrong words … with “problem” I mean that there will be a conflict because \bfseries is defined already and cant be uses with \newcommand so the user will be warned that he maybe does something he don’t want (overwrite \bfseries assuming he doesn’t know that it exist already). So the LaTeX gives the right result (error message) but it’s a problem from the users point of view. Hope that I made more clear what I wanted to say :-) –  Tobi Mar 26 '12 at 9:44

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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