40

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

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.

azetina
  • 28,884
XIAO Lishun
  • 1,041

2 Answers2

51

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}

enter image description here


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}

enter image description here


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}

enter image description here

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.

Tom Bombadil
  • 40,123
  • 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 02: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
  • Why is not the picture centered, nor "centerable" with a begin/end center ? – Olórin Nov 03 '19 at 10:26
  • Hey Tom, thanks a lot for the help. In your Lathrop coding, is there a way that I could bound the movement of the motion above 0? I need it to stay above zero (x-axis) on the grid? – Frank Swanton Jan 11 '21 at 00:44
36

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
\pgfplotstablenew{201}\loadedtable % How many steps?



\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}
   \addplot table [brownian motion] {\loadedtable};
   \addplot table [brownian motion] {\loadedtable};
\end{axis}
\end{tikzpicture}

\pgfmathsetseed{3}
\begin{tikzpicture}
\begin{axis}
    \addplot table [
        brownian motion={%
            max=0.5,
            min=-0.75
        }
    ] {\loadedtable};
    \addplot table [
        brownian motion={%
            start=0.5,
            min=-0.5, max=0.75
        }
    ] {\loadedtable};
\end{axis}
\end{tikzpicture}
\end{document} 
Jake
  • 232,450
  • Thank you very much. I would like to acknowledge both you and Tom. I will study your codes for my further drawing. – XIAO Lishun Jun 15 '12 at 06:12
  • @Jake Hi, I have once been trying to illustrate the Brownian motion and your code helped me a lot! Is it possible to modify the code in a way to make the path start at, let's say 0.7, on the y-axis. This should enable the representation of the Brownian motion with drift. Thank you very much for your help! – ajafarov Jul 26 '13 at 13:19
  • @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
  • @Jake I think I will have a problem, since I declare that command in the preamble of the document and I want to have both figures in one document, i.e. the initial one that you have shared with us and the modified one. Am I right? Thanks – ajafarov Jul 26 '13 at 13:28
  • @ajafarov: I've edited my answer with a more flexible approach. The restriction of the motion is now also more accurate: Before, I merely clipped the paths, but now the limits are taken into account while calculating the paths. – Jake Jul 26 '13 at 14:45
  • @Jake Thanks a lot, I will have a look at it and let you know. – ajafarov Jul 26 '13 at 14:49
  • @Jake Since I lack expertise, it is difficult for me to track what you are really doing while implementing that code, I still use the first code that you have written, I have also modified it a little bit according to my needs and it works. Actually I have text, then I have that graph, then I have text again and then I wanted to have a similar graph with only one growing path of brownian motion that starts at e.g. 0.6. Is it somehow possible to achieve that without changing the preamble? – ajafarov Jul 26 '13 at 21:28
  • @ajafarov: So you're not using the clipping? Because if you were, I would strongly recommend using the new code. If you're not clipping the paths, you can simply shift the path by using \addplot table [y expr=\thisrow{brown1}+0.6] {\loadedtable}; – Jake Jul 26 '13 at 22:12
  • @Jake Thanks, is it possible to make is grow, i.e. to be positive and growing, or at least only positive? – ajafarov Jul 26 '13 at 22:18
  • @ajafarov: I'm not sure I understand what you mean with "growing": Do you want the path to take random, positive steps, and never step down? Maybe it would be best if you could open a new question. – Jake Jul 26 '13 at 22:24
  • @Jake actually the problem is almost solved, a new question is not really needed. Exactly, I want that path to take random, positive and negative steps but the path should not decrease below 0, the overall evolvement of the path should take place in the first quadrant. – ajafarov Jul 26 '13 at 22:30
  • @ajafarov: That's exactly what my new code does: You would say \addplot table [brownian motion={min=0}}]{\loadedtable};. – Jake Jul 27 '13 at 01:22
  • @Jake I understand it, and I understand that your intention is to help me, only if I'll use your new code I will have to adjust it to my needs to generate the first graph and then only illustrate the second graph by using \addplot table [brownian motion={min=0}}]{\loadedtable};. Since I dont really get what happens in the new code, it is very time consuming for me to adust the code through trial and error, therefore even if not quite reasonably I would like to have something like \addplot table [y expr=\thisrow{brown1}+0.6] {\loadedtable}; – ajafarov Jul 27 '13 at 07:05
  • @Jake my first two paths from the old code look like this: \addplot table [y expr={max(\thisrow{brown1},-5.0)}] {\loadedtable}; \addplot table [y expr={min(\thisrow{brown2},5.0)}] {\loadedtable}; Is it possible to increase one of them by 0.6? Thanks a lot! – ajafarov Jul 27 '13 at 07:06
  • @ajafarov: Yes, use \addplot table [y expr={min(\thisrow{brown2}+0.6,5.0)}] {\loadedtable};. – Jake Jul 27 '13 at 13:08
  • @Jake unfortunately, it does not change anything, I think I will simply start a new topic and provide the code – ajafarov Jul 27 '13 at 14:16