# TikZ - how to draw a gradient between two curves - not necessarily functions

I would like to draw the image below - a gradient between two curves that are not necessarily functions and can probably be better described by a Bézier between certain points.

I have seen a few examples, but they all deal with either functions or arcs, or parallel curves.

I have worked the curves in detail:

\documentclass{minimal}

\usepackage{tikz}
\usetikzlibrary{svg.path}
\usetikzlibrary{intersections}

\begin{document}
\begin{tikzpicture}
\begin{scope}[yscale=-1,xscale=1]
\draw [name path=L, green] svg {M201.1,673.2c1.4-39.8,2-52.2,18.2-70.8c11.7-13.5,18.3-24.3-7.7-49.4
c-39.3-38-43.2-59.2,1-90.2c18.1-12.7,67.1-20.2,25.4-36.6c-18.2-7.2-23.5-9.7-26.9-39.2c-3-26.7-17.7-28.2-37.7-35
c-20-6.9-87.7-28.8-50.2-78.2c23.5-31,58.6-73.9,83.1-118.2c13.3-24,22.4-56.5,38.6-85.9};
\draw [name path=R, blue] svg {M295,69.4c-5.1,25.7-13.3,57.3-19.2,76.5
c-15,48.3-21.9,52.2-36.7,86.5c-21.5,49.9-47.2,77.8-1.1,90.5c46.7,12.8,49.7,16,48.9,40.6c-0.6,18.4-3.9,35.1,10.3,34.3
c15.7-0.9,40.5,6,71.5,36.8c8.2,8.1,25,18.7,25,18.7s-159.2,8.6-116.4,73.2c29.6,44.7,31.9,44.4,19.9,66.7
c-15.1,28.3-28.8,48.8-23,80.6};
\end{scope}
\end{tikzpicture}
\end{document}


which yields:

which is the easy part. I am still looking for ways to transform one curve into the other and changing the color along the way.

• Welcome to TeX.SE. It would be helpful if you composed a fully compilable MWE including \documentclass and the appropriate packages that sets up the problem. In this specific case, an MWE that draws the path that you want the gradient applied to would be sufficient. While solving problems can be fun, setting them up is not. Then, those trying to help can simply cut and paste your MWE and get started on solving the problem. – Peter Grill Apr 6 '17 at 0:42
• Take a look at this question, which deals with simpler paths, which you could concatenate into more complicated ones. – Jānis Lazovskis Apr 6 '17 at 1:51
• @Janis, I looked at that before posting. I believe that example only deals with parallel curves. – Knudsen Apr 6 '17 at 5:27
• @Janis, I believe that even if you concatenate paths on the solution you mention, you still get shadings by parallel curves only. The question here is explicitly for two curves that are not paralle, like in the example that I am going to try to attach next. – Knudsen Apr 10 '17 at 0:38
• \draw [name path=L, green] svg {M201.1,673.2c1.4-39.8,2-52.2,18.2-70.8c11.7-13.5,18.3-24.3-7.7-49.4 c-39.3-38-43.2-59.2,1-90.2c18.1-12.7,67.1-20.2,25.4-36.6c-18.2-7.2-23.5-9.7-26.9-39.2c-3-26.7-17.7-28.2-37.7-35 c-20-6.9-87.7-28.8-50.2-78.2c23.5-31,58.6-73.9,83.1-118.2c13.3-24,22.4-56.5,38.6-85.9}; – Knudsen Apr 10 '17 at 0:45

## 3 Answers

If you look into the original graphics you may observe that the shaded area is only from the middle to the left and from the middle to the right it is almost completely black. So dividing the graphics in two and building on the suggestions by Peter Grill, the SVG paths defined by the OP, and others, here is one solution that moves the entire curve to the right:

\documentclass{minimal}

\usepackage{tikz}
\usetikzlibrary{svg.path}
\usepackage{spath} % Package for manipulating paths by Andrew Stacey

% The curve that will be repeated to the left at a lower-tone.
\newcommand{\MiddleC}{%
[xshift=25] svg {M201.1,673.2c1.4-39.8,2-52.2,18.2-70.8c11.7-13.5,18.3-24.3-7.7-49.4
c-39.3-38-43.2-59.2,1-90.2c18.1-12.7,67.1-20.2,25.4-36.6c-18.2-7.2-23.5-9.7-26.9-39.2c-3-26.7-17.7-28.2-37.7-35
c-20-6.9-87.7-28.8-50.2-78.2c23.5-31,58.6-73.9,83.1-118.2c13.3-24,22.4-56.5,38.6-85.9};
}

% The repetition of this curve, by Peter Grill - answer 1.
\newcommand{\MyScope}[1][]{%
\begin{scope}[cap=round, #1]
\path[draw=black] \MiddleC;
\end{scope}
}

\newlength{\shift}

\begin{document}

\begin{tikzpicture}[transform canvas={yscale=-1}] %SVG curves were upside down.
\path [save path=\Left] svg {M201.1,673.2c1.4-39.8,2-52.2,18.2-70.8c11.7-13.5,18.3-24.3-7.7-49.4
c-39.3-38-43.2-59.2,1-90.2c18.1-12.7,67.1-20.2,25.4-36.6c-18.2-7.2-23.5-9.7-26.9-39.2c-3-26.7-17.7-28.2-37.7-35
c-20-6.9-87.7-28.8-50.2-78.2c23.5-31,58.6-73.9,83.1-118.2c13.3-24,22.4-56.5,38.6-85.9};
\path [save path=\Middle, xshift=25] svg {M201.1,673.2c1.4-39.8,2-52.2,18.2-70.8c11.7-13.5,18.3-24.3-7.7-49.4
c-39.3-38-43.2-59.2,1-90.2c18.1-12.7,67.1-20.2,25.4-36.6c-18.2-7.2-23.5-9.7-26.9-39.2c-3-26.7-17.7-28.2-37.7-35
c-20-6.9-87.7-28.8-50.2-78.2c23.5-31,58.6-73.9,83.1-118.2c13.3-24,22.4-56.5,38.6-85.9};
\path [save path=\Right] svg {M295,69.4c-5.1,25.7-13.3,57.3-19.2,76.5
c-15,48.3-21.9,52.2-36.7,86.5c-21.5,49.9-47.2,77.8-1.1,90.5c46.7,12.8,49.7,16,48.9,40.6c-0.6,18.4-3.9,35.1,10.3,34.3
c15.7-0.9,40.5,6,71.5,36.8c8.2,8.1,25,18.7,25,18.7s-159.2,8.6-116.4,73.2c29.6,44.7,31.9,44.4,19.9,66.7
c-15.1,28.3-28.8,48.8-23,80.6};

% Concatenating the 4 paths so we can get the black part:
\pgfoonew \patha=new spath(\Middle)
\pgfoonew \pathb=new spath(\Right)
\patha.concatenate with lineto(,\pathb)
\patha.close()

% Drawing and filling the black part:
\patha.use path with tikz(line width=3pt,draw=black,fill=black)

% Repeating the path for the shaded part:
\foreach \x in {1,...,200} {
\pgfmathsetlength{\shift}{\x/2 pt}%
\pgfmathsetmacro{\opacity}{1-\x/100}%
\MyScope[xshift=-\shift, line width=0.5pt, draw opacity=\opacity]
};

% The eye of the bird:
\filldraw[left color=white, right color=white, draw=white] (11.9,15.1) circle [radius=7pt];

\end{tikzpicture}

\end{document}


which yields:

Observe that applying with a gradient shade in between two curves would, in general, require a path from each point of one curve to a point on the other, which can be quite cumbersome if one of them had self-intersections or a horizontal line would intersect a curve in two or more points.

In the case at hand, horizontal lines intersected the curves in one point only each, making the job a bit easier.

The proposed solution of using a "buffer" zone in only one color would allow one to deal with more complex cases till the curve could be made more straight and then slide it to the other.

### Non-Parallel Paths:

One way to shade the area between two non-parallel paths is to draw points on a horizontal path from one end to the other and vary the opacity of the two points:

As you increase the number of \NumberOfVerticalPositions and the \NumberOfHorizontalPoints points you achieve:

## Notes:

• I am not familar with coordinates in svg.path so this will need to be adapted to your specfic case.

### Parallel Paths:

Not sure if there is a built-in tikz way, but one approach would be to do it yourself: redraw the path with a slight shift and adjust the opacity. You could also tweak the line widths as well, but the MWE below only tweaks the opacity for each path:

## Note:

• This will probably need some modifications for complex paths.

## Code: Non-Parallel Paths

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,intersections}

%\def\DebugEnabled{}% Make sure that the \YMin and \YMax are adequate.

\newcommand*{\NumberOfVerticalPositions}{200}%
\newcommand*{\NumberOfHorizontalPoints}{100}%
\newcommand*{\CircleSize}{0.75pt}% The smaller this is, the larger number of points that are required

\newcommand*{\YMin}{-3.75}% \YMin and \YMax must be chosen such that there is an intersection
\newcommand*{\YMax}{3.75}%  of a horizontal line and the two curves.

\newcommand*{\XMin}{-3}% \XMin and \XMax should be overestimates on the min and max values of x
\newcommand*{\XMax}{11}%  for which the horizontal line and the two curves intersect.

\begin{document}
\begin{tikzpicture}
\begin{scope}[domain=-3:3]% Two non-parallel paths.
%% Drawing the right one helps to make it smoother
\draw [color=gray, name path global=right curve, line width=2*\CircleSize]
plot (\x*\x,1.25*\x);
\ifdefined\DebugEnabled
\draw
\else
\path
\fi
[color=gray, name path global=left curve,  xshift=-80]
plot (\x*\x,1.25*\x);
\end{scope}

\ifdefined\DebugEnabled
%% Make sure that we are covering the entire y range:
%% Use this to determine \YMin and \YMax
\draw [ultra thick, blue] (\XMin,\YMax) -- (\XMax,\YMax);
\draw [ultra thick, red]  (\XMin,\YMin) -- (\XMax,\YMin);
\else
\pgfmathsetmacro{\DelatY}{(\YMax-\YMin)/(\NumberOfVerticalPositions-10)}%
%\foreach \y in {\YMin, -2.75, ..., \YMax} {
\foreach \y in {1, ..., \NumberOfVerticalPositions} {
\pgfmathsetmacro{\YCoordinate}{\YMin+\DelatY*(\y-1)}%

%% Create a horizontal path so we can determine the left and right coordinates
\path [ultra thick, gray, name path=horizontal line]
(\XMin,\YCoordinate) -- (\XMax,\YCoordinate);

%% The left and right endpoints are the intersection of the "horizontal line"
%% and the two curves: "left curve" and "right curve"
\path [name intersections={of=horizontal line and left curve, by={left intersection}}]
(left intersection) circle (\CircleSize);
\path [name intersections={of=horizontal line and right curve, by={right intersection}}]
(right intersection) circle (\CircleSize);

\foreach \x  in {1, ..., \NumberOfHorizontalPoints} {
\pgfmathsetmacro{\PercentOffset}{\x/\NumberOfHorizontalPoints}%
\fill [black, opacity=\PercentOffset]
($(left intersection)!\PercentOffset!(right intersection)$)
circle (\CircleSize) ;
}
}
\fi
\end{tikzpicture}%
\end{document}


## Code: Parallel Paths

\documentclass{article}
\usepackage{tikz}

\newcommand{\MyPath}{%
(0.2,2) .. controls
(0.2,2)  and (0.7,3)  .. (2,4)
}%

\newcommand{\MyScope}[1][]{%
\begin{scope}[cap=round, #1]
\path[draw=black] \MyPath;
\end{scope}
}
\newlength{\shift}

\begin{document}
\begin{tikzpicture}
\foreach \x in {1,...,50} {
\pgfmathsetlength{\shift}{\x/2 pt}%
\pgfmathsetmacro{\opacity}{1-\x/25}%
\MyScope[yshift=-\shift, line width=0.5pt, draw opacity=\opacity]
}
\end{tikzpicture}%
\end{document}

• Is it true that in your solution the beginning and ending curves are always parallel to each other? – Knudsen Apr 6 '17 at 5:29
• @Knudsen: I am just applying a shift in the y-direction to the entire curve for each subsequent draw. – Peter Grill Apr 6 '17 at 6:19
• I have added the equations of the two functions - if that makes it any easier. – Knudsen Apr 10 '17 at 1:50

Essentially there is a way to obtain gradient between cubic curve. But this method is a very tough feature of PDF and sometimes the PDF reader just do not give a shxt.

\documentclass[tikz]{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat=1.14}
\usepgfplotslibrary{patchplots}
\usetikzlibrary{svg.path}

\begin{document}

\begin{tikzpicture}[yscale=-1]
\begin{axis}[]
\addplot[colormap/blackwhite,patch,patch type=coons,shader=interp,point meta=explicit]
table[meta=z]{
x       y       z
201.1   673.2   10
202.5   633.4   10
203.1   621     10
219.3   602.4   10
219.3   602.4   10
297.2   593.2   9
297.2   593.2   0
282.1   621.5   0
268.4   642     0
274.2   673.8   0
274.2   673.8   9
201.1   673.2   10
%
219.3   602.4   10
231     588.9   10
237.6   578.1   10
211.6   553     10
211.6   553     10
277.3   526.5   9
277.3   526.5   0
306.9   571.2   0
309.2   570.9   0
297.2   593.2   0
297.2   593.2   9
219.3   602.4   10
%
211.6   553     10
172.3   515     10
168.4   493.8   10
212.6   462.8   10
212.6   462.8   10
393.7   453.3   9
393.7   453.3   0
393.7   453.3   0
234.5   461.9   0
277.3   526.5   0
277.3   526.5   9
211.6   553     10
%
212.6   462.8   10
230.7   450.1   10
279.7   442.6   10
238     426.2   10
238     426.2   10
368.7   434.6   9
368.7   434.6   0
376.9   442.7   0
393.7   453.3   0
393.7   453.3   0
393.7   453.3   9
212.6   462.8   10
%
238     426.2   10
219.8   419     10
214.5   416.5   10
211.1   387     10
211.1   387     10
297.2   397.8   9
297.2   397.8   0
312.9   396.9   0
337.7   403.8   0
368.7   434.6   0
368.7   434.6   9
238     426.2   10
%
211.1   387     10
208.1   360.3   10
193.4   358.8   10
173.4   352     10
173.4   352     10
286.9   363.5   9
286.9   363.5   0
286.3   381.9   0
283     398.6   0
297.2   397.8   0
297.2   397.8   9
211.1   387     10
%
173.4   352     10
153.4   345.1   10
85.7    323.2   10
123.2   273.8   10
123.2   273.8   10
238     322.9   9
238     322.9   0
284.7   335.7   0
287.7   338.9   0
286.9   363.5   0
286.9   363.5   9
173.4   352     10
%
123.2   273.8   10
146.7   242.8   10
181.8   199.9   10
206.3   155.6   10
206.3   155.6   10
239.1   232.4   9
239.1   232.4   0
217.6   282.3   0
191.9   310.2   0
238     322.9   0
238     322.9   9
123.2   273.8   10
}
;
\end{axis}
\end{tikzpicture}