连接点的图形动画化

4
我有一个问题,类似于这个问题,但是我要绘制少量的点和边(至少是10倍),并希望对它们进行动画处理。更具体地说,这是一个Kohonen网络在2D地图上的可视化,它会演变成一个变形的正方形晶格,参见维基百科中的这张图片:

image

这个答案中取出代码,并稍作修改,一个最小的示例看起来像这样:
import numpy as np
import matplotlib.pyplot as plt

def getXY(points, edges):
   """Return x and y arrays to pass to the plot function"""
   return [points.T[i][edges.T] for i in np.arange(points.shape[1])]

points = numpy.array([[1,2],[4,5],[2,7],[3,9],[9,2]])
edges = numpy.array([[0,1],[3,4],[3,2],[2,4]])

lines = plt.plot(*getXY(points, edges), linestyle='-', color='y',
        markerfacecolor='red', marker='o')
plt.show()

接着,发生了一次更新,改变了这些点的坐标:
points += 1 # simplified version of a real update

我希望避免“愚蠢”的重新绘制所有内容的方法,因为图形窗口中还有其他数据没有变化,而且这样做会非常慢:
# repeat after each update all the calculation
plt.cla()
x, y = [points.T[i][edges.T] for i in np.arange(points.shape[1])]
lines = plt.plot(x, y, linestyle='-', color='y',
        markerfacecolor='red', marker='o')
plt.show()

作为第一步,我将初始图中创建的Line2D数据保存在变量lines中。 我现在面临的问题是,如果我只想更新线条数据,我能想到的唯一解决方案就是需要迭代所有线条,这看起来不太优雅。
x, y = getXY(points, edges)
if len(lines) > 1: 
    for i, d in enumerate(zip(x.T, y.T)):
        lines[i].set_data(d)
else: # has to be treated seperately, since the format of x and y is different
    lines[0].set_data(x, y)
plt.show()

我正在寻找如何改进以下方面的建议:

  • 提出比我的for循环更好的解决方案
  • 提供在更加优雅的方式下解决初始问题的想法(即以指定连接绘制点)
1个回答

0

这里有一种可能的方法。您可以利用以下事实:如果在线条坐标中存在NaN或None,则将其视为线段的结束。下一个非None点被视为新段的开始。

import numpy as np, matplotlib.pyplot as plt
x,y = np.array([1, 4,2, 3, 9]), np.array([2, 5, 7, 9, 2])

edges = np.array([[0, 1],
   [3, 4],
   [3, 2],
   [2, 4],
   [2, 1]])

ys=np.vstack((y[edges[:,0]],y[edges[:,1]],y[edges[:,0]]+np.nan)).T.flatten()

xs=np.vstack((x[edges[:,0]],x[edges[:,1]],x[edges[:,0]]+np.nan)).T.flatten()

lines2d = plt.plot(xs,ys,marker='o')

现在如果要更新坐标(例如将x轴移动0.1,y轴移动0.2),只需要执行以下操作:

oldx,oldy=lines2d[0].get_data()
lines2d[0].set_data(oldx+.1,oldy+.2)
plt.draw()

顺便说一句,我并不完全确定在xs、ys数组中插入NaN的方式是否是最快的,但这可能并不重要。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接