Skip to content

Commit f8c8d2f

Browse files
Show '-' for Z-score on negative-control samples.
Controls are only used to compute background Z-scores for clinical samples, so control rows should not carry numeric Z values. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 349fbad commit f8c8d2f

1 file changed

Lines changed: 25 additions & 2 deletions

File tree

virasign/virasign.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9005,6 +9005,20 @@ def _compute_and_write_zscores(
90059005
heatmap_data[species][sample_name] = []
90069006
heatmap_data[species][sample_name].append(ref) # Store full ref data for filtering
90079007

9008+
# Controls are background only: never show a Z-score on control sample hits.
9009+
if _controls_used:
9010+
for sname in list(db_samples_data.keys()):
9011+
if sname not in _controls_used:
9012+
continue
9013+
per_db = db_samples_data.get(sname) or {}
9014+
for _db, refs in per_db.items():
9015+
if not isinstance(refs, list):
9016+
continue
9017+
for ref in refs:
9018+
if isinstance(ref, dict):
9019+
ref.pop("zscore", None)
9020+
ref.pop("zscore_controls", None)
9021+
90089022
# Prepare data for JavaScript (only this database)
90099023
# Include ALL samples, even if they have no viruses detected
90109024
db_samples_json = {}
@@ -11097,10 +11111,19 @@ def _compute_and_write_zscores(
1109711111
if sname in db_samples_data and database_name in db_samples_data[sname]:
1109811112
refs = db_samples_data[sname][database_name]
1109911113
if not refs:
11100-
writer.writerow([sname] + [""] * 11)
11114+
# Empty control samples: still mark Z-score as dash (no numeric score).
11115+
z_empty = "-" if sname in (_controls_used or set()) else ""
11116+
writer.writerow([sname] + [""] * 10 + [z_empty])
1110111117
continue
1110211118
for ref in sorted(refs, key=lambda r: r.get("coverage_breadth", 0), reverse=True):
1110311119
nogr = f"{int(ref.get('nogr_regions', ref.get('non_overlapping_reads', 0)) or 0)}|{int(ref.get('nogr_bases', ref.get('non_overlapping_bases', 0)) or 0)}"
11120+
# Controls are used only to compute Z-scores for non-control samples.
11121+
if sname in (_controls_used or set()):
11122+
z_cell = "-"
11123+
elif ref.get("zscore", None) is None:
11124+
z_cell = "-"
11125+
else:
11126+
z_cell = f"{float(ref.get('zscore') or 0.0):.2f}"
1110411127
writer.writerow([
1110511128
sname,
1110611129
ref.get("accession", ""),
@@ -11113,7 +11136,7 @@ def _compute_and_write_zscores(
1111311136
f"{ref.get('coverage_depth', 0):.2f}",
1111411137
f"{ref.get('coverage_breadth', 0) * 100:.1f}",
1111511138
nogr,
11116-
"" if ref.get("zscore", None) is None else f"{float(ref.get('zscore') or 0.0):.2f}",
11139+
z_cell,
1111711140
])
1111811141
_atomic_write_text(csv_file, csv_buf.getvalue())
1111911142
logger.info(f"Generated CSV summary for {database_name}: {csv_file}")

0 commit comments

Comments
 (0)