10

Following a previous question, this representation that might be even more pedagogic in 3D. Based on this working example extracted from This post

enter image description here

\documentclass[border=5mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.12}

\makeatletter
   \pgfdeclareplotmark{dot}
    {%
        \fill circle [x radius=0.08, y radius=0.32];
    }%
\makeatother

\begin{document}

\begin{tikzpicture}[ % Define Normal Probability Function
    declare function={
normal(\x,\m,\s) = 1/(2*\s*sqrt(pi))*exp(-(\x-\m)^2/(2*\s^2));
},
declare function={invgauss(\a,\b) = sqrt(-2*ln(\a))*cos(deg(2*pi*\b));}
]
\begin{axis}[
        %no markers,
        domain=0:12,
        zmin=0, zmax=1,
        xmin=0, xmax=3,
        samples=200,
        samples y=0,
        view={40}{30},
        axis lines=middle,
        enlarge y limits=false,
        xtick={0.5,1.5,2.5},
        xmajorgrids,
        xticklabels={},
        ytick=\empty,
        xticklabels={$t_1$, $t_2$, $t_3$},
        ztick=\empty,
        xlabel=$t$, xlabel style={at={(rel axis cs:1,0,0)}, anchor=west},
        ylabel=$S_t$, ylabel style={at={(rel axis cs:0,1,0)}, anchor=south west},
        zlabel=Probability density, zlabel style={at={(rel axis cs:0,0,0.5)}, rotate=90, anchor=south},
        set layers, mark=cube
    ]

    \pgfplotsinvokeforeach{0.5,1.5,2.5}{
        \addplot3 [draw=none, fill=black, opacity=0.25, only marks,     mark=dot, mark layer=like plot, samples=30, domain=0.1:2.9, on layer=axis background] (#1, {1.5*(#1-0.5)+3+invgauss(rnd,rnd)*#1}, 0);
    }
    \addplot3 [samples=2, samples y=0, domain=0:3] (x, {1.5*(x-0.5)+3}, 0);
    \addplot3 [cyan!50!black, thick] (0.5, x, {normal(x, 3, 0.5)});
    \addplot3 [cyan!50!black, thick] (1.5, x, {normal(x, 4.5, 1)});
    \addplot3 [cyan!50!black, thick] (2.5, x, {normal(x, 6, 1.5)});

    \pgfplotsextra{
        \begin{pgfonlayer}{axis background}
            \draw [gray, on layer=axis background] 
            (0.5, 3, 0) -- (0.5, 3, {normal(0,0,0.5)}) (0.5,0,0) -- (0.5,12,0)
            (1.5, 4.5, 0) -- (1.5, 4.5, {normal(0,0,1)}) (1.5,0,0) -- (1.5,12,0)
            (2.5, 6, 0) -- (2.5, 6, {normal(0,0,1.5)}) (2.5,0,0) -- (2.5,12,0);

        \end{pgfonlayer}
    }
\end{axis}
\end{tikzpicture}
\end{document}

How can we simulate the paths of a given number of brownian motions as in great Marmot's solution brownian-motion-and-rotated-normal-distribution and show the dynamic of the normal distribution "flattening" and spreading over time, but in 3D ?

The brownian motions would be on the bottom plane whereas the normal density would be represented in the third dimension enter image description here

enter image description here

1
  • 2
    Source code updated ! @marmot, your dynamic version in 2D was already breathtaking. I just wonder how you would adapt it to a 3D prospective. No need to have the straight line attached, but maybe in the spirit of the example here, see how the path "impact" (as here with the big dots) is distributed from one time to another. Am sketching something.
    – JeT
    Jan 5, 2019 at 15:06

1 Answer 1

20

Here is a slightly advanced proposal, taking into account your comments.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usepgfplotslibrary{fillbetween} % does intersections as well
\makeatletter
        \pgfdeclareplotmark{dot}
        {%
            \fill circle [x radius=0.08, y radius=0.32];
        }%
\makeatother
\newcommand{\CreateRandomWalkTable}[4]{%
\xdef#4{(0,0,0)}
\xdef\oldy{2.25}
\foreach \X in {1,...,#1}
{\pgfmathsetmacro{\myx}{#2*\X}
\pgfmathsetmacro{\myy}{\oldy+1.5*#2+rand*#3}
\xdef#4{#4 (\myx,\myy,0)}
\xdef\oldy{\myy}
}}
\pgfmathsetseed{1}
\CreateRandomWalkTable{140}{0.02}{0.2}{\mytabone}
\pgfmathsetseed{11}
\CreateRandomWalkTable{140}{0.02}{0.2}{\mytabtwo}
\pgfmathsetseed{17}
\CreateRandomWalkTable{140}{0.02}{0.2}{\mytabthree}
\pgfmathsetseed{32}
\CreateRandomWalkTable{140}{0.02}{0.2}{\mytabfour}

\begin{document}
\foreach \X in {0.5,0.6,...,2.5}
{\begin{tikzpicture}[ % Define Normal Probability Function
declare function={
            normal(\x,\m,\s) = 1/(2*\s*sqrt(pi))*exp(-(\x-\m)^2/(2*\s^2));
        },
    declare function={invgauss(\a,\b) = sqrt(-2*ln(\a))*cos(deg(2*pi*\b));}
       ]
\path[use as bounding box] (-0.5,-1) rectangle (6,5); % for animation
\begin{axis}[
    %no markers,
    domain=0:12,
    zmin=0, zmax=1,
    xmin=0, xmax=3,
    samples=200,
   samples y=0,
    view={40}{30},
    axis lines=middle,
    enlarge y limits=false,
    xtick={0.5,1.5,2.5},
    xmajorgrids,
    xticklabels={},
    ytick=\empty,
    xticklabels={$x_1$, $x_2$, $x_3$},
    ztick=\empty,
    xlabel=$x$, xlabel style={at={(rel axis cs:1,0,0)}, anchor=west},
    ylabel=$y$, ylabel style={at={(rel axis cs:0,1,0)}, anchor=south west},
    zlabel=Probability density, zlabel style={at={(rel axis cs:0,0,0.5)}, rotate=90, anchor=south},
    set layers,% mark=cube
  ]

\addplot3 [samples=2, samples y=0, domain=0:3] (x, {1.5*(x-0.5)+3}, 0);

\addplot3 [draw=none, fill=black, opacity=0.25, only marks, mark=dot, mark
layer=like plot, samples=30, domain=0.1:2.9, on layer=axis background,overlay] (\X, {1.5*(\X-0.5)+3+invgauss(rnd,rnd)*\X}, 0);

\begin{pgfonlayer}{axis background}
\begin{scope}
\clip (0,0,0) -- (\X,0,0)  -- (\X,12,0) -- (0,12,0) -- cycle;
\draw[red,no marks,name path=rp1] plot coordinates {\mytabone};
\draw[red,no marks,name path=rp2] plot coordinates {\mytabtwo};
\draw[red,no marks,name path=rp3] plot coordinates {\mytabthree};
\draw[red,no marks,name path=rp4] plot coordinates {\mytabfour};
\end{scope}
\draw [gray, on layer=axis background] (\X, 2.25+1.5*\X, 0) -- 
(\X, 2.25+1.5*\X, {normal(0,0,0.5*\X+0.25)});
\draw [gray, on layer=axis background,name path=vert] (\X,0,0) -- (\X,12,0);
\end{pgfonlayer}
\path[name intersections={of=vert and rp1,by={x1}},
name intersections={of=vert and rp2,by={x2}},
name intersections={of=vert and rp3,by={x3}},
name intersections={of=vert and rp4,by={x4}}];
\draw [fill=red, opacity=0.75, only marks, mark=dot] plot coordinates 
{(x1) (x2) (x3) (x4)};
\addplot3 [blue, very thick] (\X, x, {normal(x, 2.25+1.5*\X,0.5*\X+0.25)});

% \pgfplotsinvokeforeach{0.5,1.5,2.5}{
% \addplot3 [draw=none, fill=black, opacity=0.25, only marks, mark=dot, mark layer=like plot, samples=30, domain=0.1:2.9, on layer=axis background] (#1, {1.5*(#1-0.5)+3+invgauss(rnd,rnd)*#1}, 0);
% \addplot3 [cyan!50!black, thick] (#1, x, {normal(x, 2.25+1.5*#1, 0.5*#1+0.25)});
% }
% \begin{pgfonlayer}{axis background}
% \pgfplotsinvokeforeach{0.5,1.5,2.5}{
% \draw [gray, on layer=axis background] (#1, 2.25+1.5*#1, 0) -- 
% (#1, 2.25+1.5*#1, {normal(0,0,0.5*#1+0.25)})
%  (#1,0,0) -- (#1,12,0);
% }
% \end{pgfonlayer}
\end{axis}
\path (current axis.south east) -- ++ (0.4,-0.3);
\end{tikzpicture}}
\end{document}

enter image description here

If you increase the number of steps

\foreach \X in {0.5,0.525,...,2.5}

and convert with see here for more info

convert -density 300 -delay 12 -loop 0 -alpha remove multipage.pdf ani.gif

you get a smoother result:

enter image description here

Group plot.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usepgfplotslibrary{fillbetween} % does intersections as well
\usepgfplotslibrary{groupplots}
\makeatletter
        \pgfdeclareplotmark{dot}
        {%
            \fill circle [x radius=0.08, y radius=0.32];
        }%
\makeatother
\newcommand{\CreateRandomWalkTable}[4]{%
\xdef#4{(0,0,0)}
\xdef\oldy{2.25}
\foreach \X in {1,...,#1}
{\pgfmathsetmacro{\myx}{#2*\X}
\pgfmathsetmacro{\myy}{\oldy+1.5*#2+rand*#3}
\xdef#4{#4 (\myx,\myy,0)}
\xdef\oldy{\myy}
}}
\pgfmathsetseed{1}
\CreateRandomWalkTable{140}{0.02}{0.2}{\mytabone}
\pgfmathsetseed{11}
\CreateRandomWalkTable{140}{0.02}{0.2}{\mytabtwo}
\pgfmathsetseed{17}
\CreateRandomWalkTable{140}{0.02}{0.2}{\mytabthree}
\pgfmathsetseed{32}
\CreateRandomWalkTable{140}{0.02}{0.2}{\mytabfour}

\begin{document}
\begin{tikzpicture}[ % Define Normal Probability Function
declare function={
            normal(\x,\m,\s) = 1/(2*\s*sqrt(pi))*exp(-(\x-\m)^2/(2*\s^2));
        },
    declare function={invgauss(\a,\b) = sqrt(-2*ln(\a))*cos(deg(2*pi*\b));}
       ]
\begin{groupplot}[group style={group size=2 by 3},height=6cm,width=6cm,
    %no markers,
    domain=0:12,
    zmin=0, zmax=1,
    xmin=0, xmax=3,
    samples=200,
    samples y=0,
    view={40}{30},
    axis lines=middle,
    enlarge y limits=false,
    xtick={0.5,1.5,2.5},
    xmajorgrids,
    xticklabels={},
    ytick=\empty,
    xticklabels={$x_1$, $x_2$, $x_3$},
    ztick=\empty,
    xlabel=$x$, xlabel style={at={(rel axis cs:1,0,0)}, anchor=west},
    ylabel=$y$, ylabel style={at={(rel axis cs:0,1,0)}, anchor=south west},
    zlabel=Probability density, zlabel style={at={(rel axis cs:0,0,0.5)}, rotate=90, anchor=south},
    set layers
  ]
\pgfplotsinvokeforeach{0.5,0.9,1.3,1.7,2.1,2.5}
{\nextgroupplot[]
  \addplot3 [samples=2, samples y=0, domain=0:3] (x, {1.5*(x-0.5)+3}, 0);

  \addplot3 [draw=none, fill=black, opacity=0.25, only marks, mark=dot, mark
  layer=like plot, samples=30, domain=0.1:2.9, on layer=axis background,overlay]
  (#1, {1.5*(#1-0.5)+3+invgauss(rnd,rnd)*#1}, 0);

  \begin{pgfonlayer}{axis background}
  \begin{scope}
  \clip (0,0,0) -- (#1,0,0)  -- (#1,12,0) -- (0,12,0) -- cycle;
  \draw[red,no marks,name path=rp1] plot coordinates {\mytabone};
  \draw[red,no marks,name path=rp2] plot coordinates {\mytabtwo};
  \draw[red,no marks,name path=rp3] plot coordinates {\mytabthree};
  \draw[red,no marks,name path=rp4] plot coordinates {\mytabfour};
  \end{scope}
  \draw [gray, on layer=axis background] (#1, 2.25+1.5*#1, 0) -- 
  (#1, 2.25+1.5*#1, {normal(0,0,0.5*#1+0.25)});
  \draw [gray, on layer=axis background,name path=vert] (#1,0,0) -- (#1,12,0);
  \end{pgfonlayer}
  \path[name intersections={of=vert and rp1,by={x1}},
  name intersections={of=vert and rp2,by={x2}},
  name intersections={of=vert and rp3,by={x3}},
  name intersections={of=vert and rp4,by={x4}}];
  \draw [fill=red, opacity=0.75, only marks, mark=dot] plot coordinates 
  {(x1) (x2) (x3) (x4)};
  \addplot3 [blue, very thick] (#1, x, {normal(x, 2.25+1.5*#1,0.5*#1+0.25)});
  }
\end{groupplot}

\end{tikzpicture}
\end{document}

enter image description here

8
  • That's pretty !! I am going to try to adapt your code so that, as a printer (old style), the brownian in red appears at the same time the distribution moves forward in time.
    – JeT
    Jan 5, 2019 at 16:40
  • marmot, thank you, it's exactly the idea I had in mind ! So powerful a graph. Do you think it's possible to put a terminal point to show at each step where the path ends below the distribution ? I also noticed the brownians started at 0 and not 2.5.
    – JeT
    Jan 5, 2019 at 17:56
  • 1
    @Julien-ElieTaieb Sure it's possible.
    – user121799
    Jan 5, 2019 at 18:31
  • 1
    Merci ! It's fantastic!! I validate your solution.
    – JeT
    Jan 5, 2019 at 18:38
  • 1
    @Julien-ElieTaieb I don't but can you just try to run it with a truncated list like \foreach \Z in {30} .... view={\Z}{30}, check if that works, and if it does, try to extend the list? (Sometimes it is better to avoid values like 90 or 0 in the view and 85 or 5 is better because there are some sin and cos functions in the transformations, which can thus become singular.)
    – user121799
    Jan 15, 2019 at 23:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .