Matplotlib animate fill_between shape

后端 未结 5 2070
别那么骄傲
别那么骄傲 2021-01-04 02:48

I am trying to animate a fill_between shape inside matplotlib and I don\'t know how to update the data of the PolyCollection. Take this simple example: I have two lines and

相关标签:
5条回答
  • 2021-01-04 02:51

    initialize pyplot interactive mode

    import matplotlib.pyplot as plt
    
    plt.ion()
    

    use the optional label argument when plotting the fill:

    plt.fill_between(
        x, 
        y1, 
        y2, 
        color="yellow", 
        label="cone"
    )
    
    plt.pause(0.001) # refresh the animation
    

    later in our script we can select by label to delete that specific fill or a list of fills, thus animating on a object by object basis.

    axis = plt.gca()
    
    fills = ["cone", "sideways", "market"]   
    
    for collection in axis.collections:
        if str(collection.get_label()) in fills:
            collection.remove()
            del collection
    
    plt.pause(0.001)
    

    you can use the same label for groups of objects you would like to delete; or otherwise encode the labels with tags as needed to suit needs

    for example if we had fills labelled:

    "cone1" "cone2" "sideways1"

    if "cone" in str(collection.get_label()):
    

    would sort to delete both those prefixed with "cone".

    You can also animate lines in the same manner

    for line in axis.lines:
    
    0 讨论(0)
  • 2021-01-04 02:56

    this is not my answer, but I found it most useful:

    http://matplotlib.1069221.n5.nabble.com/animation-of-a-fill-between-region-td42814.html

    Hi Mauricio, Patch objects are a bit more difficult to work with than line objects, because unlike line objects are a step removed from the input data supplied by the user. There is an example similar to what you want to do here: http://matplotlib.org/examples/animation/histogram.html

    Basically, you need to modify the vertices of the path at each frame. It might look something like this:

    from matplotlib import animation
    import numpy as np
    import matplotlib.pyplot as plt
    
    fig, ax = plt.subplots()
    ax.set_xlim([0,10000])
    
    x = np.linspace(6000.,7000., 5)
    y = np.ones_like(x)
    
    collection = plt.fill_between(x, y)
    
    def animate(i):
        path = collection.get_paths()[0]
        path.vertices[:, 1] *= 0.9
    
    animation.FuncAnimation(fig, animate,
                            frames=25, interval=30)
    

    Take a look at path.vertices to see how they're laid out. Hope that helps, Jake

    0 讨论(0)
  • 2021-01-04 02:58

    If you don't want to use anitmation, or to remove everything from your figure to update only filling, you could use this way :

    call fill_lines.remove() and then call again axes_dummy.fill_between() to draw new ones. It worked in my case.

    0 讨论(0)
  • 2021-01-04 03:06

    Ok, as someone pointed out, we are dealing with a collection here, so we will have to delete and redraw. So somewhere in the update_data function, delete all collections associated with it:

    axes_dummy.collections.clear()
    

    and draw the new "fill_between" PolyCollection:

    axes_dummy.fill_between(x, y-sigma, y+sigma, facecolor='yellow', alpha=0.5)
    

    A similar trick is required to overlay an unfilled contour plot on top of a filled one, since an unfilled contour plot is a Collection as well (of lines I suppose?).

    0 讨论(0)
  • 2021-01-04 03:18

    another idiom which will work is too keep a list of your plotted objects; this method seems to work with any type of plotted object.

    # plot interactive mode on
    plt.ion()
    
    # create a dict to store "fills" 
    # perhaps some other subclass of plots 
    # "yellow lines" etc. 
    plots = {"fills":[]}
    
    # begin the animation
    while 1: 
    
        # cycle through previously plotted objects
        # attempt to kill them; else remember they exist
        fills = []
        for fill in plots["fills"]:
            try:
                # remove and destroy reference
                fill.remove()
                del fill
            except:
                # and if not try again next time
                fills.append(fill)
                pass
        plots["fills"] = fills   
    
        # transformation of data for next frame   
        x, y1, y2 = your_function(x, y1, y2)
    
        # fill between plot is appended to stored fills list
        plots["fills"].append(
            plt.fill_between(
                x,
                y1,
                y2,
                color="red",
            )
        )
    
        # frame rate
        plt.pause(1)
    
    0 讨论(0)
提交回复
热议问题