5

While browsing tex.SE I saw this answer here and was really surprised at how nice and clean it looked. Now I'm facing a slightly different problem and I'm not really familiar with tikz (I only know how to do some simple stuff) so I couldn't really adapt the code to fit my problem.

Assuming you have one A4 page of space, I'd like to divide one timeline into 13 separate "sublines", each "subline" representing one month and beginning on a new line on the paper. Then create a colored square for every event on the timeline and write the name of the event in that square.

To make it maybe a little bit clearer here is an image.

enter image description here

The goal would be to create a new command, similar to the post mentioned, with the following information:

\event{dd.mm.}{dd.mm.}{text}{color}{number}

Where the first argument would be the starting date of the event, and the second one the ending date. The third argument should represent the text inside the square, the fourth argument is the color of the square and since some of the events overlap I would also need the option to place the events at different heights, therefore the last argument.

The two biggest problems for me here are:

  1. I don't know how to create one, continuous line and than split it into thirteen pieces, each on a new line.
  2. There are some events that are only one day long, so there is no chance that the text would fit there. These cases then would need some special treatment, but I don't know how one could implement something like that.

Alternatively I'd also be fine with creating thirteen timelines separately and then putting them together in a single picture, with this at least the first problem would be solved. There was of course also the option of just creating this straight forward, with drawing an arrow as timeline, and each square, text, etc. by hand, but since the entries are probably going to change a lot in the future this seemed suboptimal.


I'm sorry for not having a working MWE, but I'm honestly a bit lost here at how to approach creating such an command.


EDIT: After some trying out I came up with the following:

\documentclass[12pt]{article}
\usepackage[a4paper, margin=1cm]{geometry}
\usepackage{amsmath}
\usepackage{xstring}
\usepackage{tikz}
\usetikzlibrary{fit, calc}
\pagestyle{empty} 

\newcommand{\anno}{1} % starting year
\newcommand{\target}{31} % ending year
\newcommand{\alto}{3} % height

\pgfmathsetmacro{\myend}{\target+1-\anno}
\pgfmathsetmacro{\myspacing}{16/(\target-1-\anno)}


\newcommand{\eventpoint}[4]{    
    \StrBefore{#1}{/}[\dstart]%x1=day_start
    \StrBehind{#1}{/}[\mstart]%y1=month_start
    \StrBefore{#2}{/}[\dend]%x2=day_end
    \StrBehind{#2}{/}[\mend]%y2=month_end
    \pgfmathsetmacro{\mmstart}{((13-\mstart)*4)}
    \pgfmathsetmacro{\mmend}{((13-\mend)*4)}
    \ifthenelse{\mstart = \mend}
               {\filldraw[fill=#3!50, draw=#3,] (\dstart, \mmstart ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#4};}
               {\filldraw[fill=#3!50, draw=#3,] (\dstart, \mmstart ) rectangle (31, \mmstart+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#4};
               \filldraw[fill=#3!50, draw=#3,] (0, \mmend ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#4};};
}

\begin{document}
\begin{tikzpicture}[x=\myspacing cm,y=5mm]
\centering

%creating the sublines needed and formating them
\foreach \y in {0,4,8,12,16,20,24,28,32,36,40,44,48}{
\draw[|->, -latex] (-.5,\y) -- (\myend+.5,\y);
\path (0,0) -- (0,\alto);
\foreach \x [evaluate=\x as \day using int(\x)] in {0,10,20,30}{ 
    \draw (\x,\y) node[below=7pt,font=\footnotesize] {$\day$}; 
    \draw (\x,\y -.2) -- (\x,\y +.2);
    \draw[loosely dotted] (\x,\y +.2) -- (\x,\y+ \alto-0.5);
}
\foreach \tick in {0,...,\myend}{
    \draw (\tick,\y +.1) -- (\tick,\y -.1);
}
}

%trying to add the events
\eventpoint{15/7}{25/7}{green}{test}
\eventpoint{17/8}{19/9}{red}{test 2}


\end{tikzpicture}
\end{document}

The code is not working, but I suspect this is due to my wrong usage of \ifthenelse. Hope someone could fix maybe that.

  • 1
    Maybe it helps to think it this way: instead of thinking of the time line as a single one that you then have to break, think of it as the set of the 13 pieces as the timeline where the place of an event happening on dd.mm is y=mm and x = dd (for appropriate scales) – Bordaigorl Aug 27 '18 at 8:59
  • Interesting approach, thank you! I'm going to try this out today and see how far I can come with it.. – Sito Aug 27 '18 at 10:18
  • @Bordaigorl tried out your advise, would be great if you could look over it since something is still not working.. – Sito Aug 27 '18 at 15:04
  • Try with \ifnum\mstart=\mend ... \else ... \fi, you don't need \ifthenelse for this kind of condition... – Bordaigorl Aug 27 '18 at 15:40
3

The \ifthenelse in your code can be easily implemented with a standard \ifnum. Additionally, I reimplemented the date setting/parsing by reusing the powerful key/val facility of pgf.

\documentclass[12pt]{article}
\usepackage[a4paper, margin=1cm]{geometry}
\usepackage{tikz}
\pagestyle{empty}

\newcommand{\anno}{1} % starting year
\newcommand{\target}{31} % ending year
\newcommand{\alto}{3} % height

\tikzset{
    start date/.code args = {#1/#2}{
        \def\dstart{#1}
        \def\mstart{#2}
    },
    end date/.code args = {#1/#2}{
        \def\dend{#1}
        \def\mend{#2}
    },
    event color/.style = {
        fill=#1!50, draw=#1,
    },
}

\pgfmathsetmacro{\myend}{\target+1-\anno}
\pgfmathsetmacro{\myspacing}{16/(\target-1-\anno)}


\newcommand{\eventpoint}[2][]{
    \begin{scope}[#1]
    \pgfmathsetmacro{\mmstart}{((13-\mstart)*4)}
    \pgfmathsetmacro{\mmend}{((13-\mend)*4)}
    \ifnum\mstart=\mend
       \filldraw (\dstart, \mmstart ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
    \else
       \filldraw (\dstart, \mmstart ) rectangle (31, \mmstart+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
      \filldraw (0, \mmend ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
    \fi
    \end{scope}
}

\begin{document}
\centering
\begin{tikzpicture}[x=\myspacing cm,y=5mm]

%creating the sublines needed and formating them
\foreach \y in {0,4,8,12,16,20,24,28,32,36,40,44,48}{
\draw[|->, -latex] (-.5,\y) -- (\myend+.5,\y);
\path (0,0) -- (0,\alto);
\foreach \x [evaluate=\x as \day using int(\x)] in {0,10,20,30}{
    \draw (\x,\y) node[below=7pt,font=\footnotesize] {$\day$};
    \draw (\x,\y -.2) -- (\x,\y +.2);
    \draw[loosely dotted] (\x,\y +.2) -- (\x,\y+ \alto-0.5);
}
\foreach \tick in {0,...,\myend}{
    \draw (\tick,\y +.1) -- (\tick,\y -.1);
}
}

%trying to add the events
\eventpoint[start date=15/7,end date=25/7,event color=green]{test}
\eventpoint[start date=17/8,end date=19/9,event color=red,yshift=5pt]{test 2} % shift just to show you can hook into standard tikz keys to change the event's features ad-hoc

\end{tikzpicture}
\end{document}

By defining the dates with keys of a scope, you get a number of benefits:

  • improved readability (no guessing of args ordering)
  • possibility of providing defaults or alternatives (exercise: implement a duration=months key that can be used alternatively to end date)
  • ability to specify ad-hoc tikz keys per-event
  • easy to extend to additional keys
  • parsing is done by matching delimiters in arguments

Additional improvements that can be made: you could define keys setting the anno, target and alto parameters as well.

\documentclass[12pt]{article}
\usepackage[a4paper, margin=1cm]{geometry}
\usepackage{tikz}
\pagestyle{empty}

% \newcommand{\anno}{1} % starting year
% \newcommand{\target}{31} % ending year
% \newcommand{\alto}{3} % height

\tikzset{
    anno/.store in=\anno,
    target/.store in=\target,
    alto/.store in=\alto,
    start date/.code args = {#1/#2}{
        \def\dstart{#1}
        \def\mstart{#2}
    },
    end date/.code args = {#1/#2}{
        \def\dend{#1}
        \def\mend{#2}
    },
    event color/.style = {
        fill=#1!50, draw=#1,
    },
    anno=1, target=1, alto=1,% here are the defaults
    auto x/.style={x=16/(\target-1-\anno)*1cm},
}



\newcommand{\eventpoint}[2][]{
    \begin{scope}[#1]
    \pgfmathsetmacro{\mmstart}{((13-\mstart)*4)}
    \pgfmathsetmacro{\mmend}{((13-\mend)*4)}
    \ifnum\mstart=\mend
       \filldraw (\dstart, \mmstart ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
    \else
       \filldraw (\dstart, \mmstart ) rectangle (31, \mmstart+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
      \filldraw (0, \mmend ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
    \fi
    \end{scope}
}

\begin{document}
\centering
\begin{tikzpicture}[
    anno=1, target=31, alto=3,
    auto x, y=5mm,
]

\pgfmathsetmacro{\myend}{\target+1-\anno}

%creating the sublines needed and formating them
\foreach \y in {0,4,8,12,16,20,24,28,32,36,40,44,48}{
\draw[|->, -latex] (-.5,\y) -- (\myend+.5,\y);
\path (0,0) -- (0,\alto);
\foreach \x [evaluate=\x as \day using int(\x)] in {0,10,20,30}{
    \draw (\x,\y) node[below=7pt,font=\footnotesize] {$\day$};
    \draw (\x,\y -.2) -- (\x,\y +.2);
    \draw[loosely dotted] (\x,\y +.2) -- (\x,\y+ \alto-0.5);
}
\foreach \tick in {0,...,\myend}{
    \draw (\tick,\y +.1) -- (\tick,\y -.1);
}
}

%trying to add the events
\eventpoint[start date=15/7,end date=25/7,event color=green]{test}
\eventpoint[start date=17/8,end date=19/9,event color=red,yshift=5pt]{test 2}

\end{tikzpicture}
\end{document}

Highly recommended if you intend to extend your events' appearance

Wrap the code to produce an event into a pic definition (see manual).

  • Thank you very much for the help! I'm not familiar with scopes, or the usage of keys for that matter, but I'm certainly going to look into it after seeing this. – Sito Aug 27 '18 at 16:14
  • @Sito I am really very pleased that you have had a better response than mine. – Sebastiano Aug 27 '18 at 19:17
5

A bit answer with Mathcha. The work is not the best but it is similar to the image.

enter image description here

\documentclass[a4paper,12pt]{article}

\usepackage{tikz}

\begin{document}
\tikzset{every picture/.style={line width=0.75pt}} %set default line width to 0.75pt        

\begin{tikzpicture}[x=0.75pt,y=0.75pt,yscale=-1,xscale=1]
%uncomment if require: \path (0,300); %set diagram left start at 0, and has height of 300
\draw  [color={rgb, 255:red, 0; green, 0; blue, 0 }  ,draw opacity=1 ][fill={rgb, 255:red, 239; green, 100; blue, 215 }  ,fill opacity=0.86 ] (381,48.33) -- (459,48.33) -- (459,80.33) -- (381,80.33) -- cycle ;
\draw    (101.33,81.67) -- (459.83,80.67) ;
\draw [shift={(461.83,80.67)}, rotate = 539.8399999999999] [color={rgb, 255:red, 0; green, 0; blue, 0 }  ][line width=0.75]    (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29)   ;
\draw    (100.67,151) -- (459.17,150.01) ;
\draw [shift={(461.17,150)}, rotate = 539.8399999999999] [color={rgb, 255:red, 0; green, 0; blue, 0 }  ][line width=0.75]    (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29)   ;
\draw    (100.67,140.5) -- (100.67,161.5) ;
\draw    (101.33,71.16) -- (101.33,92.17) ;
\draw    (201.33,72.16) -- (201.33,93.17) ;
\draw    (300.33,72.16) -- (300.33,93.17) ;
\draw    (399.33,72.16) -- (399.33,93.17) ;
\draw    (201.33,140.16) -- (201.33,161.17) ;
\draw    (300.33,139.16) -- (300.33,160.17) ;
\draw    (400.33,137.16) -- (400.33,158.17) ;
\draw  [color={rgb, 255:red, 0; green, 0; blue, 0 }  ,draw opacity=1 ][fill={rgb, 255:red, 126; green, 211; blue, 33 }  ,fill opacity=1 ] (139,49.33) -- (242,49.33) -- (242,81.33) -- (139,81.33) -- cycle ;
\draw  [color={rgb, 255:red, 0; green, 0; blue, 0 }  ,draw opacity=1 ][fill={rgb, 255:red, 248; green, 231; blue, 28 }  ,fill opacity=1 ] (219,17.33) -- (322,17.33) -- (322,49.33) -- (219,49.33) -- cycle ;
\draw  [color={rgb, 255:red, 0; green, 0; blue, 0 }  ,draw opacity=1 ][fill={rgb, 255:red, 239; green, 100; blue, 215 }  ,fill opacity=0.86 ] (100.67,119) -- (159.5,119) -- (159.5,151) -- (100.67,151) -- cycle ;
\draw    (341.33,140.16) -- (341.33,161.17) ;
\draw    (341.33,140.16) -- (374.33,120.5) ;
\draw (70,74) node  [align=left] {Apr.};
\draw (70,147) node  [align=left] {May};
\draw (101,102) node  [align=left] {1};
\draw (200,103) node  [align=left] {10};
\draw (299,102) node  [align=left] {20};
\draw (400,101) node  [align=left] {30};
\draw (102,172) node  [align=left] {1};
\draw (201,173) node  [align=left] {10};
\draw (300,172) node  [align=left] {20};
\draw (401,171) node  [align=left] {30};
\draw (189,66) node  [align=left] {event 1};
\draw (266,33) node  [align=left] {event 2};
\draw (420,64) node  [align=left] {event 3};
\draw (129,135) node  [align=left] {event 3};
\draw (405,119) node  [align=left] {event 4};
\end{tikzpicture}
\end{document}
  • 1
    I didn't even think about using Mathcha.. So thank you for suggesting that. – Sito Aug 27 '18 at 10:25
  • I have seen that your question it non haven't any answer and I have created an approximate graph :-). Regards. – Sebastiano Aug 27 '18 at 10:46

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.