Recipes¶
Short, copyable, using only implemented APIs and options. Run from the repository root unless stated.
1. Generate data and save it as AUCX¶
uv run openauc generate demo.aucx --format aucx \
--scenario moving-boundary --scans 20 --points 300 --seed 42
from openauc.synthetic import SyntheticExperimentConfig, generate_experiment
experiment = generate_experiment(
SyntheticExperimentConfig(scenario="moving-boundary", n_scans=20,
n_points=300, seed=42)
)
experiment.export("demo.aucx")
2. Generate generic-long data¶
from openauc.synthetic import write_generic_long
write_generic_long(experiment, "work/demo") # manifest.json + scans.csv
3. Inspect a CSV experiment¶
uv run openauc inspect examples/data/demo_experiment
uv run openauc inspect examples/data/demo_experiment --json | jq '.n_scans'
4. Convert CSV/TSV to AUCX¶
5. Validate every AUCX file in a directory¶
from pathlib import Path
import openauc
for path in sorted(Path("archives").glob("*.aucx")):
report = openauc.validate_aucx(path)
status = "OK " if report.is_valid else "FAIL"
print(f"{status} {path.name}")
for issue in report.issues:
print(" ", issue.code, "-", issue.message)
for f in archives/*.aucx; do
uv run openauc validate "$f" >/dev/null 2>&1 \
&& echo "OK $f" || echo "FAIL $f"
done
6. Save plots for a batch of experiments¶
from pathlib import Path
import openauc
from openauc.plotting import plot_scans
Path("figures").mkdir(exist_ok=True)
for directory in sorted(Path("data").iterdir()):
if not directory.is_dir():
continue
experiment = openauc.load(directory)
ax = plot_scans(experiment, title=experiment.metadata.experiment_id)
ax.figure.savefig(f"figures/{directory.name}.png", dpi=150, bbox_inches="tight")
ax.figure.clf() # release the figure between iterations
No display is required; pyplot is never used.
7. Produce JSON validation output¶
uv run openauc validate examples/data/demo_experiment --readiness --json > report.json
jq '.structural.counts' report.json
8. Find all ERROR findings¶
report = experiment.validate()
for issue in report.errors:
print(issue.code, "|", issue.message)
print(" fix:", issue.remediation)
uv run openauc validate my-experiment --json \
| jq -r '.structural.issues[] | select(.severity=="error") | .code'
9. Find all readiness blockers¶
from openauc.models import ValidationTier
report = experiment.validate()
for tier in (ValidationTier.SV_READINESS, ValidationTier.SE_READINESS):
print(tier.value)
for issue in report.blocking_for(tier):
print(" ", issue.code, "-", issue.remediation)
assessment = experiment.assess_readiness()
for entry in assessment.entries:
print(entry.analysis.value, entry.status.value)
for issue in entry.blocking_issues:
print(" blocked by", issue.code)
10. Compare an experiment before and after an AUCX round-trip¶
import openauc
original = openauc.load("examples/data/demo_experiment")
restored = openauc.load(original.export("check.aucx", overwrite=True))
assert restored.to_dict() == original.to_dict()
print("round trip is exact")
To compare only the data, ignoring provenance timestamps:
for key in ("metadata", "instrument", "samples", "scans", "observations"):
assert restored.to_dict()[key] == original.to_dict()[key]
11. Create an experiment programmatically¶
from openauc.models import (
AUCExperiment, ExperimentMetadata, ExperimentType, Observations,
OpticalSystem, Quantity, ScanMetadata, Unit,
)
experiment = AUCExperiment(
metadata=ExperimentMetadata(
experiment_id="hand-built-001",
experiment_type=ExperimentType.SEDIMENTATION_VELOCITY,
),
scans=(
ScanMetadata(
scan_id="scan_001", index=0,
elapsed_time=Quantity.of(0.0, Unit.SECOND),
optical_system=OpticalSystem.ABSORBANCE,
rotor_speed=Quantity.of(45000.0, Unit.RPM),
temperature=Quantity.unknown(), # explicitly unknown
),
ScanMetadata(
scan_id="scan_002", index=1,
elapsed_time=Quantity.of(600.0, Unit.SECOND),
optical_system=OpticalSystem.ABSORBANCE,
rotor_speed=Quantity.of(45000.0, Unit.RPM),
temperature=Quantity.unknown(),
),
),
observations=Observations.from_shared_axis(
radius=[6.00, 6.02, 6.04],
signal=[[0.10, 0.20, 0.30], [0.08, 0.17, 0.28]],
scan_ids=["scan_001", "scan_002"],
signal_unit=Unit.ABSORBANCE_UNIT,
),
)
print(experiment.validate_structure())
experiment.export("hand-built.aucx")
12. Work with per-scan radius vectors¶
from openauc.models import Observations, RadiusAxisMode, Unit
observations = Observations.from_per_scan(
radii=[[6.00, 6.02, 6.04], [6.00, 6.02]], # differing lengths
signals=[[0.1, 0.2, 0.3], [0.4, 0.5]],
scan_ids=["a", "b"],
signal_unit=Unit.FRINGE,
)
assert observations.mode is RadiusAxisMode.PER_SCAN
observations.points_per_scan() # (3, 2)
radius, signal = observations.scan_vectors("b") # padding removed
for scan_id, radius, signal in observations.iter_scan_vectors():
print(scan_id, radius.tolist())