使用 python-matplotlib 进行连续 3D 绘图(即图形更新)?

Posted

技术标签:

【中文标题】使用 python-matplotlib 进行连续 3D 绘图(即图形更新)?【英文标题】:Continuous 3D plotting (i.e. figure update) using python-matplotlib? 【发布时间】:2011-07-07 23:11:52 【问题描述】:

我有一个模拟,它为模拟的每次迭代计算表面数据。 我想将该数据作为曲面图连续绘制到同一窗口(在每次迭代中更新该图),以查看它如何演变并检查算法。

我的想法是创建一个类来初始化窗口/绘图,然后从模拟循环内部重绘到该窗口。这是我想出的课程:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FixedLocator, FormatStrFormatter
import matplotlib
matplotlib.interactive( False )

class plot3dClass( object ):

    def __init__( self, systemSideLength, lowerCutoffLength ):
        self.systemSideLength = systemSideLength
        self.lowerCutoffLength = lowerCutoffLength
        self.fig = plt.figure()
        self.ax = self.fig.add_subplot( 111, projection='3d' )
        self.ax.set_zlim3d( -10e-9, 10e9 )

        X = np.arange( 0, self.systemSideLength, self.lowerCutoffLength )
        Y = X
        self.X, self.Y = np.meshgrid(X, Y)

        self.ax.w_zaxis.set_major_locator( LinearLocator( 10 ) )
        self.ax.w_zaxis.set_major_formatter( FormatStrFormatter( '%.03f' ) )

        heightR = np.zeros( self.X.shape )
        self.surf = self.ax.plot_surface( self.X, self.Y, heightR, rstride=1, cstride=1, cmap=cm.jet, linewidth=0, antialiased=False )
        #~ self.fig.colorbar( self.surf, shrink=0.5, aspect=5 )

        plt.show()


    def drawNow( self, heightR ):

        self.surf = self.ax.plot_surface( self.X, self.Y, heightR, rstride=1, cstride=1, cmap=cm.jet, linewidth=0, antialiased=False )
        plt.draw()                      # redraw the canvas

        time.sleep(1)

这段代码的问题是代码在'plt.show()'处停止,只有在我关闭绘图窗口时才会继续。此外,我不确定“self.ax.plot_surface(...)”和“plt.draw()”的调用是否会按照我的意愿更新图形。

那么这个类是正确的方向吗?

如果是:需要进行哪些修改?

如果没有:有人可以给我建议如何实现我想要的吗?

我意识到这个问题对其他人来说可能看起来微不足道,但我(老实说)昨天确实花了一整天时间在 Google 上尝试,但我不知所措......

任何帮助将不胜感激,这样我就可以回到我的实际工作中。

提前很多坦克。

作为参考:

我还发现了下面的代码,我想要什么,但它是二维的,所以它不能直接帮助我:

from pylab import *
import time

ion()

tstart = time.time()               # for profiling
x = arange(0,2*pi,0.01)            # x-array
line, = plot(x,sin(x))

for i in arange(1,200):
    line.set_ydata(sin(x+i/10.0))  # update the data
    draw()                         # redraw the canvas

print 'FPS:' , 200/(time.time()-tstart)

【问题讨论】:

【参考方案1】:

如果是动画(交互式)情节,则不需要plt.show()。您还希望交互式设置为 True,而不是 False,这与在 2d 示例中调用 ion() 相同。此外,如果您不想全部查看之前帧的曲面图,则需要remove()

否则你已经很接近了。

这对我有用:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FixedLocator, FormatStrFormatter
import matplotlib, time

class plot3dClass( object ):

    def __init__( self, systemSideLength, lowerCutoffLength ):
        self.systemSideLength = systemSideLength
        self.lowerCutoffLength = lowerCutoffLength
        self.fig = plt.figure()
        self.ax = self.fig.add_subplot( 111, projection='3d' )
        self.ax.set_zlim3d( -10e-9, 10e9 )

        rng = np.arange( 0, self.systemSideLength, self.lowerCutoffLength )
        self.X, self.Y = np.meshgrid(rng,rng)

        self.ax.w_zaxis.set_major_locator( LinearLocator( 10 ) )
        self.ax.w_zaxis.set_major_formatter( FormatStrFormatter( '%.03f' ) )

        heightR = np.zeros( self.X.shape )
        self.surf = self.ax.plot_surface( 
            self.X, self.Y, heightR, rstride=1, cstride=1, 
            cmap=cm.jet, linewidth=0, antialiased=False )
        # plt.draw() maybe you want to see this frame?

    def drawNow( self, heightR ):
        self.surf.remove()
        self.surf = self.ax.plot_surface( 
            self.X, self.Y, heightR, rstride=1, cstride=1, 
            cmap=cm.jet, linewidth=0, antialiased=False )
        plt.draw()                      # redraw the canvas
        time.sleep(1)

matplotlib.interactive(True)

p = plot3dClass(5,1)
for i in range(2):
    p.drawNow(np.random.random(p.X.shape))

【讨论】:

这在我的电脑上不起作用(Win XP,python 2.7.3):我看到的只是最终的图表 在 plt.draw() 行之后需要 self.fig.canvas.flush_events() 。 (信用***.com/a/4098938/415551)【参考方案2】:

我遇到了类似的问题,这对我有用:

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

plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

for k in xrange(0,X_range):
    ax.plot(x_input, y_input, z_input)
    plt.draw()
    plt.pause(0.02)
    ax.cla()

对你来说,我想解决方案类似于the top answer,除了将time.sleep() 替换为plt.pause(),这将在睡觉前完成图形的绘制。

【讨论】:

【参考方案3】:

我很感谢 Paul 的回答,虽然我还没有尝试过。

与此同时,我找到了另一种使用 MayaVI 与 OpenGL 一起工作和渲染的解决方案,这没关系,因为我只需要实时快速的视觉反馈。但是我必须在 Ubuntu 下安装以下软件包:python-enthoughtbase 和 mayavi2

代码如下:

import numpy as np
import time
from enthought.mayavi import mlab
from enthought.tvtk.tools import visual

    class plot3dClass( object ):

        def __init__( self, systemSideLength, lowerCutoffLength ):
            self.systemSideLength = systemSideLength
            self.lowerCutoffLength = lowerCutoffLength

            rangeMax = self.systemSideLength
            X = np.arange( 0, self.systemSideLength, self.lowerCutoffLength )
            Y = X

            matrixSize = int( round( self.systemSideLength / self.lowerCutoffLength ) )
            heightR = np.zeros( ( matrixSize, matrixSize ) )

            fig = mlab.figure(size=(500,500))
            visual.set_viewer(fig)
            self.surf = mlab.surf( X, Y, heightR, warp_scale = 1e1 ) # NOTE: the warp_scale factor is relative to the scale of the x- and y-axes
            box_extent = ( 0,rangeMax, 0,rangeMax, -1e-7,1e-7 ) # NOTE: the extent options refers to the size and position in the 3D space relative to the origin

            mlab.outline(self.surf, color=(0.7, .7, .7), extent = box_extent )

        def drawNow( self, heightR ):
            self.surf.mlab_source.scalars = heightR
            time.sleep(0.033)

这门课不是我想要的,我有两个直接的问题:

    不久之后,Ubuntu 将窗口变灰,因为(我想)Ubuntu 认为应用程序没有响应。也许是一个 Ubuntu 问题,但很烦人。 我一直在尝试找出如何在制作动画时使用鼠标旋转情节。

我会尝试在另一个帖子中回答这些问题。

编辑: 好的。我刚刚尝试了 Paul 建议的代码,它也适用于我。但是,尝试它后,我意识到 MatPlotLib 可能不是实时制作动画的最佳选择。至少对我来说它非常慢(也许只在 3D 中?)。

所以最后我会坚持使用上面的 MayaVI 实现,除了提到的两点之外,效果很好。

编辑:如果您使用 MatPlotLib 解决方案,我发现您可以将行 matplotlib.interactive(True) 放在绘图类的声明中。这样你就可以只在绘图类中定义 MatPlotLib。

【讨论】:

你没有给自己一个有用的答案。 OP 标题是:如何使用 Python 和 MatPlotLib 实现连续 3D 绘图(即更新图形)?。你给自己和使用 MayaVI 而不是 matplotlib 的答案。另一方面,您使用 matplotlib 得到了有效的答案,但您并没有首先尝试...

以上是关于使用 python-matplotlib 进行连续 3D 绘图(即图形更新)?的主要内容,如果未能解决你的问题,请参考以下文章

利用python进行数据分析-学习记录python-matplotlib中Basemap插件的安装

学会Python-Matplotlib可视化,快速完成数据分析——自定义样式绘制精美统计图

Python-matplotlib:调整坐标轴位置标签位置和标签方向,以及X轴刻度标签位置

Python-Matplotlib基础

Python-Matplotlib 13 网格

学会Python-Matplotlib可视化,快速完成数据分析——自定义颜色绘制精美统计图