How to animate a scatter plot?

后端 未结 4 1834
清酒与你
清酒与你 2020-11-22 17:18

I\'m trying to do an animation of a scatter plot where colors and size of the points changes at different stage of the animation. For data I have two numpy ndarray with an x

相关标签:
4条回答
  • 2020-11-22 17:41

    Here is the thing. I used to a user of Qt and Matlab and I am not quite familiar with the animation system on the matplotlib.

    But I do have find a way that can make any kind of animation you want just like it is in matlab. It is really powerful. No need to check the module references and you are good to plot anything you want. So I hope it can help.

    The basic idea is to use the time event inside PyQt( I am sure other Gui system on the Python like wxPython and TraitUi has the same inner mechanism to make an event response. But I just don't know how). Every time a PyQt's Timer event is called I refresh the whole canvas and redraw the whole picture, I know the speed and performance may be slowly influenced but it is not that much.

    Here is a little example of it:

    import sys
    from PyQt4 import QtGui
    
    from matplotlib.figure import Figure
    from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
    
    import numpy as np
    
    
    class Monitor(FigureCanvas):
        def __init__(self):
            self.fig = Figure()
            self.ax = self.fig.add_subplot(111)
    
            FigureCanvas.__init__(self, self.fig)
            self.x = np.linspace(0,5*np.pi,400)
            self.p = 0.0
            self.y = np.sin(self.x+self.p)
    
    
            self.line = self.ax.scatter(self.x,self.y)
    
            self.fig.canvas.draw()
    
            self.timer = self.startTimer(100)
    
    
        def timerEvent(self, evt):
            # update the height of the bars, one liner is easier
            self.p += 0.1
            self.y = np.sin(self.x+self.p)
            self.ax.cla()
            self.line = self.ax.scatter(self.x,self.y)
    
            self.fig.canvas.draw()
    
    
    
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        w = Monitor()
        w.setWindowTitle("Convergence")
        w.show()
        sys.exit(app.exec_())
    

    You can adjust the refresh speed in the

            self.timer = self.startTimer(100)
    

    I am just like you who want to use the Animated scatter plot to make a sorting animation. But I just cannot find a so called "set" function. So I refreshed the whole canva.

    Hope it helps..

    0 讨论(0)
  • 2020-11-22 17:44

    I wrote celluloid to make this easier. It's probably easiest to show by example:

    import matplotlib.pyplot as plt
    from matplotlib import cm
    import numpy as np
    from celluloid import Camera
    
    numpoints = 10
    points = np.random.random((2, numpoints))
    colors = cm.rainbow(np.linspace(0, 1, numpoints))
    camera = Camera(plt.figure())
    for _ in range(100):
        points += 0.1 * (np.random.random((2, numpoints)) - .5)
        plt.scatter(*points, c=colors, s=100)
        camera.snap()
    anim = camera.animate(blit=True)
    anim.save('scatter.mp4')
    

    It uses ArtistAnimation under the hood. camera.snap captures the current state of the figure which is used to create the frames in the animation.

    Edit: To quantify how much memory this uses I ran it through memory_profiler.

    Line #    Mem usage    Increment   Line Contents
    ================================================
        11     65.2 MiB     65.2 MiB   @profile
        12                             def main():
        13     65.2 MiB      0.0 MiB       numpoints = 10
        14     65.2 MiB      0.0 MiB       points = np.random.random((2, numpoints))
        15     65.2 MiB      0.1 MiB       colors = cm.rainbow(np.linspace(0, 1, numpoints))
        16     65.9 MiB      0.6 MiB       fig = plt.figure()
        17     65.9 MiB      0.0 MiB       camera = Camera(fig)
        18     67.8 MiB      0.0 MiB       for _ in range(100):
        19     67.8 MiB      0.0 MiB           points += 0.1 * (np.random.random((2, numpoints)) - .5)
        20     67.8 MiB      1.9 MiB           plt.scatter(*points, c=colors, s=100)
        21     67.8 MiB      0.0 MiB           camera.snap()
        22     70.1 MiB      2.3 MiB       anim = camera.animate(blit=True)
        23     72.1 MiB      1.9 MiB       anim.save('scatter.mp4')
    

    To summarize this:

    • Creating 100 plots used 1.9 MiB.
    • Making the animation used 2.3 MiB.
    • This method of making animations used 4.2 MiB of memory in sum.
    0 讨论(0)
  • 2020-11-22 17:46

    Suppose you have a scatter plot, scat = ax.scatter(...), then you can

    • change the positions

          scat.set_offsets(array)
      

      where array is a N x 2 shaped array of x and y coordinates.

    • change the sizes

          scat.set_sizes(array)
      

      where array is a 1D array of sizes in points.

    • change the color

          scat.set_array(array)
      

      where array is a 1D array of values which will be colormapped.

    Here's a quick example using the animation module.
    It's slightly more complex than it has to be, but this should give you a framework to do fancier things.

    (Code edited April 2019 to be compatible with current versions. For the older code see revision history)

    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    import numpy as np
    
    class AnimatedScatter(object):
        """An animated scatter plot using matplotlib.animations.FuncAnimation."""
        def __init__(self, numpoints=50):
            self.numpoints = numpoints
            self.stream = self.data_stream()
    
            # Setup the figure and axes...
            self.fig, self.ax = plt.subplots()
            # Then setup FuncAnimation.
            self.ani = animation.FuncAnimation(self.fig, self.update, interval=5, 
                                              init_func=self.setup_plot, blit=True)
    
        def setup_plot(self):
            """Initial drawing of the scatter plot."""
            x, y, s, c = next(self.stream).T
            self.scat = self.ax.scatter(x, y, c=c, s=s, vmin=0, vmax=1,
                                        cmap="jet", edgecolor="k")
            self.ax.axis([-10, 10, -10, 10])
            # For FuncAnimation's sake, we need to return the artist we'll be using
            # Note that it expects a sequence of artists, thus the trailing comma.
            return self.scat,
    
        def data_stream(self):
            """Generate a random walk (brownian motion). Data is scaled to produce
            a soft "flickering" effect."""
            xy = (np.random.random((self.numpoints, 2))-0.5)*10
            s, c = np.random.random((self.numpoints, 2)).T
            while True:
                xy += 0.03 * (np.random.random((self.numpoints, 2)) - 0.5)
                s += 0.05 * (np.random.random(self.numpoints) - 0.5)
                c += 0.02 * (np.random.random(self.numpoints) - 0.5)
                yield np.c_[xy[:,0], xy[:,1], s, c]
    
        def update(self, i):
            """Update the scatter plot."""
            data = next(self.stream)
    
            # Set x and y data...
            self.scat.set_offsets(data[:, :2])
            # Set sizes...
            self.scat.set_sizes(300 * abs(data[:, 2])**1.5 + 100)
            # Set colors..
            self.scat.set_array(data[:, 3])
    
            # We need to return the updated artist for FuncAnimation to draw..
            # Note that it expects a sequence of artists, thus the trailing comma.
            return self.scat,
    
    
    if __name__ == '__main__':
        a = AnimatedScatter()
        plt.show()
    

    enter image description here

    If you're on OSX and using the OSX backend, you'll need to change blit=True to blit=False in the FuncAnimation initialization below. The OSX backend doesn't fully support blitting. The performance will suffer, but the example should run correctly on OSX with blitting disabled.


    For a simpler example, which just updates the colors, have a look at the following:

    import matplotlib.pyplot as plt
    import numpy as np
    import matplotlib.animation as animation
    
    def main():
        numframes = 100
        numpoints = 10
        color_data = np.random.random((numframes, numpoints))
        x, y, c = np.random.random((3, numpoints))
    
        fig = plt.figure()
        scat = plt.scatter(x, y, c=c, s=100)
    
        ani = animation.FuncAnimation(fig, update_plot, frames=xrange(numframes),
                                      fargs=(color_data, scat))
        plt.show()
    
    def update_plot(i, data, scat):
        scat.set_array(data[i])
        return scat,
    
    main()
    
    0 讨论(0)
  • 2020-11-22 18:03

    Why Not try this

    import numpy as np
    import matplotlib.pyplot as plt
    
    x=np.random.random()
    y=np.random.random()
    
    fig, ax = plt.subplots()
    ax.scatter(x,y,color='teal')
    ax.scatter(y,x,color='crimson')
    ax.set_xlim([0,1])
    ax.set_ylim([0,1])
    
    for i in np.arange(50):
        x=np.random.random()
        y=np.random.random()
        bha=ax.scatter(x,y)
        plt.draw()
        plt.pause(0.5)
        bha.remove()
    
    plt.show()
    
    0 讨论(0)
提交回复
热议问题