# Creating a rainbow color macro

I'm trying to draw a picture in tikz whose code is generated by another computer program. The program outputs hundreds of numbers in between 0 and 100, and I'd like to color objects in the picture on a spectrum according to the numbers.

For instance, suppose the spectrum I choose is red-orange-yellow-green-blue-violet. Then I would want to define a macro that has one input (a number between 0 and 100) and gives a color according to the following rules:

0=red

20=orange

40=yellow

60=green

80=blue

100=violet

Any number in between would be an appropriate mix. For example, 5 would be mostly red with a little bit of orange. 55 would be mostly green with a little bit of yellow.

• What are you coloring? Are you plotting or using shadings of random objects? How do you get the data? This still in do-it-for-me I'm afraid. Feb 26 '15 at 6:35
• @percusse: I'm coloring nodes and paths between nodes. Suppose the computer gives me the number x. Then I can use something like blue!x!white to get a spectrum from blue to white depending on the color. However, there isn't enough variation in the picture if every color is just a mixture of white and blue. I'd like to be able to access a larger spectrum of color with just one number. Does that help? Feb 26 '15 at 6:44
• This is more a question about xcolor. Look at its support for the HSB colour model. What you describe is essentially how the "hue" parameter works. Feb 26 '15 at 9:06

Nested use of \ifnum to define a color via \colorlet does the job:

## Code:

\documentclass{article}
\usepackage{xcolor}
\usepackage{pgffor}

\colorlet{MyColor}{black}%
\newcommand{\MixValue}{0}
\newcommand*{\SetColor}[1]{%
\ifnum#1<21
\pgfmathtruncatemacro{\MixValue}{100*#1/20}%
\colorlet{MyColor}{orange!\MixValue!red}%
\else
\ifnum#1<41
\pgfmathtruncatemacro{\MixValue}{100*(#1-20)/20}%
\colorlet{MyColor}{yellow!\MixValue!orange}%
\else
\ifnum#1<61
\pgfmathtruncatemacro{\MixValue}{100*(#1-40)/20}%
\colorlet{MyColor}{green!\MixValue!yellow}%
\else
\ifnum#1<81
\pgfmathtruncatemacro{\MixValue}{100*(#1-60)/20}%
\colorlet{MyColor}{blue!\MixValue!green}%
\else
\ifnum#1<101
\pgfmathtruncatemacro{\MixValue}{100*(#1-80)/20}%
\colorlet{MyColor}{violet!\MixValue!blue}%
\else
\fi%
\fi%
\fi%
\fi%
\fi%
}%

\newcommand*{\ShowInAppropriateColor}[1]{%
\SetColor{#1}%
\textcolor{MyColor}{#1}%
}%

\begin{document}
\noindent
\foreach \x in {0,...,100} {%
\ShowInAppropriateColor{\x}
}%
\end{document}


You can do this more simply using the wave colour model:

\documentclass{article}
\usepackage{xcolor}
\usepackage{pgffor}
\begin{document}
\noindent
\foreach \x in {300,320,...,900} {\textcolor[wave]{\x}{\x}\ }
\end{document}


According to the xcolor manual, the argument, λ, is supposed to be a visible-light wavelength, given in nanometers (nm), so that λ ∈ [380, 780]. As my example shows, "invisible" wavelengths are shown as black.

• Holy moly! That was simple and elegant. Feb 26 '15 at 14:01
• What do the wave values represent in the model? Feb 26 '15 at 15:44
• @Thruston: Thank you. This is wonderful and just what I'm looking for. However, I can't seem to implement the wave model to color a node of a tikz picture. I've tried \node[fill=\color[wave]{500}] at (0,0){}; along with about 10 other options along these lines. I've also tried defining a new color with \xdefinecolor{new}{wave}{500} and then filling with "new" but this too doesn't work (and many of its variations). How can I implement the wave color model to color a node of a tikz picture? Feb 26 '15 at 18:12
• By the way, I'm able to use rgb and cmyk to color nodes either by defining a new color or using something like fill={rgb:red,.1;green,.8;blue,0} in the options for coloring the node. But for some reason the wave color model won't work in tikz like rgb or cmyk. Feb 26 '15 at 18:20
• @Jared: For use with article.cls, see my answer below. Also about the TikZ error that it cannot use hsb. Again, defining a color with thewave color space, could be done with something like \definecolor{mycolor}{rgb:wave}{480}. Feb 28 '15 at 20:25

Here is an approach that, for a couple of reasons, is interesting.

\documentclass{article}

\usepackage{xcolor}
\usepackage{tikz}

\newcommand{\makemycolor}[2]{%
\pgfmathsetmacro{\hue}{(#1/100)^1.715*0.8}%
\definecolor{myhsbcolor}{hsb}{\hue,1,1}%
\textcolor{myhsbcolor}{#2}%
}

\begin{document}

\noindent\begin{tikzpicture}
\foreach \k in {0,1,...,100}{%
\pgfmathsetmacro{\hue}{(\k/100)^1.715*0.79}
\definecolor{mycolor}{rgb:hsb}{\hue,1,1}
\node[color=mycolor] () at (\k/10,0) {$\bullet$};
}%
\foreach \f in {0,1,...,10}{%
\pgfmathtruncatemacro{\num}{\f*10}
\node () at (\f,-.5) {\num};
}
\foreach \g/\h in {0/Red,2/Orange,4/Yellow,6/Green,8/Blue,10/Purple}{%
\pgfmathtruncatemacro{\num}{\g*10}
\node at (\g,-1) {\makemycolor{\num}{\h}};
}%
\end{tikzpicture}

\end{document}


First, this uses the hsb (hue-saturation-brightness) model, as Thruston suggests.

Second: Normally, TikZ cannot use the hsb model. That problem is solved by specifying \usepackage[rgb]{xcolor} which causes xcolor.sty to convert all colors from whatever color space to the rgb color space which TikZ can use. You could also say \usepackage[cmyk]{xcolor} if you were having this printed -- TikZ also understands cmyk. Also note that you could say \usepackage{xcolor} but define the color with \definecolor{mycolor}{rgb:hsb}{\hue,1,1} or \definecolor{mycolor}{cmyk:hsb}{\hue,1,1} -- again this converts hsb to rgb or cmyk, but on an individual basis.

Note that xcolor.sty must be loaded BEFORE tikz.sty.

Third, the function that actually sets up what the hue is

\pgfmathsetmacro{\hue}{(\k/100)^1.715*0.8}


can be varied at will to get a better spread of colors. The 0.8 determines the ending color, so you can adjust it a little up or down to fine-tune the shade of purple at the end of the spectrum.

So, for a macro that could be called for a specific color, you could try something like this:

\documentclass{article}

\usepackage{xcolor}
\usepackage{tikz}

\newcommand{\makemycolor}[2]{%
\pgfmathsetmacro{\hue}{(#1/100)^1.715*0.79}%
\definecolor{myhsbcolor}{hsb}{\hue,1,1}%
\textcolor{myhsbcolor}{#2}%
}

\begin{document}

\makemycolor{0}{Red}
\makemycolor{40}{Yellow}
\makemycolor{55}{Green with a touch of yellow}
\makemycolor{100}{Purple}

\end{document}


As an aside, you can also specify \usepackage[gray]{xcolor} in the preamble to get this:

Not sure of the practical use of this, but interesting nonetheless.

Here is a simple solution to make a HSB shading with xcolor:

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}[x=1mm,y=1mm]
\colorlet{color min hsb}[hsb]{red}
\colorlet{color max hsb}[hsb]{magenta}
\foreach \pos in {0,...,100}{
\colorlet{my color hsb}[rgb]{color max hsb!\pos!color min hsb}
\fill[fill=my color hsb,draw=white] (\pos,1) rectangle +(1mm,5mm);
}
\end{tikzpicture}
\end{document}


Mixing Paul Gaborit's answer with xcolor wave model and color conversions:

\documentclass[tikz, margin=2mm]{standalone}
\begin{document}
\begin{tikzpicture}[x=1mm,y=1mm]
\foreach \wav in {380, 384,...,780}{
\definecolor{tmpcolor}{wave}{\wav}
\colorlet{mycolor}[rgb]{tmpcolor}
\fill[fill=mycolor,draw=white] (\wav,1) rectangle +(4mm,15mm);
}
\end{tikzpicture}
\end{document}