21

Hello great TeX people :)

I am trying to create a timeline looking like

enter image description here

but with months down the side and with lines connected to dates.

I have been trying to modify the chronology package, but the "year" indication was way to deeply incooporated.

I have been trying with TikZ but unfortunately I really have not been able to produce anything close to the desired output.

How would you attack such a problem? how would you structure your code if trying to solve the same problem?

percusse
  • 157,807
Mathias
  • 313

3 Answers3

20

Here is a semi-automatic solution:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{matrix,calc,calendar}
\newcommand{\ts}{\textunderscore}
\begin{document}
\begin{tikzpicture}

\foreach \x[count=\xi from 4] in {1,...,5} {
\node[anchor=north,text width=2cm,align=center,font={\tiny\sffamily}] (time\x) at (0,-\x cm) {\pgfcalendarmonthname{\xi} 2012};}

\matrix (m) at (2,-1) [
anchor=north west,
matrix of nodes,
nodes={font=\sffamily\tiny,inner sep=0},
row sep=1pt,
column sep=2mm,
column 2/.style={text width=9cm,align=left}
]{
0.00000 &entering nautilus-main.c:main()\\
0.00222 &nautilus-main.c calling gnome\ts program\ts init()\\
0.16386 &nautilus\ts application\ts instance\ts init() calling signal\ts connect\ts on\ts gnome\ts vfs\ts get\ts volume\ts monitor\\
1.16386 &nautilus\ts application\ts instance\ts init() finished signal\ts connect\ts on\ts gnome\ts vfs\ts get\ts volume\ts monitor\\
1.16386 &nautilus\ts application\ts instance\ts init() had enough of calling signal\ts connect\ts on\ts gnome\ts vfs\ts get\ts volume\ts monitor\\
2.56386 &nautilus\ts application\ts instance\ts init() enjoying the idle\ts CPU\ts time\\
2.57386 &nautilus\ts application\ts instance\ts init() enjoying the idle\ts CPU\ts time\\
2.58386 &nautilus\ts application\ts instance\ts init() enjoying the idle\ts CPU\ts time\\
2.59386 &nautilus\ts application\ts instance\ts init() enjoying the idle\ts CPU\ts time\\
};
\foreach \x in {4,5} {\draw (m-\x-1.west) --++(-2mm,0) -- ([xshift=5mm]$(time1)!0.2!(time2)$) --++(-5mm,0);}
\foreach \x in {6,...,9} {\draw (m-\x-1.west) --++(-2mm,0) -- ([xshift=5mm]$(time2)!0.5!(time3)$) --++(-5mm,0);}
\end{tikzpicture}
\end{document}

enter image description here

Basically, we just draw a month list downwards on the left without too much automation. Then, we also put a matrix next to it. Then the remaining part is drawing the connections and how many of them related to a particular date node is also defined manually. You can modify further to suit your needs.

percusse
  • 157,807
  • Oh, thank you so much. This is perfect. I will work with this one and see how I can automate it a bit. Thanks :) – Mathias Jun 26 '12 at 11:39
19

Here's my solution. First you specify entries via \timeentry{time}{description}, afterwards you draw the timeline via \drawtimeline. It automatically scales to the height of your time entries. Between the lines of ===== there are a few parameters you can use to influence the apparance (spacing etc.). You could also alter the commands to use colors, thin/thick lines and other stuff:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc,arrows}

\newdimen\XCoord
\newdimen\YCoord

\newcommand*{\ExtractCoordinate}[1]{\path (#1); \pgfgetlastxy{\XCoord}{\YCoord};}%

\begin{document}

% ============================= modify these for altered appearence
\pgfmathsetmacro{\mintime}{0}
\pgfmathsetmacro{\maxtime}{15}
\newcommand{\timeunit}{Months}
\pgfmathtruncatemacro{\timeintervals}{15}
\pgfmathsetmacro{\scaleitemseparation}{4}
\pgfmathsetmacro{\timenodewidth}{2cm}
\newcounter{itemnumber}
\setcounter{itemnumber}{0}
\newcommand{\lastnode}{n-0}
% ============================= 

\newcommand{\timeentry}[2]{% time, description
\stepcounter{itemnumber}
\node[below right,minimum width=\timenodewidth, text width=\timenodewidth-1mm] (n-\theitemnumber) at (\lastnode.south west) {#1};
\node[right] at (n-\theitemnumber.east) {#2};

\edef\lastnode{n-\theitemnumber}

\expandafter\edef\csname nodetime\theitemnumber \endcsname{#1}
}

\newcommand{\drawtimeline}{%
    \draw[very thick,-latex] (0,0) -- ($(\lastnode.south west)-(\scaleitemseparation,0)+(0,-1)$);
    \ExtractCoordinate{n-\theitemnumber.south}
    \pgfmathsetmacro{\yposition}{\YCoord/28.452755}
    \foreach \x in {1,...,\theitemnumber}
    {   \pgfmathsetmacro{\timeposition}{\yposition/(\maxtime-\mintime)*\csname nodetime\x \endcsname}
        %\node[right] at (0,\timeposition) {\yposition};
        \draw (0,\timeposition) -- (0.5,\timeposition) -- ($(n-\x.west)-(0.5,0)$) -- (n-\x.west);
    }
    \foreach \x in {0,...,\timeintervals}
    {   \pgfmathsetmacro{\labelposition}{\yposition/(\maxtime-\mintime)*\x}
        \node[left] (label-\x) at (-0.2,\labelposition) {\x\ \timeunit};
        \draw (label-\x.east) -- ++ (0.2,0);
    }   
}

\begin{tikzpicture}
\node[inner sep=0] (n-0) at (\scaleitemseparation,0) {};
\timeentry{1}{The first entry.}
\timeentry{1.2}{The second entry.}
\timeentry{1.23456}{The third entry.}
\timeentry{3}{Entry number \theitemnumber}
\timeentry{5}{Entry number \theitemnumber}
\timeentry{5.1}{Entry number \theitemnumber}
\timeentry{5.2}{Entry number \theitemnumber}
\timeentry{5.3}{Entry number \theitemnumber}
\timeentry{5.4}{Entry number \theitemnumber}
\timeentry{5.5}{Entry number \theitemnumber}
\timeentry{5.6}{Entry number \theitemnumber}
\timeentry{6}{Entry number \theitemnumber}
\timeentry{7}{Entry number \theitemnumber}
\timeentry{8}{Entry number \theitemnumber}
\timeentry{9}{Entry number \theitemnumber}
\timeentry{10}{Entry number \theitemnumber}
\timeentry{11}{Entry number \theitemnumber}
\timeentry{11.1}{Entry number \theitemnumber}
\timeentry{11.2}{Entry number \theitemnumber}
\timeentry{11.3}{Entry number \theitemnumber}
\timeentry{11.5}{Entry number \theitemnumber}
\timeentry{11.7}{Entry number \theitemnumber}
\timeentry{11.9}{Entry number \theitemnumber}
\timeentry{13}{Entry number \theitemnumber}
\timeentry{15}{Entry number \theitemnumber}
\drawtimeline
\end{tikzpicture}

\end{document}

enter image description here

Tom Bombadil
  • 40,123
  • Tom, I was wondering... What part of your code tells Tikz to place the nodes one below the other one? I'd like to do this automatically with my own code but I can't really understand. :P – Alenanno Oct 02 '13 at 11:00
  • Well worth a texample.net post. – Forkrul Assail Oct 02 '13 at 14:22
  • @Alenanno: Each node gets a number (\node[right] at (n-\theitemnumber.east) {#2};). The last number is constantly updated via a counter (\edef\lastnode{n-\theitemnumber}). Then you simply draw the new node below right of the last node (\node[below right,minimum width=\timenodewidth, text width=\timenodewidth-1mm] (n-\theitemnumber) at (\lastnode.south west) {#1};). As there's no first node initially, you need to set it manually (\node[inner sep=0] (n-0) at (\scaleitemseparation,0) {};) – Tom Bombadil Oct 04 '13 at 16:51
1

I really liked the solution of Tom Bombadil, but wanted to

  1. Add a toggle to decide if the time position (first argument to the \timeentry command) is displayed
  2. Increase the height of the output - it was very squashed
  3. Allow multiple timelines in one document (with different settings)

Hence, I modified Tom's solution:

\documentclass{article}

%TIMELINE START \usepackage{tikz,ifthen} \usetikzlibrary{calc,arrows}

\newboolean{displaytimeposition} \newcounter{itemnumber} \providecommand{\lastnode}{n-0}

\newdimen\XCoord \newdimen\YCoord

\newcommand*{\ExtractCoordinate}[1]{\path (#1); \pgfgetlastxy{\XCoord}{\YCoord};}%

\newcommand{\timeentry}[2]{% time, description \stepcounter{itemnumber} \node[below right,minimum width=\timenodewidth, text width=\timenodewidth-1mm] (n-\theitemnumber) at (\lastnode.south west) {\ifthenelse{\boolean{displaytimeposition}}{#1}{#2}}; \ifdisplaytimeposition \node[right] at (n-\theitemnumber.east) {#2}; \fi \edef\lastnode{n-\theitemnumber}

\expandafter\edef\csname nodetime\theitemnumber \endcsname{#1} }

\newcommand{\drawtimeline}{% \ExtractCoordinate{n-\theitemnumber.south} \pgfmathsetmacro{\yposition}{\YCoord/\timelineScaleY} \foreach \x in {1,...,\theitemnumber} { \pgfmathsetmacro{\timeposition}{\yposition/(\maxtime-\mintime)\csname nodetime\x \endcsname} %\node[right] at (0,\timeposition) {\yposition}; \draw (0,\timeposition) -- (0.5,\timeposition) -- ($(n-\x.west)-(0.5,0)$) -- (n-\x.west); } \foreach \x in {0,...,\timeintervals} { \pgfmathsetmacro{\labelposition}{\yposition/(\maxtime-\mintime)\x} \node[left] (label-\x) at (-0.2,\labelposition) {\x\ \timeunit}; \draw (label-\x.east) -- ++ (0.2,0); } \pgfmathsetmacro{\arrowend}{\yposition/(\maxtime-\mintime)*(\maxtime+1)} \draw[very thick,-latex] (0,0) -- (0, \arrowend); } %TIMELINE END

\begin{document}

Timeline 1: % ============================= modify these for altered appearance \setboolean{displaytimeposition}{false} \pgfmathsetmacro{\mintime}{1} \pgfmathsetmacro{\maxtime}{6} \providecommand{\timeunit}{Months} \pgfmathtruncatemacro{\timeintervals}{6} \pgfmathsetmacro{\scaleitemseparation}{2} \pgfmathsetmacro{\timenodewidth}{12cm} \providecommand{\timelineScaleY}{15} % lower numbers = larger height of timeline \setcounter{itemnumber}{0} % =============================

\begin{tikzpicture} \node[inner sep=0] (n-0) at (\scaleitemseparation,0) {}; \timeentry{0}{Start: Kickoff Meeting} \timeentry{0.5}{2 Weeks: Milestone 1} \timeentry{3}{3 Month: Milestone 2} \timeentry{3.5}{3.5 Month: Milestone 3} \timeentry{6}{6 Month: Milestone 4} \drawtimeline \end{tikzpicture} \end{document}

Timeline 2:

% ============================= modify these for altered appearance \setboolean{displaytimeposition}{true} \pgfmathsetmacro{\mintime}{1} \pgfmathsetmacro{\maxtime}{12} \providecommand{\timeunit}{Months} \pgfmathtruncatemacro{\timeintervals}{12} \pgfmathsetmacro{\scaleitemseparation}{2} \pgfmathsetmacro{\timenodewidth}{2cm} \providecommand{\timelineScaleY}{30} % lower numbers = larger height of timeline \setcounter{itemnumber}{0} % =============================

\begin{tikzpicture} \node[inner sep=0] (n-0) at (\scaleitemseparation,0) {}; \timeentry{0}{Entry \theitemnumber} \timeentry{2.5}{Entry \theitemnumber} \timeentry{8}{Entry \theitemnumber} \timeentry{10}{Entry \theitemnumber} \timeentry{12}{Entry \theitemnumber} \drawtimeline \end{tikzpicture}

\end{document}

preview

PStigerID
  • 11
  • 1