Upgrade the weekly calendar

tikz-calendar

Hi evryone I have made a weekly planner based on this post and I want to make a better one by making it more easy to use.

Here is the code:

\documentclass[a5paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}
\usepackage{tikz}
\usetikzlibrary{positioning, calendar, shapes.misc, fit, shapes}
\usepackage[margin=0.5cm]{geometry}
\usepackage[spanish]{babel}
\usepackage[spanish]{translator}
\usepackage{palatino} 
\newcommand{\markday}[3]{if (equals=#1-#2-#3) {\draw (0.04,0.109) circle (3pt);}}
\newcommand{\calendar}[3]{\begin{tikzpicture}
  \calendar
  [
    dates=#1-#2-01 to #1-#2-last,
    week list,inner sep=2pt,month label above centered,
    month text=\%mt \%y0
  ]
  if (at most=#1-#2-#3) [nodes={strike out,draw}]
  if (weekend)            [black!50,nodes={draw=none}]
  ;
\end{tikzpicture}}
\newenvironment{yeramonth}[4]{%
\begin{tikzpicture}[%
        inner sep=1 pt,
        dayname/.style={%
            node font=\footnotesize, 
        },
        daynumber/.style={%
            anchor=north east,
            node font=\normalsize\bfseries, 
        },
        time/.style={%
            node font=\tiny, 
        },
        activitie/.style={%
            anchor=north east,
            node font=\scriptsize,
            text width=8 cm,
        },
        xscale = 10,
        yscale=-3
    ]
    
    \node (year_number) at (-0.15,1) [anchor = south east, minimum height = 2em] {#1};
    \node [base right = 1em of year_number, anchor=base west, node font=\large] {#2};
    \draw (-0.25,1) -- (0.6,1);
    \node (calendar) at (0.6,1.7) [daynumber] {};
    \node [base right = 2em of calendar, anchor=base west] [dayname] {\calendar{#1}{#3}{#4}}; 
\end{tikzpicture}
}



\begin{document}
\itshape
\begin{tikzpicture}[%
        inner sep=1 pt,
        dayname/.style={%
            node font=\footnotesize, 
        },
        daynumber/.style={%
            anchor=north east,
            node font=\normalsize\bfseries, 
        },
        time/.style={%
            node font=\tiny, 
        },
        activitie/.style={%
            anchor=north east,
            node font=\scriptsize,
            text width=8 cm,
        },
        xscale = 10,
        yscale=-3
    ]

    \node (saturday_number) at (-0.1,5.1) [daynumber] {14};
    \node [base right = 1em of saturday_number, anchor=base west] [dayname] {Sábado};
    \node (saturday) at (0.67,5.23) [activitie] {hola};
    \node (saturday) at (-0.2,5.25) [time] {11:00};
    \node [draw,ellipse,fit={(saturday)}] {};
    \node (saturday) at (0.67,5.38) [activitie] {hola};
    \node (saturday) at (-0.2,5.4) [time] {12:10};
    \node [draw,ellipse,fit={(saturday)}] {};
    \node (saturday) at (0.67,5.53) [activitie] {hola};
    \node (saturday) at (-0.2,5.55) [time] {13:20};
    \node [draw,ellipse,fit={(saturday)}] {};
    \node (saturday) at (0.67,5.68) [activitie] {hola};
    \node (saturday) at (-0.2,5.7) [time] {17:00};
    \node [draw,ellipse,fit={(saturday)}] {};
    \node (saturday) at (0.67,5.83) [activitie] {hola};
    \node (saturday) at (-0.2,5.85) [time] {18:10};
    \node [draw,ellipse,fit={(saturday)}] {};
    \node (saturday) at (0.67,5.98) [activitie] {hola};
    \node (saturday) at (-0.2,6) [time] {19:20};
    \node [draw,ellipse,fit={(saturday)}] {};
    \node (saturday) at (0.67,6.13) [activitie] {hola};
    \node (saturday) at (-0.2,6.15) [time] {20:30};
    \node [draw,ellipse,fit={(saturday)}] {};

    \node (sunday_number) at (0.45,5.1) [daynumber] {15};
    \node [base right = 1em of sunday_number, anchor=base west] [dayname] {Domingo};
    \node (sunday) at (1.22,5.23) [activitie] {hola};
    \node (sunday) at (0.35,5.25) [time] {11:00};
    \node [draw,ellipse,fit={(sunday)}] {};
    \node (sunday) at (1.22,5.38) [activitie] {hola};
    \node (sunday) at (0.35,5.4) [time] {12:10};
    \node [draw,ellipse,fit={(sunday)}] {};
    \node (sunday) at (1.22,5.53) [activitie] {hola};
    \node (sunday) at (0.35,5.55) [time] {13:20};
    \node [draw,ellipse,fit={(sunday)}] {};
    \node (sunday) at (1.22,5.68) [activitie] {hola};
    \node (sunday) at (0.35,5.7) [time] {17:00};
    \node [draw,ellipse,fit={(sunday)}] {};
    \node (sunday) at (1.22,5.83) [activitie] {hola};
    \node (sunday) at (0.35,5.85) [time] {18:10};
    \node [draw,ellipse,fit={(sunday)}] {};
    \node (sunday) at (1.22,5.98) [activitie] {hola};
    \node (sunday) at (0.35,6) [time] {19:20};
    \node [draw,ellipse,fit={(sunday)}] {};
    \node (sunday) at (1.22,6.13) [activitie] {hola};
    \node (sunday) at (0.35,6.15) [time] {20:30};
    \node [draw,ellipse,fit={(sunday)}] {};



    \node (friday_number) at (-0.1,4.3) [daynumber] {13};
    \node [base right = 1em of friday_number, anchor=base west] [dayname] {Viernes};
    \node (friday) at (0.67,4.43) [activitie] {hola};
    \node (friday) at (-0.2,4.45) [time] {17:00};
    \node [draw,ellipse,fit={(friday)}] {};
    \node (friday) at (0.67,4.58) [activitie] {hola};
    \node (friday) at (-0.2,4.6) [time] {18:10};
    \node [draw,ellipse,fit={(friday)}] {};
    \node (friday) at (0.67,4.73) [activitie] {hola};
    \node (friday) at (-0.2,4.75) [time] {19:20};
    \node [draw,ellipse,fit={(friday)}] {};
    \node (friday) at (0.67,4.88) [activitie] {hola};
    \node (friday) at (-0.2,4.9) [time] {20:30};
    \node [draw,ellipse,fit={(friday)}] {};
    \draw (-0.25,5.05) -- (0.99,5.05);

    \node (thursday_number) at (-0.1,3.5) [daynumber] {12};
    \node [base right = 1em of thursday_number, anchor=base west] [dayname] {Jueves};
    \node (thursday) at (0.67,3.63) [activitie] {hola};
    \node (thursday) at (-0.2,3.65) [time] {17:00};
    \node [draw,ellipse,fit={(thursday)}] {};
    \node (thursday) at (0.67,3.78) [activitie] {hola};
    \node (thursday) at (-0.2,3.8) [time] {18:10};
    \node [draw,ellipse,fit={(thursday)}] {};
    \node (thursday) at (0.67,3.93) [activitie] {hola};
    \node (thursday) at (-0.2,3.95) [time] {19:20};
    \node [draw,ellipse,fit={(thursday)}] {};
    \node (thursday) at (0.67,4.08) [activitie] {hola};
    \node (thursday) at (-0.2,4.1) [time] {20:30};
    \node [draw,ellipse,fit={(thursday)}] {};
    \draw (-0.25,4.25) -- (0.99,4.25);

    \node (wednesday_number) at (-0.1,2.7) [daynumber] {11};
    \node [base right = 1em of wednesday_number, anchor=base west] [dayname] {Miércoles};
    \node (wedneday) at (0.67,2.83) [activitie] {hola};
    \node (wednesday) at (-0.2,2.85) [time] {17:00};
    \node [draw,ellipse,fit={(wednesday)}] {};
    \node (wedneday) at (0.67,2.98) [activitie] {hola};
    \node (wednesday) at (-0.2,3) [time] {18:10};
    \node [draw,ellipse,fit={(wednesday)}] {};
    \node (wedneday) at (0.67,3.13) [activitie] {hola};
    \node (wednesday) at (-0.2,3.15) [time] {19:20};
    \node [draw,ellipse,fit={(wednesday)}] {};
    \node (wedneday) at (0.67,3.28) [activitie] {hola};
    \node (wednesday) at (-0.2,3.3) [time] {20:30};
    \node [draw,ellipse,fit={(wednesday)}] {};
    \draw (-0.25,3.45) -- (0.99,3.45);

    \node (tuesday_number) at (-0.1,1.85) [daynumber] {10};
    \node [base right = 1em of tuesday_number, anchor=base west] [dayname] {Martes};
    \node (tuesday) at (0.67,2.03) [activitie] {hola};
    \node (tuesday) at (-0.2,2.05) [time] {17:00};
    \node [draw,ellipse,fit={(tuesday)}] {};
    \node (tuesday) at (0.67,2.18) [activitie] {hola};
    \node (tuesday) at (-0.2,2.2) [time] {18:10};
    \node [draw,ellipse,fit={(tuesday)}] {};
    \node (tuesday) at (0.67,2.33) [activitie] {hola};
    \node (tuesday) at (-0.2,2.35) [time] {19:20};
    \node [draw,ellipse,fit={(tuesday)}] {};
    \node (tuesday) at (0.67,2.48) [activitie] {hola};
    \node (tuesday) at (-0.2,2.5) [time] {20:30};
    \node [draw,ellipse,fit={(tuesday)}] {};
    \draw (-0.25,2.65) -- (0.99,2.65);
    
    \node (monday_number) at (-0.1,1.05) [daynumber] {9};
    \node [base right = 1em of monday_number, anchor=base west] [dayname] {Lunes};
    \node (monday) at (0.67,1.18) [activitie] {hola};
    \node (monday) at (-0.2,1.2) [time] {17:00};
    \node [draw,ellipse,fit={(monday)}] {};
    \node (monday) at (0.67,1.33) [activitie] {hola};
    \node (monday) at (-0.2,1.35) [time] {18:10};
    \node [draw,ellipse,fit={(monday)}] {};
    \node (monday) at (0.67,1.48) [activitie] {hola};
    \node (monday) at (-0.2,1.5) [time] {19:20};
    \node [draw,ellipse,fit={(monday)}] {};
    \node (monday) at (0.67,1.63) [activitie] {hola};
    \node (monday) at (-0.2,1.65) [time] {20:30};
    \node [draw,ellipse,fit={(monday)}] {};
    \draw (-0.25,1.8) -- (0.99,1.8);
    
    \node (year_number) at (-0.15,1) [anchor = south east, minimum height = 2em] {2022};
    \node [base right = 1em of year_number, anchor=base west, node font=\large] {Diciembre};
    \draw (-0.25,1) -- (0.6,1);
    \node (calendar) at (0.6,1.7) [daynumber] {};
    \node [base right = 2em of calendar, anchor=base west] [dayname] {\calendar{2022}{12}{5}};

\end{tikzpicture}

\end{document}

And here is the output:

enter image description here
In this image I have defined a week using tikz-calendar, but the problem is that it is to much code to use it each time I have to write a new week (the idea of this calendar is to be used in latex, not printing it), thats why I want to define a newenviroment which is (you can see how I defined this enviroment in the code above):

\begin{yeramonth}{2022}{Diciembre}{12}{9}

\end{yeramonth}

This enviroment produces this:

enter image description here

It's just something like a header because I couldn't be able to make an entire week enviroment and that is something I'm looking for to make it more useable

Then is the total calendar where you could mark a day with the command \markday
This is the code:

\begin{tikzpicture}[xscale=1, yscale=1.8, rotate= 90]
\tiny
\calendar [dates=2023-01-01 to 2023-12-31,
             month list, month label left, month yshift=6em]
            if (weekend)            [black!50,nodes={draw=none}]
            \markday{2023}{3}{5}
            \markday{2023}{3}{8};
\end{tikzpicture}

And this is the output:

enter image description here

Here it would be awesome to be able to indicate below the month label what event is the day with the cricle refering to, maybe with a multicol and itemize convination could be posible.

To resume this post, I'm asking for help to make an enviroment for the week layout (and beeing able to write because I want to use it on the computer), beeing able to indicate with a list of dates what is the event with the circle and something that was asked on the original post it was to make some help lines (in this case could be placed below the weekend, and also beeing able to write on there)

Thanks in advanced, I'm sorry it was too long but.

Best Answer

Starting simple.

Let's just create the page with the seven days.

To have our own custom namespace for our keys and styles, I am using

\amcalset

that's like \tikzset but instead of /tikz our namespace is /tikz/amcal.

In this namespace, I declare the following keys:

  • every matrix,
  • weekday and
  • weekend.

For each day we use a single PGF/TikZ matrix. (We could also use a tabularx but then the ellipses would have been more work.)

The weekday and the weekend key set the corresponding day code (usually, this would be some form of \node … {\daytext}; but we will ignore all that).

The weekdays get an additional vertical space at the bottom. The columns get a minimum width that may be a bit more than we actually need but then we know exactly how wide they are and can simply calculate the remaining width for the last column.


Since PGF/TikZ takes the line width in consideration for the bounding boxes, we overlay the ellipse nodes with an outer sep = 0 so that we then can activate a better bounding box with

append after command=(\tikzlastnode.west)(\tikzlastnode.east)(\tikzlastnode.south)(\tikzlastnode.north)

so that the first column is actually minimum width wide.

Similar things need to be done to the whole picture, here I'm using the keys trim left and trim right so that we don't get an overfull hbox of about 0.4 pt (the default linewidth). These 0.4 pt gets added because of the horizontal lines atop the matrices.

For the weekend days we half the \linewidth in the calculation of the width of the third column and for the Sunday (\pgfcalendarcurrentweekday = 6) we also change the placement of the matrix.

Speaking of placement. As you can see, I don't use any day list downward or similar style to place the days below/besides each other.
These are just placed with the north west anchor at the previous matrix' south east anchor. For the Monday matrix, this previous matrix doesn't exist which is why I simply initialize a coordinate with amcal-day-1. This is basically a poor man's implementation of the functionalities of the chains library.


I've placed the translator and babel package before the loading of tikz so that when the calendar library is loaded, the translations hooks are already installed.


In the amcal-week environment I first take the mandatory argument, calculate the weekday of that day and subtract for the dates key so that we always have a proper full week. (As you see, I'm asking for 2022-12-11 which is a Sunday but the page is full of the whole week and doesn't start at 2022-12-11.

Heading

Simply replacing the auxilliary coordinate with a node and we have a heading with year and month (of the date given to the environment, not from the first day appearing on the page).

Mini calendar

Instead of a calendar inside a tikzpicture inside a node inside a tikzpicture, I just place the mini calendar in the same tikzpicture.

For this /tikz/amcal/mini/day xshift acts as top-level value-key that's forwarded to the mini calendar. (The value is stored in a @-ridden macro which is annoying to access.)

This value is also used to reduce the width of the Monday matrix (which in turn shortens the line at the top).

Some weird values are used so that mini calendar fits properly in the corner. The first week has the same baseline as the heading. (The default anchor of the days is base east.)

Of course, you could just yshift the mini calendar one day yshift down so that the the line of the Monday matrix doesn't need to shortened.

Code

\documentclass[a5paper, spanish]{article}
\usepackage[margin=0.5cm]{geometry}
\usepackage{palatino}
\usepackage{babel, translator}
\usepackage{tikz}
\usetikzlibrary{
  calendar,         % Duh!
  shapes.geometric, % → ellipse
  shapes.misc,      % → strike out
  matrix,           % → matrix of nodes
  ext.misc}         % → .ifnum handler
\newcommand*\amcalset{\pgfqkeys{/tikz/amcal}}
\amcalset{
  .code=\amcalset{#1},
  every matrix/.style={
    every outer matrix/.append style={% tight matrix
      inner xsep=+0pt, outer sep=+0pt},
    name=amcal-day\pgfcalendarcurrentweekday,
    matrix anchor=north west,
    at/.ifnum={\pgfcalendarcurrentweekday=6}% Sunday?
              {(amcal-day5.north east)}
              {(amcal-day\pgfinteval{\pgfcalendarcurrentweekday-1}.south west)},
    % alternatively: at={(amcal-day\ifnum\pgfcalendarcurrentweekday=6
    %                              5.north east\else
    %         \pgfinteval{\pgfcalendarcurrentweekday-1}.south west\fi)}
    matrix of nodes,
    append after command={
      (\tikzlastnode.north west) edge (\tikzlastnode.north east)},
    ampersand replacement = \&,
    column sep=\tabcolsep,
    row sep=+.3ex, % carefully selected
    column 1/.append style={% ellipses
      minimum width=1.5cm,
      shape=ellipse,
      nodes={
        draw,
        overlay,
        outer sep=+0pt,
        inner ysep=+.2em,
        append after command=(\tikzlastnode.west)(\tikzlastnode.east)
                             (\tikzlastnode.south)(\tikzlastnode.north),
      },
    },
    column 2/.append style={minimum width=1cm},
    column 3/.append style={% math!
      minimum width={% basically the X column
        % if weekday then only half the linewidth
        ifthenelse(%
          \pgfcalendarcurrentweekday==5,
          .5,
          ifthenelse(
            \pgfcalendarcurrentweekday==6,
            .5,
            1
          )
        )*
        \linewidth
        -2.5cm                % the minimum widths of the other columns
        -2\pgfmatrixcolumnsep % 3 columns → 2 column seps
        -(\pgfcalendarcurrentweekday==0) 
          *(7.7*(\pgfkeysvalueof{/tikz/amcal/mini/day xshift}))% 7.7‽
      },
      % minimum width minus the inner xseps on both sides
      text width={(\pgfkeysvalueof{/pgf/minimum width})
                  -2*(\pgfkeysvalueof{/pgf/inner xsep})},
    },
    row 1 column 2/.append style={font=\bfseries\large},
    /utils/exec=\small\itshape,
    inner ysep=+.29em, % carefully selected
    text depth=+0pt,
  },
  weekday/.style={
    day code={
      \matrix[amcal/every matrix] {
              \& \%d= \& \%wt \\
        17:00 \& hola \\
        18:10 \& hola \\
        19:20 \& hola \\
        20:30 \& hola \\[.9ex]\\ % carefully selected
      };
    }
  },
  weekend/.style={
    day code={
      \matrix[amcal/every matrix] {
              \& \%d= \& \%wt \\
        11:00 \& hola \\
        12:10 \& hola \\
        13:20 \& hola \\
        17:00 \& hola \\
        18:10 \& hola \\
        19:20 \& hola \\
        20:30 \& hola \\
      };
    }
  },
  heading/.style={
    node font=\itshape\large,
    inner xsep=+1.7em,
    name=amcal-day-1,
  },
  strike out/.style={
    shape=strike out,
    draw,
  },
  mini/.style={
    day xshift=\pgfkeysvalueof{/tikz/amcal/mini/day xshift},
    shift={([xshift={1.1*(\pgfkeysvalueof{/tikz/amcal/mini/day xshift})}]% 1.1‽
      amcal-day-1.base-|amcal-day0.east)},
    dates=\amcalYear-\amcalMonth-01 to \amcalYear-\amcalMonth-last,
    week list,
    day text={\%d=},
    if={(weekend) [amcal/mini/weekend]},
    if={(at most=\amcalYear-\amcalMonth-\amcalDay) [amcal/mini/day over]},
  },
  mini/weekend/.style={
    days={
      gray,
      amcal/strike out/.code=
    },
  },
  mini/day over/.style={
    days=amcal/strike out,
  },
  mini/day xshift/.initial=3.6ex, % default is 3.5ex
}
\makeatletter
\newenvironment*{amcal-week}[2][]{%
  \noindent
  \begin{tikzpicture}[trim left=(amcal-day0.west), trim right=(amcal-day0.east)]
  \pgfcalendardatetojulian{#2}{\count@}%
  \edef\amcalJulian{\the\count@}%
  \pgfcalendarjuliantoweekday{\count@}{\count@}%
  \edef\amcalWeekday{\the\count@}%
  \pgfcalendarjuliantodate{\amcalJulian}{\amcalYear}{\amcalMonth}{\amcalDay}%
  \node[amcal/heading] {\amcalYear\hspace{1em}\Large\pgfcalendarmonthname{\amcalMonth}};
  \calendar[
    dates=#2+-\amcalWeekday to #2+\pgfinteval{6-\amcalWeekday},
    if={(workday) [amcal/weekday]},
    if={(weekend) [amcal/weekend]},
  ]
}{%
  ;
  \calendar[amcal/mini];
  \end{tikzpicture}\par
}
\makeatother
\begin{document}
\begin{amcal-week}{2022-12-11}
\end{amcal-week}
\end{document}

Output

enter image description here

Related Question