2011-03-03 164 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(),這將完成繪製前圖睡眠。