SubZero
SubZero

Reputation: 123

How do I fill an animated shape with matplotlib?

I would like to plot two arbitrary polygons (using shapely for calculation of area, intersection as I am not aware of another method) and then fill the intersection, and shapes as they intersect and move during the animation.

After searching I cannot figure out how to implement this.

I have reviewed:

However, I believe I must be missing something fundamental here, or possibly it does not support filling objects during animation as the only filled object examples I can locate are static graphs.

Example code (minimum example, with two shapely shapes) is below, and has been tested as functional with python 3.

import numpy as np
import matplotlib.pyplot as plt
import shapely.geometry as sg
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()

xdata, ydata = [],[]
x2data, y2data = [],[]

ln, = plt.plot([],[])
ln2, = plt.plot([],[])

def init():
    ax.axis('equal')
    ax.set_xlim(-4, 4)
    ax.set_ylim(-4, 4)
    return ln,ln2,
 
def update(frame):
    fig.text(0,0, 'hello')
    circ1 = sg.Point(frame-2,0).buffer(1.0)
    circ2 = sg.Point(-frame+2,0).buffer(1.0)

    x,y = circ1.exterior.xy
    x2,y2 = circ2.exterior.xy
    
    intersection = circ1.intersection(circ2)
    
    xdata.append(x)
    ydata.append(y)
     
    x2data.append(x2)
    y2data.append(y2)

    ln.set_data(x,y)
    ln2.set_data(x2,y2)
    
    return ln,ln2,
  
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2, 200),
                    init_func=init, blit=True, interval = 10)
plt.show()

Upvotes: 1

Views: 844

Answers (2)

Guohan Zhao
Guohan Zhao

Reputation: 1

You first need to make a fill object by:

fill = ax.fill_between(xdata, ydata, 0, color='cyan')

Then, access the PolyCollection Class and update its vertice in the animation function by using

def animation(t):
    path = fill.get_paths()[0]
    verts = path.vertices
    # change vertice in numpy array hereof
    verts[1:-1, 1][0:2] = np.array([x, x, x])
    fill.set_color('cyan')
    return line

Upvotes: 0

Diziet Asahi
Diziet Asahi

Reputation: 40697

Since you are working with Polygons, I would suggest you use matplotlib's Polygon instead of a line to draw your shapes. This allows you to get the coordinates of the intersection shape, and draw the corresponding polygon with whatever color you choose:

import numpy as np
import matplotlib.pyplot as plt
import shapely.geometry as sg
from matplotlib.animation import FuncAnimation
from matplotlib.patches import Polygon

fig, ax = plt.subplots()

poly1 = Polygon(np.zeros(shape=(0, 2)), facecolor='none', edgecolor='C0')
poly2 = Polygon(np.zeros(shape=(0, 2)), facecolor='none', edgecolor='C1')
intersect = Polygon(np.zeros(shape=(0, 2)), facecolor='C2', edgecolor='none')

ax.add_artist(poly1)
ax.add_artist(poly2)
ax.add_artist(intersect)
t = ax.text(0.5, 0.9, "frame = ", transform=ax.transAxes, ha='center')


def init():
    ax.axis('equal')
    ax.set_xlim(-4, 4)
    ax.set_ylim(-4, 4)
    return poly1, poly2, t


def update(frame):
    t.set_text(f'frame = {frame:.3f}')
    circ1 = sg.Point(frame - 2, 0).buffer(1.0)
    circ2 = sg.Point(-frame + 2, 0).buffer(1.0)

    x, y = circ1.exterior.xy
    x2, y2 = circ2.exterior.xy

    intersection = circ1.intersection(circ2)

    poly1.set_xy(np.c_[x, y])
    poly2.set_xy(np.c_[x2, y2])

    if len(intersection.exterior.coords)>0:
        x3, y3 = intersection.exterior.coords.xy
        intersect.set_xy(np.c_[x3, y3])
        intersect.set_visible(True)
    else:
        intersect.set_visible(False)

    return poly1, poly2, intersect, t


ani = FuncAnimation(fig, update, frames=np.linspace(0, 2, 200),
                    init_func=init, blit=True, interval=10)
plt.show()

enter image description here

Upvotes: 4

Related Questions