# Decorate path at points specified by function

I know that I can decorate a path at evenly spaced intervals using mark=between positions 0.1 and 0.9 step 0.25 ... etc.

Is it possible to specify the points at which to draw decorations using a function? E.g., something likedecorate at f(k) for k between 0.1 and 0.9 step 0.1 ...?

Here's an example of where I might want to use such a decoration (distance between points is increasing linearly):

Code for that image:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows,arrows.meta,decorations.markings}

\begin{document}

\begin{tikzpicture}[
scale=0.9,
decoration={
markings,
mark=at position 0.0025 with {\arrow[black,scale=0.66]{*}},
mark=at position 0.01   with {\arrow[black,scale=0.66]{*}},
mark=at position 0.0225 with {\arrow[black,scale=0.66]{*}},
mark=at position 0.04   with {\arrow[black,scale=0.66]{*}},
mark=at position 0.0625 with {\arrow[black,scale=0.66]{*}},
mark=at position 0.09   with {\arrow[black,scale=0.66]{*}},
mark=at position 0.1225 with {\arrow[black,scale=0.66]{*}},
mark=at position 0.16   with {\arrow[black,scale=0.66]{*}},
mark=at position 0.2025 with {\arrow[black,scale=0.66]{*}},
mark=at position 0.25   with {\arrow[black,scale=0.66]{*}},
mark=at position 0.3025 with {\arrow[black,scale=0.66]{*}},
mark=at position 0.36   with {\arrow[black,scale=0.66]{*}},
mark=at position 0.4225 with {\arrow[black,scale=0.66]{*}},
mark=at position 0.49   with {\arrow[black,scale=0.66]{*}},
mark=at position 0.5625 with {\arrow[black,scale=0.66]{*}},
mark=at position 0.64   with {\arrow[black,scale=0.66]{*}},
mark=at position 0.7225 with {\arrow[black,scale=0.66]{*}},
mark=at position 0.81   with {\arrow[black,scale=0.66]{*}},
mark=at position 0.9025 with {\arrow[black,scale=0.66]{*}},
mark=at position 0.0025 with {\arrow[black,scale=0.66]{*}},
},
]
\draw[gray] (0,0) grid[step=1] (8,8);
\draw[postaction={decorate},very thick, draw=red]
(3,1) node[below]{A}
to[out=30,in=270] (6,3)
to[out =90, in =-30 ] (2,4)
to[out =150, in = 225] (2,6) node[above]{B}
;
\end{tikzpicture}

\end{document}


Remark: you can use /.list key handler to iterate a style over different values.

Using this remark I define a style mark with function that has the following syntax :

mark with function={f at positions {0,.1,...,1.57} with \arrow[black,scale=0.66]{*}}


Here is the full code.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows,arrows.meta,decorations.markings}
\tikzset{
% #1 is the function, #2 is the list of arguments, #3 is the marking
/pgf/decoration/mark with function/.code args={#1 at positions #2 with #3}{
\edef\args{#2}
\xdef\pos{} % the evaluated positions "#1(#2)"
\foreach[count=\n] \i in \args{
\pgfmathparse{#1(\i)}
\xdef\pos{\pos\ifnum\n>1,\fi\pgfmathresult}
}
\pgfkeysalso{mark temp/.style={mark=at position ##1 with {#3}}}
\pgfkeysalso{mark temp/.list/.expanded=\pos}
},
}
\begin{document}

\begin{tikzpicture}[
scale=0.9,
decoration={
markings,
/pgf/declare function={f(\x)=sin(\x r)^2;},
mark with function={f at positions {0,.1,...,1.57} with \arrow[black,scale=0.66]{*}}
},
]
\draw[gray] (0,0) grid[step=1] (8,8);
\draw[postaction={decorate},very thick, draw=red]
(3,1) node[below]{A}
to[out=30,in=270] (6,3)
to[out =90, in =-30 ] (2,4)
to[out =150, in = 225] (2,6) node[above]{B}
;
\end{tikzpicture}

\end{document}


• That's really great, thanks! These motion diagrams have been such a pain to make, I think this will help a lot. – Chris Chudzicki Oct 14 '15 at 13:26
• @mrc be careful, the function must be increasing. – Kpym Oct 14 '15 at 14:20

If you can accept redrawing the path as many times as points you want, following code could be an starting point for your final solution. It uses Jake's answer to How to animate a path or how to draw starting fraction of a complex but linear path?.

This code defines a decoration which just draws the starting segment of a path. This can be used inside a foreach loop which redraws the path as many steps you wants and with the length you need. Drawing order is from longer segment to shorter otherwise arrows tips are covered by later segments.

\documentclass[tikz,border=2mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations, arrows.meta}

% A simple empty decoration, that is used to ignore the last bit of the path
\pgfdeclaredecoration{ignore}{final}
{
\state{final}{}
}

% Declare the actual decoration.
\state{initial}[
width={0pt},
next state=middle
]
{\decoration{moveto}}

\state{middle}[
next state=final
]
{\decoration{curveto}}

\state{final}
{\decoration{ignore}}
}

\tikzset{middle segment/.style={decoration={middle},decorate, segment length=#1}}

\begin{document}
\begin{tikzpicture}
\draw[gray] (0,0) grid[step=1] (8,8);

\foreach \step [evaluate=\step as \dist using 1/\step] in {1,2,...,10} {%
\draw[middle segment=\dist,red, -{Circle[black,scale=.66]}] (3,1) node[below]{A}
to[out=30,in=270] (6,3)
to[out =90, in =-30 ] (2,4)
to[out =150, in = 225] (2,6) node[above]{B}
;}
\end{tikzpicture}

\end{document}