Add global time window control to Plot tab (1–24 h)

A spinbox above the plot grid sets the visible x range for all 8 plots.
Data outside the window is excluded from each redraw; x axis is fixed to
[now - window, now]. Setting is persisted in plot_settings.json.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 23:40:41 +02:00
co-authored by Claude Sonnet 4.6
parent dfdf6a550e
commit 02814782bf
+36 -5
View File
@@ -15,6 +15,7 @@ import json
import socket
import sys
import threading
import time
from collections import deque
from datetime import datetime
from pathlib import Path
@@ -348,6 +349,22 @@ class PlotTab(QWidget):
main_layout.setContentsMargins(4, 4, 4, 4)
main_layout.setSpacing(4)
# ── toolbar ───────────────────────────────────────────────────────────
tb = QWidget()
tb.setMaximumHeight(32)
tb_row = QHBoxLayout(tb)
tb_row.setContentsMargins(0, 0, 0, 0)
tb_row.setSpacing(6)
tb_row.addWidget(QLabel("Time window:"))
self._tw_spin = QSpinBox()
self._tw_spin.setRange(1, 24)
self._tw_spin.setSuffix(" h")
self._tw_spin.setFixedWidth(72)
self._tw_spin.valueChanged.connect(self._on_time_window_changed)
tb_row.addWidget(self._tw_spin)
tb_row.addStretch()
main_layout.addWidget(tb)
# ── data ──────────────────────────────────────────────────────────────
self._traces: list[list[str]] = [[] for _ in range(self.NUM_PLOTS)]
self._saved_traces: list[list[str]] = self._load_settings()
@@ -540,9 +557,10 @@ class PlotTab(QWidget):
def _save_settings(self):
try:
_SETTINGS_PATH.parent.mkdir(parents=True, exist_ok=True)
_SETTINGS_PATH.write_text(
json.dumps({"traces": [list(t) for t in self._traces]}, indent=2)
)
_SETTINGS_PATH.write_text(json.dumps({
"traces": [list(t) for t in self._traces],
"time_window": self._tw_spin.value(),
}, indent=2))
except OSError:
pass
@@ -552,13 +570,24 @@ class PlotTab(QWidget):
saved = data.get("traces", [])
while len(saved) < self.NUM_PLOTS:
saved.append([])
tw = int(data.get("time_window", 1))
self._tw_spin.blockSignals(True)
self._tw_spin.setValue(max(1, min(24, tw)))
self._tw_spin.blockSignals(False)
return [list(t) for t in saved[: self.NUM_PLOTS]]
except (OSError, json.JSONDecodeError, KeyError):
except (OSError, json.JSONDecodeError, KeyError, AttributeError):
return [[] for _ in range(self.NUM_PLOTS)]
# ── drawing ───────────────────────────────────────────────────────────────
def _on_time_window_changed(self):
self._save_settings()
self._redraw()
def _redraw(self):
now = time.time()
cutoff = now - self._tw_spin.value() * 3600
for i, pw in enumerate(self._plot_widgets):
pi = pw.getPlotItem()
pi.clear()
@@ -569,7 +598,7 @@ class PlotTab(QWidget):
for j, key in enumerate(self._traces[i]):
if key not in self._series:
continue
series = self._series[key]
series = [(t, v) for t, v in self._series[key] if t >= cutoff]
if not series:
continue
times, values = zip(*series)
@@ -580,6 +609,8 @@ class PlotTab(QWidget):
name=label,
)
pw.setXRange(cutoff, now, padding=0.02)
# ── cursor tracing ────────────────────────────────────────────────────────
def _on_mouse_move(self, evt, plot_idx: int):