2011-03-03 327 views
9

我有一个模拟计算每次模拟迭代的表面数据。 我想连续将该数据作为曲面图绘制到同一个窗口中(更新每次迭代中的绘图),以便了解它如何演变并检查算法。使用python-matplotlib进行连续3D绘图(即图形更新)?

我的想法是创建一个类,它将初始化窗口/绘图,然后从模拟循环内部重新绘制到该窗口。这里是我想出了类:

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()'的调用是否会按照我的意愿更新该图。

那么这堂课是否正确?

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

如果不是的话:有人可以请给我建议如何实现我想要的?

我意识到这个问题似乎微不足道的人,但我(老实说)确实花了整整一天昨日在谷歌和尝试,我不知所措......

任何帮助将不胜感激,这样我才能回到我的实际工作。

坦克很多提前。

作为参考:

我还发现以下代码呢,我想要的,但它是2D的,所以它不会帮我直接:

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) 

回答

7

你不需要如果它是动画(交互式)情节,则为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)) 
+0

这不适用于我的电脑(Win XP,python 2.7.3):我看到的只是最终的图 – 2012-07-25 12:44:38

+0

它需要plt.draw()行后面的self.fig.canvas.flush_events()。 (信用http://stackoverflow.com/a/4098938/415551) – 2017-01-20 18:49:04

1

我从保罗的回答感谢,我虽然没有试了试出来呢。

与此同时,我发现了另一种解决方案,可以使用MayaVI工作并使用OpenGL进行渲染,因为我只需要实时快速视觉反馈。但是我必须安装在Ubuntu下以下软件包:蟒蛇-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) 

这个类是不太,我想它是和我有两个直接的问题它:

  1. 经过一段时间后,Ubuntu将窗口灰显(我想)Ubuntu认为应用程序没有响应。也许不是一个Ubuntu问题,而是烦人的。
  2. 我一直在试图找出如何能够在动画时用鼠标旋转绘图。

我会尝试在另一个线程中获得这些答案。

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

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

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

+1

你没有给自己有用的答案。 OP标题是:如何使用Python和** MatPlotLib **?实现连续3D绘图(即更新图形)。而你给自己的答案是使用MayaVI而不是matplotlib。另一方面,你使用matplotlib得到了一个有效的答案,你没有尝试过它的第一件事... – joaquin 2011-11-28 15:39:36

0

我有一个类似的问题,这个工作对我来说:

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除非plt.pause()更换time.sleep(),这将完成绘制前图睡眠。