是否可以以某种方式绘制一个自定义标记(如 这个)交互式,但要它实时转动?似乎散点图不允许任何对标记的访问。
您可以通过以下方式创建一个自定义标记 FancyArrowPatch
. 许多风格和选项都是可能的。这样的补丁不容易更新,但你可以直接删除补丁,然后再创建它来创建动画。
最简单的创建动画的方法是通过 plt.pause()
但这并不是在所有的环境中都有效。另一种方法是通过 FuncAnimation
,这涉及到更多的行,但使控制动画更容易。
这里有一些例子代码来展示这些概念。
import matplotlib.pyplot as plt
from matplotlib import patches
from matplotlib.collections import PatchCollection
from matplotlib import animation
import numpy as np
fig, ax = plt.subplots()
N = 50
x = np.random.uniform(-20, 20, (N, 2))
dx = np.random.uniform(-1, 1, (N, 2))
dx /= np.linalg.norm(dx, axis=1, keepdims=True)
colors = plt.cm.magma(np.random.uniform(0, 1, N))
arrow_style = "Simple,head_length=2,head_width=3,tail_width=1"
ax.set_xlim(-40, 40)
ax.set_ylim(-30, 30)
ax.set_aspect('equal')
old_arrows = None
def animate(i):
global old_arrows, x, dx
if old_arrows is not None:
old_arrows.remove()
x += dx
dx += np.random.uniform(-.1, .1, (N, 2))
dx /= np.linalg.norm(dx, axis=1, keepdims=True)
arrows = [patches.FancyArrowPatch((xi, yi), (xi + dxi * 10, yi + dyi * 10), arrowstyle=arrow_style)
for (xi, yi), (dxi, dyi) in zip(x, dx)]
old_arrows = ax.add_collection(PatchCollection(arrows, facecolors=colors))
return old_arrows,
ani = animation.FuncAnimation(fig, animate, np.arange(1, 200),
interval=25, repeat=False, blit=True)
plt.show()
我通过以下方法解决了这个问题 remove()
和这样的静态变量。
class pltMarker:
def __init__(self, angle=None, pathString=None):
self.angle = angle or []
self.pathString = pathString or """simply make and svg, open in a text editor and copy the path XML string in here"""
self.path = parse_path( self.pathString )
self.path.vertices -= self.path.vertices.mean( axis=0 )
self.marker = mpl.markers.MarkerStyle( marker=self.path )
self.marker._transform = self.marker.get_transform().rotate_deg(angle)
def rotate(self, angle=0):
self.marker._transform = self.marker.get_transform().rotate_deg(angle)
def animate(k):
angle = ... # new angle
myPltMarker.rotate(angle)
animate.Scatter.remove()
animate.Scatter = plt.scatter(1, 0, marker=myPltMarker.marker, s=100)
return animate.Scatter,
angle = ...
myPltMarker = pltMarker(angle=angle)
animatePlt.Scatter = plt.scatter(1, 0, marker=myPltMarker.marker, s=100)
anm = animation.FuncAnimation(fig, animate, blit=False, interval=1)
plt.show()