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!

1

4 Answers 4

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.

17
  • 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 7, 2012 at 22:53
  • @Tobi: Good point! I've edited my answer accordingly.
    – Jake
    Dec 7, 2012 at 23:07
  • 1
    I think /.prefix style is a tiny bit safer.
    – percusse
    Dec 8, 2012 at 23:52
  • 1
    @Tobi What's the difference between 'globally' and 'every single environment'?
    – marczellm
    Jan 20, 2013 at 22:23
  • 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. Apr 22, 2013 at 14:28
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.

2
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

5
+50

I use this:

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .