8

In my illustration I need a sketch of clock. For it I use pic capability of TikZ. It works fine with quit annoying exception: positioning of clocks in picture. If I put a clock at some absolute coordinate, than picture is as expected, but if I put it relative, for example left from some coordinate, the clock screw up. It seems, that in may pic the internal anchors are wrong declared. So far, didn't figured out, how to do this in proper way.

I search SE if some one have similar problem. The closest is anchoring-tikz-pics, but the suggestion there doesn't help me much (probably I din't understand them completely).

My attempt is in (not quite) MWE below:

\documentclass[12pt,tikz,border=3mm]{standalone}
    \usetikzlibrary{arrows.meta,%
                    positioning,%
                    shapes
                    }
        \begin{document}
    \begin{tikzpicture}[
J/.style = {thick, bend left, shorten >=1mm, shorten <=1mm, -{Straight Barb[]}},
pics/ura/.style n args
         = {3}{code={\node[name=ura,
                           circle, minimum width=21mm,fill=gray!50] {};
                    \foreach \i in {north,south,east,west,
                                    north west,north east,south west,south east}
                    \coordinate (-\i) at (ura.\i);
                    %
                    \node[circle,draw=gray,thick, fill=#1!5,   %%%%%%%%%
                          minimum width=20mm,inner sep=0pt,node contents={}];
                    \node[font=\tiny,
                           below=1mm of ura.center] {tik-tak};
            \foreach \a/\label in {0/3,   30/2,   60/1,
                             90/12, 120/11, 150/10,
                             180/9, 210/8,  240/7,
                             270/6, 300/5,  330/4}
            {\draw[very thick] (\a:8.2mm) -- (\a:9.9mm);
             \draw (\a:7mm) node[font=\tiny] {\label};
             }
             \foreach \s in {1,2,...,60}\draw (6*\s:9mm) -- (6*\s:9.8mm);
            \draw[line width=0.8mm,red,shorten <=-2mm,
                  {Round Cap[]-Kite[length=12pt,width=6pt,inset=5pt]}]  
                  (ura.center) -- (#2,6mm); %%%%%%%%%hour
            \begin{scope}[red,thick,opacity=0.6,
                          transparency group,{-Kite[]}]
            \draw (#3-180:3mm) -- (ura.center) -- (#3:8mm);    %%%%%%%% minute
            \end{scope}
            \node[circle,draw=red!80!black,
                  inner color=white,outer color=red!50,
                  inner sep=2pt] at (ura.center) {};                      
                    }       
            },
X/.style = {above=0mm of #1-north,
            font=\footnotesize\sffamily\bfseries}
                        ]
%-------
\pic (A) at (0, 0) {ura={teal}{0}{150}};\node[X=A] {ura A};
\pic (B) at (4, 0) {ura={yellow}{0}{120}};\node[X=B] {ura B};
\pic[below=2mm of A-south] (C) {ura={yellow}{0}{120}};\node[X=C] {ura C};
%-------
\draw[J] (A-east) to node[above,sloped] {11:50} (B-west);
\draw[J] (B-west) to node[below,sloped] {11:55} (A-east);
%----------------
    \end{tikzpicture}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        \end{document}

As can be seen from picture below, the clock (ura C) is split into three parts, base circle is on right position (below of given coordinate), part of other components are centered around it and part is somewhere between.

enter image description here

1 Answer 1

10

Here's a working example. I've reformatted it a fair bit and added some styles to help keep straight what's doing what.

\documentclass[12pt,tikz,border=3mm]{standalone}
\usetikzlibrary{arrows.meta,%
                positioning,%
                shapes,calc%%
                }

\tikzset{%%
  ura hub/.style={circle,
                  anchor=center,
                  draw=red!80!black,
                  inner color=white,
                  outer color=red!50,
                  inner sep=2pt},
  ura hour hand/.style={line width=0.8mm,
                        red,
                        shorten <=-2mm,
                        {Round Cap[]-Kite[length=12pt,width=6pt,inset=5pt]},
                        },
  ura minute hand/.style={red,
                          thick,
                          opacity=0.6,
                          transparency group,
                          {-Kite[]}},
  ura matt/.style={circle,
                  draw=gray,
                  thick, 
                  fill=#1!5,
                  minimum width=20mm,
                  inner sep=0pt,
                  anchor=center,
                  },
  ura body/.style={circle, 
                   minimum width=21mm,
                   fill=gray!50}
  }
\begin{document}

\begin{tikzpicture}[
    J/.style = {thick, bend left, shorten >=1mm, shorten <=1mm, -{Straight Barb[]}},
    pics/ura/.style n args={3}{
      code={\node[ura body] (ura) at (0,0) {};
            \foreach \i in 
              {north,south,east,west,north west,north east,south west,south east}
              {\coordinate (-\i) at (ura.\i);}
            %%
            \node[ura matt=#1] at (ura.center) {};
            \node[font=\tiny,below=1mm of ura.center] {tik-tak};
            %% minutes and hours on clock
            \foreach \a/\label in 
              {0/3,   30/2,   60/1,
               90/12, 120/11, 150/10,
               180/9, 210/8,  240/7,
               270/6, 300/5,  330/4}
            {
             \draw[very thick] ($(ura.center)+(\a:8.2mm)$) -- 
                               ($(ura.center)+(\a:9.9mm)$);
             \node[inner sep=0pt,anchor=center,font=\tiny] (N/\a) at ($(ura.center)+(\a:7mm)$) {\tiny\label};
             %\draw ($(ura.center)+(\a:7mm)$) circle (1pt);
             %\draw (N/\a) -- (ura.center);
             }
            %% minute tick marks
            \foreach \s in {1,2,...,60} 
            { 
              \draw ($(ura.center)+(6*\s:9mm)$) -- ($(ura.center)+(6*\s:9.8mm)$); 
            }
            \draw[ura hour hand]   (ura.center) -- ($(ura.center)+(#2,6mm)$);
            \draw[ura minute hand] ($(ura.center)+(#3-180:3mm)$) -- (ura.center) -- ($(ura.center)+(#3:8mm)$);
            \node[ura hub] at (ura.center) {};                      
         }       
       },
    X/.style={above=0mm of #1-north,font=\footnotesize\sffamily\bfseries}
   ]
  %-------
  \pic (A) at (0, 0) {ura={teal}{0}{150}};
  \node[X=A] {ura A};

  \pic (B) at (4, 0) {ura={yellow}{0}{120}};
  \node[X=B] {ura B};

  \node[below=2mm of A-south] (myC) {};
  \pic[anchor=north] (C) at (myC) {ura={yellow}{0}{120}};
  \node[X=C] {ura C};

  %-------
  \draw[J] (A-east) to node[above,sloped] {11:50} (B-west);
  \draw[J] (B-west) to node[below,sloped] {11:55} (A-east);
  %----------------
\end{tikzpicture}

\end{document}

enter image description here

The problem seems to be how the anchoring mechanism of the pic gets smuggled into the options for the nodes you're using. So, in each of those nodes, I've specified that the anchor be anchor=center.

I've left the lines

%\draw ($(ura.center)+(\a:7mm)$) circle (1pt);
%\draw (N/\a) -- (ura.center);

in there for you to play with. Remove the anchor=center from the options for the nodes, this will show that \draw gets things right, but nodes don't.

Stylistically I think it makes better sense to use \draw instead of \node when all you're doing in drawing. So for example, for the hub for the two hands, instead of writing

\node[ura hub] at (ura.center) {};                      

it makes better sense to write

\draw[ura hub] (ura.center) circle (2.5pt);

in which case I've redefined the key 'ura hub' to be:

  ura hub/.style={red,
                  line width=1pt,
                  inner color=white,
                  outer color=red!50,
                  },

A clean version

Here's a clean version of what I'm suggesting above about how to use \draw and \node. Also, I've removed the dependency on the TikZ library calc, and I've renamed some of the keys to make clear which ones are being used for nodes and to make clear what the function of others (formerly X and J) are about. And though how you set the hours on the clock follows the example from the TikZ manual, I've rewritten in a manner that I believe is a bit easier to understand.

\documentclass[12pt,tikz,border=3mm]{standalone}
\usetikzlibrary{arrows.meta,%
                positioning,%
                shapes,
                }

\tikzset{%%
  ura body for node/.style={circle, 
                            minimum width=21mm,
                            fill=gray!50},
  ura matt/.style={draw=gray,
                   thick, 
                   fill=#1!5,
                   },
  ura hour hand/.style={line width=0.8mm,
                        red,
                        shorten <=-2mm,
                        {Round Cap[]-Kite[length=12pt,width=6pt,inset=5pt]},
                        },
  ura minute hand/.style={red,
                          thick,
                          opacity=0.6,
                          transparency group,
                          {-Kite[]}},
  ura hours for node/.style={inner sep=0pt,anchor=center,font=\tiny,node contents=#1},
  ura hub/.style={red,
                  line width=1pt,
                  inner color=white,
                  outer color=red!50,
                  },
  }
\begin{document}

\begin{tikzpicture}[
    arrow path between clocks/.style = {thick, bend left, shorten >=1mm, shorten <=1mm, -{Straight Barb[]}},
    pics/ura/.style n args={3}{
      code={\node[ura body for node] (ura) at (0,0) {};
            \foreach \i in 
              {north,south,east,west,north west,north east,south west,south east}
              {\coordinate (-\i) at (ura.\i);}
            %%
            \draw[ura matt=#1] (ura.center) circle (10mm);
            \node[font=\tiny,below=1mm of ura.center] {tik-tak};
            %% minutes and hours on clock
            %% major tick marks
            \foreach \myhour in {1,...,12}
            {
              \pgfmathsetmacro\myangle{int(90-\myhour*30)}
              %% tick mark for hour
              \draw[very thick] (ura.center) ++(\myangle:8.2mm) -- ++(\myangle:1.7mm);
              %% place numbers for the hours
              \path (ura.center) ++ (\myangle:7mm) node[ura hours for node=\myhour];
            }
            %% minor tick marks
            \foreach \mysecond in {1,2,...,60} 
            { 
              \pgfmathsetmacro\myangle{int(6*\mysecond)}
              %% tick marks for seconds
              \draw (ura.center) ++ (\myangle:9mm) -- ++ (\myangle:0.8mm); 
            }
            \draw[ura hour hand]   (ura.center) -- ++(#2,6mm);
            \draw[ura minute hand] (ura.center) ++ (#3-180:3mm) -- ++ (#3:11mm);
            \draw[ura hub]         (ura.center) circle (2.5pt);
         }       
       },
    position clock title at/.style={above=0mm of #1-north,font=\footnotesize\sffamily\bfseries}
   ]
  %% the clocks:

  %% clock A
  \pic (A) at (0, 0) {ura={teal}{0}{150}};
  \node[position clock title at=A] {ura A};

  %% clock B
  \pic (B) at (4, 0) {ura={yellow}{0}{120}};
  \node[position clock title at=B] {ura B};

  %% clock C
  \node[below=4mm of A-south] (myC) {};
  \pic[anchor=north] (C) at (myC) {ura={yellow}{0}{120}};
  \node[position clock title at=C] {ura C};

  %% Mapping between clocks
  \draw[arrow path between clocks] (A-east) to node[above,sloped] {11:50} (B-west);
  \draw[arrow path between clocks] (B-west) to node[below,sloped] {11:55} (A-east);

\end{tikzpicture}

\end{document}

enter image description here

A final example

In this last example, you can pass your clock the time in a more human readable form (instead of having to think in terms of angles and degrees). I've also adjusted the hour hand to progress continuously around the clock according to hour and minute (as with a real analogue clock).

\documentclass[12pt,tikz,border=3mm]{standalone}
\usetikzlibrary{arrows.meta,%
                positioning,%
                shapes,
                }

\tikzset{%%
  ura body for node/.style={circle, 
                            minimum width=21mm,
                            fill=gray!50},
  ura matt/.style={draw=gray,
                   thick, 
                   fill=#1!5,
                   },
  ura hour hand/.style={line width=0.8mm,
                        red,
                        shorten <=-2mm,
                        {Round Cap[]-Kite[length=12pt,width=6pt,inset=5pt]},
                        },
  ura minute hand/.style={red,
                          thick,
                          opacity=0.6,
                          transparency group,
                          {-Kite[]}},
  ura hours for node/.style={inner sep=0pt,anchor=center,font=\tiny,node contents=#1},
  ura hub/.style={red,
                  line width=1pt,
                  inner color=white,
                  outer color=red!50,
                  },
  }

\makeatletter

\def\ae@parse@hour@minutes#1:#2;{%%
  \pgfmathsetmacro\my@hour{int(90-#1*30)-30/60*#2}%%
  \pgfmathsetmacro\my@minu{int(90-#2*6)}}

\newcommand\aeUraCode[2]{%%
  \ae@parse@hour@minutes#2;
  \node[ura body for node] (ura) at (0,0) {};
  \foreach \i in 
    {north,south,east,west,north west,north east,south west,south east}
    {\coordinate (-\i) at (ura.\i);}
  %%
  \draw[ura matt=#1] (ura.center) circle (10mm);
  \node[font=\tiny,below=1mm of ura.center] {tik-tak};
  %% minutes and hours on clock
  %% major tick marks
  \foreach \myhour in {1,...,12}
  {
    \pgfmathsetmacro\myangle{int(90-\myhour*30)}
    %% tick mark for hour
    \draw[very thick] (ura.center) ++(\myangle:8.2mm) -- ++(\myangle:1.7mm);
    %% place numbers for the hours
    \path (ura.center) ++ (\myangle:7mm) node[ura hours for node=\myhour];
  }
  %% minor tick marks
  \foreach \mysecond in {1,2,...,60} 
  { 
    \pgfmathsetmacro\myangle{int(6*\mysecond)}
    %% tick marks for seconds
    \draw (ura.center) ++ (\myangle:9mm) -- ++ (\myangle:0.8mm); 
  }
  \draw[ura hour hand]   (ura.center) -- ++(\my@hour:6mm);
  \draw[ura minute hand] (ura.center) ++ (\my@minu-180:3mm) -- ++ (\my@minu:11mm);
  \draw[ura hub]         (ura.center) circle (2.5pt);
}

\makeatother

\begin{document}

\begin{tikzpicture}[
    arrow path between clocks/.style = {thick, bend left, shorten >=1mm, shorten <=1mm, -{Straight Barb[]}},
    pics/ura/.style n args={2}{code={\aeUraCode{#1}{#2}}},
    position clock title at/.style={above=0mm of #1-north,font=\footnotesize\sffamily\bfseries}
   ]
  %% the clocks:

  %% clock A
  \pic (A) at (0, 0) {ura={teal}{11:50}};
  \node[position clock title at=A] {ura A};

  %% clock B
  \pic (B) at (4, 0) {ura={yellow}{11:55}};
  \node[position clock title at=B] {ura B};

  %% clock C
  \node[below=4mm of A-south] (myC) {};
  \pic[anchor=north] (C) at (myC) {ura={yellow}{12:45}};
  \node[position clock title at=C] {ura C};

  %% clock D
  \node[below=4mm of B-south] (myD) {};
  \pic[anchor=north] (D) at (myD) {ura={blue}{3:24}};
  \node[position clock title at=D] {ura D};


  %% Mapping between clocks
  \draw[arrow path between clocks] (A-east) to node[above,sloped] {11:50} (B-west);
  \draw[arrow path between clocks] (B-west) to node[below,sloped] {11:55} (A-east);

\end{tikzpicture}

\end{document}

enter image description here

5
  • Thank you for your answer. It works! But I like to understand why. For this I need more time to investigate essential differences from my MWE. By the way, I not understand the line "\node[inner sep=0pt,anchor=center,font=\tiny] (N/\a) at ($(ura.center)+(\a:7mm)$) {\tiny\label};" . What is (N/\a)? Is this allowed names of nodes? Is names of this nodes necessary?
    – Zarko
    Commented Apr 8, 2015 at 20:48
  • @Zarko You don't need to name the nodes at all. That was just there to help illustrate how the nodes were getting misplaced on accounting of the anchoring specified in the options to \pic.
    – A.Ellett
    Commented Apr 8, 2015 at 20:57
  • Meanwhile I figured out how yoe determine and use coordinates inside pic. Now is left only one problem: how to remember this to the next my similar problem :-). It will be of big help for people like me, if in the next CVS relise of TikZ manual will be added similar complex example of use of pic.
    – Zarko
    Commented Apr 8, 2015 at 22:22
  • Has this bug been reported? I know that the pic code is buggy in many ways, so I don't know reporting does much good ;) but maybe still worth doing? My answer includes a reasonably minimal example demonstrating the issue. (That is, it is considerably more minimal pic-wise than the case dealt with here so might be useful, potentially, for reporting if anybody decides to do that.) @Zarko
    – cfr
    Commented Apr 2, 2016 at 22:58
  • As far as I know, no. I didn't do this (since I'm very clumsy in this :-( ), and recently I use pic for new design only occasionally. I still hope that in not so far futures this will be fixed.
    – Zarko
    Commented Apr 2, 2016 at 23:10

You must log in to answer this question.

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