连续 3D 绘图(即图形更新)

发布于 2024-10-19 23:41:22 字数 2260 浏览 6 评论 0原文

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

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

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

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

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

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

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

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

坦克提前很多。

作为参考:

我还发现以下代码可以实现我想要的功能,但它是二维的,所以它不能直接帮助我:

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)

I have a simulation which calculates surface data for each iteration of the simulation.
I would like to continuously plot that data as a surface plot to the same window (updating the plot in each iteration) in order to see how it evolves and to check the algorithm.

My Idea was to create a class that would initialize the window/plot and then redraw to that window from inside the simulation loop. Here is the class I came up with:

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)

The problem I have with this code, is that the code stops at the 'plt.show()' and only continues, when I close the plot-window. Also I am not sure if the calls of 'self.ax.plot_surface( ... )' and 'plt.draw()' would update the figure as I would like it.

So is this class the right direction?

If yes: What modifications are needed?

If not: Could somebody please give me advice how to achieve what I want?

I realize that this problem might seem trivial to others, but I (honestly) did spend the whole day yesterday on Google and trying and I'm at a loss...

Any help would greatly appreciated, so that I can get back to my actual work.

Tanks alot in advance.

As a reference:

I also found the following code which does, what I want, but it is in 2D, so it does not help me directly:

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

迷离° 2024-10-26 23:41:23

如果它是动画(交互式)绘图,则不需要 plt.show()。您还希望将 Interactive 设置为 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))

You do not need to plt.show() if it is an animated (interactive) plot. You also want interactive set to True, not False which is the same as calling ion() in your 2d example. Also, you need to remove() the surface plots from previous frames if you do not want to see them all.

Otherwise you were pretty close.

This works for me:

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))
败给现实 2024-10-26 23:41:23

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

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()

对于你来说,我想解决方案类似于 最上面的答案,除了用 plt.pause() 替换 time.sleep() ,这会在睡觉前完成图形的绘制。

I had a similar problem and this worked for me:

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()

For you, I'd imagine the solution be something similar to the top answer except replacing time.sleep() with plt.pause(), which would finish the drawing the figure before sleeping.

别低头,皇冠会掉 2024-10-26 23:41:23

我很感谢保罗的回答,尽管我还没有尝试过。

与此同时,我找到了另一个可以使用 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)

这个类并不完全是我想要的位置,并且我有两个直接的问题:

  1. 短暂之后,窗口变灰Ubuntu(我想)Ubuntu 认为应用程序没有响应。也许是一个 Ubuntu 问题,但很烦人。
  2. 我一直在尝试找出如何在制作动画时用鼠标旋转绘图。

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

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

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

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

I am grateful for the answer from Paul, although I haven't to tried it out yet.

In the meantime I had found another solution that works and renders with OpenGL using MayaVI, which is OK as I only need real-time quick visual feedback. However I had to install the following packages under Ubuntu: python-enthoughtbase and mayavi2

Here's the code:

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)

This class is not quite where I would like it to be and I have two immediate issues with it:

  1. After a short will the window is grayed by Ubuntu as (I suppose) Ubuntu thinks the application is not responding. Perhaps rather a an Ubuntu issue, but annoying.
  2. I have been trying to find out how I can be able to rotate the plot with the mouse while animating.

I will try getting these answered in another thread.

EDIT:
Ok. I have just tried the code as suggested by Paul and it also works for me. However, trying it I have become aware that MatPlotLib probably is not the best choice for doing animations in real-time. At least for me it is extremely slow (perhaps only in 3D?).

So in the end I will stick with the MayaVI implementation from above, which except for the two points mentioned, works great.

EDIT: If you go with the MatPlotLib solution, I have found that you can put the line matplotlib.interactive(True) inside the declaration of the plotting class. That way you can have MatPlotLib only defined within the plotting class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文