9

I would like to define the \DrawLine macro below so that it can be invoked from within a {tikzpicture} environment or from outside:

\newcommand*{\DrawLine}[1]{%
  \IfInTikzPic{}{\tikzpicture[remember picture]}
      \draw[ultra thick, ->, #1] (0,) -- (1,1) node [right] {output of DrawLine};
  \IfInTikzPic{}{\endtikzpicture}%
}

This works fine when invoked from within a {tikzpicture}, but not when it is invoked from outside (line is commented in the MWE). Invoking it from outside yields the error:

Missing \endgroup inserted.

enter image description here

The MWE below uses the first reference below. The other two references also fail on the commented out test case.

References:

Code:

\documentclass{article}
\usepackage{tikz}

\makeatletter \newcommand{\IfInTikzPic}[2]{% https://tex.stackexchange.com/a/121309/4301 \ifx\pgfpictureid@undefined#2\else#1\fi% } \makeatother

\newcommand*{\DrawLine}[1]{% \IfInTikzPic{}{\tikzpicture[remember picture]} \draw[ultra thick, ->, #1] (0,) -- (1,1) node [right] {output of DrawLine}; \IfInTikzPic{}{\endtikzpicture}% }

\begin{document} %%% The commented out code here is to show that \IfInTikzPic works as desired %%% (in a tikzpicture, outside of a \node). %%%

%\textbf{IfInTikzPic}\par %\IfInTikzPic{inside}{outside} % %\begin{tikzpicture} % \IfInTikzPic{\draw [red, ultra thick]}{\draw [blue, ultra thick]} (0,0) -- (1,0); %\end{tikzpicture} % %\medskip% -------------------------- \textbf{DrawLine}: Actual Output\par

%\DrawLine{blue}% <---- How do I get this case to work?

\begin{tikzpicture} \DrawLine{orange} \end{tikzpicture}

\medskip% -------------------------- \textbf{DrawLine}: Desired Output\par

\begin{tikzpicture} \DrawLine{blue} \end{tikzpicture}

\begin{tikzpicture} \DrawLine{orange} \end{tikzpicture} \end{document}

Peter Grill
  • 223,288
  • 1
    https://tex.stackexchange.com/questions/18652/how-can-i-check-if-the-current-code-is-inside-a-certain-environment perhaps – Torbjørn T. Nov 07 '18 at 19:57
  • Or https://tex.stackexchange.com/questions/412456/is-there-a-simple-way-to-find-out-if-a-command-is-executed-in-a-tikzpicture-en –  Nov 07 '18 at 20:02
  • @TorbjørnT.: That works for all but the commented out case below (yields a different error message though: Undefined control sequence). – Peter Grill Nov 07 '18 at 20:06
  • @marmot: Yep, that also works for all but the commented out case below and produces the same error message. – Peter Grill Nov 07 '18 at 20:07

2 Answers2

7
\documentclass{article}
\usepackage{tikz}

\makeatletter
\newcommand{\IfInTikzPic}{% https://tex.stackexchange.com/a/121309/4301
  \ifx\pgfpictureid\@undefined
    \expandafter\@firstoftwo
     \else
    \expandafter\@secondoftwo
    \fi
}
\makeatother

\newcommand*{\DrawLine}[1]{%
  \IfInTikzPic
   {\begin{tikzpicture}[remember picture]
    \draw[ultra thick, ->, #1] (0,) -- (1,1) node [right] {output of DrawLine};
   \end{tikzpicture}}%
    {\draw[ultra thick, ->, #1] (0,) -- (1,1) node [right] {output of DrawLine};}%
}

\begin{document}
%%% The commented out code here is to show that \IfInTikzPic works as desired
%%% (in a tikzpicture, outside of a \node).
%%%

\textbf{IfInTikzPic}\par
\IfInTikzPic{inside}{outside}

\begin{tikzpicture}
  \IfInTikzPic{\draw [red, ultra thick]}{\draw [blue, ultra thick]} (0,0) -- (1,0);
\end{tikzpicture}

\medskip% --------------------------
\textbf{DrawLine}: Actual Output\par

\DrawLine{blue}% <---- How do I get this case to work?

\begin{tikzpicture}
  \DrawLine{orange}
\end{tikzpicture}

\medskip% --------------------------
\textbf{DrawLine}: Desired Output\par

\begin{tikzpicture}
  \DrawLine{blue}
\end{tikzpicture}

\begin{tikzpicture}
  \DrawLine{orange}
\end{tikzpicture}
\end{document}

Or this version which directly forces tikz rather than having an if-then-else construct

\documentclass{article}
\usepackage{tikz}

\makeatletter
\newcommand{\ensuretikz}{% https://tex.stackexchange.com/a/121309/4301
  \ifx\pgfpictureid\@undefined
    \expandafter\tikzify
     \else
    \expandafter\@firstofone
    \fi
}
\makeatother

\def\tikzify#1{\begin{tikzpicture}#1\end{tikzpicture}}

\newcommand*{\DrawLine}[1]{%
    \ensuretikz
    {\draw[ultra thick, ->, #1] (0,) -- (1,1) node [right] {output of DrawLine};}%
}

\begin{document}
%%% The commented out code here is to show that \IfInTikzPic works as desired
%%% (in a tikzpicture, outside of a \node).
%%%




\medskip% --------------------------
\textbf{DrawLine}: Actual Output\par

\DrawLine{blue}% <---- How do I get this case to work?

\begin{tikzpicture}
  \DrawLine{orange}
\end{tikzpicture}

\medskip% --------------------------
\textbf{DrawLine}: Desired Output\par

\begin{tikzpicture}
  \DrawLine{blue}
\end{tikzpicture}

\begin{tikzpicture}
  \DrawLine{orange}
\end{tikzpicture}
\end{document}
David Carlisle
  • 757,742
7

The following example defines \IfInTikzPic to check the current environment against tikzpicture and define a \tikzstart...\tikzend pair accordingly:

enter image description here

\documentclass{article}

\usepackage{tikz}

\makeatletter
\def\@tikzenvironment{tikzpicture}

\newcommand{\IfInTikzPic}{%
  \edef\tikzstart{%
    \ifx\@currenvir\@tikzenvironment\else
      \noexpand\tikzpicture[remember picture]%
    \fi
  }%
  \edef\tikzend{%
    \ifx\@currenvir\@tikzenvironment\else
      \noexpand\endtikzpicture%
    \fi
  }%
}

\newcommand*{\DrawLine}[1]{%
  \IfInTikzPic
  \tikzstart
    \draw[ultra thick, ->, #1] (0,) -- (1,1) node [right] {output of DrawLine};
  \tikzend%
}
\makeatother

\begin{document}

\textbf{DrawLine}: Actual Output\par

\DrawLine{blue}

\begin{tikzpicture}
  \DrawLine{orange}
\end{tikzpicture}

\medskip% --------------------------

\textbf{DrawLine}: Desired Output\par

\begin{tikzpicture}
  \DrawLine{blue}
\end{tikzpicture}

\begin{tikzpicture}
  \DrawLine{orange}
\end{tikzpicture}

\end{document}

You could also group the tikzpicture if needed:

\newcommand{\IfInTikzPic}{%
  \edef\tikzstart{%
    \ifx\@currenvir\@tikzenvironment\else
      \noexpand\begin{tikzpicture}[remember picture]%
    \fi
  }%
  \edef\tikzend{%
    \ifx\@currenvir\@tikzenvironment\else
      \noexpand\end{tikzpicture}%
    \fi
  }%
}
Werner
  • 603,163