【问题标题】:Animate text within a circle - Matplotlib在圆圈内动画文本 - Matplotlib
【发布时间】:2020-10-17 04:49:11
【问题描述】:

以下根据给定的半径为圆和线设置动画。我希望将情节与突出显示该圈子内不同部分的动画文本结合起来。每个新框架的文本都会更新,但不会删除以前的框架文本。

注意:我正在尝试保持动画功能,因为我想保持轴相同并且只为更新的数据设置动画。

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
import matplotlib.gridspec as gridspec
import math 

df = pd.DataFrame({   
    'Time' : [1,1,1,1,2,2,2,2,3,3,3,3],                        
    'X2' : [0,0,0,0,-1,-1,-1,-1,0,0,0,0],
    'Y2' : [0,0,0,0,1,1,1,1,1,1,1,1],    
    'Angle' : [0,0,0,0,-45,-45,-45,-45,90,90,90,90],                    
    })

fig = plt.figure(figsize = (8,10))

grid = gridspec.GridSpec(1, 2)
gridsize = (1, 2)

ax = plt.subplot2grid(gridsize, (0, 0))
ax2 = plt.subplot2grid(gridsize, (0, 1))
ax2.set_xlim(-10, 10)
ax2.set_ylim(-10, 10)

# the center of the compass
moving_x = np.array(df.groupby(['Time'])['X2'].apply(list))
moving_y = np.array(df.groupby(['Time'])['Y2'].apply(list))
moving_point = ax.scatter(moving_x[0], moving_y[0], c = 'black', marker = 'o', zorder = 3)

radius = df.drop_duplicates(subset = ['Time','X2', 'Y2'])[['X2', 'Y2']].values

circle = plt.Circle(radius[0], 10, color = 'black', fill = False, lw = 0.2)
circle2 = plt.Circle(radius[0], 10, color = 'red', fill = False, lw = 0.2)

ax.add_patch(circle)
ax2.add_patch(circle2)

line1, = ax.plot([],[], color = 'k', linewidth = 1)
line2, = ax.plot([],[], color = 'k', linewidth = 1)

t = df['Angle'][0]
angles = np.array(df.groupby(['Time'])['Angle'].apply(list))

angleText = df.drop_duplicates(subset = ['Time','Angle'])['Angle'].values

rot_mat = lambda theta:np.array([
    [np.cos(np.deg2rad(theta)),-np.sin(np.deg2rad(theta))],
    [np.sin(np.deg2rad(theta)),np.cos(np.deg2rad(theta))]
])

# compass tags
annotate_tags = ['N','E','S','W']

def animate(i) :

    moving_point.set_offsets(np.c_[moving_x[0+i], moving_y[0+i]])
    circle.center = (radius[i,0], radius[i,1])

    xs1L1=-10.0/2**0.5
    ys1L1=10.0/2**0.5
    xs2L1=10.0/2**0.5
    ys2L1=-10.0/2**0.5

    xs1L2=-xs1L1
    ys1L2=ys1L1
    xs2L2=-xs1L2
    ys2L2=ys2L1

    cx=radius[i,0]
    cy=radius[i,1]

    theta=math.radians(angles[i][0])

    x1L1=(  (xs1L1+radius[i,0] - cx) * math.cos(theta) + (ys1L1+radius[i,1] - cy) * math.sin(theta) ) + cx
    x2L1=(  (xs2L1+radius[i,0] - cx) * math.cos(theta) + (ys2L1+radius[i,1]- cy) * math.sin(theta) ) + cx
    y1L1=( -(xs1L1+radius[i,0] - cx) * math.sin(theta) + (ys1L1+radius[i,1] - cy) * math.cos(theta) ) + cy
    y2L1=( -(xs2L1+radius[i,0] - cx) * math.sin(theta) + (ys2L1+radius[i,1] - cy) * math.cos(theta) ) + cy

    line1.set_data([x1L1,x2L1],[y1L1,y2L1])

    x1L2=(  (xs1L2+radius[i,0] - cx) * math.cos(theta) + (ys1L2+radius[i,1] - cy) * math.sin(theta) ) + cx
    x2L2=(  (xs2L2+radius[i,0] - cx) * math.cos(theta) + (ys2L2+radius[i,1]- cy) * math.sin(theta) ) + cx
    y1L2=( -(xs1L2+radius[i,0] - cx) * math.sin(theta) + (ys1L2+radius[i,1] - cy) * math.cos(theta) ) + cy
    y2L2=( -(xs2L2+radius[i,0] - cx) * math.sin(theta) + (ys2L2+radius[i,1] - cy) * math.cos(theta) ) + cy

    line2.set_data([x1L2,x2L2],[y1L2,y2L2])        

    # Animate compass tags for each frame
    tag_pos = np.array([[0,8.5],[8.5,0],[0,-8.5],[-8.5,0]])    
    tag_pos = tag_pos @ rot_mat(angleText[i])

    for tag,pos in zip(annotate_tags,tag_pos):
        ax.annotate(tag,xy=pos+radius[i], xycoords='data',
                      fontsize=10,horizontalalignment='right', verticalalignment='bottom')

ani = animation.FuncAnimation(fig, animate, np.arange(0,3), blit = False)

【问题讨论】:

  • 我建议您在动画功能之外使用annotate 创建文本对象。然后,您可以在 animate 函数内的这些文本对象上使用 .set_x().set_y(),类似于使用 .set_data() 的方式。

标签: pandas matplotlib animation


【解决方案1】:

您想在animate 函数之外为尽可能多的标签创建文本对象。并且,在animate 函数内部set_textset_position 如下所示:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
import matplotlib.gridspec as gridspec
import math 

df = pd.DataFrame({   
    'Time' : [1,1,1,1,2,2,2,2,3,3,3,3],                        
    'X2' : [0,0,0,0,-1,-1,-1,-1,0,0,0,0],
    'Y2' : [0,0,0,0,1,1,1,1,1,1,1,1],    
    'Angle' : [0,0,0,0,-45,-45,-45,-45,90,90,90,90],                    
    })

fig = plt.figure(figsize = (20,10))

grid = gridspec.GridSpec(1, 2)
gridsize = (1, 2)

ax = plt.subplot2grid(gridsize, (0, 0))
ax2 = plt.subplot2grid(gridsize, (0, 1))
ax2.set_xlim(-10, 10)
ax2.set_ylim(-10, 10)

# the center of the compass
moving_x = np.array(df.groupby(['Time'])['X2'].apply(list))
moving_y = np.array(df.groupby(['Time'])['Y2'].apply(list))
moving_point = ax.scatter(moving_x[0], moving_y[0], c = 'black', marker = 'o', zorder = 3)

radius = df.drop_duplicates(subset = ['Time','X2', 'Y2'])[['X2', 'Y2']].values

circle = plt.Circle(radius[0], 10, color = 'black', fill = False, lw = 0.2)
circle2 = plt.Circle(radius[0], 10, color = 'red', fill = False, lw = 0.2)

ax.add_patch(circle)
ax2.add_patch(circle2)

line1, = ax.plot([],[], color = 'k', linewidth = 1)
line2, = ax.plot([],[], color = 'k', linewidth = 1)

t = df['Angle'][0]
angles = np.array(df.groupby(['Time'])['Angle'].apply(list))

angleText = df.drop_duplicates(subset = ['Time','Angle'])['Angle'].values

rot_mat = lambda theta:np.array([
    [np.cos(np.deg2rad(theta)),-np.sin(np.deg2rad(theta))],
    [np.sin(np.deg2rad(theta)),np.cos(np.deg2rad(theta))]
])

# compass tags
annotate_tags = ['N','E','S','W']
annotation=[None]*len(annotate_tags)
for i in range(len(annotate_tags)):
    annotation[i] = ax.annotate('', xy=(0, 0),xycoords='data',fontsize=10,horizontalalignment='right', verticalalignment='bottom')


def animate(i) :

    moving_point.set_offsets(np.c_[moving_x[0+i], moving_y[0+i]])
    circle.center = (radius[i,0], radius[i,1])

    xs1L1=-10.0/2**0.5
    ys1L1=10.0/2**0.5
    xs2L1=10.0/2**0.5
    ys2L1=-10.0/2**0.5

    xs1L2=-xs1L1
    ys1L2=ys1L1
    xs2L2=-xs1L2
    ys2L2=ys2L1

    cx=radius[i,0]
    cy=radius[i,1]

    theta=math.radians(angles[i][0])

    x1L1=(  (xs1L1+radius[i,0] - cx) * math.cos(theta) + (ys1L1+radius[i,1] - cy) * math.sin(theta) ) + cx
    x2L1=(  (xs2L1+radius[i,0] - cx) * math.cos(theta) + (ys2L1+radius[i,1]- cy) * math.sin(theta) ) + cx
    y1L1=( -(xs1L1+radius[i,0] - cx) * math.sin(theta) + (ys1L1+radius[i,1] - cy) * math.cos(theta) ) + cy
    y2L1=( -(xs2L1+radius[i,0] - cx) * math.sin(theta) + (ys2L1+radius[i,1] - cy) * math.cos(theta) ) + cy

    line1.set_data([x1L1,x2L1],[y1L1,y2L1])

    x1L2=(  (xs1L2+radius[i,0] - cx) * math.cos(theta) + (ys1L2+radius[i,1] - cy) * math.sin(theta) ) + cx
    x2L2=(  (xs2L2+radius[i,0] - cx) * math.cos(theta) + (ys2L2+radius[i,1]- cy) * math.sin(theta) ) + cx
    y1L2=( -(xs1L2+radius[i,0] - cx) * math.sin(theta) + (ys1L2+radius[i,1] - cy) * math.cos(theta) ) + cy
    y2L2=( -(xs2L2+radius[i,0] - cx) * math.sin(theta) + (ys2L2+radius[i,1] - cy) * math.cos(theta) ) + cy

    line2.set_data([x1L2,x2L2],[y1L2,y2L2])        

    # Animate compass tags for each frame
    tag_pos = np.array([[0,8.5],[8.5,0],[0,-8.5],[-8.5,0]])    
    tag_pos = tag_pos @ rot_mat(angleText[i])
    k=0
    for tag,pos in zip(annotate_tags,tag_pos):
        annotation[k].set_text(tag)
        annotation[k].set_position(xy=pos+radius[i])
        k=k+1

ani = animation.FuncAnimation(fig, animate, np.arange(0,3), blit = False)
ani.save('test.gif', writer='imagemagick', fps=5)
plt.show()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-05
    • 2014-01-21
    相关资源
    最近更新 更多