From 1f146dbc0da2f39b31a34ba38756246a072433f8 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Mon, 22 Jun 2026 20:43:07 +0200 Subject: [PATCH] GUI: draw the forecast line solid instead of dashed Same color, same alpha-based fade distinguishing it from the actual measured trace - just '-b' instead of '--b'. Updates the surrounding docstrings/comments and README that described it as dashed. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01DkkuG48uHFCGKe6dPSERFk --- README.md | 10 +++++----- client/brewpi_gui.py | 21 +++++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index fb362db..95258d4 100644 --- a/README.md +++ b/README.md @@ -293,9 +293,9 @@ disabled, its temperature/heat-rate setpoint controls are inactive. ### Forecast vs. actual duration The GUI's Automatic tab plots two things against the same time axis: a -*forecast* (dashed) and, once a run starts, the *actual* measured trace -(solid) overlaid on top of it - a comparison between predicted and real -control behavior, not just a progress display. +*forecast* (faded, via alpha) and, once a run starts, the *actual* +measured trace (solid, full opacity) overlaid on top of it - a comparison +between predicted and real control behavior, not just a progress display. The forecast is computed server-side (`components/sud_forecast.py`'s `SudForecastEstimator`) by actually running the schedule through a @@ -335,8 +335,8 @@ tripped - the controller stays enabled and actively holding throughout `WAIT_USER`, so the setpoint is what it was actually converging toward during the wait, not a possibly-still-mid-ramp snapshot. The corrected forecast is sent in full each time, so the GUI's `SudForecastPlot. -show_forecast()` simply redraws -the dashed line outright rather than patching it up itself. +show_forecast()` simply redraws the (faded) forecast line outright rather +than patching it up itself. Comparing the two lines: real-world divergence from the forecast - more than a transient blip during a ramp's settling - is worth investigating as diff --git a/client/brewpi_gui.py b/client/brewpi_gui.py index ecdca4d..3d37a9a 100755 --- a/client/brewpi_gui.py +++ b/client/brewpi_gui.py @@ -110,8 +110,9 @@ class RealtimePlot(FigureCanvasQTAgg): class SudForecastPlot(FigureCanvasQTAgg): """Compares a Sud schedule's actual control behavior (line, solid) - against a simulation-based forecast (line_projected, dashed) - the - same plant/controller model the real run uses + against a simulation-based forecast (line_projected, also solid but + faded via alpha - see __init__()) - the same plant/controller model + the real run uses (components/sud_forecast.py's SudForecastEstimator - see show_computing()/show_forecast()). The forecast covers the whole schedule from the very first Load, including through any step @@ -130,7 +131,7 @@ class SudForecastPlot(FigureCanvasQTAgg): self.ax = figure.subplots(1, 1) self.line, = self.ax.plot([], [], '-b', linewidth=1.5, zorder=2) - self.line_projected, = self.ax.plot([], [], '--b', linewidth=1.5, alpha=0.5, zorder=2) + self.line_projected, = self.ax.plot([], [], '-b', linewidth=1.5, alpha=0.5, zorder=2) self.progress_line = self.ax.axvline(0, color='g', linewidth=1.5, visible=False, zorder=2) # Current temperature - drawn behind (lower zorder than) the # forecast/progress lines so it never covers them. @@ -157,7 +158,7 @@ class SudForecastPlot(FigureCanvasQTAgg): self.draw_idle() def show_forecast(self, t_min, theta, name, finished): - """The forecast curve (dashed) - computed by the server simulating + """The forecast curve (faded, via alpha) - computed by the server simulating the schedule with its real plant/controller (components/sud_forecast.py) - see Window.on_sud_forecast_ received(). Called again, with a corrected t_min/theta, each time @@ -195,12 +196,12 @@ class SudForecastPlot(FigureCanvasQTAgg): def show_dynamic(self, history): """Updates the actual measured trace (solid) only - the forecast - (dashed) is left exactly as show_forecast() last drew it (that's - the whole point: an honest, unmoving baseline - see this class's - docstring), and the axes stay locked to whatever it set, so - divergence between the two is visible rather than auto-hidden by - the view rescaling to chase whichever line is currently - drawing.""" + (also solid, but faded via alpha) is left exactly as + show_forecast() last drew it (that's the whole point: an honest, + unmoving baseline - see this class's docstring), and the axes + stay locked to whatever it set, so divergence between the two is + visible rather than auto-hidden by the view rescaling to chase + whichever line is currently drawing.""" hist_t = [t for t, _ in history] hist_theta = [theta for _, theta in history] self.line.set_data(hist_t, hist_theta)