36

How can I get a path following color gradient in TikZ? Here a quick example of the idea. On the left the result I'm looking for and on the right an example of a non path following gradient applied on a path.

path following shading

It looks like the TikZ shading library isn't covering this.

Related questions:

28

Thanks to the hints from comments, I created the following proof of concept. This solution is not elegant (yet?) and slow. result

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{decorations.markings}


\tikzset{test/.style={
    postaction={
        decorate,
        decoration={
            markings,
            mark=at position \pgfdecoratedpathlength-0.5pt with {\arrow[blue,line width=#1] {>}; },
            mark=between positions 0 and \pgfdecoratedpathlength-8pt step 0.5pt with {
                \pgfmathsetmacro\myval{multiply(divide(
                    \pgfkeysvalueof{/pgf/decoration/mark info/distance from start}, \pgfdecoratedpathlength),100)};
                \pgfsetfillcolor{blue!\myval!red};
                \pgfpathcircle{\pgfpointorigin}{#1};
                \pgfusepath{fill};}
}}}}

\begin{document}
    \begin{tikzpicture}[]
        \path [test=2pt] (-1,-1) .. controls (9,-1) and (-7,1) .. (1,1);
    \end{tikzpicture}
\end{document}
  • 1
    A node is over-qualified for this. Rather use a path: \fill[<color>] circle[radius=<radius>];. It would probably be a little bit faster if you even use PGF for this, you will need at least \pgfsetfillcolor, \pgfpathcircle and \pgfusepath{fill} for that. By the way, inside of decorations, you should be able to access the path length via \pgfdecoratedpathlength or something alike. – Qrrbrbirlbel Oct 31 '13 at 0:17
  • @Qrrbrbirlbel I tried to use pgf for drawing, but I got i.stack.imgur.com/1AWwP.png (I'm not common with pgf). \pgfdecoratedpathlength works perfectly. Any idea for the arrow tip placement? – someonr Oct 31 '13 at 22:36
  • 2
    That’s strange. If I replace your \filled path with \pgfsetfillcolor{blue!\myval!red}\pgfpathcircle{\pgfpointorigin}{#1}\pgfusepath{fill} I get the same result. I’d also replace step 0.5pt by step .5*#1 so that the step length is scaled with (half) the line width. (The 2pt is only half the line width because it is used as the radius of the circles, so the arrow tip is too small.) I don’t have any ideas on the arrow tip though, that is really annoying. – Qrrbrbirlbel Oct 31 '13 at 23:00
  • @Qrrbrbirlbel I was using (0,0) instead of \pgfpointorigin. Now it works. – someonr Oct 31 '13 at 23:07
  • 1
    You can replace #1 by .5\pgflinewidth and any 0.5pt by .25\pgflinewidth and then you can use it with usual line width. But if you say \path [test, ultra thin] (-1,-1) .. controls (9,-1) and (-7,1) .. (1,1); than it will run out of memory ! – Kpym Dec 13 '14 at 20:36
14

enter image description here

Here is a more complete answer -- still not perfect, and still slow, but at least is merges nicely with node borders:

\documentclass[tikz,border=5mm]{standalone}

\usepackage{tikz}
\usetikzlibrary{decorations.markings}


\tikzset{test/.style n args={3}{
    postaction={
    decorate,
    decoration={
    markings,
    mark=between positions 0 and \pgfdecoratedpathlength step 0.5pt with {
    \pgfmathsetmacro\myval{multiply(
        divide(
        \pgfkeysvalueof{/pgf/decoration/mark info/distance from start}, \pgfdecoratedpathlength
        ),
        100
    )};
    \pgfsetfillcolor{#3!\myval!#2};
    \pgfpathcircle{\pgfpointorigin}{#1};
    \pgfusepath{fill};}
}}}}

\definecolor{c1}{rgb}{0.2,0.8,0.3}
\definecolor{c2}{rgb}{0.8,0.3,0.2}
\definecolor{c3}{rgb}{0.3,0.2,0.8}
\definecolor{c4}{rgb}{0.7,0.1,0.5}

\begin{document}
\begin{tikzpicture}[]
    % node definitions
    \node [circle, draw=c1, ultra thick] (s1) at (0, 0) {s1};
    \node [circle, draw=c2, ultra thick] (s2) at (2, 1) {s2};
    \node [circle, draw=c3, ultra thick] (s3) at (-1, 3) {s3};
    \node [circle, draw=c4, ultra thick] (s4) at (-0.3, 5) {s4};

    % sketch
    \draw [test={0.8pt}{c1}{c2}, thick] (s1) to [bend right] (s2);
    \draw [test={0.8pt}{c1}{c3}, thick] (s1) to [bend left] (s3);
    \draw [test={1.2pt}{c2}{c3}, thick] (s2) to [bend left] (s3);
    \draw [test={0.9pt}{c3}{c4}, thick] (s2) to [bend right] (s4);
    \draw [test={1.1pt}{c2}{c4}, thick] (s3) to [bend right] (s4);
\end{tikzpicture}
\end{document}

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.