4

The calendar TikZ library creates for each day a node called (<name>-<year>-<month>-<day>). But there is a leading zero for <day> from 1 to 9, that is, to use the node of the first day we have to refer to it by (<name>-<year>-<month>-01).

Since I'm trying to connect some nodes using a \foreach loop, I'm having trouble with the leading zero. For example,

! Package pgf Error: No shape named cal-2015-01-2 is known.
! Package pgf Error: No shape named cal-2015-09-4 is known.

But if I insert the leading zero (cal-2015-09-0\x.north east) the error changes to

! Package pgf Error: No shape named cal-2015-01-016 is known.

So, I think that working with integer numbers with exactly two digits could solve the problem.

I'd like to have the same two dashed lines as in the 1st calendar below, but translated to separate the other weekends.

MWE

\documentclass[11pt]{report}
\usepackage[margin=1cm,landscape,a4paper]{geometry}
\usepackage{tikz}
\usetikzlibrary{calendar,calc,math}

\begin{document}

\begin{tikzpicture}%
  [every day/.style={anchor=mid},
   every node/.style={inner sep=2pt,rectangle,thick}
  ]
\calendar (cal)%
 [dates=\the\year-1-1 to \the\year-12-last,
  month list,
  month label left,
  month text=\textcolor{black}{\%mt},
  month yshift=1.7em,
  black
 ]
if (Saturday) [blue]
if (Sunday)   [red]
;
\draw[dashed]
  ( $(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$ ) --
  ( $(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$ )
%%
  ( $(cal-\the\year-01-04.north east)!.5!(cal-\the\year-01-05.north west)$ ) --
  ( $(cal-\the\year-12-06.south east)!.5!(cal-\the\year-12-07.south west)$ )
;
\end{tikzpicture}

\vfill\noindent\hrulefill\vfill

\begin{tikzpicture}%
  [every day/.style={anchor=mid},
   every node/.style={inner sep=2pt,rectangle,thick}
  ]
\calendar (cal)%
 [dates=\the\year-1-1 to \the\year-12-last,
  month list,
  month label left,
  month text=\textcolor{black}{\%mt},
  month yshift=1.7em,
  black
 ]
if (Saturday) [blue]
if (Sunday)   [red]
;
%%  use only one foreach below
%% the first has problems with leading zeros on day numbers
%%
\foreach \i in {0,7,...,31}{% should be tested if is >31
%\foreach \i in {16,23,...,31}{% should be tested if is >31
%%
%% January 02 and 04 are starting days
  \tikzmath{integer \xaa; \xaa = 2+\i;}
  \tikzmath{integer \xab; \xab = \xaa+1;}
  \tikzmath{integer \xba; \xba = 4+\i;}
  \tikzmath{integer \xbb; \xbb = \xba+1;}
%% December 04 and 06 are ending days
  \tikzmath{integer \yaa; \yaa = 4+\i;}
  \tikzmath{integer \yab; \yab = \yaa+1;}
  \tikzmath{integer \yba; \yba = 6+\i;}
  \tikzmath{integer \ybb; \ybb = \yba+1;}
\draw[dashed]
  ( $(cal-\the\year-01-\xaa.north east)!.5!(cal-\the\year-01-\xab.north west)$ ) --
  ( $(cal-\the\year-12-\xba.south east)!.5!(cal-\the\year-12-\xbb.south west)$ )
%%
  ( $(cal-\the\year-01-\yaa.north east)!.5!(cal-\the\year-01-\yab.north west)$ ) --
  ( $(cal-\the\year-12-\yba.south east)!.5!(cal-\the\year-12-\ybb.south west)$ )
;
}
\end{tikzpicture}

\end{document}

enter image description here

  • Add your full code please. – Alenanno Jul 19 '15 at 13:35
  • @Alenanno, sorry. I added now. – Sigur Jul 19 '15 at 13:40
  • @clemens +1 This actually works, please consider posting a solution. – AboAmmar Jul 19 '15 at 14:13
  • @clemens For the posted code yes it gives the desired two-digit output, but the error the OP shown is not actually related to the two digits. The OP is referring to a node not created. – AboAmmar Jul 19 '15 at 14:20
2

Update

Elegant solution to the whole problem:

Here is another simplified solution which avoids the two-digits problem and adds the last two columns finally requested by the OP. The idea is that calendar columns are separated by some default distance. Here, for an 11pt-document, it is 3.5ex. We make sure it is 3.5ex by setting explicitly the day xshift=3.5ex option and passing it to the calendar command.

Next, we perform a \foreach loop to draw two vertical lines and repeat after a week by adding an xshift of 7*3.5ex as this:

\foreach \i in {0,...,4}{%
\pgfmathparse{3.5*7*\i} \edef\w{\pgfmathresult}
\pgfmathparse{\w+2*3.5} \edef\x{\pgfmathresult}
\draw[dashed]
([xshift=\w ex]$(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$) --
([xshift=\w ex]$(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$)
([xshift=\x ex]$(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$) --
([xshift=\x ex]$(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$);
} 

That loop draws all vertical lines as this:

enter image description here

And the total simplified code now is this:

\documentclass[11pt]{report}
\usepackage[margin=1cm,landscape,a4paper]{geometry}
\usepackage{tikz}
\usetikzlibrary{calendar,calc,math}
\begin{document}

\begin{tikzpicture}%
  [every day/.style={anchor=mid},
   every node/.style={inner sep=2pt,rectangle,thick}
  ]
\calendar (cal)%
 [dates=\the\year-1-1 to \the\year-12-last,
  month list,
  month label left,
  month text=\textcolor{black}{\%mt},
  month yshift=1.7em,
  black
 ]
if (Saturday) [blue]
if (Sunday)   [red];

\draw[dashed]
  ( $(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$ ) --
  ( $(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$ )
%%
  ( $(cal-\the\year-01-04.north east)!.5!(cal-\the\year-01-05.north west)$ ) --
  ( $(cal-\the\year-12-06.south east)!.5!(cal-\the\year-12-07.south west)$ );
\end{tikzpicture}

\vfill\noindent\hrulefill\vfill

\begin{tikzpicture}%
  [every day/.style={anchor=mid},
   every node/.style={inner sep=2pt,rectangle,thick}
  ]
\calendar[day xshift=3.5ex](cal)%
 [dates=\the\year-1-1 to \the\year-12-last,
  month list,
  month label left,
  month text=\textcolor{black}{\%mt},
  month yshift=1.7em,
  black
 ]
if (Saturday) [blue]
if (Sunday)   [red];

% use only one foreach below
% the first has problems with leading zeros on day numbers

\foreach \i in {0,...,4}{%
\pgfmathparse{3.5*7*\i} \edef\w{\pgfmathresult}
\pgfmathparse{\w+2*3.5} \edef\x{\pgfmathresult}
\draw[dashed]
([xshift=\w ex]$(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$) --
([xshift=\w ex]$(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$)
%
([xshift=\x ex]$(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$) --
([xshift=\x ex]$(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$);
}
\end{tikzpicture}

\end{document}

Solution 1

Inspired by the error message mentioned by @clemens, a straightforward solution could be to avoid days greater than 31. To achieve this, observe the largest node number \ybb = \yba+1 which is equal to \i+7 because \yba=\i+6. This latter value should maximize to 31. So, max{ \i }= 24, which simply implies the condition:

\ifnum\i<25\draw ... \else\fi 

Here is the full code with the second solution (which gives the same results as above):

\documentclass[11pt]{report}
\usepackage[margin=1cm,landscape,a4paper]{geometry}
\usepackage{tikz}
\usetikzlibrary{calendar,calc,math}
\makeatletter
\let\twodigits\two@digits
\makeatother

\begin{document}

\begin{tikzpicture}%
  [every day/.style={anchor=mid},
   every node/.style={inner sep=2pt,rectangle,thick}
  ]
\calendar (cal)%
 [dates=\the\year-1-1 to \the\year-12-last,
  month list,
  month label left,
  month text=\textcolor{black}{\%mt},
  month yshift=1.7em,
  black
 ]
if (Saturday) [blue]
if (Sunday)   [red];

\draw[dashed]
  ( $(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$ ) --
  ( $(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$ )
%%
  ( $(cal-\the\year-01-04.north east)!.5!(cal-\the\year-01-05.north west)$ ) --
  ( $(cal-\the\year-12-06.south east)!.5!(cal-\the\year-12-07.south west)$ );
\end{tikzpicture}

\vfill\noindent\hrulefill\vfill

\begin{tikzpicture}%
  [every day/.style={anchor=mid},
   every node/.style={inner sep=2pt,rectangle,thick}
  ]
\calendar(cal)%
 [dates=\the\year-1-1 to \the\year-12-last,
  month list,
  month label left,
  month text=\textcolor{black}{\%mt},
  month yshift=1.7em,
  black
 ]
if (Saturday) [blue]
if (Sunday)   [red];

%%  use only one foreach below
%% the first has problems with leading zeros on day numbers
%%
\foreach \i in {0,7,...,31}{% should be tested if is >31
%\foreach \i in {16,23,...,31}{% should be tested if is >31
%%
%% January 02 and 04 are starting days
  \tikzmath{integer \xaa; \xaa = 2+\i;}
  \tikzmath{integer \xab; \xab = \xaa+1;}
  \tikzmath{integer \xba; \xba = 4+\i;}
  \tikzmath{integer \xbb; \xbb = \xba+1;}
%% December 04 and 06 are ending days
  \tikzmath{integer \yaa; \yaa = 4+\i;}
  \tikzmath{integer \yab; \yab = \yaa+1;}
  \tikzmath{integer \yba; \yba = 6+\i;}
  \tikzmath{integer \ybb; \ybb = \yba+1;}
\ifnum\i<25
\draw[dashed]
  ($(cal-\the\year-01-\twodigits\xaa.north east)!.5!(cal-\the\year-01-\twodigits\xab.north west)$) --
  ($(cal-\the\year-12-\twodigits\xba.south east)!.5!(cal-\the\year-12-\twodigits\xbb.south west)$)
%%
  ($(cal-\the\year-01-\twodigits\yaa.north east)!.5!(cal-\the\year-01-\twodigits\yab.north west)$) --
  ($(cal-\the\year-12-\twodigits\yba.south east)!.5!(cal-\the\year-12-\twodigits\ybb.south west)$);
\else\fi
}
\end{tikzpicture}

\end{document}

enter image description here

  • Thanks. I'll study your code now. But I'd like to have one more pair of vertical lines to split the last column of weekend days. The problem is that there is no January 32,33 to compute the initial points for the lines. Neither in December. So the idea is to draw the lines around March 28,29 for example and make them with the same height as the others. Maybe we can take the intersection of two perpendicular lines parallel to coordinate axes to find the vertex January 32.north west. – Sigur Jul 20 '15 at 5:55
  • @Sigur Please see my updated answer. – AboAmmar Jul 20 '15 at 9:13
  • So, this was the trick: for an 11pt-document, it is 3.5ex. I was trying to insert more nodes to extend the days sequence but I was not able to control the horizontal distance since day uses a node with predefined x-shifting, different from the one used by node. Let me study but I think that it is done. Thanks. – Sigur Jul 20 '15 at 9:34
  • Since the days to be used for the end points of lines could change I'm trying to define commands \dayA and \dayB to store for example, 02 and 04 to be used as \dayA.north east and \dayB.south east. But when I use \newcommand{\dayA}{02} and add 1 to compute the middle point I got Package pgf Error: No shape named cal-2015-01-3 is known. } So, in resume, \pgfmathparse{\dayA+1} \edef\dayAa{\pgfmathresult} has no leading zero. How to add 1 and get 03? – Sigur Jul 20 '15 at 10:27
  • @Sigur In all possible solutions, you must specify the first line manually, all subsequent lines can be computed iteratively by shifting (choosing days is difficult) to avoid the two-digit problem. For what you ask about now, you have to resort to the two-digit definition again. – AboAmmar Jul 20 '15 at 10:38
4

LaTeX has (the expandable) \two@digits which takes an integer as input an adds a leading 0 if the number is less than 10. So you could place

\makeatletter
\let\twodigits\two@digits
\makeatother

somewhere in your preamble and then use

\draw[red] 
  ($(cal-2015-09-\twodigits\x.north east)!.5!(cal-2015-09-05.north west)$)--
  ($(cal-2016-02-\twodigits\y.south east)!.5!(cal-2016-02-06.south west)$) ;

in your first example or

$\frac{\twodigits\i}{\twodigits\x}$

in your second example.


Edit in light of the updated question – here the code part is now:

\draw[dashed]
  ( $(cal-\the\year-01-\twodigits\xaa.north east)!.5!(cal-\the\year-01-\twodigits\xab.north west)$ ) --
  ( $(cal-\the\year-12-\twodigits\xba.south east)!.5!(cal-\the\year-12-\twodigits\xbb.south west)$ )
%%
  ( $(cal-\the\year-01-\twodigits\yaa.north east)!.5!(cal-\the\year-01-\twodigits\yab.north west)$ ) --
  ( $(cal-\the\year-12-\twodigits\yba.south east)!.5!(cal-\the\year-12-\twodigits\ybb.south west)$ )
;

BTW: this will still give errors

! Package pgf Error: No shape named cal-2015-12-32 is known.

but now it's not due to missing zeros but because 4+\i eventually is bigger than 31.

  • I edited the post. – Sigur Jul 19 '15 at 17:29
  • Well, you are right. Now my problem is other problem. Thanks for a while. – Sigur Jul 19 '15 at 17:58
  • yes. Thanks. Let's see if there is some solution related to tikz. – Sigur Jul 19 '15 at 18:04

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.