exit Real time plot and run rest of code

615 views
Skip to first unread message

Gustavo Deza

unread,
Jan 29, 2020, 6:00:54 PM1/29/20
to pyqtgraph
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)

 

Patrick

unread,
Jan 30, 2020, 12:10:34 AM1/30/20
to pyqtgraph
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>

Reply all
Reply to author
Forward
0 new messages