# Smooth option sometimes produces incorrect arrow tips in PGFplots

It seems that the smooth option applied to lines sometimes effects the arrow tips and produces incorrect results. No problem with vertical lines, but any other seems to have a problem. Is this a known bug, or is there a reason why the smooth should not be applied to straight lines?

Updated: to show problem does NOT occur with TikZ, and problem also occurs with curves if smooth option is applied.

\documentclass{article}
\usepackage{pgfplots}
\begin{document}

\tikzstyle{MyStyle}      =[->, black, ultra thick,       ]
\tikzstyle{MyStyleSmooth}=[->, black, ultra thick, smooth]

\begin{tikzpicture}
\begin{axis}
% 'smooth' option seems to have no effect on lines '1' and '2'
\addplot [MyStyle      , green ] coordinates{(0,0) (0,1)} node [above] {1};
\addplot [MyStyleSmooth, blue  ] coordinates{(1,0) (1,1)} node [below] {2};
%
% But, can't seem to have the 'smooth' on lines, '4', '5' and '6'
\addplot [MyStyle      , orange] coordinates{(2,0)   (3,0)   } node [right] {3};
\addplot [MyStyleSmooth, red   ] coordinates{(4,0)   (2,0.5) } node [below] {4};
\addplot [MyStyleSmooth, red   ] coordinates{(2,1)   (3,1)   } node [left ] {5};
\addplot [MyStyleSmooth, red   ] coordinates{(3,0.8) (2,0.8) } node [right] {6};

% Similar problem with curves: "non-smooth" is ok, "smooth" is not
\addplot[MyStyleSmooth, mark=none, domain=0:1,samples=50, red ] (x,x*x+2);

\end{axis}
\end{tikzpicture}

\begin{tikzpicture} % These are all fine
\draw [MyStyle      , green ] (0,0)   -- (0,1)    node [above] {1};
\draw [MyStyleSmooth, blue  ] (1,0)   -- (1,1)    node [above] {2};
%
\draw [MyStyle      , orange] (2,0)   -- (3,0)    node [right] {3};
\draw [MyStyleSmooth, red   ] (4,0)   -- (2,0.5)  node [below] {4};
\draw [MyStyleSmooth, red   ] (2,1)   -- (3,1)    node [right] {5};
\draw [MyStyleSmooth, red   ] (3,0.8) -- (2,0.8)  node [left ] {6};
\end{tikzpicture}
\end{document}

-
Does this also happen with normal TikZ arrow lines? –  Martin Scharrer Jun 1 '11 at 19:48
@Martin: Nope. The TikZ arrow lines seems to work fine. I updated the MWE to show this. BUT, I had to change some of the node placements for some reason which does not make sense to me. –  Peter Grill Jun 1 '11 at 19:55
Do you need to draw the arrows as plots, i.e. using \addplot, because you get the data from an external source, or do you enter the points by hand? In the latter case, you should probably draw the arrows within the axis environment using \draw [MyStyle] (axis cs:4,0) -- (axis cs:2,0.5);. Using plots for this would otherwise be a bit inefficient. –  Jake Jun 1 '11 at 20:11
That seems to work fine, although I'd prefer to continue to use \addplot so I don't need to change the way I plot just because I need an arrow tip. The problem also exists for curves and have updated the MWE to show this. –  Peter Grill Jun 1 '11 at 21:06

The problem is not one of PGFplots, but of the PGF plot commands (which PGFplots uses to draw its plots):

\tikz\draw [smooth,thick,->] plot coordinates {(0,0) (0.5,0.1) (1,0)};


yields

What's happening is the following: Setting smooth for a \draw plot command engages the \pgfplothandlercurveto routine (this is not PGFplots, but PGF) in pgflibraryplothanders.code.tex. This routine draws the last segment in the plot using the command

\pgfpathcurveto{\pgf@plot@curveto@first@support}{\pgf@plot@curveto@second}{\pgf@plot@curveto@second}%


This is a PGF curve command that continues a curve from the current position using two support points to a destination. In this case, the second support and the destination are the same point (\pgf@plot@curveto@second), which makes sure that the curve can enter the last point from any direction. It has the disadvantage, however, that the very last part of this segment is always going to be degenerate (a line from A to A...), which is interpreted as pointing up. This very last part is used to orientate the arrow tip.

In order to prevent this last part from being used, we can redefine the offending function to use \pgfpathcurvebetweentimecontinue, which only draws part of the last line. Replacing the \pgfpathcurveto command from above with

\pgfpathcurvebetweentimecontinue{0}{0.995}{\pgf@plot@curveto@first}{\pgf@plot@curveto@first@support}{\pgf@plot@curveto@second}{\pgf@plot@curveto@second}%


only the last 99.5% of the line are drawn, which excludes the degenerate part but is visually identical, especially since arrow tips overdraw the end of the line. I'm not sure if this value is going to work in all cases, but it does work for your test cases:

\documentclass{article}
\usepackage{pgfplots}
\begin{document}

\makeatletter
\def\pgf@plot@curveto@handler@finish{%
\ifpgf@plot@started%
\pgfpathcurvebetweentimecontinue{0}{0.995}{\pgf@plot@curveto@first}{\pgf@plot@curveto@first@support}{\pgf@plot@curveto@second}{\pgf@plot@curveto@second}%
\fi%
}
\makeatother

\tikzstyle{MyStyle}      =[->, black, ultra thick,       ]
\tikzstyle{MyStyleSmooth}=[->, black, ultra thick, smooth]

\begin{tikzpicture}
\begin{axis}
% 'smooth' option seems to have no effect on lines '1' and '2'
\addplot [MyStyle      , green ] coordinates{(0,0) (0,1)} node [above] {1};
\addplot [MyStyleSmooth, blue  ] coordinates{(1,0) (1,1)} node [below] {2};
%
% But, can't seem to have the 'smooth' on lines, '4', '5' and '6'
\addplot [MyStyle      , orange] coordinates{(2,0)   (3,0)   } node [right] {3};
\addplot [MyStyleSmooth, red   ] coordinates{(4,0)   (2,0.5) } node [below] {4};
\addplot [MyStyleSmooth, red   ] coordinates{(2,1)   (3,1)   } node [left ] {5};
\addplot [MyStyleSmooth, red   ] coordinates{(3,0.8) (2,0.8) } node [right] {6};

% Similar problem with curves: "non-smooth" is ok, "smooth" is not
\addplot[MyStyleSmooth, mark=none, domain=0:1,samples=50, red ] (x,x*x+2);

\end{axis}
\end{tikzpicture}

\begin{tikzpicture} % These are all fine
\draw [MyStyle      , green ] (0,0)   -- (0,1)    node [above] {1};
\draw [MyStyleSmooth, blue  ] (1,0)   -- (1,1)    node [above] {2};
%
\draw [MyStyle      , orange] (2,0)   -- (3,0)    node [right] {3};
\draw [MyStyleSmooth, red   ] (4,0)   -- (2,0.5)  node [below] {4};
\draw [MyStyleSmooth, red   ] (2,1)   -- (3,1)    node [right] {5};
\draw [MyStyleSmooth, red   ] (3,0.8) -- (2,0.8)  node [left ] {6};
\end{tikzpicture}
\end{document}


-
Works perfectly!! Thanks... –  Peter Grill Jun 2 '11 at 0:13
How do I modify this so that a beginning arrow tip also points in the right direction? If I am using <-> arrows, this fixes the end arrow but not the beginning. –  alex.jordan Nov 2 '12 at 3:29