简体   繁体   English

RuntimeError:主线程不在主循环中-绘制两个图

[英]RuntimeError: main thread is not in main loop-Plotting in two figures

I'm trying to get a value from a DHT11 temp sensor, then plot it through a GUI main window widget that has three buttons, the first one is to start getting the value from the sensor, the second one is to plot the value in realtime, and the third one to plot the FFT of the value. 我正在尝试从DHT11温度传感器获取值,然后通过具有三个按钮的GUI主窗口小部件将其绘制出来,第一个是从传感器中获取值,第二个是在中绘制值实时,第三个用于绘制FFT值。

The problem is that I can't saperate the the realtime plot and the FFT plot in two figures, because every time I change the plt.figure(1) under def plotFFTButton_clicked(self): to plt.figure(2) I get the folowing error when I press the FFT plotting button: RuntimeError: main thread is not in main loop 问题是我无法同时显示两个图形中的实时图和FFT图,因为每次我将def plotFFTButton_clicked(self):下的plt.figure(1)更改为plt.figure(2) ,当我按下FFT绘图按钮时出现以下错误: RuntimeError:主线程不在主循环中

The other problem is that I can't delete the plt.figure(1) under def runValue(self): because it will give me the same error. 另一个问题是我无法删除def runValue(self):下的plt.figure(1) def runValue(self):因为它会给我同样的错误。

I would be thankful if somebody can help me finding the issue with my code. 如果有人可以帮助我找到代码中的问题,我将不胜感激。

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

the error is a safety precaution that prevents interference in threads. 该错误是一种安全预防措施,可防止线程干扰。 each figure is a or has variables within matplotlib such that if multiple threads are working on separate figures at the same time one thread can corrupt the other's variable. 每个图形在matplotlib中都是一个或具有变量,因此,如果多个线程同时在不同的图形上工作,则一个线程会破坏另一个线程的变量。 the python threads class detects that multiple objects in parallel are trying to access same class and reacts. python线程类检测到多个并行对象正在尝试访问同一类并做出反应。 It usually finishes first thread and stops the others. 它通常完成第一个线程并停止其他线程。

in your code you never close figure 1 and thus cannot create a figure 2 in a separate thread without risking interference. 在您的代码中,您永远不会关闭图1,因此无法在单独的线程中创建图2,而不会带来干扰的风险。 so you could do one thread for acquiring data and another to do the FFT of that data and the third one can plot. 因此您可以做一个线程来获取数据,而另一个线程进行该数据的FFT,第三个线程可以绘制。 the plotting thread will have to work in such a way that it sleeps until it is triggered when data is collected so it would add raw data to figure(1) and then when triggered again by the end of the FFT, the data will be added to figure(2).(loop that checks raw data for new, then checks FFT for new. only if true do something) (recommend using a queue) since they are no longer two separate threads you no longer have to close one before running the other. 绘图线程必须以某种方式工作,直到进入数据收集触发状态为止,以便将原始数据添加到Figure(1)中,然后在FFT结束时再次触发时,将添加数据到Figure(2)。(循环检查原始数据是否为新的,然后仅当为true时才检查FFT是否为新的。)(建议使用队列),因为它们不再是两个单独的线程,您不必在运行之前关闭一个线程另一个。

if you truly wanted to plot in parallel copy matplotlib to a file with new name and plot one figure with it and the other with matplotlib. 如果您确实想以并行方式将matplotlib绘制到具有新名称的文件中,并用一个名称绘制一个图形,而另一个则使用matplotlib绘制。

I am afraid this is not completely trivial code, since you say you're a beginner. 恐怕这不是完全无关紧要的代码,因为您说自己是新手。 But then again it's not a completely trivial problem. 但这又不是一个完全无关紧要的问题。 This it what does the job for me. 这对我有什么作用。 Call 'add' from eg a GUI thread to put events (functions to be executed) in the queue, and then call 'execute' from your graphics thread to execute them on that thread. 从GUI线程调用“添加”以将事件(要执行的功能)放入队列中,然后从图形线程调用“执行”以在该线程上执行事件。 If you have multiple graphics threads, you'll have multiple queues. 如果您有多个图形线程,则将有多个队列。

Note that apart from TaskQueue, there's also a cyclic scheduler TaskRing. 请注意,除了TaskQueue之外,还有一个循环调度程序TaskRing。 You don't need that now, but this is just a piece of production code, so I've made it generally applicable to multithread scheduling problems. 您现在不需要了,但这只是一部分生产代码,因此我已将其普遍适用于多线程调度问题。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 RuntimeError:主线程不在主循环中 - RuntimeError: main thread is not in main loop Matplotlib 和 :RuntimeError: 主线程不在主循环中: - Matplotlib and :RuntimeError: main thread is not in main loop: (Python tkinter):RuntimeError:主线程不在主循环中 - (Python tkinter): RuntimeError: main thread is not in main loop kochat in use RuntimeError: 主线程不在主循环中 - kochat in use RuntimeError: main thread is not in main loop PySimpleGUI。 运行时错误:主线程不在主循环中 - PySimpleGUI. RuntimeError: main thread is not in main loop 使用 matplotlib 绘制图形时出现间歇性错误“RuntimeError: main thread is not in main loop” - Intermittent error while plotting graph using matplotlib “RuntimeError: main thread is not in main loop” 运行时错误:主线程不在主循环中使用带有 Django 的 Matplotlib - RuntimeError: main thread is not in main loop using Matplotlib with Django 调试 Tkinter 代码给出“RuntimeError:主线程不在主循环中” - Debugging Tkinter code gives "RuntimeError: main thread is not in main loop" RuntimeError:在 Timer 上设置 y 坐标时,主线程不在主循环中 - RuntimeError: main thread is not in main loop when setting y coordinate on Timer RuntimeError:使用tkinter.simpledialog时主线程不在主循环中 - RuntimeError: main thread is not in main loop while using tkinter.simpledialog
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM