diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a8e5e1..e6bdfda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,16 @@ and Recore uses semantic versioning. ### Fixed +- `evolutionary_events.tsv` no longer presents a gain or loss built on gaps + Recore never searched as an audited call. New columns `absent_not_searched` + and `not_searched_reason` count those absences and say why; a call none of + whose absences were searched drops one support level (and so in score and + priority), and every affected call is tagged in `mechanism_detail` and + explained in `recommended_wording`. +- `benchmarks/compare_runs.py` counted `NOT_SEARCHED_*` cells as calls, so a + comparison against a run from before those states listed every unsearched + cell as a new correction. They are absences now, and a cell searched in one + run and not the other is `search_coverage_changed`. - A gap Recore never searched no longer reads like one it searched and found empty. The states file writes `NOT_SEARCHED_LOW_PREVALENCE`, `NOT_SEARCHED_NO_CLUSTER_SEQUENCE` or `NOT_SEARCHED_NO_FASTA` where it wrote diff --git a/benchmarks/README.md b/benchmarks/README.md index d177e23..b79e17f 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -112,7 +112,10 @@ python3 benchmarks/compare_runs.py --old old_recore_output --new new_recore_outp The comparison uses the union of matrix cells, so clusters or genomes present in only one run are reported as `old_only_cell` / `new_only_cell` instead of -being silently ignored. +being silently ignored. A cell absent in both runs but searched in only one of +them (an `ABSENT` against a `NOT_SEARCHED_*`, as older runs wrote `ABSENT` for +both) is `search_coverage_changed`, not a correction, and is counted apart from +`changed_cells`. Generate a compact Markdown/HTML report: diff --git a/benchmarks/compare_runs.py b/benchmarks/compare_runs.py index 372c426..c6b53d3 100644 --- a/benchmarks/compare_runs.py +++ b/benchmarks/compare_runs.py @@ -72,19 +72,32 @@ def read_evolution(run_dir: Path) -> dict[str, dict[str, str]]: return {row["gene_cluster"]: row for row in reader} +def is_absent(state: str) -> bool: + """No presence and no evidence: a gap searched and found empty, or one that + was never searched. A NOT_SEARCHED_* state is an absence, and counting it as + a call made every unsearched cell a "new correction" against older runs, + which wrote ABSENT for both.""" + return state in {"", "ABSENT"} or state.startswith("NOT_SEARCHED") + + def classify_change(old_state: str, new_state: str) -> str: if old_state == "MISSING_CELL": return "new_only_cell" if new_state == "MISSING_CELL": return "old_only_cell" - old_present = old_state not in {"", "ABSENT"} - new_present = new_state not in {"", "ABSENT"} if old_state == new_state: return "same" + old_present = not is_absent(old_state) + new_present = not is_absent(new_state) if not old_present and new_present: return "new_correction" if old_present and not new_present: return "lost_correction" + if not old_present and not new_present: + # Absent in both runs, but searched in one and not the other, or left + # out of the search for a different reason: the search changed, the + # matrix did not. + return "search_coverage_changed" return "state_changed" @@ -128,6 +141,7 @@ def main() -> int: "old_only_cell", "new_only_cell", "changed_cells", + "search_coverage_changed", ]) for cluster in sorted(cluster_counts): counts = cluster_counts[cluster] @@ -138,7 +152,7 @@ def main() -> int: + counts["old_only_cell"] + counts["new_only_cell"] ) - if changed: + if changed or counts["search_coverage_changed"]: writer.writerow([ cluster, counts["same"], @@ -148,6 +162,7 @@ def main() -> int: counts["old_only_cell"], counts["new_only_cell"], changed, + counts["search_coverage_changed"], ]) old_evo = read_evolution(args.old) @@ -199,6 +214,7 @@ def main() -> int: "state_changed", "old_only_cell", "new_only_cell", + "search_coverage_changed", ]: writer.writerow([key, cell_counts[key]]) diff --git a/docs/assets/example-report.html b/docs/assets/example-report.html index 917620c..6600d2d 100644 --- a/docs/assets/example-report.html +++ b/docs/assets/example-report.html @@ -4203,7 +4203,7 @@ fill="#0265ba" d="m 734.53229,859.93067 c 6.32782,-1.50009 12.68772,2.36408 14.27189,8.67088 1.58527,6.30791 -2.19262,12.71869 -8.47839,14.38804 -4.14185,1.10073 -8.55473,-0.11394 -11.55159,-3.17829 -2.99576,-3.06324 -4.11197,-7.50267 -2.91942,-11.61907 1.19255,-4.1164 4.50691,-7.27256 8.67751,-8.26156 z" style="stroke-width:1.10626" /> -Corrected pangenome matrix
24clusters
12genomes
8corrected
20.5%of gaps
3kept out
0rejected
+3core
Balancedpolicy
v0.2.0
Phylogeny
Corrected matrixinputcorrectedabsent
Unique syntenies