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 '''
from PyQt6.QtCore import Qt
from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QTextEdit, QLabel, QDialog
from PyQt6.QtGui import QIcon
from .widgets.menubar import MenuBar
@ -22,6 +22,7 @@ from cpdctrl.utility.data import DataCollector
from cpdctrl.measurement import measure
class MainWindow(QMainWindow):
"""
MainWindow
@ -60,7 +61,8 @@ class MainWindow(QMainWindow):
init_elements = [("name1", "val1"), ("name2", "val2")]
layout.addWidget(MetadataInput(init_elements))
layout.addWidget(Plot())
self.plot_widget = Plot()
layout.addWidget(self.plot_widget)
self.verbose = True
@ -70,6 +72,13 @@ class MainWindow(QMainWindow):
self.vmdev_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:
"""
Creates and adds the top and right toolbars to the main window.
@ -81,6 +90,7 @@ class MainWindow(QMainWindow):
# Top Toolbar Buttons
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("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_separator()
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:
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)
data_collector = DataCollector(metadata=metadata, data_path=AppConfig.MAIN_CFG.get("datadir"), data_name=measurement_name)
self.led_script = LedScript(script=script, auto_update=True, verbose=True)
self.data_collector = DataCollector(metadata=metadata, data_path=AppConfig.MAIN_CFG.get("datadir"), data_name=measurement_name)
# data_collector.clear()
data_queue = mp.Queue()
command_queue = mp.Queue()
self.data_queue = mp.Queue()
self.command_queue = mp.Queue()
# Argument order must match the definition
proc_measure = mt.Thread(target=measure, args=(
self.proc_measure = mt.Thread(target=measure, args=(
self.vmdev,
self.leddev,
led_script,
data_collector,
self.led_script,
self.data_collector,
interval,
flush_after,
use_buffer,
max_measurements,
stop_on_script_end,
self.verbose, # verbose
command_queue,
data_queue
self.command_queue,
self.data_queue
))
proc_measure.start()
try:
while proc_measure.is_alive():
while not data_queue.empty():
# 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}%")
self.proc_measure.start()
self.measurement_timer = QTimer(self)
self.measurement_timer.timeout.connect(self.measure_update)
self.measurement_timer.start(300) # TODO: set interval
except KeyboardInterrupt:
pass
command_queue.put("stop")
proc_measure.join()
def measure_stop(self):
if not self.measurement_is_running():
raise RuntimeError("measure_stop: Measurement is not running")
self.command_queue.put("stop")
self.measurement_timer.stop()
self.proc_measure.join()
print("Measurement stopped" + " " * 50)
led_script.stop_updating() # stop watching for file updates (if enabled)
data_collector.save_csv(verbose=True)
data, metadata = data_collector.get_data()
self.led_script.stop_updating() # stop watching for file updates (if enabled)
self.data_collector.save_csv(verbose=True)
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:
"""
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
class Plot(pg.PlotWidget):
"""
pyqtgraph plot widget for showing voltage and LED vs time
"""
def __init__(self):
super().__init__()
self.setBackground("w")
@ -9,11 +12,29 @@ class Plot(pg.PlotWidget):
self.setLabel("bottom", "time [s]")
self.setLabel("left", "Voltage [V]")
self.setLabel("right", "LED [%]")
self.getAxis("right").setRange(0, 110) # Adding some margin
self.showGrid(x=True, y=True)
self.time = list(range(10))
self.voltage = list(range(10))
self.led = list(range(-10))
self.line = self.plot(
self.time = []
self.voltage = []
self.led = []
self.vline = self.plot(
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)