# How to draw Brownian motions in tikz/pgf

Here I want to draw some Brownian motions in tikz, like this: Furthermore, I want to truncate the trajectory of Brownian motion, like this:

I have tried many times with random functions in tikz, but always fail.

BTW, the figures uploaded are screenshots from "Brownian Motion - Draft version of May 25, 2008" written by Peter Mörters and Yuval Peres.

-
Related: Drawing random paths in TikZ – Richard Terrett Jun 15 '12 at 15:36
Why no accept answers? – leo Jun 21 '12 at 19:38
@leo Sorry, how to accept the answer? – XIAO Lishun Jun 23 '12 at 10:18
See here – leo Jun 23 '12 at 13:33

How about this? It's pseudo random, but you can make it repeatable by setting \pgfmathsetseed{integer}:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}

\begin{document}

\newcommand{\Emmett}[5]{% points, advance, rand factor, options, end label
\draw[#4] (0,0)
\foreach \x in {1,...,#1}
{   -- ++(#2,rand*#3)
}
node[right] {#5};
}

\begin{tikzpicture}
\draw[help lines] (0,-5) grid (15,5);
\Emmett{750}{0.02}{0.2}{red}{first one}
\Emmett{750}{0.02}{0.2}{green}{second one}
\Emmett{750}{0.02}{0.2}{blue}{third one}
\end{tikzpicture}

%\pgfmathsetseed{1337}

\end{document}


Edit 1: Truncated is also doable:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}

\begin{document}

\newcommand{\Emmett}[5]{% points, advance, rand factor, options, end label
\draw[#4] (0,0)
\foreach \x in {1,...,#1}
{   -- ++(#2,rand*#3)
}
node[right] {#5};
}

\newcommand{\Lathrop}[6]{% points, advance, rand factor, options, end label, truncate from point
\draw[#4] (0,0)
\foreach \x in {1,...,#6}
{   -- ++(#2,rand*#3)
}
coordinate (tempcoord) {};
\pgfmathsetmacro{\remaininglength}{(#1-#6)*#2}
\draw[#4] (tempcoord) -- ++ (\remaininglength,0) node[right] {#5};
}

\begin{tikzpicture}
\draw[help lines] (0,-5) grid (15,5);
\Lathrop{750}{0.02}{0.23}{red!70!black}{first one}{300}
\Lathrop{750}{0.02}{0.18}{green!70!black,thick}{second one}{400}
\Lathrop{750}{0.02}{0.21}{blue!70!black}{third one}{500}
\end{tikzpicture}

\end{document}


Edit 2: Ah, now I get the truncation request: Now you can specify upper and lower bounds and draw straight lines for them:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usepackage{xifthen}

\begin{document}

\newcommand{\Emmett}[5]{% points, advance, rand factor, options, end label
\draw[#4] (0,0)
\foreach \x in {1,...,#1}
{   -- ++(#2,rand*#3)
}
node[right] {#5};
}

\newcommand{\Lathrop}[9]{% points, advance, rand factor, options, end label, upper, lower trunc, draw trunc  lines, trunc draw options
\begin{scope}
\pgfmathsetmacro{\picwidth}{#1*#2}
\clip (0,#6*28.453+0.5\pgflinewidth) rectangle (\picwidth,#7*28.453-0.5\pgflinewidth);
\ifthenelse{\equal{#8}{y}}
{\draw[#9] (0,#6) -- (\picwidth,#6) (0,#7) -- (\picwidth,#7);}
{}
\draw[#4] (0,0)
\foreach \x in {1,...,#1}
{   -- ++(#2,rand*#3)
}
coordinate (#5) ;
\end{scope}
\node[right,#4] at (#5) {#5};
}

\begin{tikzpicture}
\draw[help lines] (0,-5) grid (15,5);
\Lathrop{750}{0.02}{0.2}{red!70!black}{first one}{1.5}{-2.3}{n}{}
\Lathrop{750}{0.02}{0.2}{green!70!black,thick}{second one}{1.1}{-1.7}{y}{green!70!black,densely dashed}
\Lathrop{750}{0.02}{0.3}{blue!70!black}{third one}{2.4}{-2.7}{y}{blue!70!black,thin,densely dotted}
\end{tikzpicture}

\end{document}


P.S. there are still some issues as the placements of the labels. The command now has 9 parameters, one should switch to pgfkeys for a convineant key-value interface.

-
Wow, very nice work. The truncation should be noted here. Maybe the figure uploaded before is not clear. I will upload another one. I really appreciate your work. – XIAO Lishun Jun 15 '12 at 2:19
Excellent! I think I can use you codes to make an animation when the truncation increases. Thank you very much. – XIAO Lishun Jun 15 '12 at 14:32

Here's an approach using pgfplotstable to calculate the Brownian motions as cumulative sums of random normally distributed values (thanks to horchler for pointing out the need for normality). You have to first initialise an empty table, using something like \pgfplotstablenew{200}\loadedtable, and then you can draw the brownian motions using \addplot table [brownian motion] {\loadedtable};.

You can set the initial value and the maximum and minimum values using

\addplot table [brownian motion={start=0.5, min=-1, max=1}] {\loadedtable};


\documentclass[border=5mm]{standalone}
\usepackage{pgfplots, pgfplotstable}

% Create a function for generating inverse normally distributed numbers using the Box–Muller transform
\pgfmathdeclarefunction{invgauss}{2}{%
\pgfmathparse{sqrt(-2*ln(#1))*cos(deg(2*pi*#2))}%
}
% Code for brownian motion
\makeatletter
\pgfplotsset{
table/.cd,
brownian motion/.style={
create on use/brown/.style={
create col/expr accum={
(\coordindex>0)*(
max(
min(
invgauss(rnd,rnd)*0.1+\pgfmathaccuma,
\pgfplots@brownian@max
),
\pgfplots@brownian@min
)
) + (\coordindex<1)*\pgfplots@brownian@start
}{\pgfplots@brownian@start}
},
y=brown, x expr={\coordindex},
brownian motion/.cd,
#1,
/.cd
},
brownian motion/.cd,
min/.store in=\pgfplots@brownian@min,
min=-inf,
max/.store in=\pgfplots@brownian@max,
max=inf,
start/.store in=\pgfplots@brownian@start,
start=0
}
\makeatother
%

% Initialise an empty table with a certain number of rows

\begin{document}
\pgfplotsset{
no markers,
xmin=0,
enlarge x limits=false,
scaled y ticks=false,
ymin=-1, ymax=1
}
\tikzset{line join=bevel}
\pgfmathsetseed{3}
\begin{tikzpicture}
\begin{axis}
\end{axis}
\end{tikzpicture}

\pgfmathsetseed{3}
\begin{tikzpicture}
\begin{axis}
brownian motion={%
max=0.5,
min=-0.75
}
brownian motion={%
start=0.5,
min=-0.5, max=0.75
}

@ajafarov: Sure, just use create col/expr accum={\pgfmathaccuma + 0.1*rand}{0.7} (the second parameter is the starting value). Glad it helps! – Jake Jul 26 '13 at 13:24