Skip to content

feat(live): zoom the genome map down to a gene's exons, and find any gene from the keyboard - #410

Open
geiresx wants to merge 6 commits into
GeiserX:mainfrom
geiresx:pgp/map-1e2
Open

geiresx wants to merge 6 commits into
GeiserX:mainfrom
geiresx:pgp/map-1e2

Conversation

@geiresx

@geiresx geiresx commented Nov 14, 2026

Copy link
Copy Markdown
Collaborator

The problem

The genome map on a person's page stopped at the chromosome level. A reader could open a chromosome and zoom to about 10 Mb. The reader could not see which genes sit under a finding or where in a gene a change lies, and could not find a gene by its name. A click on a finding left the map at once. With no finding in view, the map gave no way to the next one.

The fix

The fix is in the map's browser files only (assets/live/map.js, map.css). The map document and og do not change.

  • Region and gene levels. One level() rule works by bases per pixel. The chromosome level is above 16,667, the region level goes down to 833, and the gene level is below that. A view under 50 kb is the reads level, drawn as the gene level for now. The view can now narrow to 100 bp.
  • Genes lane. From the region level, the map fetches the chromosome's gene file once (/map/genes/<chrom>.json, which og map genes already serves). It draws every gene that fits in three rows. Each row has a strip for the bars and a strip for the names, so a name never covers another. The genes that a finding names come first, in bold, then the protein-coding genes, then the rest. At the gene level each gene is a model: a thin line with strand chevrons and the merged exon blocks inside its span. A finding there is a dashed tick down through every lane, with its HGVS under its gene. More than 4,000 genes in view draw as a density strip with "Dense here: zoom in to see each one".
  • Titles and path. The region title is "Chromosome 11, band 11p15.4". The gene title is " and its neighbours", else "Chromosome 11, 300 kb around 5.250 Mb". The path reads Genome › chr11 › 11p15.4 › 5.150-5.350M, and each step up is a button.
  • Keyboard. The arrows pan 10% (with Shift, a whole view). The + and − keys zoom 2×, and [ ] and 0 work as before. Esc closes the card, then steps out one level at a time. / puts the cursor in the search box, and L opens the layers. Tab steps through the findings in view (a ring on the map, the card in the margin), then leaves the map.
  • Search. One box looks through the gene names (the names file, fetched on the first key), the band names, the findings that the map draws (gene, id, title) and a typed place. Enter or a click flies there.
  • Card and Nearest. A click on a finding opens its card beside the map. The card shows the level, title, gene, position, change, the map's sentence and a link to the finding's page. When no finding of the open chromosome is in view, a Nearest button names the closest one (or the first on the next chromosome) and flies there.
  • Paint the copies. None is on, and Origin is off with its reason. On a run in a family, the reason says that the family page paints it. On a run in no family, the reason says that it needs a family run with a sequenced parent.
  • Address. Under 2 Mb the address keeps 3 decimals of Mb (#chr7:117.480-117.669M), and under 60 kb it keeps positions (#chr7:117480026-117668665). A link then opens the same close view.
  • docs/genome-map.md is new, in the nav under Guides after "Watch a Run Live". It says what the map shows, its levels, keys, search, layers, routes and the document format. The two live demo pictures are retaken, and CHANGELOG.md has one line for this change.

The veil

Search, the card, Nearest and the bold names of the genes lane all read drawn(), the list that the map already draws. That list passes every row through the page's own veil. So a closed result is never a search line or a card, Nearest never leads to it, and it never makes a gene bold. The search line of a gene comes from the names file only, so it is the same whether a closed result names that gene or not. When the page closes a result again, the card closes and the search lines are built again. The gene files are reference data, the same for every reader.

Decisions

  • A click on a finding opens its card. Before, it went straight to the finding's page. The card now links there, as the design asks: a click picks, and the card leads on.
  • The frame budget lives in tests/test_live_demo.py, not in a new tests/test_map_perf.py. This wave adds no new Python file, and that test already builds the demo, so the frame check uses it.
  • The test makes the genome-scale input by arithmetic. It rewrites DEMO-001's document to about 4,000 runs of homozygosity, and chr1's gene file to 5,000 genes and 40,000 exon blocks, all invented. Then it puts the files back. A build with og from the 200 MB synthetic ROH text would cost minutes of a CI shard for the same picture.
  • Esc steps to the gauge's next stop up: gene to region, region to the whole chromosome, chromosome to the genome. Fixed spans (400 kb, 8 Mb) can land on the same level on a wide screen, so the stops are set in bases per pixel.
  • The reason on Origin reads the family plugin's state that the page already has (window.PGP.state). It fetches nothing.

Outputs

No pipeline output, option, config key or file name changes. On the live page, the map's address gains the finer forms above, and the old forms open the same views. A click on a finding now opens its card instead of the finding's page.

How it was checked

Each new check in tests/test_live_demo.py (map_checks) also runs once against a planted mistake, and it must fail there:

Check Planted mistake
The region, gene and reads levels open from their addresses, with their titles, paths and genes. Esc steps out. The Region and Gene stops work, and so do + and the right arrow levels that stop at the chromosome
/ opens search. A gene, a band and a finding are found, and Enter flies there (a finding with its card). The son's closed result is never a line, by its gene, id or title search that reads every finding, closed or not
Nearest names the closest finding (else the next chromosome's) and flies there with its card. Esc closes the card first. Nearest never leads to the son's closed result Nearest that reads every finding
Origin is off with its reason, in a family and in none an Origin button that is on
The frame budget on the genome-scale document a 20 ms busy loop in draw()

The frame check runs a scripted pan of 300 steps, 100 each at the chromosome, region and gene levels. It sends real mouse events through Chrome's DevTools protocol. The work of each frame is the pointer handlers plus draw(), timed with performance.now() inside the page, not the frame interval. The budget is 8 ms at the median and 16 ms at the 95th percentile. The first paint must come within 150 ms of the document arriving (parse 30 ms), and the JS heap must stay at 60 MB at most.

Local measures came from a Mac mini with headless Chrome, on the genome-scale document. The work per frame was 0.60 ms at the median, 2.10 ms at p95 and 4.00 ms at most. The first paint took 47 ms, the parse 1 ms, and the heap was 5.5 MB. With the busy loop, the median was 20.60 ms and p95 22.20 ms, and the check failed, as it must.

Every map check passed locally: 42 PASS and no FAIL, with the existing veil, karyogram, fallback and 390 px checks. The person layout, phone, phone report and fold checks passed too. The docs build with zensical build --strict, and the site check found 0 errors on 97 pages. The retaken pictures pass check_pictures.py (chunks and OCR).

CI runs: to follow on this head.

Bead: pgp-iqon.9

…d frame budget

Each check runs once more against a planted mistake: a search or Nearest
that reads every finding, an Origin button that is on, and a 20 ms busy
loop in draw() for the frame budget.

Bead: pgp-iqon.9
@coderabbitai

coderabbitai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 7 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 039f11f and 0329a8c.

Files ignored due to path filters: 2

  • docs/images/demo-live-phone.png is excluded by !**/*.png
  • docs/images/demo-live-site.png is excluded by !**/*.png
Files selected for processing: 6

  • CHANGELOG.md
  • assets/live/map.css
  • assets/live/map.js
  • docs/genome-map.md
  • tests/test_live_demo.py
  • zensical.toml
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@geiresx

geiresx commented Nov 14, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

This branch has not been deployed

No deployments
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