1

Inspired by this question I tried to decorate my PGFPlots mesh with an end arrow. However, this end arrow is not properly positioned so that the end of the line shows behind the arrow tip. Here is a minimal working example. Most of it is copied from the main answer of the above-mentioned question.

\documentclass{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\usepgfplotslibrary{colormaps}
\usetikzlibrary{decorations.markings}

\def\definemappedcolor#1{%
    %\message{Got #1^^J}%
    \pgfmathparse{#1*1000}% ... transform to range [0,1000]
    \pgfplotscolormapdefinemappedcolor{\pgfmathresult}%
}%

\tikzset{
  set arrow inside/.code={\pgfqkeys{/tikz/arrow inside}{#1}},
  set arrow inside={end/.initial=>, opt/.initial=},
  /pgf/decoration/Mark/.style={
    mark/.expanded=at position #1 with
    {
      \noexpand\definemappedcolor{#1}%
      \noexpand\arrow[\pgfkeysvalueof{/tikz/arrow inside/opt}]{\pgfkeysvalueof{/tikz/arrow inside/end}}
    }
  },
  arrow inside/.style 2 args={
    set arrow inside={#1},
    postaction={
      decorate,decoration={
        markings,Mark/.list={#2}
      }
    }
  },
}

\begin{document}

\begin{tikzpicture}
\begin{axis}[x=1cm, y=1cm, colormap/hot, point meta=explicit]
    \addplot[mesh] 
        coordinates {
        (0,0) [0]
        (1,1) [1]
        (2,2) [2]
        (3,3) [3]
        (4,2) [4]
    };

    \addplot[draw=none] 
        coordinates {
        (0,0) [0]
        (1,1) [1]
        (2,2) [2]
        (3,3) [3]
        (4,2) [4]
    } [arrow inside={end=stealth,opt={mapped color, scale=3}}{1}];
\end{axis}
\end{tikzpicture}

\end{document}

This is the result:

enter image description here

As you can clearly see, the arrow tip is not properly attached to the end of the plot, but rather slightly before the end. I have tried to make use of shorten >=2pt, but it does not seem to work.

How can I position the arrow so that it is "properly" attached to the end of the plot line, i.e., how can I prevent the end of the line to be seen?

  • You mean that the "base" of the arrow tip should be touching the very end of the plot line and not be over it? – Alenanno May 12 '15 at 15:38
  • It is placed properly. But the line end is square and arrow tip is sharp. Hence at the end the line is seen. Adjust the coordinates in draw=none line like (4.02,1.98) [4] you will see the difference. – user11232 May 12 '15 at 15:39
  • Otherwise put, how can I prevent the end of the line to be seen (without changing the coordinates, of course)? – JohnSilver May 12 '15 at 15:39
1

The problem here is, that you draw the arrow on top of "whatever previously was drawn". That is why there is no "auto-correction" of this behavior as it would be the case when you would apply the arrow to the line directly.

To "simulate" that behavior you can draw a double-arrow. The first just overdraws the parts of the "other" line that should not be seen and the second being the "real" arrow what you wanted to add. To do so you have to use a negative separation length.

In addition I tried to find a solution that is independent of the chosen line width and is tested for line width up to `ultra thick'.

For more details have a look at the comments in the code.

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \usetikzlibrary{
        % load this library to make use of the advanced arrow features
        arrows.meta,
        decorations.markings,
        pgfplots.colormaps,
    }

\def\definemappedcolor#1{%
    %\message{Got #1^^J}%
    \pgfmathparse{#1*1000}% ... transform to range [0,1000]
    \pgfplotscolormapdefinemappedcolor{\pgfmathresult}%
}%

\tikzset{
    set arrow inside/.code={\pgfqkeys{/tikz/arrow inside}{#1}},
    set arrow inside={end/.initial=>, opt/.initial=},
    /pgf/decoration/Mark/.style={
        mark/.expanded=at position #1 with {
            \noexpand\definemappedcolor{#1}%
            \noexpand\arrow[\pgfkeysvalueof{/tikz/arrow inside/opt}]{\pgfkeysvalueof{/tikz/arrow inside/end}}
        }
    },
    arrow inside/.style 2 args={
        set arrow inside={#1},
        postaction={
            decorate,decoration={
                markings,Mark/.list={#2}
            },
        },
    },
    % -------------------------------------------------------------------------
    my arrow/.tip={
        % this arrow tip shall overdraw the end of the "other" draw line
        Rectangle[
            % scale this arrow to 5 times the length of `line width'
            % (you can adjust this; it must only be longer than the "free" seen
            %  stuff of the "other" line)
            % and (only) being as width as `line width'
            length={0pt 5},
            width={0pt 1},
            % now adjust the `sep' to make it independent of line width
            sep={-3.05pt -5},
            % assume white background color
%            white,
            green,  % for debugging purposes only
        ]
        % and this is the arrow you actually want to plot
        Stealth[]
    },
    % -------------------------------------------------------------------------
}
\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        x=1cm,
        y=1cm,
        colormap/hot,
        point meta=explicit,
    ]
        \addplot [
            mesh,
            % make (already) active to prove that I didn't move the line or arrow tip
            very thick,
        ] coordinates {
            (0,0) [0]
            (1,1) [1]
            (2,2) [2]
            (3,3) [3]
            (4,2) [4]
        };

        \addplot [
            draw=none,
            % make sure, this has the same `line width' as the previous plot
%            very thick,
        ]
            coordinates {
            (0,0) [0]
            (1,1) [1]
            (2,2) [2]
            (3,3) [3]
            (4,2) [4]
        % apply the defined arrow here
        } [arrow inside={end=my arrow}{1}];
    \end{axis}
\end{tikzpicture}
\end{document}

image showing the zoomed result of above code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.