17.10. Pipeline Outputs#
Pipeline outputs are the on-disk files and in-memory objects produced by
pycsamt.pipeline.Pipeline.run(). A normal run creates one
pipeline output directory containing a reproduced
canonical pipeline snapshot, optional processed EDI files,
optional QC figure files, and text or HTML reports. The same run also
returns a PipelineResult for Python workflows.
The useful way to think about outputs is not simply “files were written”. A pipeline run transforms an input site collection \(S_0\) through an ordered set of processing steps \(T_1,\ldots,T_n\):
The returned PipelineResult carries \(S_0\), \(S_n\), and one
StepResult for each transform. The output directory records the same
run in a form that a reviewer can open without Python: pipeline.yaml for
the recipe, processed/ for the final data state, plots/ for per-step
diagnostics, and reports for a human-readable audit trail.
Use this page when you need to know where files are written, which flags control each output artifact, how to run in memory, and how to inspect the result object from Python.
17.10.1. Output Lifecycle#
An output-enabled run follows a fixed order:
Resolve the output root.
Create the root,
processed/, andplots/directories.Write
pipeline.yamlbefore the first processing step starts.Run each step, recording one
StepResult.Save QC figures for successful steps when plotting is enabled.
Optionally save intermediate EDI snapshots after successful steps.
Write final processed EDIs after the last step when EDI export is enabled.
Write
summary.txtand/orreport.htmlwhen reports are enabled.Return the
PipelineResultobject.
This order matters for reproducibility. If a later step fails and the run is configured to continue, the output directory can still contain the original pipeline snapshot, the completed step records, any figures produced before the failure, and the final in-memory state used by the returned result.
17.10.2. Canonical Directory Tree#
A typical run writes this tree:
1results/basic_qc/
2|-- processed/
3| |-- station001.edi
4| |-- station002.edi
5| `-- station003.edi
6|-- plots/
7| |-- 01_notch/
8| | |-- nr_qc_harmonic_waterfall.png
9| | `-- nr_qc_snr_gain_profile.png
10| |-- 02_drop_duplicates/
11| | `-- plot_coverage_quality_heatmap.png
12| |-- 03_select_band/
13| | |-- plot_band_microstrips.png
14| | `-- plot_coverage_quality_heatmap.png
15| `-- 05_qc_snapshot/
16| |-- plot_qc_quicklook.png
17| |-- plot_station_confidence_dashboard.png
18| `-- plot_coverage_psection.png
19|-- pipeline.yaml
20|-- report.html
21`-- summary.txt
The exact plot names depend on the QC functions registered for each step. A step may produce zero, one, or several figures. The step folder name is deterministic:
where \(j\) is the 1-based step index and \(\ell_j\) is the configured step label. Stable labels therefore make output folders easier to compare between processing runs.
17.10.3. Output Directory Resolution#
Python resolves the output root with three cases:
The first case is an explicit in-memory run. The third case uses the
output_dir stored on a pipeline loaded from a configuration file, or falls
back to the global PYCSAMT_PIPE.output_root default, pipe_results.
1>>> from pycsamt.pipeline import Pipeline
2>>> pipe = Pipeline.from_preset("basic_qc")
3>>> result = pipe.run(sites, outdir="results/basic_qc")
4>>> result.outdir
5WindowsPath('results/basic_qc')
6
7>>> result = pipe.run(sites)
8>>> result.outdir
9WindowsPath('pipe_results')
10
11>>> result = pipe.run(sites, outdir=None)
12>>> result.outdir is None
13True
From the CLI, --out controls the output root:
1pycsamt pipe run data/3edis \
2 --preset basic_qc \
3 --out results/basic_qc
If --out is omitted, the CLI uses the config file’s output_dir when
available, otherwise the global default.
17.10.4. OutputDir And Defaults#
The on-disk tree is managed internally by OutputDir. It creates the root,
processed/, and plots/ directories when a run starts. The defaults
come from pycsamt.api.pipe.PipelineAPIConfig:
Config field |
Default |
Meaning |
|---|---|---|
|
|
Default output root when neither an explicit |
|
|
Subdirectory for final processed EDI files. |
|
|
Subdirectory for per-step QC figures. |
|
|
DPI used when saving Matplotlib figures. |
|
|
Plot format. CLI choices are |
|
|
Report files to write when reports are enabled. |
|
|
Save EDI snapshots after successful intermediate steps. |
Configure global defaults:
1>>> from pycsamt.api.pipe import configure_pipe, reset_pipe, PYCSAMT_PIPE
2>>> configure_pipe(
3... output_root="results/default_pipe",
4... processed_subdir="edis_processed",
5... plots_subdir="figures",
6... plot_dpi=300,
7... plot_fmt="pdf",
8... )
9>>> PYCSAMT_PIPE.plot_fmt
10'pdf'
11>>> reset_pipe()
For temporary changes, use the context manager so the previous settings are restored automatically:
1>>> from pycsamt.api.pipe import PYCSAMT_PIPE
2>>> with PYCSAMT_PIPE.context(plot_dpi=300, plot_fmt="svg"):
3... result = pipe.run(sites, outdir="results/svg_qc")
4>>> PYCSAMT_PIPE.plot_fmt
5'png'
17.10.5. Captured Minimal Run#
The following transcript was run against data/3edis with plots and EDI
export disabled so the output is small:
1>>> from pathlib import Path
2>>> from pycsamt.api import read_edis
3>>> from pycsamt.api.pipe import PYCSAMT_PIPE
4>>> from pycsamt.pipeline import Pipeline
5>>> sites = read_edis("data/3edis", strict=False).to_collection()
6>>> pipe = Pipeline.from_preset("basic_qc", pipeline_name="basic_qc")
7>>> with PYCSAMT_PIPE.context(show_progress=False, plot_dpi=72):
8... result = pipe.run(
9... sites,
10... outdir=".tmp/docs_outputs/basic_qc",
11... save_plots=False,
12... save_edis=False,
13... save_report=True,
14... )
15>>> print(result.summary())
16PipelineResult 'basic_qc'
17 Sites : 3 in -> 3 out
18 Steps : 5 (5 ok, 0 err)
19 Time : 0.95 s
20 Plots : 0
21 Output : .tmp\docs_outputs\basic_qc
22>>> sorted(p.name for p in Path(".tmp/docs_outputs/basic_qc").iterdir())
23['pipeline.yaml', 'plots', 'processed', 'report.html', 'summary.txt']
Even with save_plots=False and save_edis=False, the directories are
created because the run is output-enabled. The disabled families simply do
not add files beneath them.
17.10.6. Processed EDI Files#
Final processed EDIs are written under <outdir>/processed/ when
save_edis=True. They represent \(S_n\), the site collection after the
last step, and should not be mixed with raw field EDIs.
CLI:
1pycsamt pipe run data/3edis \
2 --preset basic_qc \
3 --out results/basic_qc
4
5pycsamt pipe run data/3edis \
6 --preset basic_qc \
7 --out results/no_edi \
8 --no-edi
Python:
1>>> result = pipe.run(
2... sites,
3... outdir="results/basic_qc",
4... save_edis=True,
5... )
6>>> len(result.processed_paths) >= 0
7True
If EDI export fails, pyCSAMT warns and returns an empty or partial
processed_paths list. The transform may still have succeeded, so inspect
result.ok, the step results, and the reports before discarding the run.
17.10.7. QC Figures#
Each registered step may declare QC plotting functions. When
save_plots=True and the step succeeds, pyCSAMT calls those functions and
saves the returned Matplotlib figure objects under:
1<outdir>/plots/<step_index>_<step_label>/<qc_function_name>.<plot_fmt>
Examples:
1results/basic_qc/plots/01_notch/nr_qc_harmonic_waterfall.png
2results/basic_qc/plots/01_notch/nr_qc_snr_gain_profile.png
3results/basic_qc/plots/05_qc_snapshot/plot_qc_quicklook.png
Control plotting from the CLI:
1pycsamt pipe run data/3edis \
2 --preset publication_ready \
3 --out results/publication_ready_pdf \
4 --dpi 300 \
5 --plot-fmt pdf
6
7pycsamt pipe run data/3edis \
8 --preset basic_qc \
9 --out results/no_plots \
10 --no-plots
Control plotting from Python:
1>>> result = pipe.run(
2... sites,
3... outdir="results/no_plots",
4... save_plots=False,
5... )
6>>> result.plots
7[]
QC plot failures are skipped individually so that a successful transform does not become a failed processing step only because a diagnostic figure could not be drawn. Missing figures usually mean one of four things: plots were disabled, the step failed, the step has no registered QC functions, or the current data do not contain the quantities required by that QC function.
17.10.8. Reports#
When save_report=True, the pipeline writes reports according to
PYCSAMT_PIPE.report_formats. By default it writes both summary.txt and
report.html. A third, opt-in format, "dashboard", writes a richer
branded report with KPI stat tiles and charts — see Dashboard Report
below.
summary.txtPlain-text report for terminals, CI logs, quick review, and diffable processing notes.
report.htmlSelf-contained HTML report with run metadata, per-step cards, linked plot thumbnails, errors, parameter values, and embedded pipeline YAML.
A text report starts like this:
1pyCSAMT Pipeline Report
2Pipeline : basic_qc
3Run at : 2026-07-18 20:43:38
4Sites : 3 in -> 3 out
5Total : 0.95s
6
7Step results
8 # Name Code Status Time(s) Sites Plots
Disable report writing:
1pycsamt pipe run data/3edis \
2 --preset basic_qc \
3 --out results/no_report \
4 --no-report
Python equivalent:
1>>> result = pipe.run(
2... sites,
3... outdir="results/no_report",
4... save_report=False,
5... )
Write only one report format:
1>>> from pycsamt.api.pipe import PYCSAMT_PIPE
2>>> with PYCSAMT_PIPE.context(report_formats=("txt",)):
3... result = pipe.run(sites, outdir="results/text_only")
17.10.9. Dashboard Report#
report_formats also accepts "dashboard", a third, richer report
tier written to <outdir>/dashboard.html alongside — not instead of —
summary.txt and report.html. Where report.html stays a plain,
cheap-to-render step-card list, the dashboard adds pyCSAMT’s own logo and
brand colors, KPI stat tiles, and three native inline-SVG charts built
from the same step_results the other two reports already use. There
is no external JavaScript or CDN dependency, so the file stays
self-contained: it opens directly from disk in a browser, or travels as a
single email attachment.
Enable it from Python by adding "dashboard" to report_formats:
1>>> from pycsamt.api.pipe import PYCSAMT_PIPE
2>>> with PYCSAMT_PIPE.context(report_formats=("html", "txt", "dashboard")):
3... result = pipe.run(sites, outdir="results/with_dashboard")
or from the CLI with --dashboard:
1pycsamt pipe run data/3edis \
2 --preset basic_qc \
3 --out results/with_dashboard \
4 --dashboard
The dashboard adds four things beyond report.html:
- Stat tiles
Steps ok/total, error count, total elapsed time, sites in → out, cache hit rate, and total figures generated — one glance at whether the run needs attention.
- Step status timeline
One colored block per step (green = OK, red = error), with a small gold-ringed dot marking any step whose result was replayed from the step cache instead of recomputed. Hovering a block shows the step name, code, elapsed time, and cache status via a native SVG
<title>— no script required.- Step duration bars
One bar per step, in the brand blue by default. A step at or above the run’s own 80th-percentile elapsed time is drawn in gold instead, so an unusually slow step stands out without a fixed, run-independent threshold.
- Site-count flow
A two-series line chart of sites in vs. sites out per step, so a step that silently drops stations is visible at a glance rather than buried in a table column.
Every chart sits above a plain <table> restating the same per-step
numbers — the table is not an afterthought; it is the accessibility twin
required for anyone who cannot read the charts, and it is what a
Ctrl-F search or a text diff actually matches against.
A run against three real EDIs, captured the same way as Captured Minimal Run above:
1>>> with PYCSAMT_PIPE.context(
2... show_progress=False,
3... plot_dpi=72,
4... report_formats=("html", "txt", "dashboard"),
5... ):
6... result = pipe.run(
7... sites,
8... outdir=".tmp/docs_outputs/basic_qc_dashboard",
9... save_plots=False,
10... save_edis=False,
11... save_report=True,
12... )
13>>> sorted(p.name for p in Path(".tmp/docs_outputs/basic_qc_dashboard").iterdir())
14['dashboard.html', 'pipeline.yaml', 'plots', 'processed', 'report.html', 'summary.txt']
The stat-tiles block from that same run (SVG icon path data elided for
brevity — each tile embeds one small currentColor icon so it inherits
the surrounding text color in both light and dark mode):
1<div class="tiles">
2 <div class="tile"><svg class="icon" ...></svg>
3 <div class="label">Steps</div><div class="value">5/5 ok</div>
4 </div>
5 <div class="tile"><svg class="icon" ...></svg>
6 <div class="label">Errors</div><div class="value">0</div>
7 </div>
8 <div class="tile"><svg class="icon" ...></svg>
9 <div class="label">Total time</div><div class="value">28.50s</div>
10 </div>
11 ...
12</div>
The dashboard’s palette is not an arbitrary restyle: the brand blue/orange pair used for the site-count-flow chart, and the good/warning/critical status colors used throughout, were both checked against pyCSAMT’s own light and dark surfaces with the project’s color-blindness and contrast validator before being wired in, and both passed without substitution. Where a status color’s contrast is intentionally low against a light surface (the gold “slow step” / “cached” marker), the mitigation is a visible caption or tooltip beside it, never color alone.
17.10.10. Pipeline Snapshot#
Every output-enabled run saves:
1<outdir>/pipeline.yaml
This file is written before the main processing loop starts. It is the resolved pipeline configuration for the run and should be treated as the source of truth for reproducing the processing sequence.
Reload a saved pipeline:
1>>> from pycsamt.pipeline import Pipeline
2>>> pipe = Pipeline.from_yaml("results/basic_qc/pipeline.yaml")
3>>> rerun = pipe.run(sites, outdir="results/basic_qc_rerun")
4>>> rerun.pipeline_name
5'basic_qc'
Use pipeline.yaml to rerun a workflow, review active parameters, compare
two output directories, archive a processing recipe with reports and figures,
or debug a CLI run from Python.
17.10.11. In-Memory Runs#
Pass outdir=None when you want a pure Python result without writing files:
1>>> result = pipe.run(
2... sites,
3... outdir=None,
4... save_plots=False,
5... save_edis=False,
6... save_report=False,
7... )
8>>> result.outdir is None
9True
10>>> result.processed_paths
11[]
This is useful in tests, notebooks, and exploratory workflows where the
processed Sites object is enough. The mathematical run state still exists
in memory as \(S_n\); only the filesystem projection is disabled.
17.10.12. Intermediate EDI Snapshots#
The global save_intermediate option can save EDI snapshots after
successful intermediate steps. These snapshots are written inside the step’s
plot directory:
1<outdir>/plots/03_select_band/edi_snapshot/
Enable snapshots temporarily:
1>>> from pycsamt.api.pipe import PYCSAMT_PIPE
2>>> with PYCSAMT_PIPE.context(save_intermediate=True):
3... result = pipe.run(sites, outdir="results/debug_snapshots")
Use this option for debugging only. It can create many files, especially for large surveys or long pipelines.
17.10.13. PipelineResult And StepResult#
The return value of Pipeline.run is the programmatic companion to the
files on disk. Important PipelineResult fields are:
Field |
Meaning |
|---|---|
|
Original input site collection. |
|
Site collection after the final step. |
|
One |
|
Output root path, or |
|
Total wall-clock runtime. |
|
Paths returned by final EDI export. |
|
Pipeline label. |
|
Derived list of all saved plot paths. |
|
|
|
Number of failed steps. |
Inspect the run:
1>>> print(result.summary())
2PipelineResult 'basic_qc'
3 Sites : 3 in -> 3 out
4 Steps : 5 (5 ok, 0 err)
5 ...
6>>> result.ok
7True
8>>> result.n_errors
90
10>>> [(sr.step_idx, sr.step_name, sr.step_code, sr.ok)
11... for sr in result.step_results]
12[(1, 'notch', 'NR001', True), ..., (5, 'qc_snapshot', 'QC001', True)]
Each StepResult also stores the parameters passed to the step, elapsed
time, input and output site counts, saved plot paths, and any captured error.
For review, the most important relation is
so result.ok is true only when every step result is true.
17.10.14. Output Control Matrix#
The output flags are independent, but they only write files when an output directory exists.
Control |
Applies to |
Result |
|---|---|---|
|
Python API |
No output directory and no files. |
|
CLI |
Sets the output root for the run. |
|
Python API |
Do not generate or save QC figures. |
|
CLI |
Do not generate or save QC figures. |
|
Python API |
Do not write final processed EDI files. |
|
CLI |
Do not write final processed EDI files. |
|
Python API |
Do not write |
|
CLI |
Do not write |
|
Figures |
Controls saved figure resolution. |
|
Figures |
Controls saved figure extension and Matplotlib output format. |
|
Reports |
Selects |
|
CLI |
Adds |
17.10.15. Recommended Output Layout#
Keep raw data, configs, and outputs separate:
1project/
2|-- data/
3| `-- raw_edis/
4|-- config/
5| |-- basic_qc.yaml
6| `-- publication_ready.yaml
7`-- results/
8 |-- basic_qc/
9 |-- noise_reduction/
10 `-- publication_ready/
Run:
1pycsamt pipe run data/raw_edis \
2 --config config/basic_qc.yaml \
3 --out results/basic_qc
This layout prevents accidental overwrites of raw files and makes it easy to compare multiple processing strategies. Use a new output root for each experimental branch, especially when changing step order, frequency bands, notch parameters, static-shift corrections, or inversion-preparation logic.
17.10.16. Comparing Two Runs#
When comparing output directories, inspect the same files in each run:
1results/basic_qc/summary.txt
2results/noise_reduction/summary.txt
3results/basic_qc/report.html
4results/noise_reduction/report.html
5results/basic_qc/pipeline.yaml
6results/noise_reduction/pipeline.yaml
Useful comparisons include step status and error count in summary.txt,
site counts before and after each step, plot counts per step, parameter
differences in pipeline.yaml, visual differences in matching
plots/<step>/ folders, and EDI differences under processed/.
17.10.17. Stratagem Output Note#
pycsamt.pipeline.stratagem.StratagemPipeline follows the normal
pipeline output tree. When rename_basename is configured, it can also
copy or rename processed EDI files from processed/ into a renamed/
directory, or into a custom rename_dir.
For raw Stratagem convenience workflows using run_stratagem_preset, the
function writes a Stratagem-oriented output layout, including corrected and
renamed directories under the requested output root.
17.10.18. Troubleshooting#
- No output directory was created
In Python, check whether
outdir=Nonewas passed. That is an explicit no-files run. If using the CLI, check that the command reached the run phase and was not a--dry-run.pipeline.yamlexists but reports are missingThe pipeline writes
pipeline.yamlbefore the main step loop. Reports are written after the run only whensave_report=Trueand the selectedreport_formatsincludehtmlortxt.- Plots are missing
Check that
--no-plotsorsave_plots=Falsewas not used. Also confirm that the step succeeded and that the step has registered QC plot functions.- Processed EDIs are missing
Check that
--no-ediorsave_edis=Falsewas not used. If export failed, pyCSAMT warns andresult.processed_pathsmay be empty.- Only some plots are present
QC plot functions are skipped individually when they cannot produce a figure for the current site collection. Inspect the report and run with verbose CLI output if needed.
- The CLI dry-run output directory looks generic
--dry-runreports the explicit--outvalue when supplied. For a real run, output resolution still follows CLI--out, configoutput_dir, then the global default.- Output files were overwritten
The output manager creates directories with
exist_ok=Trueand writes standard filenames such aspipeline.yaml,summary.txt, andreport.html. Use a new output root for each experimental run.