so I am working with some output (in a .txt file) from a separate code that takes a final matrix and just writes this matrix to a file. The output has each line of the file being the solution to the 1D heat equation at a certain timestep. This matrix could get up to a several hundred thousand rows long (based on however many timesteps I choose to run). For example, maybe the output looks like this:
1 2 3 4 5 6 7
2 3 4 5 6 7 8
3 4 5 6 7 8 9
4 5 6 7 8 9 10
and I have x-values that I create using numpy.linspace.
My goal is to create a movie (.mpeg, for example) that basically plots plt.plot(x,y), where x is the same in each frame and y is each row of the matrix, starting from the first row and ending at the last row.
In reality, I have 6000 rows and 401 nodes, giving me a 6000 by 401 matrix in an output.txt file, but I expect the matrix to be a lot larger when I increase the timestep in the solver code to possibly 1,000,000 timesteps (which could give me a few hundred thousand rows). Due to the amount of plotting, I am trying to refrain from the method of writing multiple images for each row and storing them on my computer and then compiling them onto one movie - I would like to write this data to a file all at once.
Below is what I have tried so far:
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.animation as manimation
FFMpegWriter = manimation.writers['ffmpeg']
metadata = dict(title='Movie Test', artist='Matplotlib',
comment='Movie support!')
writer = FFMpegWriter(fps=15, metadata=metadata)
fig = plt.figure()
l, = plt.plot([], [], 'k-o')
solverlist = ["explicit", "implicit", "crank-nicolson"]
filename = f"{solverlist[2]}-solver/cn_output_400_nodes.txt"
loaded_matrix = np.loadtxt(filename, dtype='f', delimiter=' ')
with writer.saving(fig, f"{solverlist[2]}_400_node_solution.mp4", 100):
x = np.linspace(0.0, 2.0, len(loaded_matrix[1]))
for i in range(len(loaded_matrix)):
y = loaded_matrix[i]
plt.plot(x,y)
plt.title("Time Evolution of Heat Equation Solver")
writer.grab_frame()
I took the bulk of this from the MatPlotLib MovieWriter documantation, and when I run this code, I do not understand why it takes so long.
Is there a better way to accomplish this task? Or does my code above have some bug I am unaware of? Thanks in advance.
You can save time by reusing the same plot object instead of creating a new one on every iteration. You have the following line in your code:
l, = plt.plot([], [], 'k-o')
Where you seem to create a plot for reusing it later, but then l
is not used after. Try with something like this:
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.animation as manimation
FFMpegWriter = manimation.writers['ffmpeg']
metadata = dict(title='Movie Test', artist='Matplotlib',
comment='Movie support!')
writer = FFMpegWriter(fps=15, metadata=metadata)
fig = plt.figure()
l, = plt.plot([], [], 'k-o')
l.set_title("Time Evolution of Heat Equation Solver")
solverlist = ["explicit", "implicit", "crank-nicolson"]
filename = f"{solverlist[2]}-solver/cn_output_400_nodes.txt"
loaded_matrix = np.loadtxt(filename, dtype='f', delimiter=' ')
with writer.saving(fig, f"{solverlist[2]}_400_node_solution.mp4", 100):
x = np.linspace(0.0, 2.0, len(loaded_matrix[0]))
for i in range(len(loaded_matrix)):
y = loaded_matrix[i]
l.set_data(x, y)
writer.grab_frame()
In my experience, writing video with Matplotlib and ffmpeg is never very fast, but there is a significant different when you reuse objects instead of recreating them.