45

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:

9

2 Answers 2

33

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}
6
  • 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. Oct 31, 2013 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, 2013 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. Oct 31, 2013 at 23:00
  • @Qrrbrbirlbel I was using (0,0) instead of \pgfpointorigin. Now it works.
    – someonr
    Oct 31, 2013 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, 2014 at 20:36
27

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}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .