1

I am working on a physics problem and trying to watch the simulation "live" by plotting after every 4 steps of the calculation. I am using Runge-Kutta (4th Order) method for the differentiation if that is relevant.

When I run the code (which should run the code for approximately 10/4 seconds, but I want to speed this up, though I am not sure how besides showing only some of the frames), I can see the axes moving, but nothing is showing in the plot.

I have stripped my code down to just generating random numbers instead of the actual function so I can share code as close to what I actually have.

import numpy as np
import matplotlib.pyplot as plt
 
# Parameters
time = 10  # maximum time for the simulation
h = 0.1  # step size
steps = int(time/h)  # number of steps
order = 4  # two second order equations
 
ICs = [0, 0, 0, 0.25, 0]  # intial conditions; t0, x1, x1dot, x2, x2dot
 
# Initializing vars array
vars = np.empty(shape=(order,steps))  # each row is another var, i.e. x1,x2,...
 
# Set initial conditions for each var
for i in range(order):
    vars[i][0] = ICs[i+1]

t = np.empty(steps)
t[0] = ICs[0]

K = np.zeros(shape=(4,len(vars))) # Each row is k1, k2, k3, k4 for each var


# ODE function
def ODE():
    dx1dt = np.random.randint(-1000,1000)
    dv1dt = np.random.randint(-1000,1000)
    dx2dt = np.random.randint(-1000,1000)
    dv2dt = np.random.randint(-1000,1000)
    
    return(np.array([dx1dt, dv1dt, dx2dt, dv2dt]))

# Loop calculates each var value using RK 4th order method
for i in range(steps-1):
    K[0] = ODE()
    K[1] = ODE()
    K[2] = ODE()
    K[3] = ODE()
    
    vars[:,i+1] = vars[:,i] + 1/6 * (K[0] + 2 * K[1] + 2 * K[2] + K[3])
    
    t[i+1] = t[i] + h
    
    # Plotting every fourth calculation
    if (i%4 == 0):
        plt.cla()
        plt.plot(t[i], vars[0,i], label='x1')
        
        plt.title(f'Title (stepsize: {h})')
        plt.xlabel('time [s]')
        plt.ylabel('position [m]')
        
        plt.legend(loc=1)
        plt.tight_layout()
        plt.pause(0.01)
 
plt.tight_layout()
 
plt.show()

Thanks for the help.

2
  • at a first glance you're plotting a single point at each iteration, maybe you could plot the arrays instead? Commented Jun 22, 2020 at 18:02
  • When do plt.plot(t, vars[0], label='x1') instead, there seems to be some initial plot despite there being no values yet. If I initialized vars as vars = np.zeros(shape=(order,steps)), I see the values slowly updating, but I want to instead see graph developing, if that makes sense. Commented Jun 22, 2020 at 19:43

2 Answers 2

1

You could make use of matplotlib's interactive mode plt.ion() to initiate interactive plotting. Then call plt.show() to display the window, and update it using plt.gcf().canvas.draw, as shown here:

import numpy as np
import matplotlib.pyplot as plt
  
# Parameters
time = 10  # maximum time for the simulation
h = 0.1  # step size
steps = int(time/h)  # number of steps
order = 4  # two second order equations
 
ICs = [0, 0, 0, 0.25, 0]  # intial conditions; t0, x1, x1dot, x2, x2dot
 
# Initializing vars array
vars = np.empty(shape=(order,steps))  # each row is another var, i.e. x1,x2,...
 
# Set initial conditions for each var
for i in range(order):
    vars[i][0] = ICs[i+1]

t = np.empty(steps)
t[0] = ICs[0]

K = np.zeros(shape=(4,len(vars))) # Each row is k1, k2, k3, k4 for each var
fig,ax=plt.subplots()
plt.ion() # set interactive mode on 
plt.show() # open display window

# ODE function
def ODE():
    dx1dt = np.random.randint(-1000,1000)
    dv1dt = np.random.randint(-1000,1000)
    dx2dt = np.random.randint(-1000,1000)
    dv2dt = np.random.randint(-1000,1000)
    
    return(np.array([dx1dt, dv1dt, dx2dt, dv2dt]))

# Loop calculates each var value using RK 4th order method
for i in range(steps-1):
    K[0] = ODE()
    K[1] = ODE()
    K[2] = ODE()
    K[3] = ODE()
    
    vars[:,i+1] = vars[:,i] + 1/6 * (K[0] + 2 * K[1] + 2 * K[2] + K[3])
    
    t[i+1] = t[i] + h
    
    # Plotting every fourth calculation
    if (i%4 == 0):
        #plt.cla()
        plt.plot(t[:i], vars[0,:i],color='black')
        
        plt.title(f'Title (stepsize: {h})')
        plt.xlabel('time [s]')
        plt.ylabel('position [m]')
        

        plt.tight_layout()
        plt.gcf().canvas.draw() #update display window
        plt.pause(0.01)
        
plt.tight_layout()

line

Sign up to request clarification or add additional context in comments.

3 Comments

This is great. I guess I have to look into this interactive mode now. Thanks!
How did you save this gif? I always have a hard time creating a gif of a graph...
Save them as individual frames and stack them to create a gif. You will find this SO helpful.
0

It might not work because your plt.show() is not in the in the if clause.

1 Comment

Adding plt.show() to the if statement appears to have no effect.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.