[Tex/LaTex] way to clear paths previously defined with name path global in TikZ

intersectionspgfplotstikz-pgf

In the solution to Intersections in PGFplots it was pointed out that each \addplot command was drawn in its own scope and using name path would not survive outside of that \addplot command. The solution was to use name path global so that the path name would be known outside of the particular \addplot that generated that path. This works fine — However, in a large document it is possible that the same name may be used again.

Am wondering if there is a way to clear the paths that were named via name path global. Even if I needed to do this outside of the current \tikzpicture environment that too would be fine as I would just simple add an empty \tikzpicture that performed this clean up after each picture where it was used. This would be preferable as then I don't need to worry about name conflicts.

I don't see anything about this is the documentation, so if it not currently possible, this might be a good feature to consider for future release.

**** Update (using sol'n provided by Andrew) ****

Attempted to use sol'n, but it seems to only clear the first path.. The following code works fine if the path names are changed in the 2nd graph (and shows 2 intersections), but as is it shows 4 intersections as shown here

\documentclass{standalone}
\usepackage{pgfplots}
\usetikzlibrary{intersections}

\makeatletter
\tikzset{%
  clear global paths/.style={
    execute at end picture=\clear@global@paths,
    name path global/.append code={
      \ifx\global@paths\pgfutil@empty
      \gdef\global@paths{##1}%
      \else
      \xdef\global@paths{\global@paths,##1}%
      \fi
    }
  },
  clear global paths now/.code={
    \expandafter\global\expandafter\let\csname tikz@intersect@path@name@#1\endcsname=\relax
  }
}
\let\global@paths=\pgfutil@empty
\def\clear@global@paths{%
  \edef\@temp{\noexpand\pgfkeys{/tikz/clear global paths now/.list={\global@paths}}}%
  \@temp
  \global\let\global@paths=\pgfutil@empty
}
\makeatother
%--------------------------------------------------

\begin{document}

\newcommand*{\ShowIntersection}[2]{
\fill 
    [name intersections={of=#1 and #2, name=i, total=\t}] 
    [red, opacity=1, every node/.style={above left, black, opacity=1}] 
    \foreach \s in {1,...,\t}{(i-\s) circle (2pt)
        node [above left] {\s}};
}

\begin{tikzpicture}[clear global paths]
\draw[name path global=GraphCurve, mark=none, domain=-2.5:2.5, thick] plot ({\x},{\x*\x});%

\draw [red, thick, name path global=HorizontalLine] (-2.5,3) -- (2.5,3);%

\ShowIntersection{GraphCurve}{HorizontalLine}
\end{tikzpicture}


\begin{tikzpicture}[clear global paths]
\begin{axis}
\addplot[name path global=GraphCurve, mark=none, domain=-2.5:2.5, thick] ({x},{x*x});%
\addplot [red, thick, name path global=HorizontalLine] coordinates{(-2.5,4) (2.5,4)};%

\ShowIntersection{GraphCurve}{HorizontalLine}
\end{axis} 
\end{tikzpicture}
\end{document}

Best Answer

The paths are stored in macros called \tikz@intersect@path@name@<name of path> so to clear the paths, you need to blank that macro. The crudest, but simplest, way is to simply \let it to \relax after the tikzpicture environment. A more fancy method would be to put in a new hook at the end of the picture which blanks the global paths defined in that picture. To do this, we need to store a list of the names of paths to blank by adding some code to the naming key, then we work through that list setting each path to \relax in turn. Thus:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{intersections}

\makeatletter
\tikzset{%
  clear global paths/.style={
    execute at end picture=\clear@global@paths,
    name path global/.append code={
      \ifx\global@paths\pgfutil@empty
      \gdef\global@paths{##1}%
      \else
      \xdef\global@paths{\global@paths,##1}%
      \fi
    }
  },
  clear global paths now/.code={
    \expandafter\global\expandafter\let\csname tikz@intersect@path@name@#1\endcsname=\relax
  }
}
\let\global@paths=\pgfutil@empty
\def\clear@global@paths{%
  \edef\@temp{\noexpand\pgfkeys{/tikz/clear global paths now/.list={\global@paths}}}%
  \@temp
  \global\let\global@paths=\pgfutil@empty
  \global\let\tikz@intersect@namedpaths=\pgfutil@empty
}
\makeatother

\begin{document}
\begin{tikzpicture}[clear global paths]
\draw[name path global=path] (0,0) -- (1,0);
\draw[name path global=another path] (0,0) -- (1,0);
\makeatletter
\show\global@paths
\makeatother
\end{tikzpicture}
\makeatletter
\show\tikz@intersect@path@name@path
\show\global@paths
\makeatother
\end{document}

Inside the tikzpicture, \global@paths is a comma-separated list of the paths that have been globally defined. At the end of the picture, we work through this list blanking each one (as can be seen by the output of the \show) and then finally blank our list ready for the next call.

Update: Turns out that TikZ tries really hard to remember paths that have been globally named, to the extent that there is a macro that can reconstruct a named path. I'm having trouble seeing where it is defined, because wherever I place the \show\tikz@intersect@namedpaths inside the tikzpicture environment then I get nothing, but if I put it straight afterwards then I get the code necessary to reconstruct the last named path (and only the last named one). So somewhere in the code to end the tikzpicture, that macro gets set. I've added code to blank it to the above and that seems to fix the problem. Since it only remembers the last globally named path, I would guess that this isn't meant to happen so I don't feel too guilty about blanking it. But be warned that I haven't a clue what it's for, nor where it is getting set, so something else may break because of this (though I doubt it).