Анимированный график точек, соединенных ребрами - PullRequest
4 голосов
/ 23 февраля 2012

У меня есть вопрос, который похож на этот вопрос , но вместо того, чтобы наносить на график очень большое количество точек, у меня меньше точек и ребер (коэффициент не менее 10), но я хочу их анимировать,Чтобы быть более конкретным, это визуализация сети Кохонена с 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 голосов
/ 16 марта 2012

Вот один из возможных способов. Вы можете использовать тот факт, что если в координатах линии есть 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 на .1 и ось y на .2, вы можете просто:

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

PS Я не совсем уверен, что мой способ вставки Nans в массивы xs, ys самый быстрый, но, вероятно, это не имеет значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...