diff --git a/pyleco_extras/gui/data_logger/data/multi_plot_widget.py b/pyleco_extras/gui/data_logger/data/multi_plot_widget.py index 090d6f9..1e626de 100644 --- a/pyleco_extras/gui/data_logger/data/multi_plot_widget.py +++ b/pyleco_extras/gui/data_logger/data/multi_plot_widget.py @@ -209,24 +209,22 @@ def update(self): x_key, y_key = self.keys try: if x_key == "index": - for key, line in self.lines.items(): - line.setData(self.main_window.lists[key][-self.autoCut:]) - else: - for key, line in self.lines.items(): - line.setData( - self.main_window.lists[x_key][-self.autoCut:], - self.main_window.lists[key][-self.autoCut:], - ) + x_key = None + for key, line in self.lines.items(): + data_pairs = self.main_window.get_xy_data( + y_key=key, x_key=x_key, start=-self.autoCut + ) + line.setData(*data_pairs) except KeyError: return # no data try: - value = self.main_window.lists[y_key][-1] + value = self.main_window.get_data(y_key, start=-1)[0] units = self.main_window.current_units.get(y_key, "") self.lbValue.setText(f"{y_key}: {value:.8g} {units}") except (IndexError, KeyError, TypeError): pass # no data except ValueError: - self.lbValue.setText(f"{y_key}: {self.main_window.lists[y_key][-1]}") + self.lbValue.setText(f"{y_key}: {self.main_window.get_data(y_key, start=-1)[0]}") if self.actionEvaluate.isChecked(): self.evaluate_data() @@ -245,7 +243,7 @@ def getYkeys(self): """Get the available keys for the y axis.""" self.model.clear() self.model.setHorizontalHeaderLabels(["pen", "key"]) - keys = self.main_window.lists.keys() + keys = self.main_window.get_data_keys() for key in keys: pen_color = self.pens.get(key, "") if pen_color and key not in self.lines: diff --git a/pyleco_extras/gui/data_logger/data/plot_widget.py b/pyleco_extras/gui/data_logger/data/plot_widget.py index e5535b4..611611d 100644 --- a/pyleco_extras/gui/data_logger/data/plot_widget.py +++ b/pyleco_extras/gui/data_logger/data/plot_widget.py @@ -6,7 +6,7 @@ import logging import math -from typing import Any, Protocol, Optional +from typing import Any, Iterable, Protocol, Optional import numpy as np import pint @@ -16,10 +16,23 @@ class DataLoggerGuiProtocol(Protocol): - lists: dict[str, list[Any]] current_units: dict[str, str] timer: QtCore.QTimer + def get_data( + self, key: str, start: Optional[int] = None, stop: Optional[int] = None + ) -> list[float]: ... + + def get_xy_data( + self, + y_key: str, + x_key: Optional[str] = None, + start: Optional[int] = None, + stop: Optional[int] = None, + ) -> tuple[list[float]] | tuple[list[float], list[float]]: ... + + def get_data_keys(self) -> Iterable[str]: ... + class PlotGroupWidget(QtWidgets.QWidget): """Abstract class for the plot widgets.""" @@ -210,7 +223,7 @@ def setKeyNames(self, comboBox: QtWidgets.QComboBox) -> None: comboBox.clear() if comboBox == self.bbX: comboBox.addItem("index") - comboBox.addItems(self.main_window.lists.keys()) + comboBox.addItems(self.main_window.get_data_keys()) comboBox.setCurrentText(current) def getXkeys(self) -> None: @@ -292,17 +305,18 @@ def evaluate_data(self, value: int = 0) -> None: l2: int = self.lineV2.value() # type: ignore l1, l2 = sorted((l1, l2)) if x_key == "index": - raw_data = self.main_window.lists[y_key][-self.autoCut:] + raw_data = self.main_window.get_data(y_key, start=-self.autoCut) start = math.floor(l1) stop = math.ceil(l2) + 1 data = raw_data[start:stop] else: # TODO only from visible data or all data (as is now)? - raw_data = np.array(self.main_window.lists[y_key]) - raw_x = np.array(self.main_window.lists[x_key]) + raw_x, raw_data = self.main_window.get_xy_data(y_key=y_key, x_key=x_key) + raw_data = np.array(raw_data) + raw_x = np.array(raw_x) data = raw_data[(l1 <= raw_x) * (raw_x <= l2)] else: - data = self.main_window.lists[y_key][-self.autoCut:] + data = self.main_window.get_data(y_key, start=-self.autoCut) mean = np.nanmean(a=data) std = np.nanstd(a=data) self.lbEvaluation.setText(f"({mean:g}\u00b1{std:g})") diff --git a/pyleco_extras/gui/data_logger/data/single_plot_widget.py b/pyleco_extras/gui/data_logger/data/single_plot_widget.py index 91f93e3..e8e8154 100644 --- a/pyleco_extras/gui/data_logger/data/single_plot_widget.py +++ b/pyleco_extras/gui/data_logger/data/single_plot_widget.py @@ -141,23 +141,21 @@ def update(self) -> None: """Update the plots.""" x_key, y_key = self.keys try: - if x_key == "index": - self.reference.setData(self.main_window.lists[y_key][-self.autoCut:]) - else: - self.reference.setData( - self.main_window.lists[x_key][-self.autoCut:], - self.main_window.lists[y_key][-self.autoCut:], - ) + data_pairs = self.main_window.get_xy_data( + y_key=y_key, x_key=None if x_key == "index" else x_key, start=-self.autoCut + ) + data = data_pairs[-1] + self.reference.setData(*data_pairs) if self.actionmm.isChecked(): l1, l2 = self.linesMM - l1.setValue(np.nanmin(self.main_window.lists[y_key])) - l2.setValue(np.nanmax(self.main_window.lists[y_key])) + l1.setValue(np.nanmin(self.main_window.get_data(y_key))) + l2.setValue(np.nanmax(self.main_window.get_data(y_key))) if self.actionlmm.isChecked(): l1, l2 = self.linesLMM - l1.setValue(np.nanmin(self.main_window.lists[y_key][-self.autoCut:])) - l2.setValue(np.nanmax(self.main_window.lists[y_key][-self.autoCut:])) + l1.setValue(np.nanmin(data)) + l2.setValue(np.nanmax(data)) try: - value = self.main_window.lists[y_key][-1] + value = data[-1] except (IndexError, KeyError): value = float("nan") self.lbValue.setText(f"{value:.8g} {self.main_window.current_units.get(y_key, '')}") @@ -165,7 +163,7 @@ def update(self) -> None: pass # no data except ValueError: try: - self.lbValue.setText(f"{y_key}: {self.main_window.lists[y_key][-1]}") + self.lbValue.setText(f"{data[-1]}") except IndexError: self.lbValue.setText("IndexError") if self.actionEvaluate.isChecked(): diff --git a/pyleco_extras/gui/data_logger/data_logger_base.py b/pyleco_extras/gui/data_logger/data_logger_base.py index 19928f2..6c7b0ba 100644 --- a/pyleco_extras/gui/data_logger/data_logger_base.py +++ b/pyleco_extras/gui/data_logger/data_logger_base.py @@ -136,6 +136,31 @@ def cut_lists(self): for key, li in self._lists.items(): self._lists[key] = li[-self.data_length_limit:] + def get_data( + self, + key: str, + start: Optional[int] = None, + stop: Optional[int] = None, + ) -> list[float]: + return self._lists[key][start:stop] + + def get_xy_data( + self, + y_key: str, + x_key: Optional[str] = None, + start: Optional[int] = None, + stop: Optional[int] = None, + ) -> tuple[list[float]] | tuple[list[float], list[float]]: + y_data = self.get_data(key=y_key, start=start, stop=stop) + if x_key is None: + return (y_data,) + else: + x_data = self.get_data(key=x_key, start=start, stop=stop) + return (x_data, y_data) + + def get_data_keys(self) -> Iterable[str]: + return self._lists.keys() + def setup_timers(self) -> None: # Timers # As trigger