Skip to content

Redesign the GUI as a workflow window (PySide6, pyqtgraph) - #16

Merged
jtravs merged 42 commits into
mainfrom
feature/gui-redesign
Nov 6, 2026
Merged

jtravs merged 42 commits into
mainfrom
feature/gui-redesign

Conversation

@jtravs

@jtravs jtravs commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

This redesigns croak's GUI in the style of the new solprop front end (LupoLab/solprop#484): a calm, light look in IBM Plex Sans, a workflow of five stages in a top bar, folding sheets, an analysis rail, and fast interactive pyqtgraph plots. Every function of the old wizard is kept; the route changes.

Retrieve

Design

  • Stack: PySide6 (PySide6-Essentials) and pyqtgraph replace PyQt6 and the matplotlib canvases. Every on-screen plot is pyqtgraph, with a crosshair, a hover readout, zoom and pan, and a double-click back to the home view. matplotlib (croak.plotting) still draws every exported figure and saved PDF.
  • Route: Home → Data (the entry's loader) · Check (the marginal check) · Prepare · Retrieve · Analyse (Overview, Traces, Pulse, Diagnostics, Dispersion, Uncertainty). Check opens as soon as a trace is loaded. One primary action in the top bar (Continue, Retrieve/Stop then Analyse, Save, Estimate/Stop) replaces Back/Next; on Retrieve, Retrieve again sits beside Analyse once a run is done. A ⋯ menu holds Save session, Open a session, Export this page as a figure, the settings as options.toml and the session as a Python script (in a drawer), help and About.
  • Home and About: a Home button leads the stage row. Home has four tiles with drawings (the three entries and Open a session), About croak and Recent sessions. About gives the version, links to the manual, GitHub, PyPI and the issues, the authors, and the copyright and licences.
  • Sheets: a fixed 340 px form column, so the plots get the rest of the window. Sections fold (Retrieve's advanced ones folded by default), a one-line help under the form comes from the focused control's tooltip, a coloured ready line replaces the status label, and Retrieve has Find a setting. Plots move below the form on a narrow window. Prepare says, in an advice box, when the λ grid clips the trace.
  • Figures for publication: right-click any plot to export it as a figure (or save or copy it as an image); Ctrl+E exports the page on screen. Figures are drawn by matplotlib from the screen views (croak.plotting.export), a journal column per plot, as PDF, SVG or PNG. Maps are rasterized inside vector files and text stays editable. Analyse's result pages keep croak's own page figures.
  • Display settings: at the foot of the window, Spectral axis (as computed, wavelength or frequency, with the density Jacobian) and Log range (5–120 dB) hold for every plot and are remembered; croak.plotting.display converts any screen view. A map's colour bar can be dragged to adjust that map alone.
  • Retrieve's numbers: the run's numbers in solprop's derived-number style (iteration, error, elapsed, peak wavelength, FWHM, the forward-model extras, the truth errors) beside a convergence plot that follows the run.
  • One source of numbers: the new Qt-free croak.plotting.screen builds what each view shows from the same helpers as the matplotlib figures, so the screen and a saved figure agree.
  • Look: one style sheet built from a palette of named colours (croak/gui/theme.py), addressed by widget role.

The design review behind it found that the wizard told the user little about where they were, showed about 50 Retrieve controls at once, carried heavy inert matplotlib toolbars, scattered saving across three stages and could not export a script.

Breaking changes

  • croak.gui.run_wizard → croak.gui.run_gui, croak.gui.Wizard → croak.gui.MainWindow (the croak-gui command is unchanged).
  • The gui extra installs PySide6 instead of PyQt6.
  • Removed from croak.plotting, which only the old GUI used: RetrievalPageView, FrogFilterView, the update_* panel functions, PlotScale/plot_scale/scaled_rc and PanelSpec.update. The drawn figures are unchanged.

Decided in review

  • The top bar's primary action is the only Run/Retrieve, Stop and Estimate; the form buttons that repeated them are gone.
  • Save session… is the only save: it also writes the dispersed pulse (result_dispersion.h5, dispersion.pdf) when a dispersion is set and uncertainty.pdf when an estimate is on screen; Dispersion and Uncertainty lose their Save… buttons.
  • Prepare shows the grid's numbers over its maps (size, Δt, time window, λ span, taper loss).
  • The post-filter stays on Retrieve's form: it changes the saved result, so it sits with the settings that make it.
  • The spectral axis and log range are display settings at the foot of the window, for every plot.

Found and filed

Left for later, filed

Checks

The GUI tests run offscreen with pytest-qt, at 100 % coverage locally for each changed module. The full gate runs here on CI. The window has been driven offscreen through a synthetic retrieval (the screenshots in docs/_static/ come from tools/make_docs_images.py) and tried by hand on macOS, Linux and Windows; the hand reviews led to the Check stage, the narrower form, the Home button, About, figure export, the synthetic-preview fix, the Analyse action, Retrieve's numbers strip and the display settings.

The IBM Plex Sans fonts ship under the SIL Open Font License, with their licence in croak/gui/assets/fonts/ and in the package's license-files.

🤖 Generated with Claude Code

jtravs and others added 8 commits November 5, 2026 21:22
The gui extra and the dev group now install PySide6-Essentials, pyqtgraph and
superqt; pytest-qt runs on PySide6. The code changes are the binding's names
(Signal, shiboken6 for object validity) with no change of behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
theme: a palette of named colours, one style sheet built from it and
addressed by widget role, and IBM Plex Sans carried under the OFL.
plots: white pyqtgraph line and map views with a crosshair, hover
readouts, a signed colour map and a home view. sheet: folding sections,
rows keyed to the stages' help, find, the narrow-window reflow and the
ready line, advice box, derived numbers, segments and progress strip.
workflow: the Data/Prepare/Retrieve/Analyse route as pure rules.

Nothing uses them yet; the window moves onto them stage by stage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
autodoc reads a constant's #: doc-comment only from the module it documents,
so after the package split the constants re-exported by
croak/plotting/__init__.py (RETRIEVAL_PANELS, EDGE_ENERGY_WARN, ...) vanished
from the API page and their cross-references stopped resolving, silently.
Seed autodoc's analyzer for the package with the submodules' comments; the
rendered API page now matches the pre-split one plus the new module map.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
croak/plotting.py (2660 lines; its deletion landed in the previous commit by
mistake) becomes croak/plotting/ with modules scale, units, figure, artists,
traces, pulse, panels, updates, retrieval and uncertainty. Bodies move
verbatim; only imports change (one relative import inside
_interaction_scale). The package re-exports the unchanged __all__ and every
other public name, so croak.plotting.X keeps working.

The tests reach private helpers through their new submodules and monkeypatch
process_result and spectrogram where panels.py calls them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MainWindow carries the top bar (brand, context, Data/Prepare/Retrieve/
Analyse, one primary action, an overflow menu), the settings drawer
(options.toml or the replay script), the menu bar and a status bar that
hides when empty. Home offers the three entries, opening a session and the
recent sessions. Saving a session and checking a saved result move to the
Qt-free croak.session.files; save.format_options gives the TOML text.

The old wizard stays the entry point until the stages move onto the window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every stage now builds on the workflow window's StagePage: a form of
folding sections beside the plots, a one-line help that shows the focused
control's tooltip, and the ready line in place of the status label. group()
returns a Section holding a QFormLayout, so the stages' rows are unchanged
and help still matches by (section, label). Retrieve's four advanced groups
fold by default. The control-column splitter and its remembered width go;
a narrow window moves the plots below the form instead. The old wizard
takes the new style sheet and font until the window replaces it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
croak-gui now opens MainWindow. Data holds the entry's loader and the
marginal check as two steps; Prepare and Retrieve are the existing stages;
Analyse is a rail with Dispersion and Uncertainty. The primary action drives
Continue, Retrieve/Stop and Estimate/Stop, and reopening a session replays it
(reusing result.h5 when it was fitted to this trace). The entry pages tell
the Data page where to go by a signal instead of calling the wizard.

run_wizard becomes run_gui and Wizard becomes MainWindow. The wizard, its
welcome page, the state's stage counter and the footer hooks are deleted;
the flow tests drive the window through a small numbered-stage driver.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jtravs jtravs added enhancement New feature or request area: gui The Qt wizard labels Nov 5, 2026
jtravs and others added 2 commits November 5, 2026 22:36
croak.plotting.screen turns a RetrievalPlotData into map and line views
(evenly spaced images, curves with roles, ranges, notes) from the panels'
own helpers, so the screen and an exported figure show the same numbers.
retrieval_views draws them: Retrieve's live overview (traces, pulse,
spectrum, or the convergence curve before the first preview) and Analyse's
Overview, Traces, Pulse and Diagnostics pages, each with Export figure (via
matplotlib) and Pop out. Maps start white and show negatives in red; trace
maps share their axes; log axes span whole decades. panel_pages goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A loaded trace is a signed map scaled by its trusted band
(screen.raw_trace_map); the marginal comparison is a line view with the
predicted and corrected marginals and coloured centroid rules. Line views
gain roles for those curves and rules with a role each, and a log axis
honours a view's fixed window in decades.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generator's pulse, spectrum and spectrogram (screen.pulse_field_views)
and the simulated scan's linear and dB maps with its marginals
(screen.simulated_trace_views) move out of the stages into Qt-free view
data. An uneven axis is now resampled at its finest spacing, so a
wavelength axis from an even frequency grid keeps its peak; the generator's
spectrogram is cropped to the band holding the pulse. Prompts name Continue
instead of the old footer buttons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jtravs and others added 10 commits November 5, 2026 22:48
screen.filter_views gives the six maps (measured, filtered and regridded,
in dB and linear on the shared filter_view_vmax scale), thinned for display;
Prepare draws them in a 2×3 grid whose wavelength and delay axes are linked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispersion shows the dispersed spectrum, pulse, applied phase and
spectrogram through screen views that now take a processed pulse directly
(temporal_view_of, spectral_view_of, spectrogram_map_of); its PDF is drawn
by matplotlib into a figure of its own. Uncertainty shows
screen.uncertainty_views: the FWHM histogram with its intervals, or FWHM
and trace error against thickness with the prior, and the temporal
confidence band. Line views gain bars, shaded bands and spans, horizontal
rules and point clouds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing on screen uses matplotlib now. MplCanvas and with_toolbar go, and
croak.gui.canvas becomes croak.gui.controls, the form builders it still
held. In croak.plotting, RetrievalPageView, FrogFilterView, the update_*
panel functions, PlotScale/plot_scale/scaled_rc and PanelSpec.update go;
the drawn figures are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tools/make_docs_images.py now drives MainWindow through a synthetic
retrieval and grabs Home, Retrieve and Analyse's Pulse page at 1440×900.
Rebuilding Home's recent list hides the old entries at once, which
deleteLater alone left drawn loose on the page; tile text sits at the top.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A query that names a section shows the whole section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Retrieve's help points at Analyse for the full pages; the Home tile says
which trace files load (HDF5 and NPZ); docstrings and comments name the
window instead of the wizard; the mirror stack's range note takes its
colour from the theme. The screenshots show the corrected tile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The GUI guide, the getting-started tour and the developer guide describe
Home, the four stages, Analyse's pages, sessions and the plots; a new
living design page records the principles, palette, type and layout rules.
Pages that named the wizard's stage numbers name the stages instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

jtravs and others added 3 commits November 6, 2026 09:50
superqt painted its text arrows into a pixmap sized by the font's point
size, -1 under the style sheet's pixel sizes, so macOS printed QPainter
warnings at every session. The chevron is redrawn afresh for croak.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The regrid's taper-loss warning only reached the console. Prepare now
shows it in the advice box with what to change, and marks failures as
errors on the ready line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generator drew its trace on the whole simulation grid, where the
signal band falls in one or two rows of the evenly resampled image and
shows as a featureless stripe. It now draws the trace sampled onto the
λ window, as the check shows it. A flat phase also no longer fills its
axis with rounding noise: phase axes span at least ±1 rad.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jtravs and others added 13 commits November 6, 2026 09:59
The form took two fifths of the window. It is now 340 px beside the
plots (the whole width when stacked on a narrow window), and its combo
boxes shrink to the column instead of clipping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The marginal check was a second step inside Data, reached by Continue
or a segment switch. It is now a stage of its own in the top bar, open
as soon as a trace is loaded, and a loader that hands its trace on
moves the window there. Home leads the stage row with an icon, and
About (Help menu, ⋯ and Home) gives the version, links to the manual,
GitHub, PyPI and issues, the authors and the copyright.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
croak.plotting.export draws any screen view into matplotlib axes with
the same data, colours and line styles, and lays a page's views out at a
journal column per plot. Maps are rasterized inside a vector file and
text is kept as text. The role colours move into croak.plotting.screen,
which the screen and the figures now share.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A plot's right-click menu exports it as a figure, or saves or copies it
as an image; Export this page as a figure (Ctrl+E) saves the page on
screen, laid out as it is shown. Analyse's result pages keep croak's own
page figures. ViewPanel moves to its own module.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Qt keeps a combo box's minimum width from before its size policy
changes, so the width is now pinned explicitly; Retrieve's four buttons
sit two by two and Dispersion's gas sliders on full-width rows. A test
checks that no page's form scrolls sideways.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Retrieve's form loses its Run, Stop and Save… buttons and Uncertainty's
its Estimate and Stop: the top bar's primary action and Save session…
already do each. A page's running state is now a flag, not the state of
its buttons, and Retrieve's own save, a copy of Save session without the
uncertainty estimates, is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Once a retrieval is done, the top bar's primary action is Analyse, as
every other stage's moves on, with Retrieve again beside it. Under the
plots, the pulse-parameter table gives way to the run's numbers in the
derived-number style (iteration, error, elapsed, peak wavelength and
FWHM, then the forward-model extras and the truth errors), beside the
convergence curve, which now follows the whole run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A bar at the foot of the window sets the spectral axis (as computed,
wavelength or frequency) and the logarithmic range of every plot, and
remembers them. croak.plotting.display moves any screen view between
wavelength and frequency with the density Jacobian, and every ViewPanel
draws through it and redraws when the setting changes. It replaces
Retrieve's Spectrum axis and Check's marginal axis controls.

A map's colour bar can now be dragged, and a double-click restores it.
Along the way: a signed map no longer paints zero red when its only
negatives are rounding noise, the generator's spectrum preview is a
wavelength density like its spectrogram, and log axes are labelled at
decades only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jtravs jtravs changed the title WIP: redesign the GUI as a workflow window (PySide6, pyqtgraph) Redesign the GUI as a workflow window (PySide6, pyqtgraph) Nov 6, 2026
jtravs and others added 3 commits November 6, 2026 12:50
Save session now also writes what Analyse holds: the dispersed pulse
and its figure when a dispersion is set, and the uncertainty figure
when an estimate is on screen, through a PageBase.save_extras hook the
window calls. Dispersion and Uncertainty lose their Save... buttons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Retrieve's numbers already say how a run goes, so its form has no ready
line: its other messages are notices at the foot of the window, and a
failed retrieval shows in the advice box until the next run.

A slider's spin box is now as wide as the numbers it takes (at most
seven characters) rather than its range's widest text, and a range
control puts its two ends either side of one slider, so the sliders get
the room. Prepare's grid size reads frequency × delay, as its ready
line does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jtravs
jtravs marked this pull request as ready for review November 6, 2026 15:13
Copilot AI balanced review requested due to automatic review settings November 6, 2026 15:13
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-06T15:17:08.307328Z 5e5b313 Draft marked ready
🔒 Security Review ✅ Completed 2026-11-06T15:17:53.036215Z 5e5b313 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5e5b31314b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread croak/gui/stage_dispersion.py Outdated
Comment on lines 702 to 704
if self._base is None or not self._applied():
return []
mod = self._modified()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Refresh the dispersion base before saving session extras

After applying dispersion, running another retrieval, and choosing Save session without revisiting Dispersion, this method uses the previous retrieval's cached _base. That cache is refreshed only by on_enter(), while _modified() combines it with the current result's metadata and grid. Consequently, result_dispersion.h5 can contain the old pulse paired with the new retrieval's trace and error, or saving can fail if the grid size changed. Refresh the base from the current result before exporting, rather than depending on whether the user revisited the page.

Useful? React with 👍 / 👎.

Comment thread croak/gui/stage_uncertainty.py Outdated
Comment on lines +271 to +274
if self._shown is None:
return []
figure = plotting.plot_uncertainty(
self._shown, truth=_truth_fwhm(self.state.truth)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude invalidated uncertainty estimates from session exports

If a user computes uncertainty, runs another retrieval, and saves the session, WizardState.set_result() correctly clears the retained uncertainty estimates but leaves this page's _shown cache untouched. The new session-wide save calls save_extras() on every Analyse page, so it still writes uncertainty.pdf from the previous retrieval alongside the new result.h5, which contains no such estimate. The former uncertainty Save action guarded against an empty state.uncertainty_results; retain an equivalent validity check or clear _shown when its estimate is invalidated.

Useful? React with 👍 / 👎.

jtravs and others added 2 commits November 6, 2026 15:42
Save session asks every Analyse page for its files, also one not shown
since a new retrieval. Dispersion paired its cached copy of the old
spectrum with the new result (and failed on a new grid size); it now
takes the current spectrum. Uncertainty wrote the figure of an estimate
the new retrieval had cleared; it now writes one only while the estimate
drawn is among the session's current ones. Both found by Codex review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jtravs
jtravs merged commit 280ba38 into main Nov 6, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: gui The Qt wizard enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants