9

I want to produce an open ring with a color gradient that goes from white (or faint red) to red and then back to white (or faint red) in the angular/tangential direction.

In the image attached below, the gradient is linear and not to my liking. What I want is a gradient that goes (anti clock wise): white at two o'clock -- red at 9 o'clock -- back to white at 4 o'clock.

enter image description here .

Ideally, I would like a flexible approach where the start and stop angle can be set arbitrarily.

I have spent many hours reading the pgf/tikz-manual and also this forum. I have not been able to find a solution. Any ideas?

Code example:

\documentclass[tikz,]{standalone}
\usepackage{tikz}
\begin{document}
\begin{centering}
\begin{tikzpicture}[scale=1]

\def\aStartA{30}
\def\aStopA{330}

\filldraw[gray!50,left color=white!25, right color=white!25, middle color=red!25] (\aStartA:2cm)--(\aStartA:2cm)--(\aStartA:3cm) arc (\aStartA:\aStopA:3cm)--(\aStopA:2cm)--(\aStopA:2cm) arc (\aStopA:\aStartA:2cm);
\draw[thin, color=gray] (\aStartA:0)--(\aStartA:3.5cm);
\draw[thin, color=gray] (\aStopA:0)--(\aStopA:3.5cm);
\end{tikzpicture}
\end{centering}
\end{document}
  • 1
    This question reminds me of my answer Waiting (Spinner) symbol (icon). It's inefficient though, so probably wait for TikZ experts here to chip in. – Troy Apr 9 '18 at 9:37
9

UPDATE: A solution based on the color wheel modification.

\documentclass[tikz,border=3.14pt]{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{Austria}{0}{white,red!80,red,red!80}
\usetikzlibrary{shadings}
\usepgfmodule{nonlineartransformations}
\makeatletter

\begin{document}
\begin{centering}
\begin{tikzpicture}[scale=1]

\def\aStartA{30}
\def\aStopA{330}

\draw[thin, color=gray] (\aStartA:0)--(\aStartA:3.5cm);
\draw[thin, color=gray] (\aStopA:0)--(\aStopA:3.5cm);
\begin{scope}
\clip (\aStartA:2cm)--(\aStartA:2cm)--(\aStartA:3cm) arc (\aStartA:\aStopA:3cm)--(\aStopA:2cm)--(\aStopA:2cm) arc (\aStopA:\aStartA:2cm);
\shade[shading=Austria,rotate=45] [even odd rule]
        (0,0) circle (3);
\end{scope}
\end{tikzpicture}
\end{centering}
\end{document}

enter image description here

This is the output with acroread. It looks very different with preview.

Original answer: Here is a proposal using nonlinear transformations. The nonlinear transformation from section 103.4 of the pgfmanual transforms a horizontal box precisely to an arc as shown in your figure. So I just shade a horizontal box linearly and then subject it to the nonlinear transformation.

\documentclass[tikz,]{standalone}
\usepackage{tikz}
\usetikzlibrary{shadings}
\usepgfmodule{nonlineartransformations}
\makeatletter
\def\polartransformation{%
% \pgf@x will contain the radius
% \pgf@y will contain the distance 
\pgfmathsincos@{\pgf@sys@tonumber\pgf@x}%
% pgfmathresultx is now the cosine of radius and 
% pgfmathresulty is the sine of radius 
\pgf@x=\pgfmathresultx\pgf@y% 
\pgf@y=\pgfmathresulty\pgf@y%
}
\makeatother

\begin{document}
\begin{centering}
\begin{tikzpicture}[scale=1]

\def\aStartA{30}
\def\aStopA{330}

\filldraw[gray!50,left color=white!25, right color=white!25, middle color=red!25] (\aStartA:2cm)--(\aStartA:2cm)--(\aStartA:3cm) arc (\aStartA:\aStopA:3cm)--(\aStopA:2cm)--(\aStopA:2cm) arc (\aStopA:\aStartA:2cm);
\draw[thin, color=gray] (\aStartA:0)--(\aStartA:3.5cm);
\draw[thin, color=gray] (\aStopA:0)--(\aStopA:3.5cm);
\clip (\aStartA:2cm)--(\aStartA:2cm)--(\aStartA:3cm) arc (\aStartA:\aStopA:3cm)--(\aStopA:2cm)--(\aStopA:2cm) arc (\aStopA:\aStartA:2cm);
\pgftransformnonlinear{\polartransformation}
\shade[left color=red,right color=white](-6.33,2) -- (-1,2)--(-1,3) --(-6.33,3) -- cycle;
\shade[left color=red,right color=white](6.33,2) -- (1,2)--(1,3) --(6.33,3) -- cycle;
\end{tikzpicture}
\end{centering}
\end{document}

enter image description here

ADDENDUM: I tried to make the code cleaner by switching to low level commands and using \pgfsetadditionalshadetransform on the shading. Unfortunately with very limited success

\documentclass[tikz,]{standalone}
\usepackage{tikz}
\usetikzlibrary{shadings}
\usepgfmodule{nonlineartransformations}
\makeatletter
\def\polartransformation{%
% \pgf@x will contain the radius
% \pgf@y will contain the distance 
\pgfmathsincos@{\pgf@sys@tonumber\pgf@x}%
% pgfmathresultx is now the cosine of radius and 
% pgfmathresulty is the sine of radius 
\pgf@x=\pgfmathresultx\pgf@y% 
\pgf@y=\pgfmathresulty\pgf@y%
}
\makeatother

\begin{document}
\pgfdeclarehorizontalshading{myshadingG}{5.34cm}
 {color(0cm)=(red); color(1cm)=(red!90);  color(3.34cm)=(red!10); 
 color(4.34cm)=(white)}



\begin{centering}
\begin{tikzpicture}[scale=1]

\def\aStartA{30}
\def\aStopA{330}

\draw[thin, color=gray] (\aStartA:0)--(\aStartA:3.5cm);
\draw[thin, color=gray] (\aStopA:0)--(\aStopA:3.5cm);
\begin{scope}
\clip (\aStartA:2cm)--(\aStartA:2cm)--(\aStartA:3cm) arc (\aStartA:\aStopA:3cm)--(\aStopA:2cm)--(\aStopA:2cm) arc (\aStopA:\aStartA:2cm);
\pgftransformnonlinear{\polartransformation}
\pgfsetadditionalshadetransform{\polartransformation}
\pgfpathrectangle{\pgfpoint{-6.34cm}{2.00cm}}{\pgfpoint{5.34cm}{1cm}}
\pgfpathrectangle{\pgfpoint{-6.34cm}{2.00cm}}{\pgfpoint{-5.34cm}{1cm}}
\pgfshadepath{myshadingG}{0}
\end{scope}
\end{tikzpicture}
\end{centering}
\end{document}

enter image description here

(Yes, I also see that there is a small gap, but that's not the point.) The point is that \pgfsetadditionalshadetransform{\polartransformation} doesn't seem to have an effect. However, there is no error message either. To me it seems a bit like this just gets ignored.

  • Thanks for your efforts marmot. Great suggestions, I will try them out as soon as possible and then report back. Regards – Henrik Petersson Apr 10 '18 at 14:33

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.