# Randomly curved arrows in TikZ

Any suggestions on how to draw something like this picture using TikZ?

Thanks!

Here is a slight extension of Milo's nice answer. The main differences (improvements?) are:

1. I rewrote Alain Matthes' nice answer to allow for arbitrary functions determining the line width. Previously it was a linearly dependence, now it can be an arbitrary function such as a sine. All you need to do is to say declare function={varyinglw(\x)=1+6*sin(1.8*\x);}. Apart from that, I made the code a bit more general, increased its speed (I think) and got rid of \makeatletter since there was nothing that cannot be achieved with commands not containing @s.
2. This variation also does not nest tikzpictures. Rather, the arrows a re attached in the usual way, and can be even bent.

## Here's how this works

• You need to find a function that determines how thick the line is at a given position of the path. This function has the name varyinglw. It's argument runs from 0 to 100. So if the function has a maximum at 50, the path will have reached its maximal width in the middle. An example for a function with this feature is declare function={varyinglw(\x)=1+6*sin(1.8*\x);} below. If you want to use different functions, use scopes. Unfortunately I do not now how one can reset functions that are declared with declare functions. Therefore you should keep your functions local.
• If you have a very long path, you may want to increase the number of segments since otherwise it won't look smooth any more. This can be done by saying e.g. /pgf/decoration/varying line width steps=180 as in the examples below.
• Other than that you can use pretty much any path.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{decorations,arrows.meta,bending}
\begin{document}

\pgfkeys{/pgf/decoration/.cd,
start color/.store in=\startcolor,
start color=black,
end color/.store in=\endcolor,
end color=black,
varying line width steps/.initial=100
}
\pgfdeclaredecoration{width and color change}{initial}{
\state{initial}[width=0pt, next state=line, persistent precomputation={%
\pgfmathparse{\pgfdecoratedpathlength/\pgfkeysvalueof{/pgf/decoration/varying line width steps}}%
\let\increment=\pgfmathresult%
\def\x{0}%
}]{}
\state{line}[width=\increment pt,   persistent postcomputation={%
\pgfmathsetmacro{\x}{\x+\increment}
},next state=line]{%
\pgfmathparse{ifthenelse(\x<\pgfdecoratedpathlength-5mm,varyinglw(100*(\x/\pgfdecoratedpathlength)),
varyinglw(100*((\pgfdecoratedpathlength-5mm)/\pgfdecoratedpathlength))*(\pgfdecoratedpathlength-\x)/14) )}
\pgfsetlinewidth{\pgfmathresult pt}%
\pgfpathmoveto{\pgfpointorigin}%
\pgfmathsetmacro{\steplength}{1.4*\increment}
\pgfpathlineto{\pgfqpoint{\steplength pt}{0pt}}%
\pgfmathsetmacro{\y}{100*(\x/\pgfdecoratedpathlength)}
\pgfsetstrokecolor{\endcolor!\y!\startcolor}%
\pgfusepath{stroke}%
}
\state{final}{%
\pgfsetlinewidth{\pgflinewidth}%
\pgfpathmoveto{\pgfpointorigin}%
\pgfmathsetmacro{\y}{100*(\x/\pgfdecoratedpathlength)}
\color{\endcolor!\y!\startcolor}%
\pgfusepath{stroke}%
}
}

\begin{tikzpicture}[varying arrow/.style={-{Stealth[length=5mm,width=3.2mm,bend]},color=\endcolor,
postaction={/utils/exec=\pgfsetarrows{-},decorate,decoration={width and color change}}
}]
\begin{scope}[declare function={varyinglw(\x)=1+6*sin(1.8*\x);}]
\draw[varying arrow] (0,0) to[out=45,in=150] ++ (1.5,0)  to[out=-30,in=-135] ++ (3,0);
\draw[varying arrow,/pgf/decoration/varying line width steps=180]
(0,-3) to[out=45,in=150] ++ (1.5,0)  to[out=-30,in=-135] ++ (3,0)
to[out=45,in=45] ++ (-2,1);
\draw[varying arrow,/pgf/decoration/varying line width steps=180,
/pgf/decoration/start color=red,/pgf/decoration/end color=blue]
(0,-5) to[out=15,in=165] ++ (2,0)  to[out=-15,in=90] ++ (1,-1)
to[out=-90,in=-20] ++ (-1.5,0);
\end{scope}

\begin{scope}[declare function={varyinglw(\x)=4-3*cos(7.2*\x);},xshift=6cm]
\draw[varying arrow] (0,0) to[out=45,in=150] ++ (1.5,0)  to[out=-30,in=-135] ++ (3,0);
\draw[varying arrow,/pgf/decoration/varying line width steps=180]
(0,-3) to[out=45,in=150] ++ (1.5,0)  to[out=-30,in=-135] ++ (3,0)
to[out=45,in=45] ++ (-2,1);
\draw[varying arrow,/pgf/decoration/varying line width steps=180,
/pgf/decoration/start color=yellow,/pgf/decoration/end color=red]
(0,-5) to[out=15,in=165] ++ (2,0)  to[out=-15,in=90] ++ (1,-1)
to[out=-90,in=-20] ++ (-1.5,0);
\end{scope}

\begin{scope}[declare function={varyinglw(\x)=4-3*cos(5.6*\x);},xshift=12cm]
\draw[varying arrow] (0,0) to[out=45,in=150] ++ (1.5,0)  to[out=-30,in=-135] ++ (3,0);
\draw[varying arrow,/pgf/decoration/varying line width steps=180]
(0,-3) to[out=45,in=150] ++ (1.5,0)  to[out=-30,in=-135] ++ (3,0)
to[out=45,in=45] ++ (-2,1);
\draw[varying arrow,/pgf/decoration/varying line width steps=180,
/pgf/decoration/start color=yellow,/pgf/decoration/end color=blue]
(0,-5) to[out=15,in=165] ++ (2,0)  to[out=-15,in=90] ++ (1,-1)
to[out=-90,in=-20] ++ (-1.5,0);
\end{scope}
\end{tikzpicture}
\end{document}


FUN: The mandatory animation.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{decorations,arrows.meta,bending}
\begin{document}

\pgfkeys{/pgf/decoration/.cd,
start color/.store in=\startcolor,
start color=black,
end color/.store in=\endcolor,
end color=black,
varying line width steps/.initial=100
}
\pgfdeclaredecoration{width and color change}{initial}{
\state{initial}[width=0pt, next state=line, persistent precomputation={%
\pgfmathparse{\pgfdecoratedpathlength/\pgfkeysvalueof{/pgf/decoration/varying line width steps}}%
\let\increment=\pgfmathresult%
\def\x{0}%
}]{}
\state{line}[width=\increment pt,   persistent postcomputation={%
\pgfmathsetmacro{\x}{\x+\increment}
},next state=line]{%
\pgfmathparse{ifthenelse(\x<\pgfdecoratedpathlength-5mm,varyinglw(100*(\x/\pgfdecoratedpathlength)),
varyinglw(100*((\pgfdecoratedpathlength-5mm)/\pgfdecoratedpathlength))*(\pgfdecoratedpathlength-\x)/14) )}
\pgfsetlinewidth{\pgfmathresult pt}%
\pgfpathmoveto{\pgfpointorigin}%
\pgfmathsetmacro{\steplength}{1.4*\increment}
\pgfpathlineto{\pgfqpoint{\steplength pt}{0pt}}%
\pgfmathsetmacro{\y}{100*(\x/\pgfdecoratedpathlength)}
\pgfsetstrokecolor{\endcolor!\y!\startcolor}%
\pgfusepath{stroke}%
}
\state{final}{%
\pgfsetlinewidth{\pgflinewidth}%
\pgfpathmoveto{\pgfpointorigin}%
\pgfmathsetmacro{\y}{100*(\x/\pgfdecoratedpathlength)}
\color{\endcolor!\y!\startcolor}%
\pgfusepath{stroke}%
}
}

\foreach \Z in {0,10,...,720}
{\begin{tikzpicture}[varying arrow/.style={-{Stealth[length=5mm,width=3.2mm,bend]},color=\endcolor,
postaction={/utils/exec=\pgfsetarrows{-},decorate,decoration={width and color change}}
}]
\path[use as bounding box] (-4,-4) rectangle (4,4);
\begin{scope}[declare function={varyinglw(\x)=1+6*sin(1.8*\x);}]
\draw[varying arrow]  plot[variable=\z,domain={\Z+90}:{\Z+180}]
(\z:{1+sqrt(\z/90)});
\end{scope}

\end{tikzpicture}}
\end{document}


ALTERNATIVE: Some additional possibilities arise with the calligraphy library. (If I understand correctly, currently you need to download the latest version from this repository.)

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{spath3}
% run "tex spath3.dtx" and then copy the spath3.sty file in the same directory
% as the tex file
\usetikzlibrary{arrows.meta,bending,decorations.pathreplacing}
\tikzset{calligraph/.style={postaction={decorate,decoration={show path construction,
moveto code={},
lineto code={},
curveto code={
\calligraphy (\tikzinputsegmentfirst) .. controls
(\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb)
..(\tikzinputsegmentlast);
},
closepath code={}}}}
}
\begin{document}
\begin{tikzpicture}[line width=1pt]
\pen (-135:.125) --  (45:.125) ;
\draw[calligraph,{Stealth[length=5mm,width=3.2mm,bend]}-] (0,0) to[out=45,in=150] ++ (1.5,0)  to[out=-30,in=-135] ++ (3,0);
\end{tikzpicture}

\begin{tikzpicture}[line width=1pt]
\pen (-135:.125) --  (45:.125) ;
\draw[calligraph,{Stealth[length=5mm,width=3.2mm,bend]}-] (0,0) to[out=45,in=150]
++ (1.5,0)  to[out=-30,in=45] ++ (1,-2);
\end{tikzpicture}
\end{document}


This isn't a complete answer. But as a proof of concept, I tried adapting this answer from Stroke with variable thickness to make something like the arrows you want.

\documentclass[tikz,margin=0.5cm]{standalone}
\usetikzlibrary{decorations,arrows.meta}

\makeatletter
\pgfkeys{/pgf/decoration/.cd,
start color/.store in =\startcolor,
end color/.store in   =\endcolor
}
\pgfdeclaredecoration{width and color change}{initial}{
\state{initial}[width=2pt, next state=line, persistent precomputation={%
\pgfmathdivide{50}{\pgfdecoratedpathlength}%
\let\increment=\pgfmathresult%
\def\x{0}%
}]{}
\state{line}[width=.5pt,   persistent postcomputation={%
\let\x=\pgfmathresult%
}]{%
\pgfsetlinewidth{\x/20*0.005pt+\pgflinewidth}%
\pgfsetarrows{-}%
\pgfpathmoveto{\pgfpointorigin}%
\pgfpathlineto{\pgfqpoint{.75pt}{0pt}}%
\pgfsetstrokecolor{\endcolor!\x!\startcolor}%
\pgfusepath{stroke}%
}
\state{final}{%
\pgfsetlinewidth{\pgflinewidth}%
\pgfpathmoveto{\pgfpointorigin}%
\color{\endcolor!\x!\startcolor}%
\pgfusepath{stroke}%
}
}
\makeatother

\begin{document}

\begin{tikzpicture}

\draw [line width=2pt, decoration={width and color change,start color=black, end color=black}, decorate,] plot [smooth, tension=1] coordinates { (0,0) (2,0.5) (5,0.7) (3,1.5) (1,1.5) } node [rotate=100] {\tikz \draw [-{Stealth[length=7mm, width=10mm]}](0,0);} ;

\end{tikzpicture}

\end{document}

• @marmot I'm actually thinking about forbidding nesting in a future version of PGF. It's just not fixable and always calls for trouble. – Henri Menke Jan 22 at 1:26