Hi,
Keep in mind that everything is based around Qt, and thus the Qt event
loop. Once you call app.exec_() (or QtGui.QApplication.instance().exec_()
in your code), then the code will block here until the Qt app is exited.
Everything you do should therefore be driven by events in your event loop
(triggered by menu actions, button presses, or QTimer timeouts etc). For a
serious GUI, you'll want to build your program around a QWidget or
QMainWindow etc. Here's an example I've used before, with some notes to
show how I'd do reading from a serial port.
(You don't want to open the serial port every time you want to read some
bytes from it etc.)
Patrick
from PyQt5 import QtCore, QtWidgets, uic
from PyQt5.QtCore import pyqtSignal, pyqtSlot
import numpy as np
import pyqtgraph as pg
from threading import Thread, Event
import time
# Routine to acquire and serve data
def generate_data(callback, threadkill):
# Open serial port
# ser = serial.Serial(port=....)
while not threadkill.is_set():
# Wait for read from serial port...
# ser.read()
# Process raw bytes...
# See python struct module for utilities for interpreting raw data
# Note, may read a variable amount of data from serial port
data = np.random.random(np.random.randint(16))
# Notify Qt thread of new data
callback(data)
time.sleep(0.01)
# Close serial port
# ser.close()
class PyQtGraphTest(QtWidgets.QMainWindow):
# Signal to indicate new data acquisition
# Note: signals need to be defined inside a QObject class/subclass
data_acquired = pyqtSignal(np.ndarray)
def __init__(self):
super().__init__()
# Load ui layout from file
uic.loadUi(__file__.split('.py')[0] + '.ui', self, package=
__package__)
# Build pyqtgraph plot layout
self.plot = self.graphicsLayoutWidget.addPlot()
self.spectrum = self.plot.plot()
# Connect signals
self.pushButton.clicked.connect(self.start_clicked)
# Connect the signal for new data acquisition
self.data_acquired.connect(self.update_data)
# An Event to indicate other thread should finish up
self.threadkill = Event()
# Buffer for data
self.data = np.zeros(2**11)
# Will use it as a circlular buffer, so adjust x-axis for correct
sample numbers
self.spectrum.setPos(-self.data.shape[0], 0)
def start_clicked(self, thing):
if self.pushButton.isChecked():
# Make and start the background thread to acquire data
# Pass it the signal.emit as the callback function
self.thread = Thread(target=generate_data, args=(self.
data_acquired.emit, self.threadkill))
self.threadkill.clear()
self.thread.start()
self.pushButton.setText("&Stop")
else:
# Stop background thread
self.threadkill.set()
self.pushButton.setText("&Start")
# Kill our data acquisition thread when shutting down
def closeEvent(self, close_event):
self.threadkill.set()
# Slot to receive acquired data and update plot
@pyqtSlot(np.ndarray)
def update_data(self, newdata):
# Circular roll buffer back to make space for new data
self.data = np.roll(self.data, newdata.shape[0])
self.data[newdata.shape[0]:0:-1] = newdata[::-1]
self.spectrum.setData(self.data[::-1])
# Adjust x-axis sample numbers
self.spectrum.translate(newdata.shape[0], 0)
# See pyqtgraph scrolling plot examples for different/better
implementations
# You probably want the one that doubles the buffer size when full,
but it
# would need to be modified to handle receiving >1 data point at a
time.
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = PyQtGraphTest()
window.show()
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
sys.exit(app.exec_())
...and a .ui file (same name as above, but with .ui file extension):
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>It's a plot</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="PlotWidget" name="plotWidget"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>19</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>PlotWidget</class>
<extends>QGraphicsView</extends>
<header>pyqtgraph</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
On Thursday, 30 January 2020 09:30:54 UTC+10:30, Gustavo Deza wrote:
>
> Hello all,
> I am new to pyqtgraph, and I can plot data from com port in real time, but
> I can't exit the window to run the rest of the code. I've tried to
> implement a while loop += 1 and a set number of "samples" n, to no avail.
> Any suggestions would be highly appretiated
>
> # -*- coding: utf-8 -*-
> from pyqtgraph.Qt import QtGui, QtCore
> import numpy as np
> from numpy import arange, sin, cos, pi
> import pyqtgraph as pg
> import sys
> import serial
> import time
>
>
>
> def bytes_to_int(bytes): # Bytes to integers
> result = 0
> for b in bytes:
> result = result * 256 + int(b)
> return result
>
> class Plot2D():
> def __init__(self):
> self.traces = dict()
>
> #QtGui.QApplication.setGraphicsSystem('raster')
> self.app = QtGui.QApplication([])
> #mw = QtGui.QMainWindow()
> #mw.resize(800,800)
>
> self.win = pg.GraphicsWindow(title="SeƱal")
> self.win.resize(1000,600)
> self.win.setWindowTitle('Voltaje')
>
> # Enable antialiasing for prettier plots
> pg.setConfigOptions(antialias=True)
>
> self.canvas = self.win.addPlot(title="Medicion")
>
> def start(self):
> if (sys.flags.interactive != 1) or not hasattr(QtCore,
> 'PYQT_VERSION'):
> QtGui.QApplication.instance().exec_()
>
> def trace(self,name,dataset_x,dataset_y):
> if name in self.traces:
> self.traces[name].setData(dataset_x,dataset_y)
> else:
> self.traces[name] = self.canvas.plot(pen='y')
>
>
> val_vol = []
> val_time = []
> n = 40
> count = 0
> #i = 0
> while (count <= n):
> ## Start Qt event loop unless running in interactive mode or using pyside.
> if __name__ == '__main__':
> p = Plot2D()
> #i = 0
> count = 0
>
> def update():
> global p, count
> ser = serial.Serial(port='com11', baudrate=9600)
> rawvol = ser.read()
> vol = bytes_to_int(rawvol)
> val_vol.append(vol)
> val_time.append(time.clock())
> p.trace("sin",val_time,val_vol)
> #i += 0.1
> print(val_vol)
> count += 1
>
> timer = QtCore.QTimer()
> timer.timeout.connect(update)
> timer.start(50)
>
> p.start()
> sys.exit()
> print(count)
>
>
>
>
--
You received this message because you are subscribed to the Google Groups
"pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/pyqtgraph/b70bd88e-5ecd-4a89-9f0a-4f71e18513de%40googlegroups.com.