# Filling optical spectrum curve with color gradient

I have some difficulties creating a plot where the area between the curve and the x-axis is filled with a gradient. I want to plot an electromagnetic spectrum and I want the color gradient to represent the actual color at given wavelengths, like in the example below.

I managed to define the desired gradient and also filling the area with it works so far. The only problem is that the color gradient does not fit to the values on the wavelength axis.

This document represents my issue:

\documentclass{article}

\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}

color(0bp)=(black);
color(50bp)=(violet);
color(56.25bp)=(blue);
color(62.5bp)=(cyan);
color(68.75bp)=(green);
color(73.75bp)=(yellow);
color(77.5bp)=(orange);
color(81.25bp)=(red);
color(100bp)=(black)
}

\begin{document}

\begin{tikzpicture}
\begin{axis}[
title= Photon Flux,
xlabel={Wavelength [nm]},
ylabel={Photon Flux [a.u.]},
xmin=400,
xmax=800,
]
( 400, 0 )
( 500, 1 )
( 520, 3 )
( 525, 8 )
( 530, 25 )
( 535, 23 )
( 540, 28 )
( 545, 34 )
( 550, 20 )
( 555, 13 )
( 560, 8 )
( 580, 9 )
( 600, 18 )
( 620, 7 )
( 680, 1 )
( 800, 0 )
};
\path[name path=axis] (axis cs:0,0) -- (axis cs:1,0);
thick,
fill opacity=0.5,
domain={400:800}
]
fill between[
of=spectrum and axis,
%soft clip={domain=400:800}
];
\end{axis}
\end{tikzpicture}

\end{document}


The respective output:

The gradient appears to be stretched. I played with the width in the shading's color specifications, but without success. Actually, I don't understand, how the shading dimensions are handled. Are they relative or absolute?

I also changed the domains for tikzpicture, addplot and fill between, but that also didn't work.

Which options do I have to align the color gradient with my plot, so it looks like in the first picture?

With the release of pgf-spectra v2.1 this is a quite easy task.

% used PGFPlots v1.18.1
\documentclass[border=5pt]{standalone}
\usepackage{pgf-spectra}
\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}
\pgfplotsset{compat=1.18}
\begin{document}
\begin{tikzpicture}
% create a variable to store the xmax value, so we don't need to repeat ourselves
\pgfmathsetmacro{\xmax}{800}
% create the shade (using the created variable)
\begin{axis}[
title=Photon Flux,
xlabel={Wavelength in nm},
ylabel={Photon Flux in a.u.},
xmin=300,
% (use the variable here too)
xmax=\xmax,
]
\addplot [smooth, name path=spectrum] coordinates {
(380,0) (400,5) (500,1) (520,3) (525,8) (530,25)
(535,23) (540,28) (545,34) (550,20) (555,13)
(560,8) (580,9) (600,18) (620,7) (680,1) (780,0)
};
% (because there is no shade start key so far the path has to start at x=0)
\path [name path=axis] (axis cs:0,0)
-- (axis cs:\pgfkeysvalueof{/pgfplots/xmax},0);
fill between [of=spectrum and axis];
\end{axis}
\end{tikzpicture}
\end{document}


I found a solution myself, though it is not perfect.

The shading used for filling seems to be scaled to fit between the most left and most right points of the area to be filled. So instead of filling between my curve and \path[name path=axis] (axis cs:0,0) -- (axis cs:1,0); I defined a line \addplot[name path=axis] plot[] coordinates{ (400,0)(800,0) }; as path, where x=400 and x=800 is where I want the shading's borders to be.

The disadvantage of this approach is that this only works as long as the bottom layer (helper path/fake "axis") is longer than the actual curve. In this case either the shading needs to be extended or the plotted data needs to be clipped to the desired range (working with domain or xmin/xmax does not work).

My final document looked like this:

\documentclass{article}

\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}

color(0bp)=(violet);
color(6.25bp)=(blue);
color(12.5bp)=(cyan);
color(18.75bp)=(green);
color(23.75bp)=(yellow);
color(27.5bp)=(orange);
color(31.25bp)=(red);
color(50bp)=(black)
}

\begin{document}

\begin{tikzpicture}
\begin{axis}[
width=5cm,
title= Photon Flux,
xlabel={Wavelength [nm]},
ylabel={Photon Flux [a.u.]},
xmin=400,
xmax=800
]
( 400, 5 )
( 420, 4 )
( 500, 9 )
( 520, 13 )
( 525, 8 )
( 530, 25 )
( 535, 23 )
( 540, 28 )
( 545, 34 )
( 550, 20 )
( 555, 13 )
( 560, 8 )
( 580, 9 )
( 600, 18 )
( 620, 7 )
( 680, 5 )
};
(400,0)
(800,0)
};
thick,