From 96c1231ed063b900db3e7e8be18a09182e79c89a Mon Sep 17 00:00:00 2001 From: CPD Date: Thu, 27 Feb 2025 17:09:26 +0100 Subject: [PATCH] Add plot update --- app/ui/main_window.py | 76 +++++++++++++++++++++++++++--------------- app/ui/widgets/plot.py | 31 ++++++++++++++--- 2 files changed, 75 insertions(+), 32 deletions(-) diff --git a/app/ui/main_window.py b/app/ui/main_window.py index 55c14dd..16bcd8c 100644 --- a/app/ui/main_window.py +++ b/app/ui/main_window.py @@ -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. diff --git a/app/ui/widgets/plot.py b/app/ui/widgets/plot.py index ecfc745..ee297a4 100644 --- a/app/ui/widgets/plot.py +++ b/app/ui/widgets/plot.py @@ -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)