Continuous 3D plotting (i.e. figure update) using python-matplotlib?

前端 未结 3 848
温柔的废话
温柔的废话 2021-01-02 07:20

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

相关标签:
3条回答
  • 2021-01-02 07:42

    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.

    0 讨论(0)
  • 2021-01-02 07:44

    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))
    
    0 讨论(0)
  • 2021-01-02 07:45

    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.

    0 讨论(0)
提交回复
热议问题