GUI Module (songs.gui)#

Full class and method reference for the Tkinter front end, auto-generated from docstrings. For a task-oriented walkthrough of the interface itself, see GUI User Guide.

SONGS GUI

Compact Tkinter-based GUI to interactively configure and run the SONGS generator. Provides a 4-column card layout of parameter frames (Initialisation, Central Galaxy, Satellite, Diffuse Features), crisp LaTeX-rendered labels, convenience sliders, and utility buttons (Generate, Slice, Moments, Spectrum, Save, New). Plotting and file I/O are intentionally kept out of the generator core; the GUI imports top-level visualisation helpers (moment0, moment1, spectrum, slice_view) to display results.

Design notes#

  • Lightweight: the GUI focuses on inspection and quick interactive

    experimentation, not production batch runs.

  • Threading: generation runs in a background thread so the UI remains

    responsive; generated figures are produced by the visualise helpers.

  • Cleanup: LaTeX labels are rendered to temporary PNG files (via

    matplotlib) and tracked in _MATH_TEMPFILES for removal when the application exits.

Usage#

Run the module as a script to display the GUI:

python -m songs.gui

Or instantiate SONGSGUI and call mainloop(). The GUI expects the package to be importable (it will try a fallback path insertion when executed as a script).

class songs.gui.LogWindow(master)[source]#

Bases: Toplevel

Top-level log window that captures and displays stdout/stderr.

LogWindow creates a simple resizable Toplevel containing a Tk Text widget and installs TextRedirector instances on sys.stdout and sys.stderr so that all subsequent print output and uncaught exception tracebacks are visible in the GUI. The window restores the original streams when closed.

Behaviour#

  • Creating an instance replaces sys.stdout and sys.stderr in

    the running interpreter until the window is closed (on_close).

  • The window configures a separate text tag for stderr so error

    messages are coloured differently.

Example

>>> log = LogWindow(root)
>>> log.deiconify()  # show the window
on_close()[source]#

Restore the original sys.stdout/sys.stderr and destroy the window.

class songs.gui.SONGSGUI(theme: str = 'light')[source]#

Bases: Tk

Main GUI application for interactively configuring and running SONGS simulations.

This class implements a compact, self-contained Tk application, launched with python -m songs.gui, that exposes the most commonly-used parameters of the generator through a 4-column dark-themed (or light-themed) card layout, with the SONGS banner running down the left side:

  1. Initialisation — grid size, number of spectral channels, number of galaxies, random seed, output directory.

  2. Central Galaxy — Sérsic index, effective radius, scale height, central flux density, inclination, position angle.

  3. Satellite — satellite offset, systemic velocity offset, beam parameters (bmin, bmaj, BPA).

  4. Diffuse Features — sliders/entries mapping onto DEFAULT_DIFFUSE_PARAMS (halo, bridge and tail amplitudes, tail velocity gradient and decay scale, master enabled toggle).

Controls include numeric sliders, textual inputs and convenience buttons that invoke high-level visualisation helpers (moment0, moment1, spectrum) or persist generated results to disk. See docs/source/gui.rst for a full description of the layout and workflow.

Key behaviour#

  • The generator is constructed from the current UI values and stored

    on self.generator. Calling Generate runs the generator in a background daemon thread so the UI remains responsive; generated results become available via self.generator.results.

  • Visualisation buttons call into functions defined in

    songs.visualise which create Matplotlib figures; these functions are intentionally separate from the generator core so the GUI remains a thin orchestration layer.

  • Temporary files created by latex_label() are tracked in the

    module-level _MATH_TEMPFILES list and cleaned up when the GUI is closed via _on_close.

Threading and shutdown#

  • Generation and save operations spawn background daemon threads. The

    UI schedules finalisation callbacks back on the main thread using self.after(...) when worker threads complete.

  • Closing the main window triggers a cleanup of temporary files and

    forces process termination to avoid orphaned interpreters. If you prefer a softer shutdown that joins worker threads, modify _on_close accordingly.

Usage example#

Run the GUI as a script:

python -m songs.gui

Or instantiate from Python:

from songs.gui import SONGSGUI
app = SONGSGUI()
app.mainloop()
create_generator()[source]#

Instantiate a SONGS object from current UI values.

The method calls _collect_parameters() to assemble a parameter dictionary and then constructs a single-cube generator instance with sensible defaults for fields not exposed directly in the GUI. After construction the per-galaxy attributes on the generator are filled from the collected parameters so the generator is ready to run.

generate()[source]#

Handle a click on the Generate button (single-cube mode).

Builds a fresh SONGS generator from the current UI values (via create_generator()), disables the theme and result buttons for the duration of the run, and launches _run_generate() on a background daemon thread so the UI stays responsive. _poll_generation_done() is scheduled on the main thread to detect completion, publish the results, and re-enable the buttons.

generate_dataset()[source]#

Kick off batch generation for Large-Dataset Mode: samples fresh parameters per cube, generates it, optionally adds correlated beam-convolved noise, and writes clean/noisy HDF5 files (with the full per-cube parameter manifest as a JSON header attribute) plus one dataset-level pickle summarising every cube. Runs in a background thread; the GUI only reads/writes Tk state before the thread starts and via self.after(0, ...) afterwards.

load_cube()[source]#

Open a SONGS HDF5 cube for viewing only (Slice/Analysis), without running the generator. Populates every slider from the file’s parameters_json header and locks the UI read-only until Reset is pressed. If the file has both a clean and a noisy version of the cube (see _save_cube_hdf5), both are loaded and the Slice/Analysis viewers get the same Clean/Noisy toggle used for live generation — no more up-front “which one?” prompt.

make_dual_slider(parent, segs, var, var_min, var_max, from_, to, resolution=0.01, fmt='{:.2f}', integer=False)[source]#

A single card row that shows a classic make_slider() (single value, var) in single-cube mode, or a make_range_slider() (var_min/var_max) in Large-Dataset Mode — swapped in place whenever the mode toggles (see self._dual_sliders, refreshed by _apply_large_dataset_mode). Every parameter in Central Galaxy / Satellite / Diffuse Features uses this so the same card works in both modes.

make_range_slider(parent, var_lo, var_hi, from_, to, resolution=0.01, fmt='{:.2f}', integer=False)[source]#

Single-row dual-handle range slider: an editable entry for each bound flanking a draggable two-handle track, used for min/max parameter ranges in Large-Dataset Mode. lo <= hi is enforced by construction (dragging/typing one handle past the other clamps it there).

make_slider(parent, label, var, from_, to, resolution=0.01, fmt='{:.2f}', integer=False)[source]#

Create a labelled slider widget with snapping and a value label.

reset_instance()[source]#

Reset the GUI to a fresh state and disable visualisation/save.

This clears the in-memory self.generator reference so that the next generate action will create a new instance from current UI values. Buttons that depend on generated results are disabled. If we were viewing a cube loaded via load_cube(), this also re-enables every parameter card that load dimmed, restores every slider/toggle to the app’s hardcoded defaults (undoing _apply_loaded_manifest), and restores Generate to its normal clickable state. If a Large-Dataset Mode batch run is currently in progress, this also requests it stop (same as clicking Stop) — the background worker unwinds cooperatively at its next safe point.

save_sim()[source]#

Generate (if needed) and save the sim tuple (cube, params).

This runs generation in a background thread and then opens a Save-As dialog on the main thread to let the user choose where to store the result. We support .npz (numpy savez) and .pkl (pickle) formats; complex parameter dicts fall back to pickle.

show_analysis()[source]#

Open the combined Analysis viewer (moments + spectrum + source checkboxes) — or, if one is already open and still current, bring it to front instead of stacking a second window.

show_logs()[source]#

Handle a click on the Logs button: raise the stdout/stderr log window.

Delegates to _show_log_window(), which deiconifies the window (it starts withdrawn at startup, so a bare lift() would leave it invisible) and applies the themed title bar.

show_slice()[source]#

Open the SONGS SliceViewer for the first generated cube — or, if one is already open and still current, bring it to front instead of stacking a second window.

stop_generation()[source]#

Request cancellation of whatever generation is currently running (single-cube or Large-Dataset Mode batch). Cooperative — the background worker checks self._stop_requested at its next safe point and unwinds itself; this just raises the flag and gives immediate feedback (disabling the Stop button so a second click can’t double-fire).

class songs.gui.TextRedirector(widget, tag='stdout')[source]#

Bases: object

Redirect writes into a Tk Text widget behaving like a stream.

Use this helper to capture and display program output inside the GUI (for example, to show progress logs, exceptions, or print() output). TextRedirector implements a minimal stream interface (write and flush) so it can be assigned directly to sys.stdout or sys.stderr; written text is inserted into the provided Tk Text widget and scrolled to the end so the latest output is visible.

Threading note#

  • The class itself is not thread-safe: writes coming from background threads should be marshalled to the Tk mainloop (e.g. via widget.after(...)) if there is a risk of concurrent access.

param widget:

The Tk Text widget where text will be appended.

type widget:

tk.Text

param tag:

Optional text tag name to apply to inserted text (default 'stdout').

type tag:

str, optional

Example

Redirect stdout into a Text widget:

txt = tk.Text(root)
txt.pack()
sys.stdout = TextRedirector(txt, tag='log')
flush()[source]#
write(string)[source]#
songs.gui.main()[source]#

Entry point for python -m songs.gui.

Parses --dark/--light command-line flags, applies the macOS HiDPI fix (must run before the Tk root window is created), then instantiates and runs SONGSGUI.

songs.gui.param_frame(parent, padding=8, border_color='#797979', bg='#303030', width=None, height=80, do_pack=True)[source]#

Create a framed parameter panel used throughout the GUI.

songs.gui.rich_label(parent, segments, bg=None, fg='white')[source]#

Render a symbol with superscript/subscript on a tk.Canvas.

Uses exact pixel placement so subscript descenders are never clipped.

Parameters:
  • parent (tk.Widget)

  • segments (list of (str, str) where the second element is one of:) – 'n' — normal baseline 's' — subscript (small, lowered) 'p' — superscript (small, raised)

  • bg (str or None Background colour; defaults to parent's background.)

  • fg (str Foreground (text) colour.)

Return type:

tk.Canvas Sized exactly to the rendered content.