# Recreating the xkcd Movie Narrative Chart

To teach myself TikZ, one of the things I've done is recreate interesting graphs/charts/etc. One of my bigger projects is attempting to recreate the xkcd Movie Narrative Charts comic.

Different elements of the chart probably warrant their own question, but my particular question now is how I would draw the lines in the Primer section of the chart (bottom right). I don't know if there's a good way to draw such messy, looping, interwoven paths. My solution as of now is to just use LaTeXDraw. Is that my only option here?

EDIT: I played around with some of the suggestions from the related thread linked in the comments. I liked the example from the TikZ/pgf manual that Jan Hlavacek suggested. I fiddled with the example some and I'm getting there, but some obstacles are still in my way. First, here's an example of a path I created: Here's code that created the above. What I was aiming for was not quite a 'random' path because I wanted the path to drift in certain directions at different times. I'm sure what I've written is not the most efficient way of doing it (if you have a better way of doing it, I'd appreciate the advice, but it's not my main concern at the moment):

\documentclass{minimal}
\usepackage{tikz}
\begin{document}

\pgfmathsetseed{1}
\begin{tikzpicture}[x=10pt,y=10pt,ultra thick,baseline,line cap=round]
\coordinate (current point) at (0,0);
\coordinate (old velocity) at (0,0);
\coordinate (new velocity) at (rand,rand);
\foreach \i in {0,1,...,15}
{
\draw[black] (current point)
.. controls ++([scale=-1]old velocity) and
++(new velocity) .. ++(1,rand)
coordinate (current point);
\coordinate (old velocity) at (new velocity);
\coordinate (new velocity) at (rand,rand);
\draw[black] (0,0)
.. controls ++([scale=-1]old velocity) and
++(new velocity) .. ++(1,rand)
coordinate (current point);
\coordinate (old velocity) at (new velocity);
\coordinate (new velocity) at (rand,rand);
}
\foreach \i in {0,1,...,15}
{
\draw[black] (current point)
.. controls ++([scale=-1]old velocity) and
++(new velocity) .. ++(rand,1)
coordinate (current point);
\coordinate (old velocity) at (new velocity);
\coordinate (new velocity) at (rand,rand);
}
\foreach \i in {0,1,...,5}
{
\draw[black] (current point)
.. controls ++([scale=-1]old velocity) and
++(new velocity) .. ++(-1,rand)
coordinate (current point);
\coordinate (old velocity) at (new velocity);
\coordinate (new velocity) at (rand,rand);
}
\foreach \i in {0,1,...,5}
{
\draw[black] (current point)
.. controls ++([scale=-1]old velocity) and
++(new velocity) .. ++(rand,-1)
coordinate (current point);
\coordinate (old velocity) at (new velocity);
\coordinate (new velocity) at (rand,rand);
}
\foreach \i in {0,1,...,15}
{
\draw[black] (current point)
.. controls ++([scale=-1]old velocity) and
++(new velocity) .. ++(1,rand-.5)
coordinate (current point);
\coordinate (old velocity) at (new velocity);
\coordinate (new velocity) at (rand,rand);
}
\end{tikzpicture}
\end{document}


Aesthetically it's still not there, but I believe all it takes now is some tweaking.

My problem now: I want to create three such paths that intertwine. I tried creating three paths within the foreach loop, but the coordinates of one path screws with the coordinates of another path in the subsequent loop -- I may just be doing something dumb. So, how would I the create image above with 3 intertwining paths instead of 1?

EDIT 2: I was able to get multiple paths working (I had just forgotten to change something after copy-pasting). Here's an example with two paths: The code for this is below. But again, this is far from ideal, so I'm wondering if there's a better way to accomplish this (or at least make my method more efficient).

\documentclass{minimal}
\usepackage{tikz}
\begin{document}

\pgfmathsetseed{1}
\begin{tikzpicture}[x=10pt,y=10pt,ultra thick,baseline,line cap=round]
\coordinate (current point) at (0,0);
\coordinate (current point2) at (0,10);
\coordinate (old velocity) at (0,0);
\coordinate (old velocity2) at (0,10);
\coordinate (new velocity) at (rand,rand);
\coordinate (new velocity2) at (rand,rand);
\foreach \i in {0,1,...,15}
{
\draw[black] (current point)
.. controls ++([scale=-1]old velocity) and
++(new velocity) .. ++(1,rand)
coordinate (current point);
\coordinate (old velocity) at (new velocity);
\coordinate (new velocity) at (rand,rand);
\draw[red] (current point2)
.. controls ++([scale=-1]old velocity2) and
++(new velocity2) .. ++(1,rand-.5)
coordinate (current point2);
\coordinate (old velocity2) at (new velocity2);
\coordinate (new velocity2) at (rand,rand);
}
\foreach \i in {0,1,...,15}
{
\draw[black] (current point)
.. controls ++([scale=-1]old velocity) and
++(new velocity) .. ++(rand,1)
coordinate (current point);
\coordinate (old velocity) at (new velocity);
\coordinate (new velocity) at (rand,rand);
\draw[red] (current point2)
.. controls ++([scale=-1]old velocity2) and
++(new velocity2) .. ++(1,rand+.5)
coordinate (current point2);
\coordinate (old velocity2) at (new velocity2);
\coordinate (new velocity2) at (rand,rand);
}
\end{tikzpicture}
\end{document}

• Believe it or not this question may be a duplicate: Drawing random paths in TikZ. – Alan Munn Oct 29 '11 at 0:14
• Well, I could definitive help you with the 12 Angry Man chart! – Martin Scharrer Oct 29 '11 at 0:22
• @AlanMunn Thanks for pointing that one out! For some reason, 'random path' wasn't one of my many searches before asking this. One thing that may be a little different is that I don't want the paths to be truly random since I want them to each reach a certain distance to the right. EDIT: Jake's answer in that thread may actually help. – user6967 Oct 29 '11 at 0:43
• @MikeWierzbicki: Did that question help? If so, we'll close this as a duplicate for housekeeping reasons. If not, could you elaborate on what doesn't work? At the moment, this question has no official answer, but it's not clear if any further action is needed. – Andrew Stacey Nov 1 '11 at 7:53
• Could you post your code that didn't work? Which foreach loop did you put the three paths in? – Andrew Stacey Nov 2 '11 at 10:10

I'll add this as an anwer, since it won't fit in a comment. The basic idea is to define some path segments, like loops, bumps, figures eight, etc. With the basic rule that they start and end at the same height. Then we can construct a path between two nodes on the same height, by linking these segments together. If we need to bridge a difference in height, we could add a parameter to the shapes to determine the offset in height. By creating more complicated segments and perhaps randomizing their parameters, we can obtain a relatively random looking path, while still having a guarantee that it will start and end at our nodes. A small example:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing, calc}
\begin{document}
\def\dloop#1#2#3{
\draw[squig] (curr) -- ++(#1,0) arc(-90:270:#2) -- ++(#3,0);
\coordinate (curr) at ($(curr) + (#1,0) + (#3,0)$);
}
\def\dhump#1{
\pgfmathsetmacro{\absone}{abs(#1)}
\draw[squig] (curr) .. controls ($(curr) + (.7*\absone,#1)$) .. ++(1.4*\absone,0);
\coordinate (curr) at ($(curr) + (1.4*\absone,0)$);
}
\def\dnor#1{
\draw[squig] (curr) -- ++(#1,0);
\coordinate (curr) at ($(curr) +(#1,0)$);
}
\begin{tikzpicture}[squig/.style={decorate, decoration={random steps,segment length=2pt,amplitude=.5pt}}]
\coordinate (curr) at (0,0);
\node[anchor=east] at (curr) {start};
\dnor{1}
\dloop{.2}{.7}{0} \dloop{0}{.77}{.5}
\dhump{1}
\dhump{-.5}
\dhump{2}
\dnor{.5}
\dloop{.1}{.5}{0}\dloop{0.05}{.55}{0.08}\dloop{.02}{.48}{.2}
\dnor{1}
\node[anchor=west] at (curr) {end};
\end{tikzpicture}
\end{document}


And the resulting document: Update: I saw Jake's post in Easy curves in TikZ and that made me think that this could be apllied here to mimic the lines in the xkcd graphic. Sticking with the idea of using path segments the output can be made to look significantly better. The code is as follows:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}
\def\twirl{(curr) ($(curr)+(.5,.2)$) ($(curr)+(1,.5)$) ($(curr)+(1,1)$) ($(curr)+(0,1.5)$) ($(curr)+(-1,1)$) ($(curr)+(-1.25,0)$)   ($(curr)+(-1,-.5)$) ($(curr)+(0,-1)$) ($(curr)+(1,0)$) ($(curr)+(1.25,0)$)}
\def\figeight{(curr) ($(curr)+(1,1)$) ($(curr)+(2,1)$) ($(curr)+(2.5,0)$) ($(curr)+(2,-1)$) ($(curr)+(-1,1)$) ($(curr)+(-2,1)$) ($(curr)+(-2.5,0)$) ($(curr)+(-2,-1)$) ($(curr)+(-1,-1)$) ($(curr)+(1,0)$) ($(curr)+(1.25,0)$)}
\def\nor{(curr) ($(curr)+(1.25,0)$)}
\def\start{(curr) ($(curr)+(.5,0)$) ($(curr)+(1,.25)$) ($(curr)+(1.5,0)$) ($(curr)+(2,0)$)}
\def\nushape{(curr) ($(curr)+(.2,.5)$) ($(curr)+(.5,.75)$) ($(curr)+(.8,.5)$) ($(curr)+(1,0)$) ($(curr)+(1.5,-1)$) ($(curr)+(2.5,0)$) ($(curr)+(2.5,1)$) ($(curr)+(2.25,1.2)$) ($(curr)+(2,.5)$) ($(curr)+(2.5,0)$) ($(curr)+(2.75,0)$)}
\begin{tikzpicture}
\coordinate (curr) at (0,0);
\path [draw, rounded corners] node[anchor=east] {start} plot[smooth,tension=1] coordinates {\start} coordinate (curr)
\foreach \x in {\nushape,\twirl,\nor,\figeight,\twirl,\nor,\figeight,\start}{
-- plot [smooth, tension=.5] coordinates {\x}
coordinate (curr)
} node[anchor=west] {end};

\end{tikzpicture}
\end{document}


The result then looks like this: If you were to parameterize the height and add some randomness, You should be able to get relatively close to the xkcd graphic.

• That is excellent. The 'easy curves' post is indeed a big help. I believe what you've given me will do the job. Thanks for your time! – user6967 Nov 4 '11 at 18:23