Python 如何使用matplotlib';加快MP4的生成速度;谁是动画作家?
我正在使用matplotlib生成一些数据的图形动画。数据的收集时间约为4小时,因此我预计动画的收集时间约为4小时。但是,生成一个较小的60秒视频大约需要15分钟。因此,生成4小时视频的总估计运行时间为2.5天。我想我正在做一些效率极低的事情。如何使用matplotlib加速动画的创建 创建_graph.pyPython 如何使用matplotlib';加快MP4的生成速度;谁是动画作家?,python,python-3.x,numpy,matplotlib,ffmpeg,Python,Python 3.x,Numpy,Matplotlib,Ffmpeg,我正在使用matplotlib生成一些数据的图形动画。数据的收集时间约为4小时,因此我预计动画的收集时间约为4小时。但是,生成一个较小的60秒视频大约需要15分钟。因此,生成4小时视频的总估计运行时间为2.5天。我想我正在做一些效率极低的事情。如何使用matplotlib加速动画的创建 创建_graph.py 导入matplotlib.pyplot作为plt 将matplotlib.animation导入为动画 导入matplotlib 作为pd进口熊猫 将numpy作为np导入 matplot
导入matplotlib.pyplot作为plt
将matplotlib.animation导入为动画
导入matplotlib
作为pd进口熊猫
将numpy作为np导入
matplotlib.use(“Agg”)
frame=pd.read\u csv(“tmp/total.csv”)
min_time=frame.iloc[0][“time”]
max_time=frame.iloc[-1][“time”]
总时间=最大时间-最小时间
赫兹频率=50
窗长=5
保存计数=赫兹频率*100
def数据_gen():
匹配的当前索引=0
t=数据_gen.t
cnt=0
当cnt 而frame.iloc[current_index_of_matching_ts][“time”]-min_time所以我在这里回答我自己的问题,如果你觉得这很有趣的话
以下是一些事实
- matplotlib创建高质量的图形
- matplotlib相对于其他一些库(如c++绑定用于提高速度)生成图形的速度较慢
- 在我的mac电脑上生成一个4小时数据的实时图表大约需要20小时李>
为了解决我的问题,我创建了单独的文件,然后将它们连接在一起。我用过图书馆
生成_graphs.py
制作视频图形mp4.py
你想要以50赫兹的速率播放4小时(=14400秒)的视频吗?总共是72万帧。我怀疑这会淹没你的内存,直到它满了,然后变得非常慢,因为它经常需要在交换文件和RAM之间来回移动。它一次只写一帧。性能似乎可以扩展,只是开始时非常慢。我不知何故缺少应该比观察到的速度更快的指示。如果我制作一个实时图形并进行屏幕录制,速度会更快。尽管如此,由于matplotlib使用单独的帧渲染,这可能是不可能的,但我认为应该有更快的解决方案。我的意思是mpeg
是一种压缩数据格式,因此编码时间与显示一组像素所需的时间无关。
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib
import pandas as pd
import numpy as np
matplotlib.use("Agg")
frame = pd.read_csv("tmp/total.csv")
min_time = frame.iloc[0]["time"]
max_time = frame.iloc[-1]["time"]
total_time = max_time - min_time
hertz_rate = 50
window_length = 5
save_count = hertz_rate * 100
def data_gen():
current_index_of_matching_ts = 0
t = data_gen.t
cnt = 0
while cnt < save_count:
print("Done: {}%".format(cnt/save_count*100.0))
predicted = cnt * (1.0/hertz_rate)
while frame.iloc[current_index_of_matching_ts]["time"] - min_time <= predicted and current_index_of_matching_ts < len(frame) - 1:
current_index_of_matching_ts = current_index_of_matching_ts + 1
y1 = frame.iloc[current_index_of_matching_ts]["var1"]
y2 = frame.iloc[current_index_of_matching_ts]["var2"]
y3 = frame.iloc[current_index_of_matching_ts]["var3"]
y4 = frame.iloc[current_index_of_matching_ts]["var4"]
y5 = frame.iloc[current_index_of_matching_ts]["var5"]
y6 = frame.iloc[current_index_of_matching_ts]["var6"]
y7 = frame.iloc[current_index_of_matching_ts]["var7"]
y8 = frame.iloc[current_index_of_matching_ts]["var8"]
y9 = frame.iloc[current_index_of_matching_ts]["var9"]
t = frame.iloc[current_index_of_matching_ts]["time"] - min_time
# adapted the data generator to yield both sin and cos
yield t, y1, y2, y3, y4, y5, y6, y7, y8, y9
cnt+=1
data_gen.t = 0
# create a figure with two subplots
fig, (ax1, ax2, ax3, ax4, ax5, ax6, ax7, ax8, ax9) = plt.subplots(9,1,figsize=(7,14)) # produces a video of 700 × 1400
# intialize two line objects (one in each axes)
line1, = ax1.plot([], [], lw=2, color='b')
line2, = ax2.plot([], [], lw=2, color='b')
line3, = ax3.plot([], [], lw=2, color='b')
line4, = ax4.plot([], [], lw=2, color='g')
line5, = ax5.plot([], [], lw=2, color='g')
line6, = ax6.plot([], [], lw=2, color='g')
line7, = ax7.plot([], [], lw=2, color='r')
line8, = ax8.plot([], [], lw=2, color='r')
line9, = ax9.plot([], [], lw=2, color='r')
line = [line1, line2, line3, line4, line5, line6, line7, line8, line9]
# the same axes initalizations as before (just now we do it for both of them)
for ax in [ax1, ax2, ax3, ax4, ax5, ax6, ax7, ax8, ax9]:
ax.set_ylim(-1.1, 1.1)
ax.grid()
# initialize the data arrays
xdata, y1data, y2data, y3data, y4data, y5data, y6data, y7data, y8data, y9data = [], [], [], [], [], [], [], [], [], []
my_gen = data_gen()
for index in range(hertz_rate*window_length-1):
t, y1, y2, y3, y4, y5, y6, y7, y8, y9 = my_gen.__next__()
xdata.append(t)
y1data.append(y1)
y2data.append(y2)
y3data.append(y3)
y4data.append(y4)
y5data.append(y5)
y6data.append(y6)
y7data.append(y7)
y8data.append(y8)
y9data.append(y9)
def run(data):
# update the data
t, y1, y2, y3, y4, y5, y6, y7, y8, y9 = data
xdata.append(t)
y1data.append(y1)
y2data.append(y2)
y3data.append(y3)
y4data.append(y4)
y5data.append(y5)
y6data.append(y6)
y7data.append(y7)
y8data.append(y8)
y9data.append(y9)
# axis limits checking. Same as before, just for both axes
for ax in [ax1, ax2, ax3, ax4, ax5, ax6, ax7, ax8, ax9]:
ax.set_xlim(xdata[-1]-5.0, xdata[-1])
# update the data of both line objects
line[0].set_data(xdata, y1data)
line[1].set_data(xdata, y2data)
line[2].set_data(xdata, y3data)
line[3].set_data(xdata, y4data)
line[4].set_data(xdata, y5data)
line[5].set_data(xdata, y6data)
line[6].set_data(xdata, y7data)
line[7].set_data(xdata, y8data)
line[8].set_data(xdata, y9data)
return line
ani = animation.FuncAnimation(fig, run, my_gen, blit=True, interval=20, repeat=False, save_count=save_count)
Writer = animation.writers['ffmpeg']
writer = Writer(fps=hertz_rate, metadata=dict(artist='Me'), bitrate=1800)
ani.save('lines.mp4', writer=writer)
import multiprocessing as mp
from multiprocessing import Pool
from make_video_graph_mp4 import write_chart_to_file_wrapper
total_parts = 6
if __name__ == '__main__':
#spawn is critical to not share plt across threads.
mp.set_start_method('spawn')
with Pool() as p:
print(p.map(write_chart_to_file_wrapper, [[i, total_parts] for i in range(total_parts)]))
def write_chart_to_file(my_part, parts):
# ... code to create part my_part/parts of the video.
Writer = animation.writers['ffmpeg']
writer = Writer(fps=hertz_rate, metadata=dict(artist='Me'), bitrate=1800)
filename = 'out/videos/{}-lines{}-{}.mp4'.format(band_name, start_index, end_index)
ani.save(filename, writer=writer, dpi=100)