# PGFplots: Plot end arrows without specifying domain

I want to draw functions in a standard way (like you would find in a textbook) using PGFplots. This question relates to the end arrows on a function.

Using restrict x to domain (and y) works for most functions, but has a problem with asymptotes, as in tan(deg(x)):

\documentclass{standalone}
\usepackage{pgfplots}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
samples=50,smooth,axis lines=middle,axis equal image=true,xmin=-3,xmax=3,ymin=-2,ymax=2,
restrict y to domain={\pgfkeysvalueof{/pgfplots/ymin}:\pgfkeysvalueof{/pgfplots/ymax}},
restrict x to domain={\pgfkeysvalueof{/pgfplots/xmin}:\pgfkeysvalueof{/pgfplots/xmax}}
]
\end{axis}
\end{tikzpicture}
\end{document}


The desired output should have arrows on the other intervals (and lines for the asymptotes would be nice, but that may be another issue altogether)

My goal is to plot any function in one command, like \addplot[color,arrows] {function(x)}; without micromanaging domain restrictions. I know I could restrict the domain manually and add three plots of the same function.

Is there a generic way to make PGFplots show the proper arrows for all (most) functions, including those with asymptotes? This would include elementary functions like x^2, \frac{1}{x}, sin(x), log(x). A perfect solution would also do polar functions like \frac{1}{1-2*cos(\theta)}, though that is outside the immediate scope of this question.

It is possible to tell pgfplots to add arrows whenever it jumps. Originally I was hoping to achieve this with jump mark left and jump mark right, see p. 80 of the pgfplotsmanual v.16. However, I could not make this work. So I went a more complicated way.

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usetikzlibrary{decorations.pathreplacing,calc}
\newcounter{ppoint}
\begin{document}
\begin{tikzpicture}[reset ppoint/.code={\setcounter{ppoint}{0}},
my arrows/.style={reset ppoint,
decoration={show path construction,
curveto code={\stepcounter{ppoint}
\ifnum\value{ppoint}=1
\draw[<-]  (\tikzinputsegmentfirst)  .. controls
(\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb)
..(\tikzinputsegmentlast);
\else
\path let \p1=($(prev0)-(\tikzinputsegmentfirst)$),\n1={veclen(\x1,\y1)}
in \pgfextra{\ifdim\n1<1cm
\xdef\NewStart{0}
\else
\xdef\NewStart{1}
\fi};
\ifnum\NewStart=1
\draw[<-]  (\tikzinputsegmentfirst)  .. controls
(\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb)
..(\tikzinputsegmentlast);
\draw[->]  (prev0)  .. controls
(preva) and (prevb)
..(prev1);
\else
\draw[-]  (\tikzinputsegmentfirst)  .. controls
(\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb)
..(\tikzinputsegmentlast);
\fi
\fi
\path (\tikzinputsegmentfirst) coordinate (prev0)
(\tikzinputsegmentsupporta) coordinate (preva)
(\tikzinputsegmentsupporta) coordinate (prevb)
(\tikzinputsegmentlast) coordinate (prev1);
}}}]
\begin{axis}[
samples=50,smooth,axis lines=middle,axis equal image=true,xmin=-3,xmax=3,ymin=-2,ymax=2,
restrict y to domain={\pgfkeysvalueof{/pgfplots/ymin}:\pgfkeysvalueof{/pgfplots/ymax}},
restrict x to domain={\pgfkeysvalueof{/pgfplots/xmin}:\pgfkeysvalueof{/pgfplots/xmax}},
%unbounded coords=jump,
]
my arrows,postaction={-,decorate},->
] {tan(deg(x))};
\end{axis}
\end{tikzpicture}
\end{document}


Note that this version only works for smooth plots. If you want to make it work for non-smooth curves, too, you need also to add a similar lineto code.

One may also add the asymptotes. However, this version tacitly assumes that the asymptotes are vertical.

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usetikzlibrary{decorations.pathreplacing,calc}
\newcounter{ppoint}
\begin{document}
\begin{tikzpicture}[reset ppoint/.code={\setcounter{ppoint}{0}},
my arrows/.style={reset ppoint,
decoration={show path construction,
curveto code={\stepcounter{ppoint}
\ifnum\value{ppoint}=1
\draw[<-]  (\tikzinputsegmentfirst)  .. controls
(\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb)
..(\tikzinputsegmentlast);
\else
\path let \p1=($(prev0)-(\tikzinputsegmentfirst)$),\n1={veclen(\x1,\y1)}
in \pgfextra{\ifdim\n1<1cm
\xdef\NewStart{0}
\else
\xdef\NewStart{1}
\fi};
\ifnum\NewStart=1
\draw[<-]  (\tikzinputsegmentfirst)  .. controls
(\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb)
..(\tikzinputsegmentlast);
\draw[->]  (prev0)  .. controls
(preva) and (prevb)
..(prev1);
\path ($(prev1)!0.5!(\tikzinputsegmentfirst)$) coordinate (aux);
\draw[dashed,cyan,thick,<->] (prev1-|aux) --
(aux|-\tikzinputsegmentfirst);
\else
\draw[-]  (\tikzinputsegmentfirst)  .. controls
(\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb)
..(\tikzinputsegmentlast);
\fi
\fi
\path (\tikzinputsegmentfirst) coordinate (prev0)
(\tikzinputsegmentsupporta) coordinate (preva)
(\tikzinputsegmentsupporta) coordinate (prevb)
(\tikzinputsegmentlast) coordinate (prev1);
}}}]
\begin{axis}[
samples=50,smooth,axis lines=middle,axis equal image=true,xmin=-3,xmax=3,ymin=-2,ymax=2,
restrict y to domain={\pgfkeysvalueof{/pgfplots/ymin}:\pgfkeysvalueof{/pgfplots/ymax}},
restrict x to domain={\pgfkeysvalueof{/pgfplots/xmin}:\pgfkeysvalueof{/pgfplots/xmax}},
%unbounded coords=jump,
]

• This solution works for almost every function I have given it. But using 0.2/sin(deg(3*x)) shows the vertical line restrict y to domain= should have blocked. Not all the function lines cut off at the ymin and ymax parameters set manually. I tried setting samples=150 or higher, but it doesn't help. Even tan(deg(x)) as plotted above cuts off around -1.8 at x=-1 but closer to -2 at x=2. – onomou Dec 27 '18 at 11:35