11

In the pgf manual one can get a circle with a jet-colormap color-wheel-shading with:

\tikz \shade[shading=color wheel] (0,0) circle (1.5);

How can I get the same but with another colormap? This 'other' colormap probably needs to be cyclic (the first color needs to be equal to the last color) for it to work in a color wheel. But other solutions would be also appreciated. Thanks!

16

Not sure this is strictly answering the question, but shows the principles for 2, 3, 4 and 5 color wheels. It is a bit fiddly to extend to an arbitrary number of colors in this way so some (rather tortuous) LaTeX macro magic can be used to generate a PGF shading from a list of colors.

The definition of \pgfdeclarecolorwheelshading is shown below, but first the individual shadings:

\documentclass[tikz,border=5]{standalone}
\begin{document}

\colorlet{col1}{red}
\colorlet{col2}{green}
\colorlet{col3}{blue}
\colorlet{col4}{yellow}
\colorlet{col5}{cyan}

\pgfdeclarefunctionalshading[col1,col2]{2-color-wheel}
{\pgfpoint{-50bp}{-50bp}}{\pgfpoint{50bp}{50bp}}
{
\pgfshadecolortorgb{col1}{\first}\pgfshadecolortorgb{col2}{\second}
}{
  2 copy 
  abs exch abs add 0.0001 ge 
  { atan }                   
  { pop } 
  ifelse
  360 2 div div dup floor dup 3 1 roll neg add dup neg 1 add exch
  2 copy 2 copy 7 -1 roll 
  0 eq
  { 
    \firstred mul exch \secondred mul add
    5 1 roll
    \firstgreen mul exch \secondgreen mul add
    3 1 roll
    \firstblue mul exch \secondblue mul add
  }
  { 
    \secondred mul exch \firstred mul add
    5 1 roll
    \secondgreen mul exch \firstgreen mul add
    3 1 roll
    \secondblue mul exch \firstblue mul add
  }
  ifelse
}


\pgfdeclarefunctionalshading[col1,col2,col3]{3-color-wheel}
{\pgfpoint{-50bp}{-50bp}}{\pgfpoint{50bp}{50bp}}
{
\pgfshadecolortorgb{col1}{\first}\pgfshadecolortorgb{col2}{\second}
\pgfshadecolortorgb{col3}{\third}
}{
  2 copy 
  abs exch abs add 0.0001 ge 
  { atan }                   
  { pop } 
  ifelse
  360 3 div div dup floor dup 3 1 roll neg add dup neg 1 add exch
  2 copy 2 copy 7 -1 roll 
  dup 
  0 eq
  { 
    pop
    \firstred mul exch \thirdred mul add
    5 1 roll
    \firstgreen mul exch \thirdgreen mul add
    3 1 roll
    \firstblue mul exch \thirdblue mul add
  } 
  {
    1 eq
    {
      \secondred mul exch \firstred mul add
      5 1 roll
      \secondgreen mul exch \firstgreen mul add
      3 1 roll
      \secondblue mul exch \firstblue mul add
    }
    {
      \thirdred mul exch \secondred mul add
      5 1 roll
      \thirdgreen mul exch \secondgreen mul add
      3 1 roll
      \thirdblue mul exch \secondblue mul add
    }
    ifelse
  }
  ifelse
}




\pgfdeclarefunctionalshading[col1,col2,col3,col4]{4-color-wheel}
{\pgfpoint{-50bp}{-50bp}}{\pgfpoint{50bp}{50bp}}
{
\pgfshadecolortorgb{col1}{\first}\pgfshadecolortorgb{col2}{\second}
\pgfshadecolortorgb{col3}{\third}\pgfshadecolortorgb{col4}{\fourth}
}{
  2 copy 
  abs exch abs add 0.0001 ge 
  { atan }                   
  { pop } 
  ifelse
  360 4 div div dup floor dup 3 1 roll neg add dup neg 1 add exch
  2 copy 2 copy 7 -1 roll
  dup 
  dup 
  0 eq
  {
    pop pop
    \firstred mul exch \fourthred mul add
      5 1 roll
      \firstgreen mul exch \fourthgreen mul add
      3 1 roll
      \firstblue mul exch \fourthblue mul add
  }
  {
    1 eq
    {
      pop
      \secondred mul exch \firstred mul add
      5 1 roll
      \secondgreen mul exch \firstgreen mul add
      3 1 roll
      \secondblue mul exch \firstblue mul add
    }
    {
      2 eq
      {
        \thirdred mul exch \secondred mul add
      5 1 roll
      \thirdgreen mul exch \secondgreen mul add
      3 1 roll
      \thirdblue mul exch \secondblue mul add
      }
      {
       \fourthred mul exch \thirdred mul add
      5 1 roll
      \fourthgreen mul exch \thirdgreen mul add
      3 1 roll
      \fourthblue mul exch \thirdblue mul add
      } ifelse
    } 
    ifelse
  } 
  ifelse
}



\pgfdeclarefunctionalshading[col1,col2,col3,col4,col5]{5-color-wheel}
{\pgfpoint{-50bp}{-50bp}}{\pgfpoint{50bp}{50bp}}
{
\pgfshadecolortorgb{col1}{\first}\pgfshadecolortorgb{col2}{\second}
\pgfshadecolortorgb{col3}{\third}\pgfshadecolortorgb{col4}{\fourth}
\pgfshadecolortorgb{col5}{\fifth}
}{
  2 copy 
  abs exch abs add 0.0001 ge 
  { atan }                   
  { pop } 
  ifelse
  360 5 div div dup floor dup 3 1 roll neg add dup neg 1 add exch
  2 copy 2 copy 7 -1 roll
  dup 
  dup 
  dup
  0 eq 
  {
    pop pop pop
    \firstred mul exch \fifthred mul add
    5 1 roll
    \firstgreen mul exch \fifthgreen mul add
    3 1 roll
    \firstblue mul exch \fifthblue mul add
  }
  {
    1 eq 
    {
      pop pop
      \secondred mul exch \firstred mul add
      5 1 roll
      \secondgreen mul exch \firstgreen mul add
      3 1 roll
      \secondblue mul exch \firstblue mul add
    }
    {
      2 eq 
      {
        pop
        \thirdred mul exch \secondred mul add
        5 1 roll
        \thirdgreen mul exch \secondgreen mul add
        3 1 roll
        \thirdblue mul exch \secondblue mul add
      }
      {
        3 eq 
        {
          \fourthred mul exch \thirdred mul add
          5 1 roll
          \fourthgreen mul exch \thirdgreen mul add
          3 1 roll
          \fourthblue mul exch \thirdblue mul add
        }
        {
          \fifthred mul exch \fourthred mul add
          5 1 roll
          \fifthgreen mul exch \fourthgreen mul add
          3 1 roll
          \fifthblue mul exch \fourthblue mul add
        }
        ifelse
      }
      ifelse
    }
    ifelse
  }
  ifelse
}




\begin{tikzpicture}[even odd rule]
 \path [shading=2-color-wheel] 
   ( 45:1.5) circle [radius=1] circle [radius=0.5];
 \path [shading=3-color-wheel] 
   (135:1.5) circle [radius=1] circle [radius=0.5];
 \path [shading=4-color-wheel] 
   (225:1.5) circle [radius=1] circle [radius=0.5];
 \path [shading=5-color-wheel] 
   (315:1.5) circle [radius=1] circle [radius=0.5];
\end{tikzpicture}
\end{document}

enter image description here

And secondly, a \pgfdeclarecolorwheelshading macro. This macro takes three arguments: the name for shading, the rotation of the shading (the first color in the color list is at angle 0), and the color list. I think it works OK.

\documentclass[tikz,border=5]{standalone}

\makeatletter
\newtoks\pgf@ps@toks
\newcount\c@pgf@ps

\def\pgf@ps@sp{ }

\def\pgf@ps@esettoks#1{\edef\pgf@ps@tmp{#1}\pgf@ps@toks\expandafter{\pgf@ps@tmp}}

\def\pgf@ps@repop#1#2{%
  \c@pgf@countb=#2\relax%
  \def\pgf@ps@op{#1}%
  \def\pgf@ps@ops{}\pgf@ps@@repop}
\def\pgf@ps@@repop{%
  \ifnum\c@pgf@countb<1\relax%
  \else%
    \edef\pgf@ps@ops{\pgf@ps@op\pgf@ps@ops}%
    \advance\c@pgf@countb by-1\relax%
    \expandafter\pgf@ps@@repop%
  \fi%
}

\def\pgf@ps@generate@ps{%
  \c@pgf@counta=\pgf@ps@ncol\relax%
  \c@pgf@countb=\c@pgf@counta%
  \advance\c@pgf@countb by-1\relax%
  \pgf@ps@esettoks{ \noexpand\pgf@ps@interp{col@\the\c@pgf@counta}{col@\the\c@pgf@countb} }%
  \pgfmathloop
  \ifnum\c@pgf@counta<2\relax%
  \else%
    \c@pgf@countb=-\c@pgf@counta%
    \advance\c@pgf@countb by\pgf@ps@ncol\relax%
    \advance\c@pgf@counta by-1\relax%
    \pgf@ps@repop{pop\pgf@ps@sp}{\c@pgf@countb}%
    \c@pgf@countb=\c@pgf@counta%
    \advance\c@pgf@countb by-1\relax%
    \ifnum\c@pgf@countb=0\relax%
      \c@pgf@countb=\pgf@ps@ncol\relax%
    \fi%
    \pgf@ps@esettoks{ \the\c@pgf@counta\pgf@ps@sp eq { \pgf@ps@ops \noexpand\pgf@ps@interp{col@\the\c@pgf@counta}{col@\the\c@pgf@countb} }{ \the\pgf@ps@toks } ifelse}%
  \repeatpgfmathloop%
  \c@pgf@counta=\pgf@ps@ncol\relax%
  \advance\c@pgf@counta by-2\relax%
  \pgf@ps@repop{dup\pgf@ps@sp}{\c@pgf@counta}%
  \pgf@ps@esettoks{ \pgf@ps@ops \the\pgf@ps@toks }%
}

\def\pgf@ps@colorstorgb#1{%
  \c@pgf@ps=1\relax%
  \pgfutil@for\pgf@ps@:={#1}\do{%
     \pgf@ps@coltorgb{\pgf@ps@}{col@\the\c@pgf@ps}%
     \advance\c@pgf@ps by1\relax}%
}

\def\pgf@ps@coltorgb#1#2{%
 \edef\pgf@ps@marshal{\noexpand\pgfshadecolortorgb{#1}}%
 \expandafter\pgf@ps@marshal\expandafter{\csname#2\endcsname}%
}

\def\pgf@ps@rgb#1{\csname#1\endcsname}
\def\pgf@ps@interp#1#2{%
  \pgf@ps@rgb{#1red} mul exch \pgf@ps@rgb{#2red} mul add
    5 1 roll
  \pgf@ps@rgb{#1green} mul exch \pgf@ps@rgb{#2green} mul add
    3 1 roll
  \pgf@ps@rgb{#1blue} mul exch \pgf@ps@rgb{#2blue} mul add
}




\def\pgfdeclarecolorwheelshading#1#2#3{%
  \pgf@ps@getcols{#3}%
  \pgfmathparse{mod(#2+360/\pgf@ps@ncol-90,360)}%
  \pgf@x=\pgfmathresult pt\relax%
  \ifdim\pgf@x<0pt\relax%
    \advance\pgf@x by360pt\relax%
  \fi%
  \edef\pgf@ps@rot{\pgfmath@tonumber{\pgf@x}}%
  \pgf@ps@generate@ps%
  \pgf@ps@esettoks{%
    \noexpand\pgfdeclarefunctionalshading[#3]{#1}%
    {\noexpand\pgfpoint{-50bp}{-50bp}}{\noexpand\pgfpoint{50bp}{50bp}}%
    {\noexpand\pgf@ps@colorstorgb{#3}}%
    {%
      2 copy abs exch abs add 0.0001 ge { atan } { pop } ifelse
      \pgf@ps@rot\pgf@ps@sp add dup 360 ge { -360 add } { } ifelse
      360 \pgf@ps@ncol\pgf@ps@sp 
      div div dup floor dup 3 1 roll neg add dup neg 1 add exch
      2 copy 2 copy 7 -1 roll 1 add
      \the\pgf@ps@toks}}%
  \edef\pgf@ps@marshal{\the\pgf@ps@toks}%
  \pgf@ps@marshal}

\def\pgf@ps@getcols#1{%
  \c@pgf@ps=0\relax%
  \pgfutil@for\pgf@ps@:={#1}\do{\advance\c@pgf@ps by1}%
  \edef\pgf@ps@ncol{\the\c@pgf@ps}%
}

\pgfdeclarecolorwheelshading{rgb}{0}{red,green,blue}
\pgfdeclarecolorwheelshading{rgb-90}{90}{red,green,blue}
\pgfdeclarecolorwheelshading{rainbow}{-45}{red,yellow,pink,green,orange,purple,blue}
\begin{document}

\begin{tikzpicture}

\path [shading=rgb]     (30:1.5)  circle [radius=1];
\path [shading=rgb-90]  (150:1.5) circle [radius=1];
\path [shading=rainbow] (270:1.5) circle [radius=1];

\end{tikzpicture}

\end{document}

enter image description here

  • when I compile your examples with pdflatex(TeX 3.1415926 (TeX Live 2013/Debian)), the output is not like yours. The disks have an array that cuts the shape in small squares. I guess of equal colors, looks like rasterized except the circles are ok. – Vser Jan 30 '15 at 10:15
  • @Vser the "small squares" effect is to do with the rendering of the image in the PDF viewer (or actually the library that it uses). This is usually found when viewing with evince but not okular or acrobat (as I recall). I think I took screen-shots from gv for these images. – Mark Wibrow Jan 31 '15 at 20:25
  • You're right, gv renders it perfectly. MuPdf based viewer also. – Vser Feb 3 '15 at 12:07
  • @Mark Wibrow: Can you modify the code such, that one is able to set the angles for each colour individually? My related question is tex.stackexchange.com/questions/285996/… – Make42 Jan 5 '16 at 9:58
6

Look at section 110.2.3 "General (Functional) Shadings", p. 1087, pgfmanual.

Here is an example (original color wheel with small modification):

enter image description here

\documentclass[tikz]{standalone}

\pgfdeclarefunctionalshading{my color wheel}
{\pgfpoint{-50bp}{-50bp}}
{\pgfpoint{50bp}{50bp}}
{}
{ % x y
  2 copy abs exch abs add 0.0001 ge 
  {atan 360.0 div} % ... x y heading;  heading being in
                   %the interval [0, 1.0]
  { pop } % silently deal with error: return
                  % arbitrary heading of zero for origin
  ifelse  % because we will use it for 'Hue'
  1 copy .5 gt {0.5 sub 0.5 exch sub} {} ifelse
  1 1.0 % ... H S V 
  % C version to use as model:
  % H' = H * 6
  % i = floor(H')
  % f = H' - i
  % P = V * (1.0 - S)
  % Q = V * (1.0 - (S*f))
  % T = V * (1.0 - (S * (1.0 - f)))
  3 2 roll 6.0 mul dup 4 1 roll % H' S V H'
  floor cvr  % H' S V i
  dup 5 1 roll % i H' S V i
  3 index sub neg % i H' S V f
  1.0 3 index sub % i H' S V f (1.0 - S )
  2 index mul % i H' S V f P
  6 1 roll % P i H' S V f
  dup 3 index mul neg 1.0 add % P i H' S V f ( 1.0 - (f*S))
  2 index mul % P i H' S V f Q
  7 1 roll % Q P i H' S V f
  neg 1.0 add % Q P i H' S V (1.0 - f)
  2 index mul neg 1.0  add % Q P i H' S V (1.0 - S * (1.0 - f))
  1 index mul % Q P i H' S V T
  7 2 roll % V T Q P i H' S
  pop pop % V T Q P i
  %%% 
  % end of BLOCK B. The rest is just stack manipulation
  dup 0.5 le % TEST II [ i == 0 ]
  { % BLOCK C [ take stack to V T P ]
    pop exch pop
  }
  { dup 1.5 le % TEST III [ i == 1 ]
    { % BLOCK D [ take stack to Q V P ]
      pop exch 4 1 roll exch pop
    }
    { dup 2.5 le % TEST IV [ i == 2 ]
      { % BLOCK E [ take stack to P V T ]
        pop 4 1 roll pop
      }
      { dup 3.5 le % TEST V [ i == 3 ]
        { % BLOCK F [ take stack to P Q V ]
          pop exch 4 2 roll pop
        }
        { dup 4.5 le % TEST VI [ i == 4 ]
          { % BLOCK G [ take stack to T P V ]
            pop exch pop 3 -1 roll
          }
          { % BLOCK H [ take stack to V P Q ]
            pop 3 1 roll exch pop
          }
          ifelse
        }
        ifelse % for V
      }
      ifelse % for IV
    }
    ifelse % for III
  }
  ifelse % for II
}

\begin{document}
\begin{tikzpicture}
  \shade[shading=my color wheel] (0,0) circle (2);
\end{tikzpicture}
\end{document}
  • Wah. Think I'll give up on that one. Thanks though! – 12.yakir Jun 21 '14 at 12:40
  • This solution is well rendered by all PDF readers, but... How can one customize the wheel colors ? – SDrolet Mar 6 '15 at 2:27
  • @SDrolet You may change the PDF part of my code to match your requirements... Or use Marc's answer, above. – Paul Gaborit Mar 6 '15 at 7:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.