Numpy: измененные массивы ведут себя странно - PullRequest
0 голосов
/ 22 октября 2018

Я пытаюсь изменить массив «numpy» [ link ], а затем снова изменить этот массив, но не могу достичь желаемого результата.Мои данные начинаются в форме (n_vertices, n_time, n_dimensions).Затем я преобразую его в форму (n_time, n_vertices * n_dimensions):

import numpy as np

X = np.load('dance.npy')

n_vertices, n_time, n_dims = X.shape    

X = X.reshape(n_time, n_vertices * n_dims)

Визуализируя данные, я вижу, что приведенное выше преобразование не искажает внутренние значения:

import mpl_toolkits.mplot3d.axes3d as p3
from mpl_toolkits.mplot3d.art3d import juggle_axes
import matplotlib.pyplot as plt
from IPython.display import HTML
from matplotlib import animation
import matplotlib

matplotlib.rcParams['animation.embed_limit'] = 2**128

def update_points(time, points, df):
  points._offsets3d = juggle_axes(df[:,time,0], df[:,time,1], df[:,time,2], 'z')

def get_plot(df, lim=1, frames=200, duration=45, time_axis=1, reshape=False):
  if reshape: df = df.reshape(n_vertices, df.shape[time_axis], n_dims)
  fig = plt.figure()
  ax = p3.Axes3D(fig)
  ax.set_xlim(-lim, lim)
  ax.set_ylim(-lim, lim)
  ax.set_zlim(-lim, lim)
  points = ax.scatter(df[:,0,0], df[:,0,1], df[:,0,2], depthshade=False) # x,y,z vals
  return animation.FuncAnimation(fig, update_points, frames, interval=duration, fargs=(points, df), blit=False ).to_jshtml()

HTML(get_plot(X, frames=200, time_axis=0, reshape=True))

Это показываетданные в движении (вершины являются частями тела танцора, а визуализация выглядит как человеческое тело).Это все хорошо.Тем не менее, когда я пытаюсь визуализировать только первые 10 временных срезов данных, результирующий график не показывает первые несколько кадров визуализации выше - форма фактически не имеет человеческой формы:

HTML(get_plot(X[:20], frames=10, time_axis=0, reshape=True))

Может ли кто-нибудь помочь мне понять, почему эта операция среза не соответствует первым нескольким временным рамкам X?Любые предложения или замечания будут очень полезны.

1 Ответ

0 голосов
/ 22 октября 2018

Оказывается, мои операции по изменению формы не манипулировали моими массивами так, как я думал.Следующие функции преобразуют мой исходный массив X в сплющенную форму (с двумя осями), а затем обратно в неоплощенную форму (с тремя осями) должным образом.Я добавил комментарии и тесты, чтобы убедиться, что все было так, как и ожидалось:

from math import floor

def flatten(df, run_tests=True):
  '''
  df is a numpy array with the following three axes:
    df.shape[0] = the index of a vertex
    df.shape[1] = the index of a time stamp
    df.shape[2] = the index of a dimension (x, y, z)
  So df[1][0][2] is the value for the 1st vertex (0-based) at time 0 in dimension 2 (z).
  To flatten this dataframe will mean to push the data into shape:
    flattened.shape[0] = time index
    flattened.shape[1] = [vertex_index*3] + dimension_vertex
  So flattened[1][3] will be the 3rd dimension of the 1st index (0-based) at time 1. 
  '''
  if run_tests:
    assert df.shape == X.shape and np.all(df == X)

  # reshape X such that flattened.shape = time, [x0, y0, z0, x1, y1, z1, ... xn-1, yn-1, zn-1]
  flattened = X.swapaxes(0, 1).reshape( (df.shape[1], df.shape[0] * df.shape[2]), order='C' )

  if run_tests: # switch to false to skip tests
    for idx, i in enumerate(df):
      for jdx, j in enumerate(df[idx]):
        for kdx, k in enumerate(df[idx][jdx]):
          assert flattened[jdx][ (idx*df.shape[2]) + kdx ] == df[idx][jdx][kdx]

  return flattened

И чтобы развернуть сглаженные данные:

def unflatten(df, run_tests=True):
  '''
  df is a numpy array with the following two axes:
    df.shape[0] = time index
    df.shape[1] = [vertex_index*3] + dimension_vertex

  To unflatten this dataframe will mean to push the data into shape:
    unflattened.shape[0] = the index of a vertex
    unflattened.shape[1] = the index of a time stamp
    unflattened.shape[2] = the index of a dimension (x, y, z)

  So df[2][4] == unflattened[1][2][0]
  '''
  if run_tests:
    assert (len(df.shape) == 2) and (df.shape[1] == X.shape[0] * X.shape[2])

  unflattened = np.zeros(( X.shape[0], df.shape[0], X.shape[2] ))

  for idx, i in enumerate(df):
    for jdx, j in enumerate(df[idx]):
      kdx = floor(jdx / 3)
      ldx = jdx % 3
      unflattened[kdx][idx][ldx] = df[idx][jdx]

  if run_tests: # set to false to skip tests
    for idx, i in enumerate(unflattened):
      for jdx, j in enumerate(unflattened[idx]):
        for kdx, k in enumerate(unflattened[idx][jdx]):
          assert( unflattened[idx][jdx][kdx] == X[idx][jdx][kdx] )

  return unflattened

Затем визуализировать:

import mpl_toolkits.mplot3d.axes3d as p3
from mpl_toolkits.mplot3d.art3d import juggle_axes
import matplotlib.pyplot as plt
from IPython.display import HTML
from matplotlib import animation
import matplotlib

# ask matplotlib to plot up to 2^128 frames in animations
matplotlib.rcParams['animation.embed_limit'] = 2**128

def update_points(time, points, df):
  points._offsets3d = juggle_axes(df[:,time,0], df[:,time,1], df[:,time,2], 'z')

def get_plot(df, lim=1, frames=200, duration=45):
  if len(df.shape) == 2: df = unflatten(df)
  fig = plt.figure()
  ax = p3.Axes3D(fig)
  ax.set_xlim(-lim, lim)
  ax.set_ylim(-lim, lim)
  ax.set_zlim(-lim, lim)
  points = ax.scatter(df[:,0,0], df[:,0,1], df[:,0,2], depthshade=False) # x,y,z vals
  return animation.FuncAnimation(fig,
    update_points,
    frames,
    interval=duration,
    fargs=(points, df),
    blit=False  
  ).to_jshtml()

HTML(get_plot(unflat, frames=200))

Это позволяет мне без проблем разрезать временную ось:

flat = flatten(X)
unflat = unflatten(flat)

HTML(get_plot(unflat, frames=200))
HTML(get_plot(flat[:20], frames=20))
HTML(get_plot(unflat[:,:20,:], frames=20))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...