[Tex/LaTex] Recreating the xkcd Movie Narrative Chart

diagramsfunpathstikz-pgf

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:

enter image description here

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:

enter image description here

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}

Best Answer

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:

semi-random path

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:

semi random paths using plot

If you were to parameterize the height and add some randomness, You should be able to get relatively close to the xkcd graphic.