5

I am using code by @szantaii from How can you create a vertical timeline?

I know there other timeline code in Latex, but I like to use the above solution, since the vertical timeline has the actual distance between the years proportional to the actual physical difference in the years.

This gives the vertical time line a more realistic layout by showing how long the time is between the entries.

It is the only Latex code I could find which does this scaling.

The only issue is that, if the entry itself contains too much text, it tends to clobber (overflow) into the next entry.

I do not know enough Tikz to modify the code to fix this problem.

I will post a complete MWE below. The code is the same as in the above link, but I added my own timeline entries to show the problem. (Added fbox around each entry to make it more clear what the problem is).

I tried to add \vspace between the entries, but that had no effect.

\documentclass[10pt]{article}

%code by szantaii from 
%https://tex.stackexchange.com/questions/196794/how-can-you-create-a-vertical-timeline#196808

\usepackage[paperwidth=210mm,%
    paperheight=297mm,%
    tmargin=7.5mm,%
    rmargin=7.5mm,%
    bmargin=7.5mm,%
    lmargin=7.5mm,
    vscale=1,%
    hscale=1]{geometry}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\usepackage{tikz}

\usetikzlibrary{arrows, calc, decorations.markings, positioning}

\pagestyle{empty}

\makeatletter
\newenvironment{timeline}[6]{%
    % #1 is startyear
    % #2 is tlendyear
    % #3 is yearcolumnwidth
    % #4 is rulecolumnwidth
    % #5 is entrycolumnwidth
    % #6 is timelineheight

    \newcommand{\startyear}{#1}
    \newcommand{\tlendyear}{#2}

    \newcommand{\yearcolumnwidth}{#3}
    \newcommand{\rulecolumnwidth}{#4}
    \newcommand{\entrycolumnwidth}{#5}
    \newcommand{\timelineheight}{#6}

    \newcommand{\templength}{}

    \newcommand{\entrycounter}{0}

    % https://tex.stackexchange.com/questions/85528/checking-whether-or-not-a-node-has-been-previously-defined
    % https://tex.stackexchange.com/questions/37709/how-can-i-know-if-a-node-is-already-defined
    \long\def\ifnodedefined##1##2##3{%
        \@ifundefined{pgf@sh@ns@##1}{##3}{##2}%
    }

    \newcommand{\ifnodeundefined}[2]{%
        \ifnodedefined{##1}{}{##2}
    }

    \newcommand{\drawtimeline}{%
        \draw[timelinerule] (\yearcolumnwidth+5pt, 0pt) -- (\yearcolumnwidth+5pt, -\timelineheight);
        \draw (\yearcolumnwidth+0pt, -10pt) -- (\yearcolumnwidth+10pt, -10pt);
        \draw (\yearcolumnwidth+0pt, -\timelineheight+15pt) -- (\yearcolumnwidth+10pt, -\timelineheight+15pt);

        \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(\startyear, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
        \node[year] (year-\startyear) at (\yearcolumnwidth, \templength) {\startyear};

        \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(\tlendyear, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
        \node[year] (year-\tlendyear) at (\yearcolumnwidth, \templength) {\tlendyear};
    }

    \newcommand{\entry}[2]{%
        % #1 is the year
        % #2 is the entry text

        \pgfmathtruncatemacro{\lastentrycount}{\entrycounter}
        \pgfmathtruncatemacro{\entrycounter}{\entrycounter + 1}

        \ifdim \lastentrycount pt > 0 pt%
            \node[entry] (entry-\entrycounter) [below of=entry-\lastentrycount] {##2};
        \else%
            \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(\startyear, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
            \node[entry] (entry-\entrycounter) at (\yearcolumnwidth+\rulecolumnwidth+10pt, \templength) {##2};
        \fi

        \ifnodeundefined{year-##1}{%
            \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(##1, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
            \draw (\yearcolumnwidth+2.5pt, \templength) -- (\yearcolumnwidth+7.5pt, \templength);
            \node[year] (year-##1) at (\yearcolumnwidth, \templength) {##1};
        }

        \draw ($(year-##1.east)+(2.5pt, 0pt)$) -- ($(year-##1.east)+(7.5pt, 0pt)$) -- ($(entry-\entrycounter.west)-(5pt,0)$) -- (entry-\entrycounter.west);
    }

    \newcommand{\plainentry}[2]{% plainentry won't print date in the timeline
        % #1 is the year
        % #2 is the entry text

        \pgfmathtruncatemacro{\lastentrycount}{\entrycounter}
        \pgfmathtruncatemacro{\entrycounter}{\entrycounter + 1}

        \ifdim \lastentrycount pt > 0 pt%
            \node[entry] (entry-\entrycounter) [below of=entry-\lastentrycount] {##2};
        \else%
            \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(\startyear, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
            \node[entry] (entry-\entrycounter) at (\yearcolumnwidth+\rulecolumnwidth+10pt, \templength) {##2};
        \fi

        \ifnodeundefined{invisible-year-##1}{%
            \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(##1, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
            \draw (\yearcolumnwidth+2.5pt, \templength) -- (\yearcolumnwidth+7.5pt, \templength);
            \node[year] (invisible-year-##1) at (\yearcolumnwidth, \templength) {};
        }

        \draw ($(invisible-year-##1.east)+(2.5pt, 0pt)$) -- ($(invisible-year-##1.east)+(7.5pt, 0pt)$) -- ($(entry-\entrycounter.west)-(5pt,0)$) -- (entry-\entrycounter.west);
    }

    \begin{tikzpicture}
        \tikzstyle{entry} = [%
            align=left,%
            text width=\entrycolumnwidth,%
            node distance=10mm,%
            anchor=west]
        \tikzstyle{year} = [anchor=east]
        \tikzstyle{timelinerule} = [%
            draw,%
            decoration={markings, mark=at position 1 with {\arrow[scale=1.5]{latex'}}},%
            postaction={decorate},%
            shorten >=0.4pt]

        \drawtimeline
}
{
    \end{tikzpicture}
    \let\startyear\@undefined
    \let\tlendyear\@undefined
    \let\yearcolumnwidth\@undefined
    \let\rulecolumnwidth\@undefined
    \let\entrycolumnwidth\@undefined
    \let\timelineheight\@undefined
    \let\entrycounter\@undefined
    \let\ifnodedefined\@undefined
    \let\ifnodeundefined\@undefined
    \let\drawtimeline\@undefined
    \let\entry\@undefined
}
\makeatother


\begin{document}
%added this below. This was not in the original code.

\begin{timeline}{1625}{1671}{2cm}{2.5cm}{14cm}{10cm}
\entry{1625}{\fbox{\parbox{\textwidth}{Pietro Mengoli. Alternative proof that harmonic series diverges}}}
\entry{1638}{\fbox{\parbox{\textwidth}{James Gregory. Born in Drumoak, United Kingdom. Scottish mathematician. Taylor series}}}
\entry{1643}{\fbox{\parbox{\textwidth}{Isaac Newton. Born in Woolsthorpe, Lincolnshire, England}}}
\entry{1646}{\fbox{\parbox{\textwidth}{Gottfried Wilhelm Leibniz. Born in Leipzig, Germany}}}
\entry{1655}{\fbox{\parbox{\textwidth}{Jacob Bernoulli. Born in Basel, Switzerland}}}
\entry{1667}{\fbox{\parbox{\textwidth}{Johann Bernoulli. Born in Basel, Switzerland}}}
 %note: adding \vspace{20pt} here did not fix it.
\entry{1669}{\fbox{\parbox{\textwidth}{Isaac Newton. Writes major Work on Calculus. "De analysi" or
"On Analysis by Equations with an infinite number of terms".
First time the series for $\sin(x)$ and $\cos(x)$ derived. Also
gives Quadrature rules for first time. This work was 
actually published in 1711}}}
\entry{1671}{\fbox{\parbox{\textwidth}{James Gregory. Finds power series for $\arctan(x)$}}}
\end{timeline}

\end{document}

When I compile the above using lualatex, this is the output:

enter image description here

5

Modify below of=entry to below=of entry, and change node distance=10mm to node distance=1mm. below of=.. is deprecated syntax, where the distance is calculated between node centers, while with below=of .. (requires the positioning library) the distance is calculated between node borders by default.

I also removed the use of \tikzstyle, as that is considered deprecated as well.

Finally, if you want borders around the text, don't use \fbox like that, but add draw to the entry style.

\documentclass[10pt]{article}

%code by szantaii from 
%https://tex.stackexchange.com/questions/196794/how-can-you-create-a-vertical-timeline#196808

\usepackage[paperwidth=210mm,%
    paperheight=297mm,%
    tmargin=7.5mm,%
    rmargin=7.5mm,%
    bmargin=7.5mm,%
    lmargin=7.5mm,
    vscale=1,%
    hscale=1]{geometry}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\usepackage{tikz}

\usetikzlibrary{arrows, calc, decorations.markings, positioning}

\pagestyle{empty}

\makeatletter
\newenvironment{timeline}[6]{%
    % #1 is startyear
    % #2 is tlendyear
    % #3 is yearcolumnwidth
    % #4 is rulecolumnwidth
    % #5 is entrycolumnwidth
    % #6 is timelineheight

    \newcommand{\startyear}{#1}
    \newcommand{\tlendyear}{#2}

    \newcommand{\yearcolumnwidth}{#3}
    \newcommand{\rulecolumnwidth}{#4}
    \newcommand{\entrycolumnwidth}{#5}
    \newcommand{\timelineheight}{#6}

    \newcommand{\templength}{}

    \newcommand{\entrycounter}{0}

    % https://tex.stackexchange.com/questions/85528/checking-whether-or-not-a-node-has-been-previously-defined
    % https://tex.stackexchange.com/questions/37709/how-can-i-know-if-a-node-is-already-defined
    \long\def\ifnodedefined##1##2##3{%
        \@ifundefined{pgf@sh@ns@##1}{##3}{##2}%
    }

    \newcommand{\ifnodeundefined}[2]{%
        \ifnodedefined{##1}{}{##2}
    }

    \newcommand{\drawtimeline}{%
        \draw[timelinerule] (\yearcolumnwidth+5pt, 0pt) -- (\yearcolumnwidth+5pt, -\timelineheight);
        \draw (\yearcolumnwidth+0pt, -10pt) -- (\yearcolumnwidth+10pt, -10pt);
        \draw (\yearcolumnwidth+0pt, -\timelineheight+15pt) -- (\yearcolumnwidth+10pt, -\timelineheight+15pt);

        \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(\startyear, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
        \node[year] (year-\startyear) at (\yearcolumnwidth, \templength) {\startyear};

        \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(\tlendyear, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
        \node[year] (year-\tlendyear) at (\yearcolumnwidth, \templength) {\tlendyear};
    }

    \newcommand{\entry}[2]{%
        % #1 is the year
        % #2 is the entry text

        \pgfmathtruncatemacro{\lastentrycount}{\entrycounter}
        \pgfmathtruncatemacro{\entrycounter}{\entrycounter + 1}

        \ifdim \lastentrycount pt > 0 pt%
            \node[entry] (entry-\entrycounter) [below=of entry-\lastentrycount] {##2};
        \else%
            \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(\startyear, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
            \node[entry] (entry-\entrycounter) at (\yearcolumnwidth+\rulecolumnwidth+10pt, \templength) {##2};
        \fi

        \ifnodeundefined{year-##1}{%
            \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(##1, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
            \draw (\yearcolumnwidth+2.5pt, \templength) -- (\yearcolumnwidth+7.5pt, \templength);
            \node[year] (year-##1) at (\yearcolumnwidth, \templength) {##1};
        }

        \draw ($(year-##1.east)+(2.5pt, 0pt)$) -- ($(year-##1.east)+(7.5pt, 0pt)$) -- ($(entry-\entrycounter.west)-(5pt,0)$) -- (entry-\entrycounter.west);
    }

    \newcommand{\plainentry}[2]{% plainentry won't print date in the timeline
        % #1 is the year
        % #2 is the entry text

        \pgfmathtruncatemacro{\lastentrycount}{\entrycounter}
        \pgfmathtruncatemacro{\entrycounter}{\entrycounter + 1}

        \ifdim \lastentrycount pt > 0 pt%
            \node[entry] (entry-\entrycounter) [below of=entry-\lastentrycount] {##2};
        \else%
            \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(\startyear, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
            \node[entry] (entry-\entrycounter) at (\yearcolumnwidth+\rulecolumnwidth+10pt, \templength) {##2};
        \fi

        \ifnodeundefined{invisible-year-##1}{%
            \pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(##1, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
            \draw (\yearcolumnwidth+2.5pt, \templength) -- (\yearcolumnwidth+7.5pt, \templength);
            \node[year] (invisible-year-##1) at (\yearcolumnwidth, \templength) {};
        }

        \draw ($(invisible-year-##1.east)+(2.5pt, 0pt)$) -- ($(invisible-year-##1.east)+(7.5pt, 0pt)$) -- ($(entry-\entrycounter.west)-(5pt,0)$) -- (entry-\entrycounter.west);
    }

    \begin{tikzpicture}[
       entry/.style={
            align=left,%
            text width=\entrycolumnwidth,%
            node distance=1mm,%  
            anchor=west,
            draw % <------ draw node outline
       },
       year/.style={anchor=east},
       timelinerule/.style={
            draw,%
            decoration={markings, mark=at position 1 with {\arrow[scale=1.5]{latex'}}},%
            postaction={decorate},%
            shorten >=0.4pt}
    ]

        \drawtimeline
}
{
    \end{tikzpicture}
    \let\startyear\@undefined
    \let\tlendyear\@undefined
    \let\yearcolumnwidth\@undefined
    \let\rulecolumnwidth\@undefined
    \let\entrycolumnwidth\@undefined
    \let\timelineheight\@undefined
    \let\entrycounter\@undefined
    \let\ifnodedefined\@undefined
    \let\ifnodeundefined\@undefined
    \let\drawtimeline\@undefined
    \let\entry\@undefined
}
\makeatother


\begin{document}
%added this below. This was not in the original code.

\begin{timeline}{1625}{1671}{2cm}{2.5cm}{14cm}{10cm}
\entry{1625}{Pietro Mengoli. Alternative proof that harmonic series diverges}
\entry{1638}{James Gregory. Born in Drumoak, United Kingdom. Scottish mathematician. Taylor series}
\entry{1643}{Isaac Newton. Born in Woolsthorpe, Lincolnshire, England}
\entry{1646}{Gottfried Wilhelm Leibniz. Born in Leipzig, Germany}
\entry{1655}{Jacob Bernoulli. Born in Basel, Switzerland}
\entry{1667}{Johann Bernoulli. Born in Basel, Switzerland}
\entry{1669}{Isaac Newton. Writes major Work on Calculus. "De analysi" or
"On Analysis by Equations with an infinite number of terms".
First time the series for $\sin(x)$ and $\cos(x)$ derived. Also
gives Quadrature rules for first time. This work was 
actually published in 1711}
\entry{1671}{James Gregory. Finds power series for $\arctan(x)$}
\end{timeline}

\end{document}

enter image description here

|improve this answer|||||
  • Thanks also. I've been testing your code. Just minor issue. Where there is only ONE year difference, the actual year is printed too close to the previous one. Is there a way to make min spacing a little larger? For example, if you change "1669" above to "1668", you'll see what I mean. Here is screen shot !Mathematica graphics I can't figure what I need to change for this. Thank you. – Nasser Sep 14 '19 at 7:20
  • @Nasser Quick fix: comment out \draw (\yearcolumnwidth+2.5pt, \templength) -- (\yearcolumnwidth+7.5pt, \templength); in the definition of \entry, and add \tikzset{year/.append style={yshift=-3pt}} between \entry{1667}...`` and \entry{1668}..`. – Torbjørn T. Sep 14 '19 at 8:28
  • @Nasser Sorry, should perhaps have said explicitly, but didn't think of it. Change the node distance that I set to 1mm. – Torbjørn T. Sep 14 '19 at 11:32
6

With simple tikzpicture:

enter image description here

\documentclass[10pt]{article}
\usepackage[a4paper, %showframe,
            margin=7.5mm]{geometry}
\usepackage[T1]{fontenc}
\usepackage{tikz}
\usetikzlibrary{arrows, chains, positioning}

\begin{document}
    \begin{center}
\begin{tikzpicture}[
node distance = 4mm and 22mm,
    start chain = Y going below
                    ]
\draw[-latex] (0,0) -- (0,-10);
\foreach \i [evaluate=\i as \iy using (\i-1625)]
    in {1625, 1638, 1643, 1646, 1655, 1667, 1669, 1671}
    \draw (2pt,-2*\iy mm) coordinate (y\i) -- ++ (-6pt,0) node[left] {\i};
    \begin{scope}[every node/.style = {draw,
                                       text width=0.77*\linewidth,
                                       align=left,
                                       on chain=Y}
                 ]
\node [right=of y1625]{Pietro Mengoli. 
             Alternative proof that harmonic series diverges};
\node{James Gregory. Born in Drumoak, United Kingdom. 
             Scottish mathematician. Taylor series};
\node{Isaac Newton. 
             Born in Woolsthorpe, Lincolnshire, England};
\node{Gottfried Wilhelm Leibniz. 
             Born in Leipzig, Germany};
\node{Jacob Bernoulli. 
             Born in Basel, Switzerland};
\node{Johann Bernoulli. 
             Born in Basel, Switzerland};
\node{Isaac Newton. 
             Writes major Work on Calculus. "De analysi" or
             "On Analysis by Equations with an infinite number of terms".
             First time the series for $\sin(x)$ and $\cos(x)$ derived. Also gives Quadrature rules for first time. This work was actually published in 1711};
\node{James Gregory. 
             Finds power series for $\arctan(x)$};
    \end{scope}
\foreach \i [count=\j] 
    in {1625, 1638, 1643, 1646, 1655, 1667, 1669, 1671}
    \draw (y\i) -- ++ (0.3,0) -- ([xshift=-4mm] Y-\j.west) -- (Y-\j);
\end{tikzpicture}
    \end{center}
\end{document}

addendum: Simplicity of code is payed with some small additional effort if you like to change time line. In above MWE I considered the following fact from showed image:

  • events are at least two years apart. If they are closer, than you need to increase differences between years to
\draw (2pt,-2.8*\iy mm) coordinate (y\i) -- ++ (-6pt,0) node[left] {\i};
  • the length of the arrow, which present time line is rounded to *
  • node distance is defined by "trial and error" method such, that all description of event are about evenly distributed along time line

Considering aforementioned your new example is:

\documentclass[10pt]{article}
\usepackage[a4paper, %showframe,
            margin=7.5mm]{geometry}
\usepackage[T1]{fontenc}
\usepackage{tikz}
\usetikzlibrary{arrows, chains, positioning}

\begin{document}
    \begin{center}
\begin{tikzpicture}[
node distance = 8mm and 22mm,   % <---
    start chain = Y going below
                    ]
\draw[-latex] (0,0) -- (0,-18);  % <---
\foreach \i [evaluate=\i as \iy using (\i-1625)]
    in {1625, 1638, 1643, 1646, 1655, 1667, 1669, 1671,1675,1676,1684,1687  }
    \draw (2pt,-2.8*\iy mm) coordinate (y\i) -- ++ (-6pt,0) node[left] {\i}; % <----
    \begin{scope}[every node/.style = {draw,
                                       text width=0.77*\linewidth,
                                       align=left,
                                       on chain=Y}
                 ]

\node [right=of y1625]{Pietro Mengoli.
             Alternative proof that harmonic series diverges};

\node{James Gregory. Born in Drumoak, United Kingdom.
             Scottish mathematician. Taylor series};

\node{Isaac Newton.
             Born in Woolsthorpe, Lincolnshire, England};

\node{Gottfried Wilhelm Leibniz.
             Born in Leipzig, Germany};

\node{Jacob Bernoulli.
             Born in Basel, Switzerland};

\node{Johann Bernoulli.
             Born in Basel, Switzerland};

\node{Isaac Newton.
             Writes major Work on Calculus. "De analysi" or
             "On Analysis by Equations with an infinite number of terms".
             First time the series for $\sin(x)$ and $\cos(x)$ derived. Also gives Quadrature rules for first time. This work was actually published in 1711};

\node{James Gregory.
             Finds power series for $\arctan(x)$};

\node{James Gregory.
        Died in Edinburgh, United Kingdom};

\node{Isaac Newton.
epistola prio letter Newton sends to Leibniz giving
for first time account of the Binomial series expansion.};

\node{Gottfried Wilhelm Leibniz.
Publish first paper on differential calculus. "A new method
for maxima and minima, and also tangents, which is impeded 
neither by fractional nor by irrational quantities, and a remarkable 
type of calculus for this"};

\node{Isaac Newton.
First edition of Principia Mathematica published};
\end{scope}
%
\foreach \i [count=\j]
    in {1625, 1638, 1643, 1646, 1655, 1667, 1669, 1671,1675,1676,1684,1687  }
    \draw (y\i) -- ++ (0.3,0) -- ([xshift=-4mm] Y-\j.west) -- (Y-\j);
\end{tikzpicture}
    \end{center}
\end{document}

enter image description here

|improve this answer|||||
  • The same problem you have with your original code. A possible solution is draw longer time line and define bigger space between years, for example instead 2*\iy mm you can select 3*\iy mm. Length of "timeline" is adopted to time difference. If you will change it, accordingly change the its length. – Zarko Sep 14 '19 at 7:11
  • Thank you. I will try to fix it. Tikz is too complicated for me :) but this is good improvement from before. – Nasser Sep 14 '19 at 7:16

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.