chromosomix 0.7.0
What changed in chromosomix 0.7.0, released on 6 August 2026.
-
Picking the newest build did nothing, on the one page where it mattered. Reported from the deployed site: the menu showed
0.6.0selected with0.6.1marked latest, and choosing0.6.1reloaded quickly and changed nothing at all.Every part of that was working as built. A visitor at the site root is served by their service worker, whose cache was a build old — which is the design, since an update installs and waits for consent rather than swapping code under a half-read file. The picker sent them to the site root. The worker answered that navigation from the same cache. Nothing in the round trip ever asked the network for anything, so it would have done that for ever.
The newest build is now taken rather than navigated to: check for an update now, take what is waiting by the same
skip-waitinghandshake the update bar uses, and only if the shell is known stale and nothing is waiting, drop the worker and reload. The first path replaces the cache rather than dropping it, and so keeps offline.The state is no longer silent either. When the running build is not the one the root publishes, the dialog now says which build is on screen, which one the site has, and that an ordinary reload will not fetch it — the absence of that sentence is what made this hard to read from the outside.
This cannot rescue a page that is already stuck, since that page is running the code without the fix. The update bar is the way out of one, as it always was.
-
A drawn pixel no longer straddles two sequences. A metagenome view was reducing the same picture three times over, and two of the three did not know where the contigs were: the read summed bins into contig-snapped cells, the renderer then pooled those into raster pixels flat and two at a time, and the browser filtered the result down to the screen. On a 4,882-contig genome each drawn pixel therefore held two different contigs and was coloured by the brighter of their two diagonals, so pairs of sequences that never touched were drawn as one solid block on the diagonal — with the boundary hairline running through the middle of it, because the separators were the one layer still drawn at the true positions.
There is now one rule and one place that keeps it: a cell is a run of bins inside one sequence, or a run of whole sequences, never part of one plus something else.
partitionAxisbuilds every grid in the app against a cap it never exceeds, so the grid the reader builds is the grid the renderer draws and nothing pools a second time.POOLED_CELL_LIMIT— the 1,024 cells of slack that guaranteed the second pooling for any axis between 4,096 and 5,120 cells — is gone, and so isflatBinPooling, which above 5,120 contigs was mixing whole sequences together in the data rather than only in the picture. -
Where sequences outnumber pixels, cells hold whole sequences and say so. An axis of 4,882 contigs cannot give each one a cell in a 4,096-pixel picture, and the old answer was to pretend otherwise. Now such a cell is a named set of whole sequences, summed, kept inside one genome — the rule the metagenome overview already applied to its slots, for the same reason and for the further one that a cell belonging to exactly one genome is a cell that can be clicked through. The summary states it in the unit the cells actually are:
2 contigs per cell, summed, rather than a base-pair width that no longer means anything. -
The genome view plans its grid instead of asking for whatever fits. It sent no resolution at all, so a genome of thousands of contigs arrived as a dense block that the renderer coarsened on arrival — the path the report above came through — and a mammalian chromosome at 10 kb was refused outright for being larger than one typed array. The reader now plans any block that begins on a contig boundary and reports the plan it used, which is where the view reads its resolution from. A region starting mid-contig is left alone: its coordinate origin has no cell in a coarse grid, and moving it silently is worse than refusing by size.
Changed
Section titled “Changed”-
The line under a map says two things and stops. How large the picture is and what one cell of it is worth —
4,046 × 4,046 bins · **effective resolution: 3.0 kb**— from one function all four views share, so they cannot drift apart on the same fact. Gone from it:matched chromosome XV ·andXV × XV ·, which the title above already says;bins 28,911–34,679andcontacts between the two regions, which nobody reads; and· balanced, which is the colourbar’s to say, in the units it is drawn in, beside the numbers it applies to.The count is the cells, and they are called bins, because a cell of the picture is a bin of the effective resolution:
4,046 × 4,046at3.0 kbmultiplies out to the 12.1 Mb on screen. Counting the file’s own bins would put5,769 binsbeside200 bpfor a 577 kb chromosome — two numbers on one line describing something twice its size. Above one sequence per cell there is no bin to speak of, and they are cells again. -
A cell is a capacity of bins, not a count of sequences. The first version of this had two rules, and the second was wrong: past the point where an assembly’s sequences outnumbered the cells, every cell took a fixed number of whole sequences — so a contig of four bins was crushed into half a cell beside a contig of one, while the picture had room to draw all four. One rule now: a cell holds at most
kbins and never part of one sequence beside anything else. A sequence longer thankkeeps cells of its own, cut at its own start; only the ones too small to fill a cell share. On a 6,174-contig genome at 10 kb that is 3,100 cells of 20 kb, with the four-bin contig drawn as two cells and the one-bin contigs two to a cell — where before it was one cell for both, and the four-bin contig had lost its inside. -
A group is one sequence, however many cells it spans. The first cut of the membership list walked a group’s cells and named the sequence in each, so a contig longer than the capacity — which has several cells of its own — was listed once per cell: its name appeared twice in the sequence list, its cell described itself as holding two sequences, and the bin count was suppressed because the cell looked shared. Members are the distinct sequences now.
-
The sequence list counts a sequence’s own bins. It was showing
end - start, which counts the cells a sequence is drawn in — so a contig of two bins read “1 bins” the moment the capacity reached two. It comes from the sequence’s own length now, which is the number that does not move when the picture is coarsened. -
A shared cell says what is in it. It used to be labelled with the first sequence and nothing else, so the readout named one of two and gave it a coordinate inside a cell that is not only its (
Contig_184898,0 bp × 0 bp), and the sequence list beside the map listed one contig in two. The readout now names them —Contig_184898 + Contig_321167— and the list is built from what the cells hold rather than from what they are labelled with, so every sequence is there and every one of them opens. -
The metagenome’s own views join the rest. Three of them were reducing a second time behind the reader:
- the whole-metagenome overview capped its axis at 16,384 units where the
renderer draws 4,096, so the last two steps were taken flat and blind to the
genome boundaries
poolUnitshad just snapped to — sixteen genome pairs to a pixel, the pointer resolving one of them. The cap is the raster’s width now. It was a memory bound, and memory was never what binds a picture four thousand pixels wide; - the contig-level roll-up had no bound at all: one cell per contig, so a genome of 4,882 contigs was a 190 MB accumulator for a 4,096-pixel picture, pooled two contigs to a pixel on arrival. It is coarsened where it is built now, by the same partition the bin grid uses, inside one genome;
- the genome-pair view stated no resolution at all, and can be pooled like any other block.
All four metacool views — genomes, genome, genome pair, region — and the overview now draw the same line, from the same function.
- the whole-metagenome overview capped its axis at 16,384 units where the
renderer draws 4,096, so the last two steps were taken flat and blind to the
genome boundaries
-
The overview says it once. Under the map it used to add “7,748 contigs are more than are readable at once, so each row sums about 2 consecutive contigs, never across a genome boundary. Every one is included.” — which is the summary’s
2 contigs per cell, summedat length, and dates from when the same view threw 98% of the contigs away and had to promise it no longer did. The line says it; the paragraph is gone. So is· full scan: where the numbers came from is not a property of the picture, and the gate above asked before the scan ran. -
A selection is the same axis, scattered. It was the last path on the old rule: a cell opened at every ticked sequence, so the axis could not fall below the number of them however coarse the bins were made. Past the cap the renderer pooled what arrived, flat and blind to the sequences — and far past it,
select allon a large metagenome asked for an accumulator ofcells²that the machine refused, where the previous release had at least said “Select fewer sequences”. It takes the range’s capacity now, so a large sequence keeps its own cells among small ones, shared cells name what they hold, and ticking twenty thousand contigs is a picture. -
A selection reads only the sequences it asked for. Pixels are sorted by
bin1, so every pixel a selection wants lies in the row band of one of its own sequences, andbin1_offset— already in memory — says where each band is in two lookups. Bands are merged where the gap is smaller than the byte source’s own chunk and walked as one operation, with one progress count. Four MAGs out of two thousand used to cost a pass over every stored pixel in the file. -
__unbinned__is out of the whole-file view. It is not a genome and is shown nowhere else (§7.4) — absent from the tables, unselectable, excluded from the overview — but the whole-file map read[0, nBins)and drew it. On a 1.9 M-bin metagenome that is 56% of the bins: a band across the picture, and, being among the drawn pixels, the thing setting the autovmaxfor everything else. Undergenome-then-lengthit is one contiguous range at index 0, so leaving it out is a range rather than a gap.
-
A pooled balanced block is an approximation, and now says nothing about it. Summing balanced values is not balancing at a coarser resolution — the marginals of a
k-bin cell arektimes a fine bin’s, which is whycooler zoomify --balancere-balances every level from raw counts rather than summing the level below. A second cost is quieter: a filtered bin carries aNaNweight, the dense read multiplies it through so the whole row draws transparent (§6.4, “a blank row is an unbalanced row”), and a pooled read dropsNaNcontributions instead, so that row returns as an ordinary number. The whole-file view has done this since pooling was added; the views above now do it too, because the alternative — keeping balanced blocks dense — refuses a mammalian chromosome outright and draws everything else through a contig-blind raster. Balancing at the read’s own resolution, and taking a coarser rung of a laddered.mcoolwhere one exists, are the real answers and are not attempted here. -
A coarse cell belongs to the sequence, not to the question. The grid falls at
contigStart + m·kwhatever range was asked for, and a request is widened to those edges rather than starting its own grid at its own left edge. So a base pair lands in the same cell, holding the same sum, in every view of it, and a region of a chromosome now behaves exactly as the chromosome does: one coordinate under one pixel, showing the sum beneath it. It also gives the first cell a place in the contig’s own coordinates — a block opening 320 kb in used to call its first cell 0 bp — which is what let the restriction go that kept mid-contig regions on the dense path. At mostk − 1bins are added at each end, and the range reported is the range drawn. -
The reader plans the grid exactly rather than from a bound.
poolPlan’sn / (cap − contigs)is what a caller needs, having to name a resolution before anything is read. The reader has the contig extents in hand, so it searches for the smallest grid that fits — which at a bin count just over a multiple of the cap is a whole step finer than the bound allows. -
Selections larger than the picture are drawn rather than refused. “This selection is 6,000 cells per axis … Select fewer sequences” is a strange thing to say to someone who has just ticked select all. The axis is named sequences either way; only how many share a cell was ever in question, and that is a number the summary can state.
-
The summary counts the assembly, not the pooling. An axis run is one cell’s name, so counting runs counts cells — and a 4,882-contig genome was reported as “across 2,441 contigs” the moment its cells held two apiece.
-
Filtering is decided in the pixels it happens in.
imageSmoothingEnabledwas tested in CSS pixels while the image was placed in device pixels, so on a 2x display everything between one and two raster pixels per device pixel was magnified through a bilinear filter — the one combination with nothing to recommend it. The same slip applied to every export, where the DPI scale takes the place of the device ratio, so a 300 dpi figure was asked the screen’s question.
Documentation of chromosomix v0.20.0 · built from 40ec1ec · source
