-
Notifications
You must be signed in to change notification settings - Fork 0
How to add a new visualization
This document explains how to add descriptive visualizations to the project, without modifying analyses to introduce interpretation.
Visualization is:
- optional,
- non-intrusive,
- strictly based on already computed data.
Analyses compute data.
Visualizations represent it.
No analytical computation must be moved to the graphical layer.
-
audio_toolkit/visualization/plots.py→ implementation of all plots (matplotlib lives here) -
audio_toolkit/engine/runner.py→ visualization orchestration / dispatch -
audio_toolkit/engine/results.py→ data transport (AnalysisResult)
All plot implementations must be done exclusively in plots.py.
In the current code, the runner triggers plots using AnalysisResult.visualization_data.
If required data does not exist, add it in the analysis, not in the plot (and store critical values in measurements as well, because visualization_data may be dropped during JSON export).
Note (code-accurate): plotting directly from
measurementsis a design possibility, but it is not part of the current automatic plotting path unless you also update the runner to read it.
Common plot types:
- time series
- frequency spectrum
- time-frequency representation
- histogram
- matrix / heatmap
Each type corresponds to a clear data pattern that should already be computed by the analysis.
Create a function plot_<name> that:
- receives only plot-ready data,
- creates the matplotlib figure,
- saves it using the existing helper(s),
- explicitly closes the figure (
plt.close(fig)).
No dependency on the runner or the analysis layer.
In plots.py, add the corresponding method to the Visualizer class.
Wrapper responsibilities:
- inject
dpi,formats,figsizefrom configuration, - keep figure saving / naming consistent,
- simplify runner code.
In audio_toolkit/engine/runner.py, visualizations are triggered by a method-identifier dispatch.
To enable automatic plotting for a new analysis method:
- Ensure the analysis returns an
AnalysisResultwithvisualization_datapopulated (plot-ready). - In the runner’s visualization dispatch (currently implemented as
if method == "..."cases), add a new branch for your method identifier. - In that branch, call the appropriate
Visualizermethod and pass thevisualization_data(and any needed config-derived values already available to the runner).
The runner performs no DSP computation; it only selects the right plot function and passes precomputed data.
- If
visualization_datais channel-indexed:- iterate over channels in the runner (or inside the Visualizer wrapper, if that’s the chosen convention for that plot)
- If data is global:
- generate a single plot
The choice of channel-indexed vs global must be made in the analysis (i.e., by how it structures visualization_data), not by recomputing or reshaping data in the plot function.
Best practices:
- one folder per method
- one file per channel and per plot type
Examples:
spectral/fft_global_left.pngtime_frequency/stft_right.png
- descriptive titles only
- explicitly labeled axes
- no annotations suggesting conclusions
- no hard-coded interpretative thresholds
- when
visualization.enabled = true, your plots are generated for the new method - when
visualization.enabled = false, the pipeline runs normally (no plot code is executed) - no data is modified during plotting (read-only usage)
- all figures are closed (
plt.close) - matplotlib code lives only in
plots.py
| Action | File |
|---|---|
| Add plot function + wrapper | plots.py |
| Ensure plot-ready data exists | analysis → AnalysisResult.visualization_data
|
| Enable automatic plotting for a method |
runner.py (dispatch branch) |
This guide defines the code-accurate way to add visualizations to the project.