PGF/TikZ Manual | PGFplots | TikZ Editor

TikZ and PGF Manual

Libraries

47 Calendar Library

47.1 Calendar Command

The core command for creating calendars in TikZ is the \calendar command. It is available only inside {tikzpicture} environments (similar to, say, the \draw command).

In the rest of the following subsections we have a look at how the different scope codes can be used to create different calendar arrangements.

47.1.1 Creating a Simple List of Days

We start with a list of the days of the calendar, one day below the other. For this, we simply shift the coordinate system downward at the end of the code for each day. This shift must be outside the day scope as we want day shifts to accumulate. Thus, we use the following code:

(-tikz- diagram)

\usetikzlibrary {calendar}
\tikz
\calendar [dates=2000-01-01 to 2000-01-08,
execute after day scope=
{\pgftransformyshift{-1em}}];

Clearly, we can use this approach to create day lists going up, down, right, left, or even diagonally.

47.1.2 Adding a Month Label

We now want to add a month label to the left of the beginning of each month. The idea is to do two things:

  • 1. We add code that is executed only on the first of each month.

  • 2. The code is executed before the actual day is rendered. This ensures that options applying to the days do not affect the month rendering.

We have two options where we should add the month code: Either we add it at the beginning of the day scope or before. Either will work fine, but it might be safer to put the code inside the scope to ensure that settings to not inadvertently “leak outside”.

(-tikz- diagram)

\usetikzlibrary {calendar}
\tikz
\calendar
[dates=2000-01-01 to 2000-01-08,
execute after day scope={\pgftransformyshift{-1em}},
execute at begin day scope=
{\ifdate{day of month=1}{\tikzmonthcode}{}},
every month/.append style={anchor=base east,xshift=-2em}];

In the above code we used the \ifdate{condition}{then code}{else code} command, which is described in section 89.2 in detail and which has much the same effect as if (condition){then code} else {else code}, but works in normal code.

47.1.3 Creating a Week List Arrangement

Let us now address a more complicated arrangement: A week list. In this arrangement there is line for each week. The horizontal placement of the days is thus that all Mondays lie below each other, likewise for all Tuesdays, and so on.

In order to typeset this arrangement, we can use the following approach: The origin of the coordinate system rests at the anchor for the Monday of each week. That means that at the end of each week the origin is moved downward one line. On all other days, the origin at the end of the day code is the same as at the beginning. To position each day correctly, we use code inside and at the beginning of the day scope to horizontally shift the day according to its day of week.

(-tikz- diagram)

\usetikzlibrary {calendar}
\tikz
\calendar
[dates=2000-01-01 to 2000-01-20,
% each day is shifted right according to the day of week
execute at begin day scope=
{\pgftransformxshift{\pgfcalendarcurrentweekday em}},
% after each week, the origin is shifted downward:
execute after day scope=
{\ifdate{Sunday}{\pgftransformyshift{-1em}}{}}];
47.1.4 Creating a Month List Arrangement

For another example, let us create an arrangement that contains one line for each month. This is easy enough to do as for weeks, unless we add the following requirement: Again, we want all days in a column to have the same day of week. Since months start on different days of week, this means that each row has to have an individual offset.

One possible way is to use the following approach: After each month (or at the beginning of each month) we advance the vertical position of the offset by one line. For horizontal placement, inside the day scope we locally shift the day by its day of month. Furthermore, we must additionally shift the day to ensure that the first day of the month lies on the correct day of week column. For this, we remember this day of week the first time we see it.

(-tikz- diagram)

\usetikzlibrary {calendar}
\newcount\mycount
\tikz
\calendar
[dates=2000-01-01 to 2000-02-last,
execute before day scope=
{
\ifdate{day of month=1} {
% Remember the weekday of first day of month
\mycount=\pgfcalendarcurrentweekday
% Shift downward
\pgftransformyshift{-1em}
}{}
}
,
execute at begin day scope=
{
% each day is shifted right according to the day of month
\pgftransformxshift{\pgfcalendarcurrentday em}
% and additionally according to the weekday of the first
\pgftransformxshift{\the\mycount em}
}
];
47.2 Arrangements

An arrangement specifies how the days of calendar are arranged on the page. The calendar library defines a number of predefined arrangements.

We start with arrangements in which the days are listed in a long line.

  • /tikz/day list right(style, no value)

  • This style also works as before, but the list of days grows to the right. Instead of day yshift and month yshift, the values of day xshift and month xshift are used.

    (-tikz- diagram)

    \usetikzlibrary {calendar}
    \tikz
    \calendar [dates=2000-01-28 to 2000-02-03,
    day list right,month xshift=1em];
  • /tikz/day list left(style, no value)

  • As above, but the list grows left.

The next arrangement lists days by the week.

  • /tikz/week list(style, no value)

  • This style creates one row for each week in the range. The value of day xshift is used for the distance between days in each week row, the value of day yshift is used for the distance between rows. In both cases, “distance” refers to the distance between the anchors of the nodes of the days (or, more generally, the distance between the origins of the little pictures created for each day).

    The days inside each week are shifted such that Monday is always at the first position (to change this, you need to copy and then modify the code appropriately). If the date range does not start on a Monday, the first line will not start in the first column, but rather in the column appropriate for the first date in the range.

    At the beginning of each month (except for the first month in the range) an additional vertical space of month yshift is added. If this is set to 0pt you get a continuous list of days.

    (-tikz- diagram)

    \usetikzlibrary {calendar}
    \tikz
    \calendar [dates=2000-01-01 to 2000-02-last,week list];

    (-tikz- diagram)

    \usetikzlibrary {calendar}
    \tikz
    \calendar [dates=2000-01-01 to 2000-02-last,week list,
    month yshift=0pt];

The following arrangement gives a very compact view of a whole year.

47.3 Month Labels

For many calendars you may wish to add a label to each month. We have already covered how month nodes are created and rendered in the description of the \calendar command: use month text, every month, and also month code (if necessary) to change the appearance of the month labels.

What we have not yet covered is where these labels are placed. By default, they are not placed at all as there is no good “default position” for them. Instead, you can use one of the following options to specify a position for the labels:

  • /tikz/month label right(style, no value)

  • This style places the month label to the right of the row in which the first day of the month lies. This means that for a day list the label is to the right of the first day, for a week list it is to the right of the first week, and for a month list it is to the right of the whole month.

    (-tikz- diagram)

    \usetikzlibrary {calendar}
    \tikz
    \calendar [dates=2000-01-28 to 2000-02-03,
    day list downward,month yshift=1em,
    month label right];
  • /tikz/month label below left(style, no value)

  • Works like month label above left, only the label is placed below the row. This placement is not really useful with the week list arrangement, but rather with the day list right or month list arrangement.

    (-tikz- diagram)

    \usetikzlibrary {calendar}
    \tikz
    \calendar [dates=2000-02-01 to 2000-02-last,
    day list right,month label below left];
47.4 Examples

In the following, some example calendars are shown that come either from real applications or are just nice to look at.

Let us start with a year-2100-countdown, in which we cross out dates as we approach the big celebration. For this, we set the shape to strike out for these dates.

(-tikz- diagram)

\usetikzlibrary {calendar,shapes.misc}
\begin{tikzpicture}
\calendar
[
dates=2099-12-01 to 2100-01-last,
week list,inner sep=2pt,month label above centered,
month text=\%mt \%y0
]
if (at most=2099-12-29) [nodes={strike out,draw}]
if (weekend) [black!50,nodes={draw=none}]
;
\end{tikzpicture}

The next calendar shows a deadline, which is 10 days in the future from the current date. The last three days before the deadline are in red, because we really should be done by then. All days on which we can no longer work on the project are crossed out.

(-tikz- diagram)

\usetikzlibrary {calendar,shapes.misc}
\begin{tikzpicture}
\calendar
[
dates=\year-\month-\day+-25 to \year-\month-\day+25,
week list,inner sep=2pt,month label above centered,
month text=\textit{\%mt \%y0}
]
if (at least=\year-\month-\day) {}
else [nodes={strike out,draw}]
if (at most=\year-\month-\day+7)
[green!50!black]
if (between=\year-\month-\day+8 and \year-\month-\day+10)
[red]
if (Sunday)
[gray,nodes={draw=none}]
;
\end{tikzpicture}

The following example is a futuristic calendar that is all about circles:

(-tikz- diagram)

\usetikzlibrary {calendar}
\sffamily

\colorlet{winter}{blue}
\colorlet{spring}{green!60!black}
\colorlet{summer}{orange}
\colorlet{fall}{red}

% A counter, since TikZ is not clever enough (yet) to handle
% arbitrary angle systems.
\newcount\mycount

\begin{tikzpicture}
[transform shape,
every day/.style={anchor=mid,font=\fontsize{6}{6}\selectfont}]
\node{\normalsize\the\year};
\foreach \month/\monthcolor in
{1/winter,2/winter,3/spring,4/spring,5/spring,6/summer,
7/summer,8/summer,9/fall,10/fall,11/fall,12/winter}
{
% Compute angle:
\mycount=\month
\advance\mycount by -1
\multiply\mycount by 30
\advance\mycount by -90

% The actual calendar
\calendar at (\the\mycount:6.4cm)
[
dates=\the\year-\month-01 to \the\year-\month-last,
]
if (day of month=1) {\color{\monthcolor}\tikzmonthcode}
if (Sunday) [red]
if (all)
{
% Again, compute angle
\mycount=1
\advance\mycount by -\pgfcalendarcurrentday
\multiply\mycount by 11
\advance\mycount by 90
\pgftransformshift{\pgfpointpolar{\mycount}{1.4cm}}
};
}
\end{tikzpicture}

Next, let’s us have a whole year in a tight column:

(-tikz- diagram)

\usetikzlibrary {calendar}
\begin{tikzpicture}
\small\sffamily
\colorlet{darkgreen}{green!50!black}
\calendar[dates=\year-01-01 to \year-12-31,week list,
month label left,month yshift=0pt,
month text=\textcolor{darkgreen}{\%m0}]
if (Sunday) [black!50];
\end{tikzpicture}