Непрерывное трехмерное построение (т.е. обновление рисунка) с использованием python-matplotlib? - PullRequest
10 голосов
/ 03 марта 2011

У меня есть симуляция, которая вычисляет данные поверхности для каждой итерации симуляции.Я хотел бы непрерывно отображать эти данные как поверхностный график в одном и том же окне (обновляя график на каждой итерации), чтобы увидеть, как он развивается, и проверить алгоритм.

Моя идея заключалась в создании классаэто инициализирует окно / график, а затем перерисовывает это окно из цикла симуляции.Вот класс, который я придумал:

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 и пытался, и я в растерянности ...

Любая помощь будет принята с благодарностью, так что я могу вернуться кмоя настоящая работа.

Танки много заранее.

Для справки:

Я также нашел следующий код, который делает то, что я хочу, но это в 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)

Ответы [ 3 ]

8 голосов
/ 03 марта 2011

Вам не нужно plt.show(), если это анимированный (интерактивный) сюжет.Вы также хотите, чтобы в интерактивном режиме было установлено значение True, а не False, что аналогично вызову ion() в вашем 2d-примере.Кроме того, вам нужно 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))
1 голос
/ 17 марта 2011

Я благодарен за ответ от Пола, хотя я еще не пробовал его.

Тем временем я нашел другое решение, которое работает и рендерит с OpenGL с использованием MayaVI, и это нормально, так как мне нужна только быстрая визуальная обратная связь в реальном времени. Однако мне пришлось установить следующие пакеты под 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. Я пытался выяснить, как я могу поворачивать сюжет с помощью мыши во время анимации.

Я постараюсь получить ответы на эти вопросы в другой теме.

EDIT: Хорошо. Я только что попробовал код, предложенный Полом, и он также работает для меня. Однако, пробуя это, я осознал, что MatPlotLib, вероятно, не лучший выбор для анимации в реальном времени. По крайней мере, для меня это очень медленно (возможно, только в 3D?).

Итак, в конце я остановлюсь на реализации MayaVI сверху, которая отлично работает, за исключением двух упомянутых пунктов.

РЕДАКТИРОВАТЬ: Если вы используете решение MatPlotLib, я обнаружил, что вы можете поместить строку matplotlib.interactive(True) внутри объявления класса построения. Таким образом, вы можете иметь MatPlotLib, определенную только в классе построения.

0 голосов
/ 16 ноября 2016

У меня была похожая проблема, и у меня это сработало:

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

Для вас я мог бы представить, что решение будет похоже на верхний ответ , за исключением замены time.sleep() на plt.pause(), что завершит рисование фигуры перед сном.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...