我正在尝试从DHT11温度传感器获取值,然后通过具有三个按钮的GUI主窗口小部件绘制它,第一个是从传感器开始获取值,第二个是绘制实时值,第三个绘制值的FFT。
问题在于我无法用两位数来分析实时图和FFT图,因为每次我将plt.figure(1)
更改为def plotFFTButton_clicked(self):
到plt.figure(2)
我都会得到按FFT绘图按钮时出现以下错误:
RuntimeError:主线程不在主循环中
另一个问题是我无法删除plt.figure(1)
下的def runValue(self):
,因为它会给我同样的错误。
如果有人可以帮我找到我的代码问题,我将感激不尽。
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 :(得分:0)
错误是一种防止线程干扰的安全预防措施。每个数字都是matplotlib中的一个或者有变量,这样如果多个线程同时处理单独的数字,一个线程就会破坏另一个线程的变量。 python threads类检测到并行的多个对象正在尝试访问同一个类并做出反应。它通常会完成第一个线程并停止其他线程。
在您的代码中,您永远不会关闭图1,因此无法在单独的线程中创建图2而不会产生干扰。所以你可以做一个线程来获取数据,另一个线程来做这个数据的FFT,第三个可以绘制。绘图线程必须以这样一种方式工作,即在收集数据时它会被触发,因此它会将原始数据添加到图(1),然后当FFT结束时再次触发时,数据将被添加图(2)。(循环检查新数据的原始数据,然后检查FFT是否为新的。只有当真的做某事时)(推荐使用队列)因为它们不再是两个单独的线程,你不再需要在运行之前关闭一个另一个。
如果您真的想要将matplotlib并行复制到具有新名称的文件中,并使用matplotlib绘制一个图形,另一个使用matplotlib。
答案 1 :(得分:-1)
我担心这不是完全琐碎的代码,因为你说你是初学者。但话说回来并不是一个完全无足轻重的问题。这对我来说有什么作用。致电'添加'从例如一个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 ()