8

How can I make a filled and how an unfilled circle in TikZ with multiple color transitions? I need about five distinct colors which shall be defined at specific angles and the blur area / transition area should be rather small. In other words, there should be larger areas of a single color and then a rather a small (angle) area in which the colors blur/transition into each other.

Filled circle would look something like this (but with smaller transition areas):

enter image description here

An unfilled circle would look like this (but with smaller transition areas): enter image description here

I am guessing that shade or shadedraw are my friends, but I am still kind of lost.

First try...

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

\begin{document}
\begin{tikzpicture}[scale=3]
\shade[shading=color wheel] [even odd rule] (0,0) circle (1.5) (0,0) circle (1);
\shade[shading=color wheel white center] (0,5) circle (1.5);
\end{tikzpicture}
\end{document}

but

  • I am not sure how to change the number of colours,
  • nor the transition area,
  • nor a way to set the angle for the colours.

Second try...

In How to create a color wheel shading with other colors? there is code that allows to change the colours and the number of colours. I guess I could make the transition area smaller by adding a colour multiple times, like

\documentclass[tikz,border=5]{standalone}
% \usetikzlibrary{shapes,arrows,chains,positioning,calc,trees,mindmap,backgrounds,shadows,decorations.text}
\usetikzlibrary{decorations.text}


\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{mywheel}{90}{red,red,red!80!green,red!20!green,green,green,green!80!blue,green!20!blue,blue,blue,blue!80!yellow,blue!20!yellow,yellow,yellow,yellow!80!red,yellow!20!red}
\pgfdeclarecolorwheelshading{rainbow}{-45}{red,yellow,pink,green,orange,purple,blue}

\begin{document}

\begin{tikzpicture}

\path [shading=mywheel]  (0,0) circle [radius=10];
\path[fill=white] (0,0) circle[radius=9];

\draw[-latex,
    postaction={decorate},
    decoration={
        text along path,
        text={|\LARGE|Data Science},
        text align=center,
        text color=black,
%       every character/.style={fill=white, yshift=-0.5ex},
        raise=-9mm
    },
    draw=none]
(180:10) arc [start angle=180,end angle=200,radius=10]; % Grad 190

\draw[-latex,
    postaction={decorate},
    decoration={
        text along path,
        text={|\LARGE|Mathematical Modelling},
        text align=center,
        text color=black,
%       every character/.style={fill=white, yshift=-0.5ex},
        raise=-9mm
    },
    draw=none]
(200:10) arc [start angle=200,end angle=260,radius=10]; % Grad 230

\draw[-latex,
    postaction={decorate},
    decoration={
        text along path,
        text={|\LARGE|Big Data},
        text align=center,
        text color=black,
        raise=3mm
    },
    draw=none]
(100:10) arc [start angle=100,end angle=80,radius=10]; % Grad 90

\draw[-latex,
    postaction={decorate},
    decoration={
        text along path,
        text={|\LARGE|Industry 4.0},
        text align=center,
        text color=black,
%       every character/.style={fill=white, yshift=-0.5ex},
        raise=-9mm
    },
    draw=none]
(320:10) arc [start angle=320,end angle=340,radius=10]; % Grad 330

\path (0,15) (0,-15) (15,0) (-15,0);

\end{tikzpicture}

\end{document}

with

enter image description here

But how can the code be altered so that I can set the angles for the colours?

In this case namely at 90, 190, 230, and 330 degree.

  • By blur area, do you mean the transition from one color to the other? – Alenanno Jan 4 '16 at 21:08
  • @Alenanno: Yes. – Make42 Jan 4 '16 at 21:08
  • 1
    Somebody (can't remember the user name exactly) just deleted his answer post... that is a pity. If you are reading this: Please put it back, even though it might not be exactly what I was looking for. – Make42 Jan 4 '16 at 23:50
  • I've rolled the answer back to the original and voted to undelete it because I'm not sure how else to get Zarko's attention. I'm hoping that s/he will not object too much. (I don't know what happens if I do this but usually I get a ping if somebody edits one of my posts, so I'm hoping that Zarko will do so and will then think to read these comments for explanation. And not be too annoyed with me.) – cfr Jan 5 '16 at 0:06
  • 1
    @cfr I don't think s/he'll be annoyed :D I think s/he deleted his answer because the version that appears in the question is more advanced. Or at least, that'd be my reasoning since it's advanced for me as well. But I hope s/he sees the comments, so s/he can post his rationale, if s/he wants. – Alenanno Jan 5 '16 at 1:23
3

This solution is not perfect but others might be able to improve it.

I made a command \ColourTransitionCircle that takes a comma separated list of colours as an argument. It also has 3 optional key=value arguments inner, outer and angle. They define the inner radius, the outer radius and the start angle of the first colour.

\begin{document}
    \begin{tikzpicture}
        \ColourTransitionCircle{red,yellow,blue,green}
    \end{tikzpicture}

    \begin{tikzpicture}
        \ColourTransitionCircle[angle=75]{red,yellow,blue,green}
    \end{tikzpicture}

    \begin{tikzpicture}
        \ColourTransitionCircle[inner=2,outer=2.3,angle=20]{red,yellow,blue,blue,green}
    \end{tikzpicture}

    \begin{tikzpicture}[xshift=2cm]
        \ColourTransitionCircle[inner=2,outer=2.3,angle=20]{red,yellow,blue,blue,green}
        \draw (0,0) --++ (20:2.5) node[right] {$20^\circ$};
        \draw (0,0) --++  (100:2.3)node[midway,right] {outer};
        \draw (0,0) --++  (120:2)node[midway,left] {inner};
    \end{tikzpicture}
\end{document}

enter image description here

As I said before this is not perfect. Some circles look quite good but other combinations of angle, radius and number of colours result in visible straight lines (see middle circle)

By adding a colour multiple times (blue in the third circle), coloured areas can be made bigger/smaller which in turn decreases/increases the transition area.

All code:

\documentclass[border=2mm]{standalone}
\usepackage{xparse}
\usepackage{tikz}

\ExplSyntaxOn

\keys_define:nn { colour_transition_circle } {
    inner   .fp_set:N   = \l__inner_radius,
    inner   .initial:n  = {2},
    outer   .fp_set:N   = \l__outer_radius,
    outer   .initial:n  = {3},
    angle   .fp_set:N   = \l__start_angle,
    angle   .initial:n  = {0}
}

\NewDocumentCommand \ColourTransitionCircle { O{} m } {
\group_begin:
    \keys_set:nn { colour_transition_circle } {#1}
    \clist_clear:N \l_tmpa_clist
    \clist_map_inline:nn {#2} {
        \clist_put_right:Nn \l_tmpa_clist {##1}
        %\clist_put_right:Nn \l_tmpa_clist {##1}
    }
    \exp_args:Nx \col_trans_circ:n \l_tmpa_clist
\group_end:
}

\cs_new_protected:Npn \col_trans_circ:n #1 {
    \int_step_inline:nnnn {1} {1} {\clist_count:n {#1} - 1} {
        \path[top~color=\clist_item:nn {#1} {##1}, bottom~color=\clist_item:nn {#1} {##1+1}, shading~angle={270-(180-360/\clist_count:n {#1})/2+(##1-1)*360/\clist_count:n {#1}+\fp_use:N \l__start_angle}] ({\fp_use:N \l__inner_radius*cos((##1-1)*360/\clist_count:n {#1}+\fp_use:N \l__start_angle)},{\fp_use:N \l__inner_radius*sin((##1-1)*360/\clist_count:n {#1}+\fp_use:N \l__start_angle)}) arc[radius = \fp_use:N \l__inner_radius, start~angle={(##1-1)*360/\clist_count:n {#1}+\fp_use:N \l__start_angle}, delta~angle=360/\clist_count:n {#1}] -- ({\fp_use:N \l__outer_radius*cos(##1*360/\clist_count:n {#1}+\fp_use:N \l__start_angle)},{\fp_use:N \l__outer_radius*sin(##1*360/\clist_count:n {#1}+\fp_use:N \l__start_angle)}) arc[radius = \fp_use:N \l__outer_radius, start~angle={##1*360/\clist_count:n {#1}+\fp_use:N \l__start_angle}, delta~angle=-360/\clist_count:n {#1}] -- cycle;
    }
    \path[top~color=\clist_item:nn {#1} {\clist_count:n {#1}}, bottom~color=\clist_item:nn {#1} {1}, shading~angle={180-180/\clist_count:n {#1}+\fp_use:N \l__start_angle}]({\fp_use:N \l__inner_radius*cos((\clist_count:n {#1}-1)*360/\clist_count:n {#1}+\fp_use:N \l__start_angle)},{\fp_use:N \l__inner_radius*sin((\clist_count:n {#1}-1)*360/\clist_count:n {#1}+\fp_use:N \l__start_angle)}) arc[radius = \fp_use:N \l__inner_radius, start~angle={(\clist_count:n {#1}-1)*360/\clist_count:n {#1}+\fp_use:N \l__start_angle}, delta~angle=360/\clist_count:n {#1}] -- ({\fp_use:N \l__outer_radius*cos(\clist_count:n {#1}*360/\clist_count:n {#1}+\fp_use:N \l__start_angle)},{\fp_use:N \l__outer_radius*sin(\clist_count:n {#1}*360/\clist_count:n {#1}+\fp_use:N \l__start_angle)}) arc[radius = \fp_use:N \l__outer_radius, start~angle={\clist_count:n {#1}*360/\clist_count:n {#1}+\fp_use:N \l__start_angle}, delta~angle=-360/\clist_count:n {#1}] -- cycle;
}

\ExplSyntaxOff

\begin{document}
    \begin{tikzpicture}
        \ColourTransitionCircle{red,yellow,blue,green}
    \end{tikzpicture}

    \begin{tikzpicture}
        \ColourTransitionCircle[angle=75]{red,yellow,blue,green}
    \end{tikzpicture}

    \begin{tikzpicture}
        \ColourTransitionCircle[inner=2,outer=2.3,angle=20]{red,yellow,blue,blue,green}
        \draw (0,0) --++ (20:2.5) node[right] {$20^\circ$};
        \draw (0,0) --++  (100:2.3)node[midway,right] {outer};
        \draw (0,0) --++  (120:2)node[midway,left] {inner};
    \end{tikzpicture}
\end{document}

I used one of my previous answers https://tex.stackexchange.com/a/247900/46716 as a start as this question quite resembles it.

  • The result seems to be similar to my second try. However the transition seems to be a little weird - being in a triangle... I am not able to understand your code, so I don't know what you did. Also, it seems it also does not support setting the angles for the colours, does it? (Where is the advantage to what I posted?) – Make42 Jan 5 '16 at 9:30
  • You can not set the angles directly this is true. (I did mention is was not perfect). You can however give a start angle. The colours will then be used to fill a circle counter clock wise starting at that angle. So if you start at angle 20° and have 6 colours (360°/6 = 60), then the angles will we 20°, 80°, 140°, ... So by choosing the start angle and the number of colours carefully you should be able to have any angle you want. Only dissadvantage: if you need a lot of colours (to achieve the right angles) the transition area might be smaller than you'd like. – Maarten Dhondt Jan 5 '16 at 9:35
  • I undstand what you mean and this is how I am trying to do it currently. However, the fiddling is rather tedious and the result is not quite perfect. It would be great if the code could be improved on that - e.g. the code I posted. However, since I do not understand the code, there is not much I can do. (My code comes from a different post after all.) – Make42 Jan 5 '16 at 9:48

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.