41

How can I shade a path witout filling? In particular, I wand to draw a curved arrow that starts colored blue and ends colored green, where in between it gradually changes its color. I can't find a way to shade a path without filling it.

The following code does not work, as it shades the filling area, although it compiles.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,automata,patterns,decorations,decorations.pathmorphing}
\usetikzlibrary{fadings}
\begin{document}
\begin{tikzpicture}

\draw[path fading=south,very thick,top color=blue!80!white,
      bottom color=green!80!white,->] (0,0) .. controls +(0,-1) and +(0,1) .. (1,-2);

\end{tikzpicture}
\end{document}

Example image

Christian
  • 19,238
DCTLib
  • 1,914

4 Answers4

35

I don't remember why the scaling was happening but please let me know the missing detail or fix it so I can delete this. ( Stolen from How to draw multiple lines inside the circle )

Something along these lines can be a very impractical but a possible way to do it. I can't think of anything clever how to automate it other than the obvious tedious way.

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

\begin{tikzfadingfrompicture}[name=custom fade]%
\path(-0.2cm,0.2cm) rectangle (1.2cm,-2cm); % Arrow line is an overlay!
\pgfinterruptboundingbox
\draw[very thick,transparent!20,->] (0cm,0cm) .. controls +(0cm,-1cm) and +(0cm,1cm) .. (1cm,-2cm);
\endpgfinterruptboundingbox
\end{tikzfadingfrompicture}


\begin{document}

\begin{tikzpicture}
\draw[style=help lines] (0,-2) grid[step=1cm] (2,0);
\draw[path fading=custom fade,
      top color=blue!80,
      bottom color=green!80,
     ] (0,0) rectangle (1cm,-2cm);
\end{tikzpicture}

\end{document}

enter image description here

percusse
  • 157,807
17

Here's a quick attempt to automate percusse's solution:

curved arrow whose colour is a blue-to-green gradient, from top to bottom

Here's the main file:

\documentclass[tikz,border=5mm]{standalone}
\usepackage{tikz}
\usepackage{fade-no-fill}
\begin{document}

\begin{tikzpicture}
  \draw[style=help lines] (0,-2) grid[step=1cm] (2,0);
  \path[
    fade path but don't fill={
      very thick,
      transparent!20,
      ->
    }{
      top color=blue!80,
      bottom color=green!80,
    },
  ] (0cm,0cm) .. controls +(0cm,-1cm) and +(0cm,1cm) .. (1cm,-2cm);


  \begin{scope}[x=0.5cm,y=0.5cm]
    % Circles, each with a distinct fading
    \foreach \i in {1,...,5}{
      \pgfmathsetmacro{\j}{18*\i}
      \path[
        fade path but don't fill={
          very thick,
          transparent!\j,
        }{
          top color=green!80,
          bottom color=blue!80,
          shading angle=45,
        },
      ] (1+\i,-\i) circle (\i mm);
    }

    % Circles, with a global fading
    \path[
      fade path but don't fill={
        very thick,
        transparent!60,
      }{
        top color=blue!80,
        bottom color=green!80,
      },
    ] foreach \i in {1,...,5}{
      (\i-1,-\i-3) circle (\i mm)
    };
  \end{scope}
\end{tikzpicture}

\end{document}

You will need to paste the following code into fade-no-fill.sty, which uses the spath library from the TeX.SX package. You will therefore need to download spath.dtx, run it with pdflatex spath.dtx and copy the resulting spath.sty in the same folder.

\usetikzlibrary{intersections}% for "name path".
\usetikzlibrary{math}%
\usetikzlibrary{fadings}%
\usepackage{spath}% for "use path", from the TeX.SX package
                  % at http://bazaar.launchpad.net/~tex-sx/tex-sx/development/files
\usepgfmodule{oo}% for spath
\usetikzlibrary{arrows.meta}% needed so that bounding boxes correctly include arrows.
% Copied from https://tex.stackexchange.com/a/26386/5699
\tikzset{
  use path for main/.code={%
    \tikz@addmode{%
      \expandafter\pgfsyssoftpath@setcurrentpath\csname tikz@intersect@path@name@#1\endcsname
    }%
  },
  use path for actions/.code={%
    \expandafter\def\expandafter\tikz@preactions\expandafter{\tikz@preactions\expandafter\let\expandafter\tikz@actions@path\csname tikz@intersect@path@name@#1\endcsname}%
  },
  use path/.style={%
    use path for main=#1,
    use path for actions=#1,
  }
}
\tikzset{
  fade path but don't fill/.style 2 args={
    preaction={save path=\tmppath,},
    postaction={
      /utils/exec={
        \coordinate (oldbb-ne) at (current bounding box.north east);
        \coordinate (oldbb-sw) at (current bounding box.south west);
        \pgfresetboundingbox
        \begin{tikzfadingfrompicture}[name=tempfade]%
          \pgfresetboundingbox
          \pgfoonew \thepathsav=new spath(\tmppath)
          \thepathsav.use path with tikz(draw,#1)
          \coordinate (temp-fade-bb-ne) at (current bounding box.north east);
          \coordinate (temp-fade-bb-sw) at (current bounding box.south west);
          \coordinate (temp-fade-bb-center) at (current bounding box.center);
        \end{tikzfadingfrompicture}
        %
        \useasboundingbox (oldbb-ne) rectangle (oldbb-sw);
        %
        \tikzmath{
          coordinate \ctempfadebbcenter;
          \ctempfadebbcenter = (temp-fade-bb-center);
        }
        \tikzset{tempstyle/.style/.expand once={#2}}
        \path[
          path fading=tempfade,
          fit fading=false,
          fading transform={
            yshift=\ctempfadebbcentery,
            xshift=\ctempfadebbcenterx,
          },
          tempstyle,
        ] (temp-fade-bb-ne) rectangle (temp-fade-bb-sw);
      },
    },
  },
}
Suzanne Soy
  • 3,043
  • 1
    See https://tex.stackexchange.com/q/337898/86 for an updated version using spath3 instead of the (depreciated) spath library. – Andrew Stacey Jul 24 '17 at 11:15
11

I think that this answer is worth including to this old question. I simply draw the arrow twice fading from different ends.It presumably only works because of newer versions of TikZ.

\documentclass[tikz, border=1 cm]{standalone}
\usetikzlibrary{fadings}
\begin{document}
\begin{tikzpicture}   
\draw [blue!80!white, very thick , ->, path fading=south,
  postaction={draw, green!80!white, path fading=north}]
  (0,0) .. controls +(0,-1) and +(0,1) .. (1,-2);
\end{tikzpicture}
\end{document}

Blue to green fading arrow

  • I would even say because of a very recent version of TikZ, as it actually does not work in my TeX Live 2021 installation. – Archange Sep 18 '21 at 05:28
  • @Archange: Strange. What goes wrong? Can you run this more than a year old code?: https://tex.stackexchange.com/q/597927/8650 – hpekristiansen Sep 18 '21 at 18:09
  • So on the TeX Live 2019 distribution that comes with Ubuntu 20.10, this does not seem to work - I'm just getting a green arrow. – DCTLib Sep 18 '21 at 20:01
  • @DCTLib How long time ago did you update your packages? According to this, your installation is at its very limit of when to expect having problems: https://tex.stackexchange.com/a/46140/8650 – hpekristiansen Sep 18 '21 at 20:49
  • @hpekristiansen Well, I've updated today. As far as I know, there are no TeX Live version upgrades without updating the Ubuntu version. Ubuntu 20.04 (sorry, had the wrong number in the previous comment) will stay supported until April 2023. Installing TeX Live without the package manager of the OS distribution is tricky (https://tex.stackexchange.com/questions/1092/how-to-install-vanilla-texlive-on-debian-or-ubuntu), so I believe few users do this. The post that you referred to targets MikTex, which works differently and has its own package manager. – DCTLib Sep 18 '21 at 21:15
  • 1
    Ok - and it still does not work!? I have mactex with tikz.sty 2021/05/15 v3.1.9a (3.1.9a). Can you maybe try another viewer? My .pdf also shows correctly here: https://smallpdf.com/pdf-reader – hpekristiansen Sep 18 '21 at 21:24
  • 4
    @hpekristiansen Thanks for pointing at the viewer being the likely culprit. So it does not work with evince/any poppler based viewers I guess (no shading, green arrow). It works in Chromium, but not in Firefox also (only blue arrow with shading). mupdf based viewers seems OK too. I’ll try to open an issue at poppler as soon as I have time to properly investigate this. – Archange Sep 19 '21 at 08:19
  • @Archange Can confirm. Firefox shades out the blue arrow. Chromium shows the arrow correctly (as does okular). Evince shows only the green arrow. The hack from (https://tex.stackexchange.com/questions/9261/using-opacity-in-tikz-causes-strange-rendering-in-acrobat) about wrong rendering when using opacity does not appear to make a difference. – DCTLib Sep 19 '21 at 10:44
  • Reported here for poppler: https://gitlab.freedesktop.org/poppler/poppler/-/issues/1142. For Firefox/pdfjs here: https://bugzilla.mozilla.org/show_bug.cgi?id=1731493 – Archange Sep 19 '21 at 13:47
  • Interestingly, the rendering issue vanishes when postprocessing with ghostscript as gs -o output.pdf -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress input.pdf. – Archange Sep 24 '23 at 20:57
6

In Metapost, it is possible to get the "envelope" of a path using envelope. One can then fill in the path with a linear shade.

\starttext

\startMPpage[offset=1mm]
  path p, q;

  p := origin{dir -90} .. {dir -90} (2, -2);
  p := p scaled 1cm;

  q := envelope pensquare scaled 3bp of p;
  draw q;

  q := q xshifted 2cm;
  linear_shade(q, 0, blue, red);
\stopMPpage
\stoptext

which gives

enter image description here

Aditya
  • 62,301