How can I create an animation of a plot (like an mpeg movie) from a text file without saving it separately to the computer?
So I'm processing some output (in a .txt file) from a separate code that takes the final matrix and writes that matrix to a file. The output is that each line of the file is the solution to the one-dimensional heat equation for a specific time step. This matrix can be hundreds of thousands of rows long (based on many time steps 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 created using numpy.linspace.
My goal is to create a movie (eg. .mpeg) that basically plots plt.plot(x,y) where x is the same in every frame and y is each row of the matrix, Start on the first line and end on the last line.
Actually, I have 6000 rows and 401 nodes, which gives me a 6000 x 401 matrix in the output.txt file, but when I increase the timesteps in the solver code to a possible 1,000,000 timesteps, I want The matrix will be much larger (can give me hundreds of thousands of rows). Due to the number of plots, I'm trying to avoid the approach of writing multiple images for each line and storing them on the computer and then compiling it into a movie - I want to write this data to a file all at once.
Here's what I've 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 got most of it from the MatPlotLib MovieWriter documantation and when I run this code I don't understand why it is taking so long.
Is there a better way to accomplish this task? Or is there a bug in the code above that I don't know about? Thanks in advance.
You can save time by reusing the same plot object instead of creating a new plot object on each iteration. You have the following lines in your code:
l, = plt.plot([], [], 'k-o')
You seem to be creating a diagram here to reuse it later, but then l
it's not used anymore. Try 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()
Writing videos with Matplotlib and ffmpeg is never very fast in my experience, but it makes a big difference when you reuse objects instead of recreating them.