Visualisation#

Plotting and visualisation support for SONGS-generated spectral cubes.

This module provides small, focused plotting utilities that operate on the results list produced by generate_cubes(). Each public helper accepts the results container and an index selecting which generated cube to visualise. The functions are intentionally lightweight and return a Matplotlib (fig, ax) pair so callers (GUIs, scripts, tests) can further customise or save figures. It also provides the interactive Tkinter viewer windows (SliceViewer, AnalysisViewer) used by the SONGS GUI to inspect generated cubes channel-by-channel and to browse per-source moment maps and spectra.

Dependencies#

  • matplotlib (this module sets the TkAgg backend by default, unless an

    inline backend is already active).

  • astrodendro, used to compute a coarse dendrogram-based mask that highlights

    contiguous emission for the moment-map helpers.

Notes

  • _prepare_cube() extracts the cube and its metadata and computes the

    dendrogram-based mask shared by the moment-map helpers. The dendrogram parameters are deliberately conservative and may need tuning for different signal-to-noise regimes.

  • The plotting functions attempt to save to figures/<shape>/ when

    save=True is passed; save failures are intentionally ignored to keep UI flows robust.

class songs.visualise.AnalysisViewer(master, data, idx: int = 0, noisy_data=None)[source]#

Bases: Toplevel

Combined analysis viewer: Moment 0, Moment 1, and integrated spectrum.

Source checkboxes (one per galaxy) and diffuse-component checkboxes let the user select which components contribute to all three panels. The layout mirrors the nemo analysis viewer: two moment maps side-by-side on top, spectrum spanning the full width below.

Parameters:
  • master (tkinter widget) – Parent window this viewer is opened as a Toplevel of.

  • data (sequence) – The results container produced by SONGS.generate_cubes. data[idx] must be a (cube, meta) tuple where cube is a NumPy array of shape (n_vel, ny, nx) in Jy/beam and meta is a dict with keys including 'average_vels' (km/s), 'beam_info', 'pix_spatial_scale' (kpc/pixel), and optionally 'per_galaxy_cubes', 'halo_cube', and 'bridges_cube'.

  • idx (int, optional) – Index of the cube to display (default 0).

  • noisy_data (sequence or None, optional) – A results-like container in the same shape/idx convention as data, holding the noisy version of the same cube (present only when noise was simulated at generation time). When given, the viewer defaults to displaying the noisy cube and exposes a Clean/Noisy toggle; per-source and diffuse component arrays remain the clean ground truth either way, since noise is an instrument effect on the observed total rather than a per-source quantity.

class songs.visualise.SliceViewer(master, data, idx: int = 0, noisy_data=None)[source]#

Bases: Toplevel

Channel-by-channel IFU slice viewer matching nemo aesthetics.

Displays the full spectral cube with colormap / normalization controls, vmin/vmax sliders, and (when per-galaxy cubes are available) a sources sidebar with per-source contours, bounding boxes, and intensity-threshold masks whose threshold percentage is tunable via a dedicated slider.

Parameters:
  • master (tkinter widget) – Parent window this viewer is opened as a Toplevel of.

  • data (sequence) – The results container produced by SONGS.generate_cubes. data[idx] must be a (cube, meta) tuple where cube is a NumPy array of shape (n_vel, ny, nx) in Jy/beam and meta is a dict with keys including 'average_vels' (km/s), 'beam_info', 'pix_spatial_scale' (kpc/pixel), and optionally 'per_galaxy_cubes' (shape (n_gal, n_vel, ny, nx)).

  • idx (int, optional) – Index of the cube to display (default 0).

  • noisy_data (sequence or None, optional) – A results-like container in the same shape/idx convention as data, holding the noisy version of the same cube (present only when noise was simulated at generation time). When given, the viewer defaults to displaying the noisy cube and exposes a Clean/Noisy toggle; per-source component arrays remain the clean ground truth either way, since noise is an instrument effect on the observed total rather than a per-source quantity.

songs.visualise.moment0(data, idx, save=False, fname_save=None, inline=False)[source]#

Plot the zeroth moment (integrated intensity) of a spectral cube.

Parameters:
  • data (sequence) – The results container produced by SONGS.generate_cubes.

  • idx (int) – Index selecting which cube to plot.

  • save (bool, optional) – If True, attempt to save the figure to figures/<shape>/moment0.pdf.

  • fname_save (str or None, optional) – Optional directory to save the figure. If None a path under the current working directory is chosen automatically.

Returns:

fig, ax – Matplotlib figure and axes objects containing the rendered moment map.

Return type:

(Figure, Axes)

songs.visualise.moment1(data, idx, save=False, fname_save=None)[source]#

Plot the first moment (intensity-weighted velocity) of a spectral cube.

Parameters:
  • data (sequence) – The results container produced by SONGS.generate_cubes.

  • idx (int) – Index selecting which cube to plot.

  • save (bool, optional) – If True, attempt to save the figure to figures/<shape>/moment1.pdf.

  • fname_save (str or None, optional) – Optional directory to save the figure. If None a path under the current working directory is chosen automatically.

Returns:

fig, ax – Matplotlib figure and axes objects containing the rendered moment map.

Return type:

(Figure, Axes)

songs.visualise.slice_view(data, idx=0, channel=None, cmap='viridis', parent=None)[source]#

Show a per-channel slice viewer embedded in a Tk window.

This viewer embeds the Matplotlib figure into a Tk Toplevel and uses a ttk-styled slider to step through spectral channels. The viewer keeps the lower colour limit fixed at 0 and computes an upper limit per slice so contrast adapts to the currently displayed channel.

Parameters:
  • data (sequence) – The results container produced by SONGS.generate_cubes.

  • idx (int, optional) – Index of the cube within data to display (default 0).

  • channel (int, optional) – Initial spectral channel index to show. If None (the default) the viewer will open on the central spectral channel (int(n/2)).

  • cmap (str, optional) – Matplotlib colormap to use for imshow.

  • parent (tkinter widget, optional) – If provided, the slice viewer will be a child Toplevel of this widget. Otherwise a new Toplevel (or root) is used.

Returns:

fig, ax – The Matplotlib figure and axes used by the embedded viewer.

Return type:

(Figure, Axes)

songs.visualise.spectrum(data, idx, save=False, fname_save=None)[source]#

Plot the integrated spectrum (total flux vs velocity) for a cube.

Parameters:
  • data (sequence) – The results container produced by SONGS.generate_cubes.

  • idx (int) – Index selecting which cube to plot.

  • save (bool, optional) – If True, save the figure as spectrum.pdf under figures/<shape>/ unless fname_save overrides the path.

  • fname_save (str or None, optional) – Optional directory to save the figure.

Returns:

fig, ax – The Matplotlib figure and axes containing the spectrum.

Return type:

(Figure, Axes)

Helper Functions#

The songs.visualise module provides lightweight wrappers around Matplotlib for the most common cube inspection tasks.

moment0#

from songs.visualise import moment0
moment0(cube, save=False, fname=None)

Computes and displays the moment-0 (integrated intensity) map by summing the cube along the spectral axis. Optionally saves the figure to fname as a PDF.

moment1#

from songs.visualise import moment1
moment1(cube, vels, beam_info=None, save=False, fname=None)

Computes the intensity-weighted velocity map:

\[M_1(x, y) = \frac{\sum_v v \cdot S(v, x, y)}{\sum_v S(v, x, y)}\]

An optional beam marker (ellipse) is overlaid when beam_info is provided.

spectrum#

from songs.visualise import spectrum
spectrum(cube, vels, save=False, fname=None)

Plots the spatially-integrated line-of-sight spectrum: flux summed over the spatial axes as a function of velocity channel.

SliceViewer Class#

SliceViewer provides an interactive channel-by-channel viewer launched either from the GUI or standalone:

from songs.visualise import SliceViewer
viewer = SliceViewer(cube, sources=sources_list, vels=vels)
viewer.show()

sources mode: when sources is a list of per-source component cubes, the viewer activates the per-source sidebar so that contours, bounding boxes and threshold masks are computed independently for each source component.

Key interactive controls:

  • Channel slider — step through spectral slices.

  • Source selector sidebar — toggle which source’s overlays are shown.

  • Contour level spinner — set contour threshold as a fraction of the channel peak.

  • Threshold slider — mask voxels below a chosen intensity fraction.

  • Bounding-box toggle — show/hide axis-aligned bounding boxes per source.