P5b: self-contained HTML QC report and QC table (simurg qc report)
- pipeline/qc_report: dataset discovery/labels/types (QC-041..043), robust TSV/CSV reading (QC-061), join + unmatched warning (QC-040), privacy options (QC-046), xlsx (4 sheets, conditional fills) / csv table (QC-045), byte-deterministic HTML with gzip+base64 embedded data (QC-044, QC-047) - qc/report: template, CSS and JS app — Control Dashboard, Automated QC (table with sort/filter/search/ paging/column menu/export, metric scatters with threshold lines), Sample Heatmaps (chip/plate, continuous/binary), Trend Analysis (grouped summary, Tukey box plots, counts, sex, PCA), thresholds modal (apply / download / upload YAML), linked selection across plots and table (QC-048..060) - bundled plotly.js 2.35.2 (MIT); openpyxl dependency (MIT) - tests: discovery/labels/errors/determinism/xlsx + headless-browser self-test - known_unknowns K-020: remaining report deviations Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01814GKVzZVL3FuF3DeiZXhv
This commit is contained in:
1 parent
56d250c621
commit
95be85a76b
13 files changed
+1601
No files matched your search
@@ -602,6 +602,62 @@ def qc_loci_cmd(
|
||||
_qc_cohort("loci", out, bpm, gtcs, sheet, egt, threads, force, log_json, debug, quiet)
|
||||
|
||||
|
||||
@qc_app.command("report")
|
||||
def qc_report_cmd(
|
||||
data: Annotated[list[str], typer.Option("--data", help="Dataset folder(s): one, a comma list, or a parent.")],
|
||||
out: Annotated[Path, typer.Option("--out", help="Output folder.")] = Path("."),
|
||||
label: Annotated[
|
||||
list[str] | None, typer.Option("--label", help="Dataset labels (list or discovery order).")
|
||||
] = None,
|
||||
config: Annotated[Path | None, typer.Option("--config", help="QC threshold YAML (QC-020).")] = None,
|
||||
profile: Annotated[str | None, typer.Option("--profile", help="QC profile name or 'auto'.")] = None,
|
||||
threshold_call_rate: Annotated[float | None, typer.Option("--threshold-call-rate")] = None,
|
||||
threshold_lrr_sd: Annotated[float | None, typer.Option("--threshold-lrr-sd")] = None,
|
||||
threshold: Annotated[list[str] | None, typer.Option("--threshold", help="KEY=VALUE (repeatable).")] = None,
|
||||
output_format: Annotated[str, typer.Option("--output-format", help="xlsx|csv|both")] = "xlsx",
|
||||
report_name: Annotated[str | None, typer.Option("--report-name", help="Fixed output file stem.")] = None,
|
||||
drop_metadata: Annotated[
|
||||
list[str] | None, typer.Option("--drop-metadata", help="Metadata columns to drop.")
|
||||
] = None,
|
||||
keep_metadata: Annotated[list[str] | None, typer.Option("--keep-metadata", help="Metadata allowlist.")] = None,
|
||||
no_metadata: Annotated[bool, typer.Option("--no-metadata", help="Embed no metadata columns.")] = False,
|
||||
redact_paths: Annotated[bool, typer.Option("--redact-paths", help="Blank sample_folder.")] = False,
|
||||
split_by: Annotated[str, typer.Option("--split-by", help="none|dataset")] = "none",
|
||||
log_json: LogJson = False,
|
||||
debug: Debug = False,
|
||||
quiet: Quiet = False,
|
||||
) -> None:
|
||||
"""Self-contained HTML QC report and QC table from dataset folders (QC-040 … QC-063)."""
|
||||
from simurg.pipeline.qc_report import QcReportOptions, run_qc_report
|
||||
from simurg.qc.thresholds import parse_cli_pairs, resolve_thresholds
|
||||
|
||||
rep = _reporter("qc report", None, log_json, debug, quiet)
|
||||
|
||||
def body() -> int:
|
||||
cli: dict[str, Any] = parse_cli_pairs(list(threshold or []))
|
||||
if threshold_call_rate is not None:
|
||||
cli["callRate"] = threshold_call_rate
|
||||
if threshold_lrr_sd is not None:
|
||||
cli["logRDev"] = threshold_lrr_sd
|
||||
th = resolve_thresholds(config=config, profile=profile, cli=cli)
|
||||
opts = QcReportOptions(
|
||||
data=list(data),
|
||||
out=out,
|
||||
labels=list(label) if label else None,
|
||||
output_format=output_format,
|
||||
report_name=report_name,
|
||||
drop_metadata=list(drop_metadata or []),
|
||||
keep_metadata=list(keep_metadata) if keep_metadata else None,
|
||||
no_metadata=no_metadata,
|
||||
redact_paths=redact_paths,
|
||||
split_by=split_by,
|
||||
thresholds=th,
|
||||
)
|
||||
return run_qc_report(opts, rep)
|
||||
|
||||
run_guarded(rep, body)
|
||||
|
||||
|
||||
@qc_app.command("suggest-thresholds")
|
||||
def qc_suggest_cmd(
|
||||
data: Annotated[list[Path], typer.Option("--data", help="Dataset folder(s) with controls_qc.tsv.")],
|
||||
|
||||
Reference in new issue
Block a user