运行时错误: 主线程不在主循环中-在两个图中绘图

2024-09-28 05:25:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图从DHT11温度传感器获取一个值,然后通过GUI主窗口小部件绘制它,这个窗口小部件有三个按钮,第一个是开始从传感器获取值,第二个是实时绘制值,第三个是绘制值的FFT。在

问题是我不能将实时图和FFT图分成两个图形,因为每次我将def plotFFTButton_clicked(self):下的plt.figure(1)更改为plt.figure(2),当我按下FFT绘图按钮时,会出现以下错误: 运行时错误:主线程不在主循环中

另一个问题是我不能删除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_())

Tags: fromimportselffftvaluedef错误绘制
2条回答

该错误是一种安全预防措施,可防止线程中的干扰。每个图形都是matplotlib中的或变量,因此,如果多个线程同时处理不同的图形,一个线程可能会损坏另一个线程的变量。python threads类检测到并行的多个对象正在尝试访问同一个类并作出反应。它通常完成第一个线程并停止其他线程。在

在您的代码中,您永远不会关闭图1,因此无法在独立线程中创建图2,而不会冒着干扰的风险。所以你可以用一个线程来获取数据,用另一个线程对数据进行FFT,第三个线程可以绘图。绘图线程必须以这样一种方式工作:它将休眠,直到它在收集数据时被触发,以便将原始数据添加到图(1)中,然后在FFT结束时再次触发时,数据将添加到图(2)。(检查原始数据的新循环,然后检查FFT的新数据。仅当true时执行某些操作)(建议使用队列)由于它们不再是两个独立的线程,因此在运行另一个线程之前,您不再需要关闭其中一个线程。在

如果您确实想并行打印,请将matplotlib复制到具有新名称的文件中,并使用matplotlib打印一个地物,另一个图形使用matplotlib打印。在

恐怕这不是一个完全琐碎的代码,因为你说你是初学者。但话说回来,这不是一个完全微不足道的问题。这就是我的工作。从GUI线程调用'add'将事件(要执行的函数)放入队列,然后从图形线程调用'execute'在该线程上执行它们。如果您有多个图形线程,您将有多个队列。在

请注意,除了TaskQueue之外,还有一个循环调度程序任务环。您现在不需要它,但这只是一段生产代码,所以我已经将它一般地应用于多线程调度问题。在

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

相关问题 更多 >

    热门问题