# 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? – Dr. belisarius Jun 14 '12 at 13:15
@belisarius I think it's a reasonable task for Mathematica with some potentially interesting solutions. – Mr.Wizard Jun 14 '12 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. – Szabolcs Jun 14 '12 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. – jVincent Jun 14 '12 at 13:38
This presentation, Dynamic Timeline Plots, by Daniel G Martinez, may be of interest. – TomD Jun 14 '12 at 14:40

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. – Verbeia Jun 14 '12 at 22:25
Thanks, I forgot about that. Added LeapYearQ function – FDSg Jun 15 '12 at 0:43
Instead of DateConv[], you might consider the use of AbsoluteTime[]... – J. M. Jun 17 '12 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 Jun 19 '12 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 Jun 19 '12 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? – Mr.Wizard Jan 25 '15 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. – alancalvitti Jan 27 '15 at 22:21
Thanks for the update. +1 – Mr.Wizard Jan 27 '15 at 22:24
@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. – alancalvitti Jan 27 '15 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. – alancalvitti Apr 27 '15 at 17:17