I want do define a set with dates chemistryclasses={2021-05-25,2021-06-01,2021-06-08,2021-06-15,2021-06-22,2021-06-29,2021-07-06,2021-07-13} and then I want the code to paint the corresponding dates in tikz-calendar. In the MWE below I could do that. However, I would like to automatize the routine. It is tedious to write all those if (equals=2021-05-25). At the moment I use Python to write the .tex file. It reads a CSV file with the dates and the generate the .tex file. But I was thinking about an all-LaTeX solution. I tried something like

\foreach \x in {2021-05-25,2021-06-01,2021-06-08,2021-06-15,2021-06-22,2021-06-29,2021-07-06,2021-07-13} {%
  if (equals=\x) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}

but it didn't work. So how can I automatize these things inside LaTeX? A good workflow would be:

1)Write the dates in a file

2)LaTeX reads the dates and save to a variable

3)LaTeX generates the calendar.



% =============
% = TColorBox =
% =============
\tcbset{left=4mm,sharpish corners,colback=white}

% ============
% = Calendar =
% ============
\node[anchor=base,xshift=0.5ex](mon){M}; % Shift first weekday
\node[base right=0.1em of mon](tue){T}; 
\node[base right=0.0em of tue](wed){W};
\node[base right=0.0em of wed](thu){T}; 
\node[base right=0.1em of thu](fri){F};
\node[base right=0.2em of fri](sat){S}; 
\node[base right=0.2em of sat](sun){S};
\node[black,above=0.1em of thu]{\textbf{#1}};}
    \calendar (month-#1)[dates=2021-#1-01 to 2021-#1-last,
    every day/.style={anchor=base}, % Center days
    day text={\%d=},rounded corners=0,
    anchor=base,text height=1ex,text depth=-0.5ex] % Make node placement easier
    if(Sunday) [red] 
if (equals=2021-05-11) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-05-18) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-05-25) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-06-01) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-06-08) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-06-15) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-06-22) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-06-29) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-07-06) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-07-13) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-05-11) [blue]
if (equals=2021-05-18) [blue]
if (equals=2021-05-25) [blue]
if (equals=2021-06-01) [blue]
if (equals=2021-06-08) [blue]
if (equals=2021-06-15) [blue]
if (equals=2021-06-22) [blue]
if (equals=2021-06-29) [blue]
if (equals=2021-07-06) [blue]
if (equals=2021-07-13) [blue]
\node [hyperlink node=data01,draw=none,regular polygon,regular polygon sides=4] at (month-05-2021-05-11) {};
\node [hyperlink node=data02,draw=none,regular polygon,regular polygon sides=4] at (month-05-2021-05-18) {};
\node [hyperlink node=data03,draw=none,regular polygon,regular polygon sides=4] at (month-05-2021-05-25) {};
\node [hyperlink node=data04,draw=none,regular polygon,regular polygon sides=4] at (month-06-2021-06-01) {};
\node [hyperlink node=data05,draw=none,regular polygon,regular polygon sides=4] at (month-06-2021-06-08) {};
\node [hyperlink node=data06,draw=none,regular polygon,regular polygon sides=4] at (month-06-2021-06-15) {};
\node [hyperlink node=data07,draw=none,regular polygon,regular polygon sides=4] at (month-06-2021-06-22) {};
\node [hyperlink node=data08,draw=none,regular polygon,regular polygon sides=4] at (month-06-2021-06-29) {};
\node [hyperlink node=data09,draw=none,regular polygon,regular polygon sides=4] at (month-07-2021-07-06) {};
\node [hyperlink node=data10,draw=none,regular polygon,regular polygon sides=4] at (month-07-2021-07-13) {};
    hyperlink node/.style={
        append after command={
            let     \p1 = (sourcenode.north west),
                \p2=(sourcenode.south east),
                \n2={\y1-\y2} in
            node [inner sep=0pt, outer sep=0pt,anchor=north west,at=(\p1)] {\hyperlink{#1}{\XeTeXLinkBox{\phantom{\rule{\n1}{\n2}}}}}
                    %xelatex needs \XeTeXLinkBox, won't create a link unless it
                    %finds text --- rules don't work without \XeTeXLinkBox.
                    %Still builds correctly with pdflatex and lualatex


% ============
% = Calendar =
% ============

\begin{tikzpicture}[every calendar/.style={week list}]
            row 1/.style={black,node distance=.3ex},%
            row 3/.style={black,node distance=.3ex},
            column sep=1ex,draw=none]{%
            % first row: week day and month
            \calrow{May} & \calrow{June} & \calrow{July} \\
            % second row: calendar
            \calperiod{05} & \calperiod{06} & \calperiod{07} \\

    \item \hypertarget{data01}{01}
    \item \hypertarget{data02}{02}
    \item \hypertarget{data03}{03}
    \item \hypertarget{data04}{04}
    \item \hypertarget{data05}{05}
    \item \hypertarget{data06}{06}
    \item \hypertarget{data07}{07}
    \item \hypertarget{data08}{08}
    \item \hypertarget{data09}{09}
    \item \hypertarget{data10}{10}

1 Answer 1


It is tedious to write all those if (equals=2021-05-25).

Then don't. Take a look at the /pgf/calendar/equals-strip key that takes an argment as #1/#2 and forwards #1 to equals. The second part after / is only used to place the \items later.

We can use the list inside \teachingdays once expanded and fed as a list to equals-strip:

if (equals-strip/.list/.expand once=\teachingdays) [teaching day]

The \teachingdays macro can then simply be:

  2021-05-18/Basics I,
  2021-05-25/Basics II,

This should make it much easier to use the calendar libraries by TikZ/PGF.


\hypersetup{colorlinks=true, citecolor=blue}

%%% Shorthand w- for Weekday
\expandafter\def\csname pgfcalendar@shorthand@w-\endcsname{\ifcase\pgfcalendarcurrentweekday M\or T\or W \or T\or F\else S\fi}

%%% equal key that strips /<text>
\pgfqkeys{/pgf/calendar}{equals-strip/.style args={#1/#2}{equals={#1}}}

%%% A simple parser for <year>-<month>-<day> so we can use shorthands outside of a calendar

%%% hyperling node
    hyperlink node/.style={
        append after command={
            let \p1 = (@hyper.north west),
                \p2 = (@hyper.south east),
                \n1 = {\x2-\x1}, \n2 = {\y1-\y2} in
            node [inner sep=+0pt, outer sep=+0pt, anchor=center, at=(@hyper)] {\hyperlink{ref-#1}{\XeTeXLinkBox{\phantom{\rule{\n1}{\n2}}}}}}}}

\newcommand*{\calrow}[1]{\node[draw,black, minimum width=7*\csname tikz@lib@cal@xshift\endcsname]{\textbf{#1}};}

    \calendar [
      dates=2021-#1-01 to 2021-#1-last,
      day text={\%d=},
      % we name every weekday node (even though we only need the Thursday)
      weekday node/.style={
        black, name=weekday-\pgfcalendarcurrentmonth-\pgfcalendarcurrentweekday},
      % teaching day, include hyperlink node based on the date
      teaching day/.style={
        days={text=blue, fill=yellow, hyperlink node=\pgfcalendarcurrentyear-\pgfcalendarcurrentmonth-\pgfcalendarcurrentday}}]
      % standard stuff
      if (Saturday) [red!50!black]
      if (Sunday)   [red]
      % the first day of the month is in the upmost row,
      % let's place the weekday above it and align it properly
      % the name @firstweekday can be referenced later
      if (day of month=1) [days={append after command={
        node [anchor=base east, at={(\tikzlastnode.base east)}, alias=@firstweekday,
          yshift=\csname tikz@lib@cal@yshift\endcsname, weekday node/.try] {\%w-}}}]
      % for all other days 2 to 7 we place the weekday text similar but we use the
      % the first placed weekday text to make sure we align it at the same height
      if (day of month=2, day of month=3, day of month=4, day of month=5, day of month=6, day of month=7) [days={append after command={
        node [anchor=base east, at={(@firstweekday.base east-|\tikzlastnode.base east)}, weekday node/.try] {\%w-}}}]
      % and go
      if (equals-strip/.list/.expand once=\teachingdays) [teaching day]
  2021-05-18/Basics I,
  2021-05-25/Basics II,
  2021-06-29/To Do,

\begin{tikzpicture}[every calendar/.style={week list}]
    \matrix[column sep=1.5ex]{%
       \calperiod{05} & \calperiod{06} & \calperiod{07} \\
    \foreach \mon/\t in {05/May, 06/Jun, 07/Jul}
      \node[anchor=south, yshift=2ex, at=(weekday-\mon-3)] {\textbf{\t}};

    \foreach \target/\name[/utils/exec=\let\%\pgfcalendarshorthand] in \teachingdays {
      \item[\%m. \%d= \%y-] \hypertarget{ref-\target}{\name}}


three months side by side list of teachings

You must log in to answer this question.

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