2016-09-30 5 views
0

PyQt4를 사용하여 GUI가 구현 된 프로그램이 있습니다. 이 프로그램은 4 개의 7500 요소 벡터를 반환하는 빔 프로파일 러를 제어합니다. 처음 두 개는 위치 벡터 (X와 Y)이고 두 번째 두 개는 각각 X와 Y의 강도 벡터입니다. 내가하고 싶은 것은 그리드 (XY)를 만들고 다음 그림과 같이 플롯에서 색으로 강도를 플롯하는 것입니다. Figure 1 - Side Gaussian function are my raw data and I want to plot like thispyqt에서 2D 그리드의 컬러 플롯 최적화

나는 이미이 작업을 수행했지만 최적화에 문제가 있습니다. 다음 코드에서 볼 수 있듯이

def emitGraph(self): 
    zz = zeros([len(self.slit_data_pos[self.slit][::100]), len(self.slit_data_pos[self.slit + 1][::100])]) 
    for i in xrange(len(self.slit_data_pos[self.slit][::100])): 
     for j in xrange(len(self.slit_data_pos[self.slit + 1][::100])): 
      zz[i,j] = self.mesh(i, j, self.slit_data_int[self.slit][::100], self.slit_data_int[self.slit + 1][::100]) 

    self.graph.emit(
     self.slit_data_pos[self.slit][::100], 
     self.slit_data_int[self.slit][::100], 
     self.slit_data_pos[self.slit + 1][::100], 
     self.slit_data_int[self.slit + 1][::100], 
     zz 
     ) 
    self.timerGraph = threading.Timer(0.2, self.emitGraph).start() 

def mesh(self, i, j, intx, inty): 
    norm_max = max(max(intx), max(inty)) 
    intx = [x/norm_max for x in intx] 
    inty = [y/norm_max for y in inty] 
    return intx[i]*inty[j] 

은 내가 ZZ 매트릭스 (원래 7500x7500)를 채우기 위해 두 개의 루프가 있습니다. 저는 이제 각 벡터에 75 포인트 만 사용하고 타이머를 사용하여 0.2 초마다 표시합니다. 모든 데이터를 사용하면 zz 행렬을 채우고 그 다음 플롯을 작성하는 데 시간이 걸리기 때문에이 작업을 수행해야했습니다.

내가 (다른 개체/스레드에서) 그것이 음모 코드의 일부 :

def graph_update(self, slit_samples_positionsX, slit_samples_intensitiesX, slit_samples_positionsY, slit_samples_intensitiesY, zz): 

    # self.matplotlibWidget.axis.plot(slit_samples_positionsX, slit_samples_intensitiesX) 
    # self.matplotlibWidget.axis.plot(slit_samples_positionsY, slit_samples_intensitiesY) 
    self.matplotlibWidget.axis.imshow(zz, cmap=cm.jet) 
    self.matplotlibWidget.canvas.draw() 

내 질문은 내가 내 그래프의 해상도와 화면 비율을 높이기 위해 내 데이터 계산을 개선 할 수있는 방법인가? 아니면 이런 종류의 줄거리를 더 빠르게 만드는 다른 방법이 있습니까?

감사합니다.

답변

0

0.2 초마다 전체 눈금을 만듭니다. 0.2 초마다 새 플롯을 작성합니다. 이렇게하면 응용 프로그램 속도가 느려집니다. 새 타이머를 만들 때마다 emitGraph이 호출 될 때도 문제가 될 수 있습니다.

프로그램을 향상 시키려면 그리드를 한 번 만들고 내부의 데이터 만 업데이트하는 것이 좋습니다. 또한 플롯을 한 번만 만들고 새 데이터로 업데이트하십시오. 원칙적으로 numpy는 배열 작업에서 매우 빠르며 화면의 데이터를 플로팅해도 문제가되지 않습니다. 귀하의 코드를 살펴보면, 문제는 숫자가없는 배열 대신 목록을 사용하여 실제로 많은 작업을하는 것일 수 있습니다. 따라서 목록 생성 및 for-loops를 피하십시오. 사실, 당신은 mesh 기능을 완전히 없애고 많은 시간을 절약 할 수 있다고 생각합니다.

플롯과 관련하여 매번 업데이트 할 때 imshow()으로 전화하지 마십시오! 예를 self.image에 대한 귀하의 imshow 플롯 인 경우, 당신은 당신이 사용하고 self.slit이 무엇인지 우리에게있는 배열의 형태에 대한 자세한 정보를 제공 할 수있는 경우 self.image.set_data(zz)

를 호출하여이 음모를 업데이트, 아마도 당신을 도울 수 더.

이 시점에서 빔 프로파일 러를 모방하려고 시도하고 매우 빠르게 실행되는 다음 코드를 살펴볼 수도 있습니다.

from PyQt4 import QtGui, QtCore 
import numpy as np 

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas 
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar 
from matplotlib.figure import Figure 

import sys, time, random 


class WorkerObject(QtCore.QObject): 

    signalStatus = QtCore.pyqtSignal(object) 

    def __init__(self, parent=None): 
     super(self.__class__, self).__init__(parent) 

     self.data = np.zeros((600,800)) 
     self.x = np.arange(0,800) 
     self.y = np.arange(0,600) 
     self.Y, self.X = np.meshgrid(self.x, self.y) 
     self.f = lambda x, y, x0, y0, sigmax, sigmay : 0.96*np.exp(-((x-x0)/float(sigmax))**2)*np.exp(-((y-y0)/float(sigmay))**2) 


    @QtCore.pyqtSlot()   
    def startWork(self): 
     print "StartWork" 
     x0 = random.randint(250,550) 
     y0 = random.randint(250,350) 
     sigmax = random.randint(100,200) 
     sigmay = random.randint(100,200) 
     while 1 > 0: 
      x0, y0, sigmax, sigmay = self.doWork(x0, y0, sigmax, sigmay) 

    def doWork(self, x0, y0, sigmax, sigmay): 
     dx, dy, dsx, dsy = random.randint(0,1)*2-1, random.randint(0,1)*2-1, random.randint(0,1)*2-1, random.randint(0,1)*2-1 
     self.data[:,:] = (self.f(self.X, self.Y, x0+dx, y0+dy, sigmax+dsx, sigmay+dsy)+np.random.random((600,800))*0.04)*(1.+np.random.rand()*0.04-0.02) 
     self.signalStatus.emit(self.data) 
     time.sleep(0.04) 
     return x0+dx, y0+dy, sigmax+dsx, sigmay+dsy 



class App(QtGui.QMainWindow): 

    signalStatus = QtCore.pyqtSignal(object) 
    abortSignal = QtCore.pyqtSignal() 

    def __init__(self, parent=None): 
     super(App, self).__init__(parent) 

     self.button_start = QtGui.QPushButton('Start',self) 
     self.button_cancel = QtGui.QPushButton('Cancel', self) 
     self.label_status = QtGui.QLabel('', self) 

     self.mainbox = QtGui.QWidget(self) 
     self.layout = QtGui.QVBoxLayout() 
     self.mainbox.setLayout(self.layout) 
     self.setCentralWidget(self.mainbox) 
     self.layout.addWidget(self.button_start) 
     self.layout.addWidget(self.button_cancel) 
     self.layout.addWidget(self.label_status) 

     self.fig = Figure((6.0, 3.0), dpi=72) 
     self.canvas = FigureCanvas(self.fig) 
     self.canvas.setParent(self) 
     self.canvastoolbar = NavigationToolbar(self.canvas, self) 
     self.fig.patch.set_alpha(0.0) 
     self.ax = self.fig.add_subplot(111) 
     self.x = np.arange(0,800); self.y = np.arange(0,600) 
     self.im = self.ax.imshow(np.zeros((600, 800)), origin='upper', vmin=0, vmax=1) 
     self.pv, = self.ax.plot(np.zeros(600) ,self.y , color="white" , alpha=0.6, lw=2) 
     self.ph, = self.ax.plot(self.x ,np.zeros(800) , color="white" , alpha=0.6, lw=2) 
     self.ax.set_xlim([0,800]); self.ax.set_ylim([0,600]) 
     self.layout.addWidget(self.canvas) 
     self.layout.addWidget(self.canvastoolbar) 

     self.initWorker() 



    def initWorker(self): 
     self.worker = WorkerObject() 
     self.worker_thread = QtCore.QThread() 
     self._connectSignals() 
     self.worker.moveToThread(self.worker_thread) 
     self.worker_thread.start() 


    def _connectSignals(self): 
     self.button_start.clicked.connect(self.worker.startWork) 
     self.button_cancel.clicked.connect(self.forceWorkerQuit) 
     self.worker.signalStatus.connect(self.updateStatus) 


    def forceWorkerQuit(self): 
     print "calculation aborted" 
     if self.worker_thread.isRunning(): 
      self.worker_thread.terminate() 
     self.worker_thread.start() 


    @QtCore.pyqtSlot(object) 
    def updateStatus(self, obj): 
     self.im.set_data(obj) 
     argm = np.unravel_index(np.argmax(obj), (600,800)) 
     self.pv.set_data(obj[:,argm[0]]*250, self.y) 
     self.ph.set_data(self.x, obj[argm[1], :]*250) 
     self.fig.canvas.draw() 


if __name__=='__main__': 
    app = QtGui.QApplication(sys.argv) 
    thisapp = App() 
    thisapp.show() 
    sys.exit(app.exec_()) 

편집 (대답은 zz을 계산하는 방법을 묻는 아래에 언급) :

만약 내가 제대로 이해하고, 당신의 slit_data_int[0]는 X 방향으로 누적 강도, slit_data_int[1]는 Y 방향의 하나입니다.zz[j,i] = slit_data_int[1][j]*slit_data_int[0][i]는 다음이 NumPy와의 행렬 곱셈 (np.outer)를 사용하여 더 나은 계산 된 경우 :

zz[:,:] = np.outer(slit_data_int[1], slit_data_int[0])

+0

대단히 감사합니다! 그것은 대부분의 문제를 해결했지만 zz 데이터를 계산하는 방법에 대해서는 여전히 문제가 있습니다. 빔 프로 파일러는 4 개의 슬릿에서 데이터를 반환합니다. 그러므로이 np.array ([[slit1data], [slit2data], [slit3data], [slit4data]])와 같은 벡터입니다. 슬릿 0 (X 축)과 1 (Y 축)은 25um 슬릿이고 2와 3은 5um 슬릿입니다. 그래서 나는 셀프 슬릿을 사용하여 내가 선택한 슬릿을 선택합니다. 강도 매트릭스를 플로팅하기 때문에 위치 벡터가 사용되지 않기 때문에 데이터를 플롯 할 방법을 실제로 이해하지 못했습니다. – Eduardo

+0

그럼 2와 3은 무엇입니까? 그들은 전혀 사용됩니까? 어쨌든, 슬릿이 움직이는 지, 아니면 단 두 개의 1D 어레이에서 어떻게 완전한 2 차원 정보를 얻을 수 있습니까? – ImportanceOfBeingErnest

+0

내 Gui에는 슬릿을 변경하는 라디오 버튼이 있습니다. 그래서 그것의 0과 1 또는 2와 3입니다. 실제로는 4 개의 1D 배열입니다. X 축과 Y 축의 2 쌍이라고 가정 해 보겠습니다. 첫 번째 쌍의 경우 한 위치 배열과 위치 배열의 모든 지점에 대한 강도를 보여주는 한 개의 강도 배열이 있습니다. 전체 2D 데이터를 재구성하려면 X 및 Y 위치를 기반으로 그리드를 작성한 다음 강도가있는 행렬을 작성해야합니다.이 행렬의 요소는 직교 축상의 투영의 강도 곱입니다. 이렇게 : ZMatrix [i, j] = intx (i) * inty (j) – Eduardo