# how to make graphic timelines in mathematica

Hi does anyone know how to make timelines with mathematica?

Something like that would be great!

• Interesting ... but sounds like a convoluted requirement for Mma. Why don't use a hammer if you gotta nail a nail? Commented Jun 14, 2012 at 13:15
• @belisarius I think it's a reasonable task for Mathematica with some potentially interesting solutions. Commented Jun 14, 2012 at 13:17
• This is clearly doable, and not very difficult, but it's a lot of work. It's much more likely that you'll get an answer if you first try to implement it on your own, show us what you have, and ask about the specific point you got stuck at. Commented Jun 14, 2012 at 13:34
• In agreement with Szabolcs I would suggest you try out on your own first. Look up the documentation for Graphics, Line and Text, it's really just a task of combining these depending on your input list. Commented Jun 14, 2012 at 13:38
• This presentation, Dynamic Timeline Plots, by Daniel G Martinez, may be of interest. Commented Jun 14, 2012 at 14:40

## 3 Answers

I tried to do something similar a few months ago

The easiest way is to write several functions:

EventFrame function creates event lables

EventFrame[str_, {date_, height_}, OptionsPattern[FontSize -> 14]] :=
Graphics[{
Black, Thick, Line[{{date, height}, {date, 0}}],
Text[Framed[Style[str, FontSize -> OptionValue[FontSize]],
{Background -> White, FrameStyle -> Black,FrameMargins -> Automatic}], {date, height}]
}]


DateConv converts date {yr,mon,day} into single real number

Needs["Calendar"]
LeapYearQ[year_] := DateQ[{year, 2, 29}]
DateConv[y_, m_, d_]:=y+(DateDifference[{y},{y, m, d}]+1)/If[LeapYearQ[y], 366, 365]
DateConv[{y_, m_, d_}]:=y+(DateDifference[{y},{y, m, d}]+1)/If[LeapYearQ[y], 366, 365]


TimeLine function creates timeline

TimeLine[min_, max_] :=
Graphics[{
(* TimeLine *)
Black, Thick, Line[{{min, 0}, {max, 0}}],
(* year ticks *)
Thin, Table[Line[{{x, 0.5}, {x, 0}}], {x, min, max}],
(* year labels *)
Table[Text[Framed[Style[x, FontSize -> 20],
{Background -> White, FrameStyle -> White}], {x, 1}], {x, min, max}]
}]


Now all we need is a Show function. Use Pane for for easier viewing

Pane[Show[
EventFrame["Event 1", {DateConv[1988, 6, 2], 4}],
EventFrame["Event 2", {DateConv[1990, 8, 15], -2}],
(************************)
TimeLine[1985, 1995],
(************************)
AspectRatio -> 1/6, ImageSize -> {1400, 280}],
(************************)
ImageSize -> {550, 280}, Scrollbars -> {True, False}]


Output without Pane

Edit

EventFrame2 function

EventFrame2[str_, {date_, height_}, OptionsPattern[{FontSize -> 14, offsets -> {0, 0}}]] :=
Graphics[{
Thick,Line[{{date, height}, {date, 0}}],
Text[Framed[Style[Column@{Style[ToString[Floor[date]],
Bold,TextAlignment -> Left], str},
FontSize -> OptionValue[FontSize]],
{Background -> White, FrameStyle -> Black,FrameMargins -> Automatic}],
{date, height},OptionValue[offsets]]
} ]


Example

EventFrame2["Event 1", {DateConv[1988, 6, 2], 4}, offsets -> {-0.97, -0.5}]


Update 2014 - Mathematica 10

LeapYearQ is now a standard Mathematica function.

DateDifferencenow returns Quantity[n_,"Days"]

New DateConv function:

DateConv[y_, m_, d_] :=
y + (DateDifference[{y}, {y, m, d}][[1]] + 1)/If[LeapYearQ[y], 366, 365]

• Does this handle leap years? The division by 365 in DateConv makes me wonder. Commented Jun 14, 2012 at 22:25
• Thanks, I forgot about that. Added LeapYearQ function
– FDSg
Commented Jun 15, 2012 at 0:43
• Instead of DateConv[], you might consider the use of AbsoluteTime[]... Commented Jun 17, 2012 at 3:12
• this is fantastic. some ideas i'm going to try to implement: tooltip for difference between dates, title and eventually tagging. my original idea was to have certain events with tags like : event 1 - green tag, red tag, yellow tag; event 2 - green tag; event 3 - red tag; when red tag is selected only events 1 and 2 are displayed. in that vein. will begin work and modifications tonight
– user582
Commented Jun 19, 2012 at 23:40
• what exactly does the second DateConv[] function do? DateConv[{y_, m_, d_}]:=y+(DateDifference[{y},{y, m, d}]+1)/If[LeapYearQ[y], 366, 365]
– user582
Commented Jun 19, 2012 at 23:53

Based on data in Comm ACM. This took a while to only partially automate, largely through a helper function that spreads out the years:

diffuse[a_][years_List] :=
Module[{x0 = 1, x1 = Length[years], y0 = Min[years],
y1 = Max[years]},
years //
MapIndexed[ {#1, (((y1 - y0)/(x1 - x0))*(First[#2] - x0) +
y0) a + (#1) (1 - a)} &]];


diffuse maps a list of time points and spreads the interor points. The parameter a in principle can be any real number but higher values in [0,1] correspond to increasingly uniform spacing.

is defined in op form for use in Dataset:

data = {<|"Year" -> 1906, "Author" -> "Markov", "Contribution" -> "Markov theory"|>, <|"Year" -> 1907, "Author" -> "Perron","Contribution" -> "Perron theorem"|>, <|"Year" -> 1912, "Author" -> "Frobenius", "Contribution" -> "Perron-Frobenius theorem"|>, <|"Year" -> 1929, "Author" -> "von Mises", "Contribution" -> "Power method"|>, <|"Year" -> 1941,"Author" -> "Leontief",  "Contribution" -> "Econometric model"|>, <|"Year" -> 1949,  "Author" -> "Seeley", "Contribution" -> "Sociometric model"|>, <|"Year" -> 1952, "Author" -> "Wei", "Contribution" -> "Sport ranking model"|>, <|"Year" -> 1953, "Author" -> "Katz", "Contribution" -> "Sociometric model"|>, <|"Year" -> 1965, "Author" -> "Hubbell", "Contribution" -> "Sociometric model"|>, <|"Year" -> 1976,  "Author" -> "Pinsk, Narin",  "Contribution" -> "Bibliometric model"|>, <|"Year" -> 1998, "Author" -> "Kleinberg", "Contribution" -> "HITS"|>, <|"Year" -> 1998, "Author" -> "Brin, Page", "Contribution" -> "PageRank"|>} //Dataset;


Some years cluster:

data[All, "Year"] // Normal // NumberLinePlot


Make interpolation function (alternatively, can define an Association)

shift = data[
GroupBy[#Year &] /* Keys /* diffuse[0.35] /* Interpolation]


Values a ~ 1/3 work for this particular data and graphics w/ coorindated shift:

itemGraphics := {{Darker@Blue, Disk[{#Year, 0}, 0.25]},
{Thickness[0.001], Opacity[0.5],
BezierCurve[{{#Year, 0}, {#Year, 2}, {shift[#Year],
1 + 3/4}, {shift[#Year], 1 + 3/2}, {shift[#Year], 3}}]},
Text[Column[{Style[ToLowerCase@#Author, Darker@Blue,
FontSize -> 14, Bold],
Style[ToLowerCase@#Contribution, Small]},
Spacings -> 0], {shift[#Year], 4}, {-1, 1/2}, {1, 1},
BaseStyle -> None]} &


Layout w/o timeline shows label clashing :

data[Graphics, itemGraphics]


data[GroupBy[#Year &]][Values,
MapIndexed[Translate[#1, {0, 6 (First[#2] - 1)}] &], itemGraphics] //
Normal // Graphics[{#}, Axes -> {True, False},
PlotRange -> {{1900, 2020}, All},
TicksStyle -> Directive@{FontSize -> 15, Darker@Blue},
ImageSize -> 1000, ImagePadding -> 50] &


At a=0.7 balloon lines are stretched and spacing is more even but many labels are shifted way off past the years of future events.

This illustrates the interaction of ImageSize, AspectRatio, fonts, and data content (time clustering, ties, label dimensions (no easy way to get bounding boxes) seriously complicates automating layout.

• Pardon me, but how is this supposed to be used? Commented Jan 25, 2015 at 19:56
• @Mr.Wizard, you can similarly ask of many system functions, like how is BarChart supposed to be used in the real world when it never does exactly what you want. In any case added methods. Commented Jan 27, 2015 at 22:21
• @Mr.Wizard, btw, the Brin & Page baloon line ideally would curve around Kleinberg, but then that graphic component would have to be refactored one Level up. Also there's likely more modular approach naming and processing graphics in Associations. Commented Jan 27, 2015 at 22:28

As of Mathematica 10.1, creating a timeline is built-in with TimelinePlot[].

TimelinePlot[{
Labeled[Interval[{DateObject[{2010, 2, 1}], DateObject[{2013, 5, 4}]}], "label1"],
Labeled[DateObject[{2012, 4, 6}], "label2"],
Labeled[Interval[{DateObject[{2011, 3, 1}], DateObject[{2012, 12, 21}]}], "label3"]
}]


Lots of possibilities, looking at the documentation!

TimelinePlot[EntityClass["Movie", "BackToTheFutureFranchise"] -> "ReleaseDate"]


• As of 10.1 TimelinePlot doesn't have a robust layout engine. For example try to display all disasters from here airdisaster.com/cgi-bin/database.cgi, the labels crowd on top of each other so they become unreadable - this can only be avoided by selecting subsets or extreme AspectRatio`. Compare to GIS layout engines like Google Maps, where stree names may disappear on zoomout, but don't crowd each other. Commented Apr 27, 2015 at 17:17