15

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.

Thank you in advance!

3
  • 1
    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.
    – percusse
    Commented Feb 26, 2015 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?
    – Jared
    Commented Feb 26, 2015 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.
    – Thruston
    Commented Feb 26, 2015 at 9:06

5 Answers 5

21

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

enter image description here

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}
45

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}

a spectrum of coloured letters

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.

9
  • 5
    Holy moly! That was simple and elegant. Commented Feb 26, 2015 at 14:01
  • 1
    What do the wave values represent in the model?
    – Werner
    Commented Feb 26, 2015 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?
    – Jared
    Commented Feb 26, 2015 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.
    – Jared
    Commented Feb 26, 2015 at 18:20
  • 1
    @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}.
    – sgmoye
    Commented Feb 28, 2015 at 20:25
20

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}

Better sample

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}

Sample colors

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

enter image description here

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

11

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

enter image description here

\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}
3

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}

Rainbow

You must log in to answer this question.

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