2017-02-01 10 views
1

DHT11温度センサーから値を取得しようとしていて、3つのボタンを持つGUIメインウィジェットにプロットしています。センサーから値を取得し始め、2番目はリアルタイムで値をプロットし、3番目の値は値のFFTをプロットすることです。RuntimeError:メインスレッドがメインループにありません - 2つの図でプロットしています

私はボタンをプロットFFTを押したときに、私はplt.figure(2)def plotFFTButton_clicked(self):plt.figure(1)を変更するたびに、私はfolowingエラーを取得するため、問題は、私はリアルタイムプロットと2つの図にFFTプロットをsaperateことができないということです。 はRuntimeError:メインスレッドはメインループ

他の問題ではありませんが、それは私に同じエラーを与えるので、私はdef runValue(self):plt.figure(1)を削除することはできませんということです。

誰かが私のコードで問題を見つけるのを助けることができたら、私は感謝します。

from PyQt4 import QtCore, QtGui 
import sys 
import time 
from threading import Event, Thread 

from mainwindow import Ui_MainWindow 

from PyQt4.Qt import QString, QFileDialog 
from pylab import * 

import threading 
from threading import Thread 

#DH11 tempSensor Library 
import Adafruit_DHT 

#Library to find FFT and FFTshift 
from scipy.fftpack import fft, fftshift 

from numpy import linspace 

class dataAcquisition(QtGui.QMainWindow, Ui_MainWindow): 
    def __init__(self, parent=None):   
     super(dataAcquisition, self).__init__(parent) 
     self.setupUi(self) 

     self.startButton.clicked.connect(self.startButton_clicked) 
     self.th = Thread(target = self.runValue) 

     self.plotRTButton.clicked.connect(self.plotRTButton_clicked) 

     self.plotFFTButton.clicked.connect(self.plotFFTButton_clicked) 

     self.Value = 0.0 
     self.X = 0.0 
     self.Y = 0.0 

     self.ChageValueState = False 
    def runValue(self): 
     self.X = [] 
     self.Y = [] 
     i = 0.0 

     plt.figure(1) #an error comes out if I delete this 

     while True: 
      self.ChageValueState = True 

      self.Value = Adafruit_DHT.read_retry(11, 4)[1] ‫#‬Or you could give the self.Value any number 

      i += 0.10 
      self.X.append(i) 
      self.Y.append(self.Value) 
      pause(0.01) 

    def startButton_clicked(self): 
     self.th.start() 

    def plotRTButton_clicked(self): 
     plt.figure(1) 
     ax1 = subplot(3, 1, 1) 
     Line1 = plot(0,0,'r-')[0] 

     Line1.set_xdata(self.X) 
     Line1.set_ydata(self.Y) 
     ax1.relim() 
     ax1.autoscale_view() 

    def plotFFTButton_clicked(self): 
     Fs = 8000 
     N = 256 
     f = linspace(-Fs/2, Fs/2, N) 

     plt.figure(1) #an error comes out if I plot in a new figure 

     ax2 = plt.subplot(3, 1, 2) 
     Line2 = plot(f,0*f,'r-')[0] 

     FFT = log10(abs(fft(self.Y, N))) 
     FFT = fftshift(FFT) 

     Line2.set_ydata(FFT) 
     ax2.relim() 
     ax2.autoscale_view() 

if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
    MainWindow = dataAcquisition() 
    MainWindow.show() 
    sys.exit(app.exec_()) 
+0

問題は、グラフィックスレッドの関数を別のスレッドから直接呼び出してしまうことです。グラフィックスレッドにキューを与え、GUIスレッドから直接関数を呼び出すのではなく、そのキューにイベントを入れます。スレッド自体のキューを読み取り、独自のスレッドからの呼び出しによって各グラフのプロットを開始します。 –

+0

私はPythonの初心者であるので、キューの使い方を教えてください。 –

+0

すべてのQt GUI操作(プロットを含む)は、メインスレッドで行う必要があります。セカンダリスレッドからのプロットは禁止されています。セカンダリスレッドでデータを取得できますが、プロットするにはGUIスレッドに戻す必要があります。通常、 'QThread'とQtのシグナルとスロットのメカニズムを使って、安全にデータを渡します。スレッド間でデータを渡す方法と 'QThread'を使う方法については、スタックオーバーフローに関する多くのpyqtの例があります。 –

答えて

-1

あなたが初心者だと言っているので、これは完全に簡単なコードではないと思いますか?しかし、それは再び完全に自明な問題ではありません。これは私のために仕事をします。たとえば、「追加」を呼び出します。キューにイベント(実行される関数)を配置し、グラフィックススレッドから 'execute'を呼び出してスレッド上で実行するためのGUIスレッドです。グラフィックスカードが複数ある場合は、複数のキューがあります。

TaskQueueとは別に、周期的スケジューラTaskRingもあります。今は必要ありませんが、これは単なる生産コードなので、一般的にマルチスレッドスケジューリングの問題に適用できます。

class TaskBuffer: 
    def __init__ (self): 
     self.tasks = [] 

    def add (self, task): 
     self.tasks.append (task) 

    def execute (self, time): 
     for task in self.tasks: 
      try: 
       task (time) 
      except: 
       lg.debug ('{} {}'.format (self.skipMessage, task)) 

class TaskRing (TaskBuffer): 
    skipMessage = 'Ring task skipped:' 

taskRing = TaskRing() 

class TaskQueue (TaskBuffer): 
    skipMessage = 'Queue task skipped:' 

    def execute (self, time): 
     super() .execute (time) 
     self.tasks = [] 

taskQueue = TaskQueue() 
0

このエラーはスレッドでの干渉を防ぐ安全対策です。各図形は、複数のスレッドが別々の図形で同時に動作しているときに、一方のスレッドが他方の変数を破損する可能性があるような、またはmatplotlib内に変数を持ちます。 Pythonスレッドクラスは、複数の並列オブジェクトが同じクラスにアクセスしようとしていることを検出して反応します。通常、最初のスレッドを終了し、他のスレッドを停止します。

あなたのコードで決してあなたは干渉を危険にさらすことなく別のスレッドで図2を作成することはできません。データを取得するために1つのスレッドを実行し、そのデータのFFTを実行する別のスレッドを実行し、第3のスレッドをプロットすることができます。プロットスレッドは、データが収集されるときにトリガされるまでスリープしてfigure(1)に生データを追加し、FFTの最後までに再びトリガされるとデータが追加されるように動作する必要がありますfigure 2へ(未処理のデータをチェックして新しいものをチェックし、trueの場合のみ新しいものをチェックするループ)(実行する前に閉じる必要がなくなった2つの別々のスレッドではないのでキューを使うことをお勧めします)もう片方。

あなたが本当に新しい名前のファイルにmatplotlibをコピーしてコピーしたいのであれば、それに1つの図とmatplotlibをプロットします。

関連する問題