19

I would like to declare functions in tikz for multiple uses of the same function within the code.

Sadly, it seems that the tikz "declare function" is not compatible with the french option in babel. Indeed, the following code (that I simplifed on purpose) runs fine :

\documentclass[english]{article}
\usepackage{babel}                      
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
    \tikzset{declare function={Carre(\t)=\t*\t;}}
    \draw plot [domain=-1:1] (\x,{Carre(\x)});
\end{tikzpicture}
\end{document}

But when I replace

\documentclass[english]{article}

with

\documentclass[english,french]{article}

compilation generates an error. This is what the log file says :

Missing character: There is no = in font nullfont! Missing character: There is no @ in font nullfont! Missing character: There is no @ in font nullfont!

Runaway argument? -1:1] (\x ,{Carre(\x )}); \end {tikzpicture} \end {document} ! Paragraph ended before \pgfmath@local@@functions was complete.

                 \par 

l.18

I suspect you've forgotten a `}', causing me to apply this control sequence to too much text. How can we recover? My plan is to forget the whole thing and hope for the best.

Before posting this, I updated all packages without success.

Any help welcome!

4 Answers4

22

The semicolon is made active by the french babel option, which throws the TikZ parser off. You can say \shorthandoff{;} in your tizpicture to fix this.

You can do this either by manually putting \shorthandoff{;} at the start of each tikzpicture, or you can use a TikZ style for inserting the code automatically into each tikzpicture by setting

\tikzset{
    every picture/.prefix style={
        execute at begin picture=\shorthandoff{;}
    }
}

or, as Tobi points out in a comment, you can load the etoolbox package and use

\AtBeginEnvironment{tikzpicture}{\shorthandoff{;}}

to patch the tikzpicture environment.

Jake
  • 232,450
  • 4
    It seems to work too with \AtBeginEnvironment{tikzpicture}{\shorthandoff{;}} (command form etoolbox package) So one can hack the environment globally and not every single environment. – Tobi Dec 07 '12 at 22:53
  • @Tobi: Good point! I've edited my answer accordingly. – Jake Dec 07 '12 at 23:07
  • 1
    I think /.prefix style is a tiny bit safer. – percusse Dec 08 '12 at 23:52
  • @percusse: What situation are you thinking about? – Jake Dec 09 '12 at 08:22
  • @Jake Some rare stuff like adding styles that involves some drawing commands etc. given before this key at the start of the picture but indeed probably not worth considering. – percusse Dec 09 '12 at 12:55
  • @percusse: Ah yes, you're right. I've edited my answer. – Jake Dec 09 '12 at 17:45
  • 1
    @Tobi What's the difference between 'globally' and 'every single environment'? – marczellm Jan 20 '13 at 22:23
  • @marczellm: I made a new question http://tex.stackexchange.com/q/94710/4918 since the answer is to long for a comment … – Tobi Jan 21 '13 at 12:32
  • @Tobi Although the new question serves as a good reference, I don’t think that is what @marczellm was asking about. The \AtBeginEnvironment solution is not really global to begin with (globally, all tikzpicture environments are affected, yes, but the every picture solution does affect all TikZ pictures too). – Qrrbrbirlbel Jan 21 '13 at 12:37
  • @Qrrbrbirlbel: Yes the \shorthandoff is local even with \AtBeginEnvironment but the change fo {tikzpicture} is global in a wider sens of meaning … but I guess you’re right and my new question doesn’t answer the question … O:-) – Tobi Jan 21 '13 at 13:22
  • @marczellm: Next try: with “globally” I meant to affect all {tikzpicture} environment in the same way, whereas “every single environment” menas the one must add the \shorthandoff manually to every environment. – Tobi Jan 21 '13 at 13:24
  • @Tobi Ah! I think the confusion stems from the fact that only Jake’s first revision of his answer shows the “every single environment” solution. This is also the reason I upvoted @marczellm’s comment. Now it all makes sense. :) – Qrrbrbirlbel Jan 21 '13 at 13:44
  • @Jake I’d add every node/.style={execute at begin node=\shorthandon{;}} globally so that the ; shorthand is active for the node’s content. – Qrrbrbirlbel Jan 21 '13 at 13:47
  • @Qrrbrbirlbel: Good idea. That won't work for something like \node [label=A;B] {...}, though, because the every node style doesn't apply here, so one has to be careful not to think of this as a proper fix. Seems like the issue is fixed in the CVS version of TikZ, thankfully. – Jake Jan 21 '13 at 14:02
  • 3
    Note that this won't work in beamer unless the fragile option is given to the frame since in beamer the frames are read in before processing and catcodes are frozen at that time. – Andrew Stacey Apr 22 '13 at 14:28
  • @AndrewStacey: What will work in beamer, then? – anonymous Jul 22 '13 at 19:43
  • @anonymous Either use the fragile option for the relevant frames or use my solution below. – Andrew Stacey Jul 22 '13 at 20:42
19

TikZ 3.0 introduced a new babel tikzlibrary to solve these kind of problems.

A tiny library that make the interaction with the babel package easier. Despite the name, it may also be useful in other contexts, namely whenever the catcodes of important symbols are changed globally. Normally, using this library is always a good idea; it is not always loaded by default since in some rare cases it may break old code.

\documentclass[english]{article}
\usepackage[english,french]{babel}                      
\usepackage{tikz}
\usetikzlibrary{babel}

\begin{document}
\begin{tikzpicture}
    \tikzset{declare function={Carre(\t)=\t*\t;}}
    \draw plot [domain=-1:1] (\x,{Carre(\x)});
\end{tikzpicture}
\end{document}

enter image description here

Update:

As has been shown in Babel, active chars, ifthenelse and tikz, babel tikzlibrary has some limitations when combined with babel-spanish package.

Ignasi
  • 136,588
  • Yes, it works, but notice http://tex.stackexchange.com/questions/314884/babel-active-chars-ifthenelse-and-tikz#314891 ... – Rmano Jun 15 '16 at 14:50
  • @Ignasi The ifthen package has no relevance whatsoever in that issue. The problem is with babel-spanish. – egreg Jun 15 '16 at 17:55
10

As with the question that Claudio links to, the problem is in some extra code that TikZ loads which doesn't have the same amount of checking for active characters as the main TikZ parser does. As Babel doesn't change the catcode of ; until the start of the document all of the semicolons involved in the declare function routine are inactive and thus don't match the active semicolon in the declaration of the function. Also as in that question, one solution is as Jake says: to switch off the activeness of ; in a tikzpicture. Another is to hack the code to make it robust with respect to the catcode of the semicolon:

\documentclass[french]{article}
%\url{http://tex.stackexchange.com/q/86023/86}
\usepackage{babel}                      
\usepackage{tikz}

\makeatletter
\pgfkeys{%
        /pgf/declare function/.code={%
          \ifnum\the\catcode`\;=\active\relax%
          \let\pgfmath@local@function@body=\pgfmath@local@function@body@active
          \let\pgfmath@local@@functions=\pgfmath@local@@functions@active
          \pgfmath@local@functions@active{#1}%
          \else
          \pgfmath@local@functions@notactive{#1}%
          \fi
        }
}

\def\pgfmath@local@functions@notactive#1{%
  \pgfmath@local@functions#1@=@;%
}

\begingroup
\catcode`\;=\active\relax
\gdef\pgfmath@local@functions@active#1{%
  \pgfmath@local@functions#1@=@;%
}

\gdef\pgfmath@local@@functions@active#1=#2;{%
        \def\pgfmath@local@temp{#1}%
        \ifx\pgfmath@local@temp\pgfmath@local@at%
                \let\pgfmath@local@next=\relax%
        \else%
                \pgfmath@local@function#1=#2;%
                \let\pgfmath@local@next=\pgfmath@local@functions%
        \fi%
        \pgfmath@local@next%
}
\gdef\pgfmath@local@function@body@active#1;{%
        \def\pgfmath@local@body{#1}%
        \begingroup%
                \c@pgf@counta=0\relax%
                \ifx\pgfmath@local@args\pgfmath@empty%
                        \expandafter\pgfmath@toks\expandafter=\expandafter{\pgfmath@local@body}%
                \else%
                        \pgfmath@toks={}%
                        \expandafter\pgfmath@local@function@@body\pgfmath@local@args,,%
                \fi%
                \xdef\pgfmath@local@temp{%
                        \noexpand\pgfmathdeclarefunction{\pgfmath@local@name}{\the\c@pgf@counta}%
                                {\noexpand\pgfmathparse{\the\pgfmath@toks}}%
                }%
        \endgroup%
        \pgfmath@local@temp%
}

\endgroup


\makeatother

\begin{document}
\begin{tikzpicture}
    \tikzset{declare function={Carre(\t)=\t*\t;}}
    \draw plot [domain=-1:1] (\x,{Carre(\x)});
\end{tikzpicture}

\shorthandoff{;}

\begin{tikzpicture}
    \tikzset{declare function={Carre(\t)=\t*\t;}}
    \draw plot [domain=-1:1] (\x,{Carre(\x)});
\end{tikzpicture}
\end{document}

As with the other question, the result here is that it compiles. To prove that, here's the result (sort of, standalone puts the pictures side by side):

declare function with active and inactive semicolon

Andrew Stacey
  • 153,724
  • 43
  • 389
  • 751
5

I use this:

\usepackage[babel=true, kerning=true]{microtype}
thisirs
  • 558