4

I'm using a custom shading to make cylindrical bars.

The shading uses a color that is defined in the color list.

I can change the color by using a \colorlet expression. But I'd like to be able to do it with an option in the draw command.

Here's my code, with my latest attempts to set the color commented out. I haven't been able to find anything in the documentation or on stackexchange that shows me how to do it.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations}
\usetikzlibrary{shadings}

\pgfdeclareradialshading[mycolor,white]
  {barendshading}
  {\pgfpoint{0bp}{5bp}}
  {color(0bp)=(white);
   color(28bp)=(mycolor);
   color(60bp)=(mycolor)}

\pgfdeclareverticalshading[mycolor,white]
  {barshading}
  {100bp}
  {color(0bp)=(mycolor); 
   color(25bp)=(mycolor); 
   color(55bp)=(white); 
   color(75bp)=(mycolor);
   color(100bp)=(mycolor)}

\def\cylindricalsphere{
  \begin{pgfscope}
    \pgfpathcircle{\pgfpoint{0}{0}}{5pt}
    \pgfshadepath{barendshading}{\pgfdecoratedangle}
  \end{pgfscope}}

\pgfdeclaredecoration{cylindricalbarspheres}{initial}
{
  \state{initial}[width=1pt,next state=middle]{\cylindricalsphere}
  \state{middle}[width=1pt]{}
  \state{final}{\cylindricalsphere}}

\def\cylindricalsegment{
  \begin{pgfscope}
    \pgfpathrectanglecorners
      {\pgfpoint{-.55pt}{-5pt}}
      {\pgfpoint{.55pt}{5pt}}
    \pgfshadepath{barshading}{\pgfdecoratedangle}
  \end{pgfscope}}

\pgfdeclaredecoration{cylindricalbarsegments}{initial}
    {
      \state{initial}[width=1pt,next state=middle]{
        %\pgfkeysgetvalue{/tikz/path color}{pcolor}
        %\colorlet{mycolor}{pcolor}
        \cylindricalsegment}
      \state{middle}[width=1pt]{
        \cylindricalsegment}
      \state{final}{}
    } 

\tikzset{
    cylindricalbar/.style={
        preaction={decorate,decoration=cylindricalbarspheres},
        postaction={decorate,decoration=cylindricalbarsegments},
    }}

\begin{document}
  \begin{tikzpicture}


  \colorlet{mycolor}{blue}
  \path [cylindricalbar,color=green] (0,0) arc (90:0:3.5);
 \end{tikzpicture}
\end{document}

Blue shaded bar

4

You can declare a new TikZ option to store the color and use it into shading declarations.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations}
\usetikzlibrary{shadings}

\tikzset{
    /tikz/cylindrical shading color/.store in=\mycolor,
    /tikz/cylindrical shading color=black
}

\pgfdeclareradialshading[\mycolor]
  {barendshading}
  {\pgfpoint{0bp}{5bp}}
  {color(0bp)=(white);
   color(28bp)=(\mycolor);
   color(60bp)=(\mycolor)}

\pgfdeclareverticalshading[\mycolor]
  {barshading}
  {100bp}
  {color(0bp)=(\mycolor); 
   color(25bp)=(\mycolor); 
   color(55bp)=(white); 
   color(75bp)=(\mycolor);
   color(100bp)=(\mycolor)}

\def\cylindricalsphere{
  \begin{pgfscope}
    \pgfpathcircle{\pgfpoint{0}{0}}{5pt}
    \pgfshadepath{barendshading}{\pgfdecoratedangle}
  \end{pgfscope}}

\pgfdeclaredecoration{cylindricalbarspheres}{initial}
{
  \state{initial}[width=1pt,next state=middle]{\cylindricalsphere}
  \state{middle}[width=1pt]{}
  \state{final}{\cylindricalsphere}}

\def\cylindricalsegment{
  \begin{pgfscope}
    \pgfpathrectanglecorners
      {\pgfpoint{-.55pt}{-5pt}}
      {\pgfpoint{.55pt}{5pt}}
    \pgfshadepath{barshading}{\pgfdecoratedangle}
  \end{pgfscope}}

\pgfdeclaredecoration{cylindricalbarsegments}{initial}
    {
      \state{initial}[width=1pt,next state=middle]{
        %\pgfkeysgetvalue{/tikz/path color}{pcolor}
        %\colorlet{mycolor}{pcolor}
        \cylindricalsegment}
      \state{middle}[width=1pt]{
        \cylindricalsegment}
      \state{final}{}
    } 

\tikzset{
    cylindricalbar/.style={
        preaction={decorate,decoration=cylindricalbarspheres},
        postaction={decorate,decoration=cylindricalbarsegments},
    }}

\begin{document}
  \begin{tikzpicture}
  \path [cylindricalbar, cylindrical shading color=red] (0,0) arc (90:0:3.5);
  \path [cylindricalbar, cylindrical shading color=green] (0,-0.5) arc (90:0:2.75);
  \path [cylindricalbar, cylindrical shading color=blue] (0,-1) arc (90:0:2);
  \path [cylindricalbar] (0,-1.5) arc (90:0:1.5);
 \end{tikzpicture}
\end{document}

enter image description here

  • I guess your bar endings disappeared in some cases, too? – cfr Mar 1 '17 at 2:07
  • @cfr Do you have an example of disappearance? – Paul Gaborit Mar 1 '17 at 6:55
  • 1
    @cfr. Yes. But I've not investigated the problem. – Ignasi Mar 1 '17 at 8:54
  • 1
    @PaulGaborit: In my code, change green bar to be: \path [cylindricalbar, cylindrical shading color=green] (0,-0.5) arc (90:0:3.0); and lower end disappears. – Ignasi Mar 1 '17 at 8:55
  • @PaulGaborit I tried the same with -0.5, but also had some where y was positive. I think if you change all the arcs to 90:0 in my answer, you'll get 2 disappearing lower ends, which is why I used 90:-5. – cfr Mar 1 '17 at 14:17
3

I tend to use a .code handler and just set the colour directly.

  cylindrical bar colour/.code={
    \colorlet{mycolor}{#1}%
  },
  cylindrical bar colour=black,

This creates a key cylindrical bar colour whose argument will be used to set mycolor. black is used as an initial value.

Then,

\begin{tikzpicture}
  \path [cylindricalbar] (0,.5)  arc (90:-5:4);
  \path [cylindricalbar, cylindrical bar colour=green] (0,0) arc (90:-5:3.5);
  \path [cylindricalbar, cylindrical bar colour=blue] (0,1) arc (90:-5:4.5);
  \path [cylindricalbar, cylindrical bar colour=magenta] (0,1.5) arc (90:-5:5);
\end{tikzpicture}

gives

multi-coloured cylindrical bars

Complete code:

\documentclass[border=10pt,tikz]{standalone}
\usetikzlibrary{arrows.meta,decorations,shadings}
\pgfdeclareradialshading[mycolor,white]
{barendshading}
{\pgfpoint{0bp}{5bp}}
{color(0bp)=(white);
  color(28bp)=(mycolor);
  color(60bp)=(mycolor)}
\pgfdeclareverticalshading[mycolor,white]
{barshading}
{100bp}
{color(0bp)=(mycolor);
  color(25bp)=(mycolor);
  color(55bp)=(white);
  color(75bp)=(mycolor);
  color(100bp)=(mycolor)}
\def\cylindricalsphere{
  \begin{pgfscope}
    \pgfpathcircle{\pgfpoint{0}{0}}{5pt}
    \pgfshadepath{barendshading}{\pgfdecoratedangle}
  \end{pgfscope}}
\pgfdeclaredecoration{cylindricalbarspheres}{initial}
{
  \state{initial}[width=1pt,next state=middle]{\cylindricalsphere}
  \state{middle}[width=1pt]{}
  \state{final}{\cylindricalsphere}}
\def\cylindricalsegment{
  \begin{pgfscope}
    \pgfpathrectanglecorners
    {\pgfpoint{-.55pt}{-5pt}}
    {\pgfpoint{.55pt}{5pt}}
    \pgfshadepath{barshading}{\pgfdecoratedangle}
  \end{pgfscope}}
\pgfdeclaredecoration{cylindricalbarsegments}{initial}
{
  \state{initial}[width=1pt,next state=middle]{
    %\pgfkeysgetvalue{/tikz/path color}{pcolor}
    %\colorlet{mycolor}{pcolor}
    \cylindricalsegment}
  \state{middle}[width=1pt]{
    \cylindricalsegment}
  \state{final}{}
}
\tikzset{
  cylindricalbar/.style={
    preaction={decorate,decoration=cylindricalbarspheres},
    postaction={decorate,decoration=cylindricalbarsegments},
  },
  cylindrical bar colour/.code={
    \colorlet{mycolor}{#1}%
  },
  cylindrical bar colour=black,
}
\begin{document}
\begin{tikzpicture}
  \path [cylindricalbar] (0,.5)  arc (90:-5:4);
  \path [cylindricalbar, cylindrical bar colour=green] (0,0) arc (90:-5:3.5);
  \path [cylindricalbar, cylindrical bar colour=blue] (0,1) arc (90:-5:4.5);
  \path [cylindricalbar, cylindrical bar colour=magenta] (0,1.5) arc (90:-5:5);
\end{tikzpicture}
\end{document}

By the way, are your cylinder endings meant to disappear in some cases? I had to do some experimentation to get 4 arcs which all had two round ends.

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.