I am trying to animate the path of a Brownian motion in manim, however my plot looks discontinuous whereas it should not be.
Here is the image (white path is the Brownian motion, green path is the quadratic variation):
I am using python 3.9.13 and manim CE 0.19.0. Here is the code
from manim import *
import numpy as np
class BrownianPath():
def __init__(self, drift = 0.0, sigma = 1.0):
self.drift = drift
self.sigma = sigma
self.T = [0]
self.path = [0]
self.qv = [0]
self.rng = np.random.default_rng()
def increment(self, dT):
self.path.append(self.path[-1] + self.drift*dT + self.rng.normal()*self.sigma*np.sqrt(dT))
self.qv.append(self.qv[-1] + (self.path[-1] - self.path[-2])**2)
self.T.append(self.T[-1] + dT)
def run_for_time(self, T = 1.0, n = 100):
for t in np.arange(0, T, T/n):
self.increment(T/n)
self.T.append(self.T[-1] + T/n)
def get_last_path(self):
return self.path[-1]
def get_last_qv(self):
return self.qv[-1]
def get_last_T(self):
return self.T[-1]
class Brownian(Scene):
def construct(self):
axes = Axes([0, 5], [-1, 6])
self.add(axes)
# Create the brownian path
bm = BrownianPath(drift=0.1)
# Animate its path and its quadratic variation
self.path = VGroup()
self.path.add(Line(axes.c2p(0, 0, 0), axes.c2p(0, 0, 0)))
self.qv = VGroup()
self.qv.add(Line(axes.c2p(0, 0, 0), axes.c2p(0, 0, 0)))
def brownian_updater(mob, dt):
bm.increment(dt)
mob.move_to(axes.c2p(bm.get_last_T(), bm.get_last_path(), 0))
def qv_updater(mob, dt):
# assumes brownian updater called first (?)
mob.move_to(axes.c2p(bm.get_last_T(), bm.get_last_qv(), 0))
def add_path_element():
last_line = self.path[-1]
self.path.add(Line(last_line, axes.c2p(bm.get_last_T(), bm.get_last_path(), 0)))
return self.path
def add_qv_element():
last_line = self.qv[-1]
self.qv.add(Line(last_line, axes.c2p(bm.get_last_T(), bm.get_last_qv(), 0), color=GREEN))
return self.qv
dot = Dot(radius=0.07, color=BLUE)
dot.move_to(axes.c2p(0, 0, 0))
dot_qv = Dot(radius=0.08, color=GREEN)
dot_qv.move_to(axes.c2p(0, 0, 0))
dot.add_updater(brownian_updater)
dot_qv.add_updater(qv_updater)
curve_to_path = always_redraw(add_path_element)
curve_to_qv = always_redraw(add_qv_element)
self.add(dot, dot_qv)
self.add(curve_to_path, curve_to_qv)
self.wait(5)
Perhaps it has something to do with how the scene calls the updaters, and the order is not consistent?
As you already found your way to Discord by now I suggest to continue the discussion over there, since the possibilities to include images and videos in answers and to online render code are better there.
But as a short answer: the order of the execution of updaters depends on the order in which the corresponding objects are added to the scene.