7

I am having a very similar problem to this question

but the suggested solution doesn't work for me.

I have set up an animated scatter plot using the matplotlib animation module. This works fine when it is displaying live. I would like to save it to an avi file or something similar. The code I have written to do this does not error out but the video it produces just shows a blank set of axes or a black screen. I've done several checks and the data is being run and figure updated it's just not getting saved to video...

I tried removing "animated=True" and "blit=True" as suggested in this question but that did not fix the problem.

I have placed the relevant code below but can provide more if necessary. Could anyone suggest what I should do to get this working?

def initAnimation(self):
        rs, cfgs = next(self.jumpingDataStreamIterator)     
        #self.scat = self.axAnimation.scatter(rs[0], rs[1], c=cfgs[0], marker='o')
        self.scat = self.axAnimation.scatter(rs[0], rs[1], c=cfgs[0], marker='o', animated=True)
        return self.scat,


def updateAnimation(self, i):
    """Update the scatter plot."""
    rs, cfgs = next(self.jumpingDataStreamIterator)
    # Set x and y data...
    self.scat.set_offsets(rs[:2,].transpose()) 
    #self.scat = self.axAnimation.scatter(rs[0], rs[1], c=cfgs[0], animated=True)
    # Set sizes...
    #self.scat._sizes = 300 * abs(data[2])**1.5 + 100
    # Set colors..
    #self.scat.set_array(cfgs[0])
    # We need to return the updated artist for FuncAnimation to draw..
    # Note that it expects a sequence of artists, thus the trailing comma.
    matplotlib.pyplot.draw()
    return self.scat,

def animate2d(self, steps=None, showEvery=50, size = 25):
    self.figAnimation, self.axAnimation = matplotlib.pyplot.subplots()
    self.axAnimation.set_aspect("equal")
    self.axAnimation.axis([-size, size, -size, size])
    self.jumpingDataStreamIterator = self.jumpingDataStream(showEvery)

    self.univeseAnimation = matplotlib.animation.FuncAnimation(self.figAnimation, 
                            self.updateAnimation, init_func=self.initAnimation,
                            blit=True)
    matplotlib.pyplot.show()

def animate2dVideo(self,fileName=None, steps=10000, showEvery=50, size=25):
    self.figAnimation, self.axAnimation = matplotlib.pyplot.subplots()
    self.axAnimation.set_aspect("equal")
    self.axAnimation.axis([-size, size, -size, size])
    self.Writer = matplotlib.animation.writers['ffmpeg']
    self.writer = self.Writer(fps=1, metadata=dict(artist='Universe Simulation'))
    self.jumpingDataStreamIterator = self.jumpingDataStream(showEvery)

    self.universeAnimation = matplotlib.animation.FuncAnimation(self.figAnimation, 
                            self.updateAnimation, scipy.arange(1, 25), init_func=self.initAnimation)

    self.universeAnimation.save('C:/universeAnimation.mp4', writer = self.writer)
Community
  • 1
  • 1
user2175850
  • 193
  • 2
  • 13
  • Could you reduce this down to a the minimal amount of code you need to reproduce the issue? This is clearly part of a larger class, and it is not clear that this is functional as stand alone code. Please help us to help you. – tacaswell Mar 16 '13 at 03:36
  • does the _exact_ code in http://stackoverflow.com/a/14740703/380231 work or not work if you run it on your system? – tacaswell Mar 16 '13 at 14:04
  • 1
    Sorry for the delay. I have found a work around by simply saving lots of individual images and then calling ffmpeg to chain them together. This isn't ideal but gets the job done. When I run the code here http://stackoverflow.com/a/14740703/380231 I get the following error: .... File "C:\Python27\lib\site-packages\matplotlib\backend_bases.py", line 2093, in print_figure **kwargs) File "C:\Python27\lib\site-packages\matplotlib\backends\backend_agg.py", line 483, in print_raw renderer._renderer.write_rgba(filename_or_obj) RuntimeError: Error writing to file – user2175850 Mar 21 '13 at 22:28
  • Please post your last comment as an answer and accept it. – tacaswell Mar 31 '13 at 00:37

1 Answers1

0

Sorry for the delay. I have found a work around by simply saving lots of individual images and then calling ffmpeg to chain them together. This isn't ideal but gets the job done. (part of larger class)

def easyway(self, frames):
    ##INSERT CODE TO GET xdata and ydata!
    for i in range(0, frames):
       fileName = "videoName"+"%04d.png" % i
       matplotlib.pyplot.scatter(xdata,ydata,c=coldata, marker='*',
                              s=15.0, edgecolor='none')
       matplotlib.pyplot.savefig(self.workingDirectory+'temp/'+fileName, dpi=dpi)
       matplotlib.pyplot.close()   
       ##INSERT CODE TO UPDATE xdata and ydata!
    self.createVideoFile(fps)#calls FFMpeg to chain together all the pictures

    if cleanUp:#removes all the picture files created in the process
        print "temporary picture files being removed..."
        self.clearDirectory()
    print "FINISHED"

def clearDirectory(self,directoryName='temp'):
    files = glob.glob(self.workingDirectory+directoryName+"/*")
    for f in files:
        os.remove(f)

def createVideoFile(self,fps=3):
    command="ffmpeg -f image2 -r %s -i %s%s" % (str(fps), self.workingDirectory+'temp/', self.universe.description)
    command+="%04d.png"
    command+=" -c:v libx264 -r 30 %s.mp4" % (self.workingDirectory+'videos/'+self.universe.description)
    print "Running command:"
    print command
    p = subprocess.Popen(command, shell=True, stdout = subprocess.PIPE, stderr=subprocess.STDOUT)
    output = p.communicate()[0]
    print "output\n"+"*"*10+"\n"
    print output
    print "*"*10
    print "Video file has been written"
user2175850
  • 193
  • 2
  • 13