Add plot update

This commit is contained in:
CPD 2025-02-27 17:09:26 +01:00
parent 8d6ae914db
commit 96c1231ed0
2 changed files with 75 additions and 32 deletions

View File

@ -1,5 +1,5 @@
''' app/ui/main_window.py ''' ''' app/ui/main_window.py '''
from PyQt6.QtCore import Qt from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QTextEdit, QLabel, QDialog from PyQt6.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QTextEdit, QLabel, QDialog
from PyQt6.QtGui import QIcon from PyQt6.QtGui import QIcon
from .widgets.menubar import MenuBar from .widgets.menubar import MenuBar
@ -22,6 +22,7 @@ from cpdctrl.utility.data import DataCollector
from cpdctrl.measurement import measure from cpdctrl.measurement import measure
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
""" """
MainWindow MainWindow
@ -60,7 +61,8 @@ class MainWindow(QMainWindow):
init_elements = [("name1", "val1"), ("name2", "val2")] init_elements = [("name1", "val1"), ("name2", "val2")]
layout.addWidget(MetadataInput(init_elements)) layout.addWidget(MetadataInput(init_elements))
layout.addWidget(Plot()) self.plot_widget = Plot()
layout.addWidget(self.plot_widget)
self.verbose = True self.verbose = True
@ -70,6 +72,13 @@ class MainWindow(QMainWindow):
self.vmdev_autoconnect() self.vmdev_autoconnect()
self.leddev_autoconnect() self.leddev_autoconnect()
# Measurement
self.measurement_timer = None
self.led_script = None
self.data_collector = None
self.data_queue = None
self.proc_measure = None
def create_toolbars(self) -> None: def create_toolbars(self) -> None:
""" """
Creates and adds the top and right toolbars to the main window. Creates and adds the top and right toolbars to the main window.
@ -81,6 +90,7 @@ class MainWindow(QMainWindow):
# Top Toolbar Buttons # Top Toolbar Buttons
self.topbar.add_button("Devices", QIcon.fromTheme(QIcon.ThemeIcon.Printer), self.vmdev_connect_from_dialog) self.topbar.add_button("Devices", QIcon.fromTheme(QIcon.ThemeIcon.Printer), self.vmdev_connect_from_dialog)
self.topbar.add_button("Start", QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStart), self.measure_start) self.topbar.add_button("Start", QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStart), self.measure_start)
self.topbar.add_button("Stop", QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStop), self.measure_stop)
self.topbar.add_button("Save", "resources/assets/icons/windows/shell32-259.ico", self.save_file) self.topbar.add_button("Save", "resources/assets/icons/windows/shell32-259.ico", self.save_file)
self.topbar.add_separator() self.topbar.add_separator()
self.topbar.add_button("Exit", "resources/assets/icons/windows/shell32-220.ico", self.exit_app) self.topbar.add_button("Exit", "resources/assets/icons/windows/shell32-220.ico", self.exit_app)
@ -179,46 +189,58 @@ class MainWindow(QMainWindow):
if self.verbose: if self.verbose:
print(f"Starting measurement with:\n\tinterval = {interval}\n\tflush_after = {flush_after}\n\tuse_buffer = {use_buffer}\n\tmax_measurements = {max_measurements}\n\tstop_on_script_end = {stop_on_script_end}") print(f"Starting measurement with:\n\tinterval = {interval}\n\tflush_after = {flush_after}\n\tuse_buffer = {use_buffer}\n\tmax_measurements = {max_measurements}\n\tstop_on_script_end = {stop_on_script_end}")
led_script = LedScript(script=script, auto_update=True, verbose=True) self.led_script = LedScript(script=script, auto_update=True, verbose=True)
data_collector = DataCollector(metadata=metadata, data_path=AppConfig.MAIN_CFG.get("datadir"), data_name=measurement_name) self.data_collector = DataCollector(metadata=metadata, data_path=AppConfig.MAIN_CFG.get("datadir"), data_name=measurement_name)
# data_collector.clear() # data_collector.clear()
data_queue = mp.Queue() self.data_queue = mp.Queue()
command_queue = mp.Queue() self.command_queue = mp.Queue()
# Argument order must match the definition # Argument order must match the definition
self.proc_measure = mt.Thread(target=measure, args=(
proc_measure = mt.Thread(target=measure, args=(
self.vmdev, self.vmdev,
self.leddev, self.leddev,
led_script, self.led_script,
data_collector, self.data_collector,
interval, interval,
flush_after, flush_after,
use_buffer, use_buffer,
max_measurements, max_measurements,
stop_on_script_end, stop_on_script_end,
self.verbose, # verbose self.verbose, # verbose
command_queue, self.command_queue,
data_queue self.data_queue
)) ))
proc_measure.start() self.proc_measure.start()
try: self.measurement_timer = QTimer(self)
while proc_measure.is_alive(): self.measurement_timer.timeout.connect(self.measure_update)
while not data_queue.empty(): self.measurement_timer.start(300) # TODO: set interval
# print(data_queue.qsize(), "\n\n")
current_data = data_queue.get(block=False)
i, tval, vval, led_val = current_data
print(f"Data {i:03}: {tval}s, {vval}V, {led_val}%")
except KeyboardInterrupt: def measure_stop(self):
pass if not self.measurement_is_running():
command_queue.put("stop") raise RuntimeError("measure_stop: Measurement is not running")
proc_measure.join() self.command_queue.put("stop")
self.measurement_timer.stop()
self.proc_measure.join()
print("Measurement stopped" + " " * 50) print("Measurement stopped" + " " * 50)
led_script.stop_updating() # stop watching for file updates (if enabled) self.led_script.stop_updating() # stop watching for file updates (if enabled)
data_collector.save_csv(verbose=True) self.data_collector.save_csv(verbose=True)
data, metadata = data_collector.get_data() data, metadata = self.data_collector.get_data()
self.proc_measure = None
self.led_script = None
def measure_update(self):
if self.proc_measure.is_alive():
while not self.data_queue.empty():
# print(data_queue.qsize(), "\n\n")
current_data = self.data_queue.get(block=False)
i, tval, vval, led_val = current_data
print(f"Data {i:03}: {tval}s, {vval}V, {led_val}%")
# update the plot
self.plot_widget.update(tval, vval, led_val)
def measurement_is_running(self):
return self.proc_measure is not None
def create_edit(self) -> QTextEdit: def create_edit(self) -> QTextEdit:
""" """
Creates and adds the QTextEdit widget to the main window. Creates and adds the QTextEdit widget to the main window.

View File

@ -2,6 +2,9 @@ import pyqtgraph as pg
from PyQt6.QtWidgets import QWidget from PyQt6.QtWidgets import QWidget
class Plot(pg.PlotWidget): class Plot(pg.PlotWidget):
"""
pyqtgraph plot widget for showing voltage and LED vs time
"""
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.setBackground("w") self.setBackground("w")
@ -9,11 +12,29 @@ class Plot(pg.PlotWidget):
self.setLabel("bottom", "time [s]") self.setLabel("bottom", "time [s]")
self.setLabel("left", "Voltage [V]") self.setLabel("left", "Voltage [V]")
self.setLabel("right", "LED [%]") self.setLabel("right", "LED [%]")
self.getAxis("right").setRange(0, 110) # Adding some margin
self.showGrid(x=True, y=True) self.showGrid(x=True, y=True)
self.time = list(range(10)) self.time = []
self.voltage = list(range(10)) self.voltage = []
self.led = list(range(-10)) self.led = []
self.line = self.plot(
self.vline = self.plot(
self.time, self.time,
self.voltage self.voltage,
pen=pg.mkPen("b", width=2),
symbol="o",
symbolSize=5,
symbolBrush="b",
) )
self.lline = self.plot(
self.time,
self.led,
pen=pg.mkPen("r", width=2)
)
def update(self, time, voltage, led):
self.time.append(time)
self.voltage.append(voltage)
self.led.append(led)
self.vline.setData(self.time, self.voltage)
self.lline.setData(self.time, self.led)