4

I would like to create a wavy arrow with a color gradient along the wave. For this, I tried to combine the solution from https://tex.stackexchange.com/a/197867/96546 for color gradients with the solution from https://tex.stackexchange.com/a/193451/96546 for wavy arrows.

Here is a MWE:

    \documentclass[tikz, border=5]{standalone}
    \usetikzlibrary{shapes.arrows}
    \makeatletter
    \def\createshadingfromlist#1#2#3{%
        \pgfutil@tempcnta=0\relax
        \pgfutil@for\pgf@tmp:={#3}\do{\advance\pgfutil@tempcnta by1}%
        \ifnum\pgfutil@tempcnta=1\relax%
        \edef\pgf@spec{color(0)=(#3);color(100)=(#3)}%
        \else%
        \pgfmathparse{50/(\pgfutil@tempcnta-1)}\let\pgf@step=\pgfmathresult%
        %
        \pgfutil@tempcntb=1\relax%
        \pgfutil@for\pgf@tmp:={#3}\do{%
            \ifnum\pgfutil@tempcntb=1\relax%
            \edef\pgf@spec{color(0)=(\pgf@tmp);color(25)=(\pgf@tmp)}%
            \else%
            \ifnum\pgfutil@tempcntb<\pgfutil@tempcnta\relax%
            \pgfmathparse{25+\pgf@step/4+(\pgfutil@tempcntb-1)*\pgf@step}%
            \edef\pgf@spec{\pgf@spec;color(\pgfmathresult)=(\pgf@tmp)}%
            \else%
            \edef\pgf@spec{\pgf@spec;color(75)=(\pgf@tmp);color(100)=(\pgf@tmp)}%
            \fi%
            \fi%
            \advance\pgfutil@tempcntb by1\relax%
        }%
        \fi%
        \csname pgfdeclare#2shading\endcsname{#1}{100}\pgf@spec%
    }
\createshadingfromlist{shading1}{vertical}{red,yellow,green,cyan,blue}
\createshadingfromlist{shading2}{vertical}{red,yellow}
\createshadingfromlist{shading3}{vertical}{black,blue,cyan,white}

%%%
\usetikzlibrary{decorations.shapes}
\usetikzlibrary{shapes.geometric, arrows}
\usetikzlibrary{patterns}
\usepackage[compat=1.0.0]{tikz-feynman}
\usetikzlibrary{decorations.pathreplacing,angles,quotes,decorations.pathmorphing}
\usepackage{tkz-euclide}
%\usetkzobj{all}
\usepackage{pgfplots}
\pgfplotsset{compat=1.9}

\begin{document}
    \tikzset{decorate sep/.style 2 args=
        {decorate,decoration={shape backgrounds,shape=circle,shape size=#1,shape sep=#2}}}
    \begin{tikzpicture}[colorbar arrow/.style={
            shape=double arrow,
            double arrow head extend=0.125cm, 
            shape border rotate=90, 
            minimum height=5cm,
            shading=#1
        },
        wavy/.style={decorate,decoration={snake,post length=1.2mm}}
        ]

        \node [colorbar arrow=shading1,wavy] at (0,0) {};
%       \node [colorbar arrow=shading2] at (1,0) {};
%       \node [colorbar arrow=shading3] at (2,0) {};
    \end{tikzpicture}  
\end{document}

which creates the following figure: enter image description here

So it almost works, but somehow the ends are not really arrows any more and the wave modifies both sides of the arrow boundary. What I would like to create is something like

enter image description here

with a color gradient across. This can be obtained in the above MWE by replacing the \node line with \draw[red,wavy,->,>=stealth'] (5.0,0.2) -- (2.2,0.2) node [above] {};

Any hints on what is going wrong in this combination or how to do it properly appreciated!

  • Hi! What do you need to control in the end? The start and end points I suppose, and the color gradient. But, is the number of "waves" important? Or their amplitude? Do you need to control them? What about the line width? – Daniel N Dec 12 '23 at 09:22
  • @DanielN hm, I guess it would be nice to be able to control all of these (you can control most of them in the solution that I linked). Any intermediate solution would potentially be valuable too though if it still looks reasonably like a wavy arrow. – Wolpertinger Dec 12 '23 at 12:59

1 Answers1

2

enter image description here

I propose a solution in which the wavy path and the colour change are realized at the same time through a loop and the sin function; there is no decoration involved.

The arrow is a pic object, w arrow, that depends on six arguments: the starting and ending points, the amplitude of the "wave", the number of (complete) periods, the starting and ending colours.

Remark. In case you need a gradient with more than two colors, then the colors must be given as a list. The modification is minimal. We can talk about it if you need it.

The code

\documentclass[margin=10pt]{standalone}

\usepackage{tikz} \usetikzlibrary{math, calc}

\tikzset{% pics/w arrow/.style args={from=#1 to=#2, amplitude=#3, periods=#4, s-color=#5, e-color=#6% }{% code={% \tikzmath{% integer \nbSteps, \i, \j; real \d, \r, \angle, \nbPeriods, \h, \ecst, \acst; coordinate \S, \E; \nbPeriods = #4 +.75; \nbSteps = 25; \S = #1; \E = #2; \d = veclen(\Ex-\Sx, \Ey-\Sy)1pt/1cm; \acst = .65; % controls the horizontal segment supporting the arrow \r = \d/(\nbPeriods +\acst); \ecst = (\nbPeriods +.3)/(\nbPeriods +\acst); \angle = atan2(\Ey-\Sy, \Ex-\Sx); \h = \nbPeriods/\nbSteps; % domain length for \x \a = 0; \b = \a +\h; for \i in {1,...,\nbSteps}{% \j = 4\i; {% \draw[#6!\j!#5, line cap=round, domain=\a:\b, samples=15, shift={(\S)}, rotate=\angle] plot ({\r\x}, {-#3sin(360\x)}); }; \a = \b; \b = \a +\h; }; {% \path[shift={(\S)}, rotate=\angle] ({\r\nbPeriods}, {-#3sin(360\nbPeriods)}) coordinate (tmpPoint); \draw[#6, ->] (tmpPoint)
to[out=\angle, in=\angle+180] ($(\S)!\ecst!(\E)$) -- (\E); }; } } } }

\begin{document} \begin{tikzpicture}[] \draw[fill=gray!20] (0, 0) circle (1.5pt) node[left] {$S$}; \draw[fill=gray!20] (3, 1) circle (1.5pt) node[right] {$E$};

\path pic[very thick] {w arrow={from=(0, 0) to=(3, 1), amplitude=.2, periods=3, s-color=green, e-color=blue}}; \path pic[] {w arrow={from=(0, -.5) to=(4, -.5), amplitude=.1, periods=5, s-color=cyan, e-color=red}}; \path pic[line width=4pt] {w arrow={from=(0, -.5) to=(4, -3), amplitude=.3, periods=2, s-color=cyan, e-color=violet}}; \end{tikzpicture} \end{document}

Daniel N
  • 5,687