Skip to content

manhattan: opt-in thinning of overlapping chromosome labels#82

Open
wdecoster wants to merge 1 commit into
Psy-Fer:devfrom
wdecoster:manhattan-label-collision-avoidance
Open

manhattan: opt-in thinning of overlapping chromosome labels#82
wdecoster wants to merge 1 commit into
Psy-Fer:devfrom
wdecoster:manhattan-label-collision-avoidance

Conversation

@wdecoster
Copy link
Copy Markdown

This feature was implemented using Claude, but supervised.

Description

Adds ManhattanPlot::with_thin_overlapping_labels(), an opt-in that makes chromosome labelling on the Manhattan x-axis collision-aware.

Problem. add_manhattan_chr_labels draws every chromosome's name at its band midpoint, suppressing only bands narrower than 6px. Adjacent narrow chromosomes (e.g. 17 / 19 / 21 on a default-width genome-wide plot) are wider than 6px but their two-digit labels are wider than the band, so the labels overprint each other and become unreadable. There was no way to control this.

Fix. A new builder flag (off by default) enables a single left-to-right pass that tracks the right edge of the last drawn label and skips any label whose estimated horizontal footprint would collide with it, leaving a small gap. Spans are already in genomic order, so one pass thins the labels of crowded small chromosomes while keeping the rest readable. It works for both horizontal and rotated (Layout::with_x_tick_rotate) labels — rotation shrinks the horizontal footprint by cos(angle). Default behaviour is unchanged.

Label width is estimated from glyph count (len * tick_size * 0.6) because this stage has no font metrics; this matches the existing 6px band heuristic and the estimate stays local to chromosome-label placement.

Before (default) vs. with with_thin_overlapping_labels() on an hg38 genome-wide plot: the cluster 17 18 19 20 21 22 that previously overprinted is thinned to non-overlapping labels.

Type of change

  • New plot type
  • New feature / API addition
  • Bug fix
  • Documentation / assets only
  • Refactor / housekeeping

Checklist

Library (new plot type)

  • N/A — not a new plot type. Touches existing ManhattanPlot (src/plot/manhattan.rs: new field + with_thin_overlapping_labels() builder) and add_manhattan_chr_labels (src/render/render.rs).

Tests

  • Added to tests/manhattan_svg.rs: labels all drawn by default, thinned (and verified non-overlapping) when enabled at default width, and fully drawn on a wide plot.
  • cargo test --features cli,full — all 180 tests pass.

CLI (if applicable)

  • Not included — no CLI flag added for the manhattan subcommand. Happy to add a --thin-labels flag if you'd like it wired through the CLI.

Documentation

  • Rustdoc added on with_thin_overlapping_labels() with a usage example.
  • No new docs page / gallery card — this is a builder flag on an existing plot, not a new plot type.

Visual inspection

  • Rendered before/after PNGs of an hg38 genome-wide plot: default overprints 17/19/21; with the flag the labels are thinned and non-overlapping.
  • Existing test_outputs/ SVGs unaffected (feature is off by default).
  • No text clipped, no legend overlap, thresholds and bands unchanged.

Housekeeping

  • CHANGELOG.md — entry added under ## [Unreleased]### Added.

Branch / target: opened against dev, single commit, rebased on the current
dev tip.

The Manhattan x-axis draws every chromosome's name at its band midpoint,
suppressing only bands narrower than 6px. Adjacent narrow chromosomes
(e.g. 17/19/21 on a default-width genome-wide plot) therefore print
labels directly on top of each other.

Add ManhattanPlot::with_thin_overlapping_labels() (off by default). When
enabled, labels are placed in a single left-to-right pass and any label
whose estimated horizontal footprint would collide with the previously
drawn one is skipped, leaving a small gap. Spans are already in genomic
order, so one pass thins the labels of crowded small chromosomes while
keeping the rest readable. Works for both horizontal and rotated
(with_x_tick_rotate) labels; rotation shrinks the footprint by cos(angle).
Default behaviour is unchanged.

Label width is estimated from glyph count since this stage has no font
metrics; the estimate stays local to chromosome-label placement.

Adds regression tests: labels are all drawn by default, thinned (and
never overlapping) when enabled on a default-width plot, and fully drawn
on a wide plot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Psy-Fer
Copy link
Copy Markdown
Owner

Psy-Fer commented May 29, 2026

Hey mate,

This is looking good. Can you drop in a screen cap or 2 of what it looks like with an example code block?

Cheers,
James

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.

2 participants