TikZ is a drawing language for LaTeX that can produce all sorts of diagrams, including commutative diagrams with the tikz-cd package, which is possibly the best package for commutative diagrams, at least with regards to typesetting quality and usability. Sometimes when you draw a diagram, though, you might want a little more programming language thrown in to make drawing easier. A classic example is a timeline. Though probably not useful for research math papers, a timeline could be helpful for a survey paper or history text.
Suppose you have a tab-delimited text file of dates of birthdays:
1809-02-12 Charles Darwin 1822-12-27 Louis Pasteur 1826-09-17 Bernhard Riemann 1877-02-07 Godfrey Harold Hardy 1845-03-03 Georg Cantor
You could draw them on a timeline in TikZ directly, but the problem is you’d have to worry about manually calculating how far down the line these dates are. This is a good case where writing a program in Python 3 that outputs the TikZ picture drawing commands is much easier and painless, especially if you need several timelines:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
#!/usr/bin/python3 import datetime import re from sys import argv #Constants monthNames = ["January", "Feburary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] #Data dates = [] description = [] lengthOfLine = 10 #Input of the form string "yyyy-mm-dd" def dashedToDate(dashed): dateArray = dashed.split('-') year = int(dateArray[0]) month = int(dateArray[1]) day = int(dateArray[2]) return datetime.date(year,month,day) if len(argv) > 1: data = open(argv[1],'r') else: data = open('dates.txt', 'r') while True: line = data.readline() if not line: break entry = line.split('\t') dates.append(dashedToDate(entry[0])) description.append(re.sub("\n","",entry[1])) data.close() # create file to put the TeX/Tikz code texfile = open('picture.tex','w') texfile.writelines("\\begin{tikzpicture}") # Styles used texfile.writelines("[datemarker/.style={circle,draw=black,fill=white,radius=4pt},\n") texfile.writelines("textlabel/.style={anchor=west,text height=1.7ex,text depth=.25ex}]\n") # Draw the background texfile.writelines("\\draw (0,0) -- (0,"+ str(lengthOfLine)+ ");\n") startDate = dates[0] endDate = dates[0] for x in range(len(dates)): if dates[x] < startDate: startDate = dates[x] if dates[x] > endDate: endDate = dates[x] span = (endDate - startDate).days # Draw the dates for x in range(len(dates)): diff = (dates[x] - startDate).days month = monthNames[dates[x].month-1] dateText = month+" "+str(dates[x].day)+", "+str(dates[x].year) yCoordOnLine = lengthOfLine - (diff/span)*lengthOfLine#!/usr/bin/python3 import datetime import re from sys import argv #Constants monthNames = ["January", "Feburary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] #Data dates = [] description = [] lengthOfLine = 10 #Input of the form string "yyyy-mm-dd" def dashedToDate(dashed): dateArray = dashed.split('-') year = int(dateArray[0]) month = int(dateArray[1]) day = int(dateArray[2]) return datetime.date(year,month,day) if len(argv) > 1: data = open(argv[1],'r') else: data = open('dates.txt', 'r') while True: line = data.readline() if not line: break entry = line.split('\t') dates.append(dashedToDate(entry[0])) description.append(re.sub("\n","",entry[1])) data.close() # create file to put the TeX/Tikz code texfile = open('picture.tex','w') texfile.writelines("\\begin{tikzpicture}") # Styles used texfile.writelines("[datemarker/.style={circle,draw=black,fill=white,radius=4pt},\n") texfile.writelines("textlabel/.style={anchor=west,text height=1.7ex,text depth=.25ex}]\n") # Draw the background texfile.writelines("\\draw (0,0) -- (0,"+ str(lengthOfLine)+ ");\n") startDate = dates[0] endDate = dates[0] for x in range(len(dates)): if dates[x] < startDate: startDate = dates[x] if dates[x] > endDate: endDate = dates[x] span = (endDate - startDate).days # Draw the dates for x in range(len(dates)): diff = (dates[x] - startDate).days month = monthNames[dates[x].month-1] dateText = month+" "+str(dates[x].day)+", "+str(dates[x].year) yCoordOnLine = lengthOfLine - (diff/span)*lengthOfLine textToPrint = dateText +": "+ description[x] texfile.writelines("\\node at (0, "+ str(yCoordOnLine)+ ") [datemarker] {};\n") texfile.writelines("\\draw (0.1, "+ str(yCoordOnLine)+ ") node [textlabel] {"+textToPrint+"};\n") texfile.writelines("\\end{tikzpicture}") texfile.close() textToPrint = dateText +": "+ description[x] texfile.writelines("\\node at (0, "+ str(yCoordOnLine)+ ") [datemarker] {};\n") texfile.writelines("\\draw (0.1, "+ str(yCoordOnLine)+ ") node [textlabel] {"+textToPrint+"};\n") texfile.writelines("\\end{tikzpicture}") texfile.close() |
What it does is read the file in, do all the calculations, and ouputs the following TikZ code into a file called “picture.tex”:
\begin{tikzpicture}[datemarker/.style={circle,draw=black,fill=white,radius=4pt},
textlabel/.style={anchor=west,text height=1.7ex,text depth=.25ex}]
\draw (0,0) — (0,10);
\node at (0, 10.0) [datemarker] {};
\draw (0.1, 10.0) node [textlabel] {Feburary 12, 1809: Charles Darwin};
\node at (0, 7.959890463917526) [datemarker] {};
\draw (0.1, 7.959890463917526) node [textlabel] {December 27, 1822: Louis Pasteur};
\node at (0, 7.412210051546392) [datemarker] {};
\draw (0.1, 7.412210051546392) node [textlabel] {September 17, 1826: Bernhard Riemann};
\node at (0, 0.0) [datemarker] {};
\draw (0.1, 0.0) node [textlabel] {Feburary 7, 1877: Godfrey Harold Hardy};
\node at (0, 4.697164948453608) [datemarker] {};
\draw (0.1, 4.697164948453608) node [textlabel] {March 3, 1845: Georg Cantor};
\end{tikzpicture}
You can then include it into a LaTeX document using the tikz package by using the comamnd “\input{picture.tex}” to get:
1 Comment
Whaat dude this is really cool code! hahahaha. Nice diagram.