title: How can I speed up the generation of an MP4 using matplotlib's Animation Writer?
body: <p>I am using matplotlib to generate a graphical animation of some data. The data has about 4 hours of collection time so I expect the animation to be about 4 hours. However, generating a smaller 60 second video takes approximately 15 minutes. Thus, the total estimated run time for generating the 4 hour video is 2.5 days. I assume I am doing something incredibly inefficient. How can I speed up the creation of an animation with matplotlib? </p>
  
  <h2>create_graph.py</h2>
  
  <pre><code>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 &lt; 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 &lt;= predicted and current_index_of_matching_ts &lt; 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)
  </code></pre>