Jul-21-2020, 01:02 AM
Newbie here, learning python.
I am trying to make a very simple code to "animate" a random walk. I use the quotation marks because I don't really know if python (or the way I wrote the code anyway) is the best solution to create an animation.
My objective is to explore different types of random walks by extracting useful visual information besides the usual statistical approach.
My code basically creates two arrays: one with random step lengths and another with random turning angles. From these I create a path (ie list of x, y positions) and then draw the path step by step. I also show the distribution of angles and step lengths.
The first problem I see is that I am very bad using matplotlib (probably this is the most important issue) and I don't know how to optimize the code for speed: the code works and I can see the random walk being developed in the plot, but it is annoyingly slow. I have coded in Pascal many (many!) years ago (Lazarus) and it was SO much faster. Further, it seems to redraw all 3 plots instead of only updating the figure with the random walk itself.
Can you point me what should I start with? Again, I am surely missing lots of optimization from matplotlib alone (or maybe it is not the best choice for my objective?
Here is the code:
I am trying to make a very simple code to "animate" a random walk. I use the quotation marks because I don't really know if python (or the way I wrote the code anyway) is the best solution to create an animation.
My objective is to explore different types of random walks by extracting useful visual information besides the usual statistical approach.
My code basically creates two arrays: one with random step lengths and another with random turning angles. From these I create a path (ie list of x, y positions) and then draw the path step by step. I also show the distribution of angles and step lengths.
The first problem I see is that I am very bad using matplotlib (probably this is the most important issue) and I don't know how to optimize the code for speed: the code works and I can see the random walk being developed in the plot, but it is annoyingly slow. I have coded in Pascal many (many!) years ago (Lazarus) and it was SO much faster. Further, it seems to redraw all 3 plots instead of only updating the figure with the random walk itself.
Can you point me what should I start with? Again, I am surely missing lots of optimization from matplotlib alone (or maybe it is not the best choice for my objective?
Here is the code:
# Generates a 2D random walk #!/usr/bin/env python3 # -*- coding: utf-8 -*- import numpy as np import math from numpy.random import seed from numpy.random import randint from numpy.random import randn import matplotlib.pyplot as plt # Number of total steps in this walk number_of_steps = 100 # Time for drawing pause ("animation") pauseduration = 0.001 # Size of figures for angles and step sizes distribution sizeFig = 4.5 # Seed seed(22) # Mean turning angles mean = 0 # Standard deviation of the angles SDev = 1 # Create a vector with random angles # The angles are drawn from a UNIFORM distribution # They are integer values within the range 0-360 degrees angles = randint(0, 360, number_of_steps) # Plot histogram to show distribution of angles fig = plt.figure(num=1, figsize=(sizeFig,sizeFig)) ax = plt.axes() ax.set(xlabel="Angle (degrees)", ylabel="Number of cases", title='Angles') plt.hist(angles, bins=35) # Now convert angles to radians. This is needed later when # calculating the new x,y position from angle and step-length angles = np.radians(angles) # Create an array with random step sizes # The step sizes are drawn from a normal distribution # First, draw values from standard normal distribution # ie mean = 0 and SD = 1 normalized_step_size = randn(number_of_steps) # Then scale the values to fit this particular normal dist # with mean = mean and standard deviation = SDev step_sizes = mean + normalized_step_size * SDev # Plot histogram to show distribution of step sizes fig = plt.figure(num=2 ,figsize=(sizeFig,sizeFig)) ax = plt.axes() ax.set(xlabel="Step size", ylabel="Number of cases", title='Step lengths') plt.hist(step_sizes, bins=35) # apparently I could have used directly this: # normalized_step_size = np.random.normal(mean, SDev, number_of_steps) # Create a vector of 2 dimensions # to store X, Y positions positions = np.zeros((2, number_of_steps)) # Starting position x_start = 0 y_start = 0 positions[0,0] = x_start positions[1,0] = y_start # Prepare for plotting fig = plt.figure(num=3,figsize=(8,8)) ax = plt.axes() ax.set(xlabel="x (steps)", ylabel="y (steps)", title='A Simple Plot') ax.set_aspect('equal') # For each step: # move (using an angle and step size from 'angle' and 'steps') # draw the current position for step in range(1, number_of_steps): # Calculate x2,y2 from x1,y1 and angle # Update x position positions[0,step] = positions[0,step-1] + step_sizes[step] * math.cos(angles[step]) # Update y position positions[1,step] = positions[1,step-1] + step_sizes[step] * math.sin(angles[step]) x1x2 = np.array([positions[0,step-1],positions[0,step]]) y1y2 = np.array([positions[1,step-1],positions[1,step]]) ax.set(title='A Simple Plot - #'+str(step)) plt.plot(x1x2,y1y2) # Wait a bit to make it look animated plt.pause(pauseduration)