三维散点图动画化

12

我正在尝试在matplotlib中获得一个散点图的3D动画,基于这里发布的2D散点图动画here和这里发布的3D线性图here

问题出现在set_dataset_offsets在3D中无法工作,因此您应该使用set_3d_properties来附加z信息。尝试使用它时,通常会出现错误,但是使用下面发布的代码可以运行。但是,透明度增加到足够高的程度后,几帧后点就会消失。我在这里做错了什么?我想让点在盒子的范围内跳动一段时间。即使将步长调整为非常小的值,透明度也不会减慢。

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

FLOOR = -10
CEILING = 10

class AnimatedScatter(object):
    def __init__(self, numpoints=5):
        self.numpoints = numpoints
        self.stream = self.data_stream()
        self.angle = 0

        self.fig = plt.figure()
        self.ax = self.fig.add_subplot(111,projection = '3d')
        self.ani = animation.FuncAnimation(self.fig, self.update, interval=100, 
                                           init_func=self.setup_plot, blit=True)

    def change_angle(self):
        self.angle = (self.angle + 1)%360

    def setup_plot(self):
        x, y, z = next(self.stream)
        c = ['b', 'r', 'g', 'y', 'm']
        self.scat = self.ax.scatter(x, y, z,c=c, s=200, animated=True)

        self.ax.set_xlim3d(FLOOR, CEILING)
        self.ax.set_ylim3d(FLOOR, CEILING)
        self.ax.set_zlim3d(FLOOR, CEILING)

        return self.scat,

    def data_stream(self):
        data = np.zeros((3, self.numpoints))
        xyz = data[:3, :]
        while True:
            xyz += 2 * (np.random.random((3, self.numpoints)) - 0.5)
            yield data

    def update(self, i):
        data = next(self.stream)
        data = np.transpose(data)

        self.scat.set_offsets(data[:,:2])
        #self.scat.set_3d_properties(data)
        self.scat.set_3d_properties(data[:,2:],'z')

        self.change_angle()
        self.ax.view_init(30,self.angle)
        plt.draw()
        return self.scat,

    def show(self):
        plt.show()

if __name__ == '__main__':
    a = AnimatedScatter()
    a.show()

4
弄清楚了,如果有人需要的话。删除所有关于set_offsets和set_3d_properties的行,并只使用以下内容:self.scat._offsets3d =(x,y,z),在这段代码中显然从数据中提取x,y和z。 - eric p
能否使用plot()函数来绘制点图而不是散点图?顺便说一下,你的解决方案对我很有用。 - PerroNoob
1
@ericp 你应该把你的解决方案发布为一个答案... - Saullo G. P. Castro
2个回答

6

终于找到解决方案了,以下是如何更新点而不影响颜色的方法:

from mpl_toolkits.mplot3d.art3d import juggle_axes
scat._offsets3d = juggle_axes(xs, ys, zs, 'z')

这是由set_3d_properties内部完成的,同时重新初始化颜色。


4
我找到了一种更通用的解决方案: 在将数据插入集合之前,您应该添加np.ma.ravel(x_data) ...
但是散点图似乎不适用于动画效果,它太慢了。
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

FLOOR = -10
CEILING = 10

class AnimatedScatter(object):
    def __init__(self, numpoints=5):
        self.numpoints = numpoints
        self.stream = self.data_stream()
        self.angle = 0

        self.fig = plt.figure()
        self.ax = self.fig.add_subplot(111,projection = '3d')
        self.ani = animation.FuncAnimation(self.fig, self.update, interval=100, 
                                           init_func=self.setup_plot, blit=True)

    def change_angle(self):
        self.angle = (self.angle + 1)%360

    def setup_plot(self):
        X = next(self.stream)
        c = ['b', 'r', 'g', 'y', 'm']
        self.scat = self.ax.scatter(X[:,0], X[:,1], X[:,2] , c=c, s=200, animated=True)

        self.ax.set_xlim3d(FLOOR, CEILING)
        self.ax.set_ylim3d(FLOOR, CEILING)
        self.ax.set_zlim3d(FLOOR, CEILING)

        return self.scat,

    def data_stream(self):
        data = np.zeros(( self.numpoints , 3 ))
        xyz = data[:,:3]
        while True:
            xyz += 2 * (np.random.random(( self.numpoints,3)) - 0.5)
            yield data

    def update(self, i):
        data = next(self.stream)
        data = np.transpose(data)

        self.scat._offsets3d = ( np.ma.ravel(data[:,0]) , np.ma.ravel(data[:,0]) , np.ma.ravel(data[:,0]) )

        self.change_angle()
        self.ax.view_init(30,self.angle)
        plt.draw()
        return self.scat,

    def show(self):
        plt.show()

if __name__ == '__main__':
    a = AnimatedScatter()
    a.show()

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