Skip to content

Floor genome-wide scatter y-axis so deep deletions don't distort it (gh#385)#1079

Merged
etal merged 1 commit into
masterfrom
fix-385-genome-autoscale-floor
May 24, 2026
Merged

Floor genome-wide scatter y-axis so deep deletions don't distort it (gh#385)#1079
etal merged 1 commit into
masterfrom
fix-385-genome-autoscale-floor

Conversation

@etal
Copy link
Copy Markdown
Owner

@etal etal commented May 24, 2026

Summary

Plotting homozygous deletions (very large negative log2) distorted the y-axis of cnvkit.py scatter. The region/chromosome view was fixed long ago — it clamps its auto-scaled lower limit at -5.0 and flags clipped segments (commits ca8d5cc / 0920829). The genome-wide view (cnv_on_genome) never got the same treatment.

Root cause

cnv_on_genome computed y_min = np.nanmin([seg_auto_vals.min() - 0.2, -1.5]) with no lower bound. A single homozygous-deletion segment (log2 ≈ -12) drove y_min to ≈ -12.2, compressing all real signal into the top ~10% of the plot.

Empirically, before the fix:

view ylim with a log2≈-12 segment
region (cnv_on_chromosome) (-5.0, 0.3)
genome (cnv_on_genome) (-12.2, 1.5)

Fix

  • Add a shared AUTO_Y_MIN_FLOOR = -5.0 constant.
  • Apply it in cnv_on_genome: max(AUTO_Y_MIN_FLOOR, np.nanmin([seg.min() - 0.2, -1.5])). This keeps the existing -1.5 default-extend (quiet genomes are unaffected), extends to fit moderate deletions, and floors pathological ones at -5.0.
  • Warn when segments are clipped below the floor — parity with the region view — pointing users to --y-min.
  • Switch the region view's literal -5.0 to the shared constant (no behavior change).

After the fix: genome (-5.0, 1.5); quiet genome (no deep deletion) still (-1.5, 1.5); explicit --y-min -15 still honored.

Tests

  • New PlotTests::test_scatter_genome_y_floor (test/test_commands.py): asserts the genome-wide y-axis is floored at AUTO_Y_MIN_FLOOR for a deep-deletion dataset, and that an explicit --y-min overrides it. Written failing first (-12.2 not >= -5.0), passes with the fix.
  • test_commands.py (74) and test_cnvlib.py (30) pass; mypy and ruff clean.

Clinical-impact note

Plotting-only. Genome-wide scatter plots containing very deep deletions now render with a -5.0 lower bound instead of an arbitrarily low one (this is the intended fix). No change to .cnr/.cns/.cnn/SEG/VCF output, so downstream pipelines are unaffected. The --y-min escape hatch is preserved.

Closes #385.

🤖 Generated with Claude Code

@codecov
Copy link
Copy Markdown

codecov Bot commented May 24, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 67.83%. Comparing base (86bf4da) to head (a2742cf).

Files with missing lines Patch % Lines
cnvlib/scatter.py 83.33% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1079      +/-   ##
==========================================
+ Coverage   67.81%   67.83%   +0.02%     
==========================================
  Files          74       74              
  Lines        7686     7691       +5     
  Branches     1366     1368       +2     
==========================================
+ Hits         5212     5217       +5     
  Misses       2034     2034              
  Partials      440      440              
Flag Coverage Δ
unittests 67.83% <83.33%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…gh#385)

The region/chromosome scatter view already clamps its auto-scaled y-axis
lower limit at -5.0 and flags segments below it (commits ca8d5cc /
0920829). The genome-wide view (cnv_on_genome) never got the same
treatment: it used np.nanmin([seg.min() - 0.2, -1.5]) with no floor, so a
single homozygous-deletion segment (log2 ~ -12) pulled y_min down to
~-12.2 and compressed all real signal into the top sliver of the plot.

Add a shared AUTO_Y_MIN_FLOOR (-5.0) constant and apply it in
cnv_on_genome, keeping the existing -1.5 default-extend so quiet genomes
are unaffected. Warn (as the region view does) when segments are clipped
below the floor, pointing users to --y-min. Switch the region view's
literal -5.0 to the shared constant.

Plotting-only change: genome-wide scatter plots with very deep deletions
now render with a -5.0 lower bound instead of an arbitrarily low one; no
change to .cnr/.cns/.cnn/SEG/VCF output. An explicit --y-min still
overrides the floor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@etal etal force-pushed the fix-385-genome-autoscale-floor branch from a7d6aad to a2742cf Compare May 24, 2026 16:36
@etal etal merged commit 1987cf7 into master May 24, 2026
13 checks passed
@etal etal deleted the fix-385-genome-autoscale-floor branch May 24, 2026 16:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Graph autoscale is broken in cnvkit scatter v0.9.5

1 participant