spacr.ops_cycles¶
Registering one field across the sequencing cycles that imaged it.
THE CYCLE AXIS IS NOT THE TILE AXIS, and the difference decides everything
in this module. spacr.ops_register places two DIFFERENT fields that
overlap by a fraction of a tile; here the same field is imaged eleven times
and the stage returns to it, so the displacement is a handful of pixels
rather than a pitch.
AND IT CANNOT USE HOECHST. Measured on the reference acquisition: cycle 1
holds one five-channel DAPI-CY3-A594-CY5-CY7 stack per site, and
cycles 2 to 11 hold four separate base-channel files with NO DAPI at all.
So the channel every tile-axis registration runs on does not exist on this
axis after the first cycle, and averaging Hoechst across cycles is not
available here either.
WHAT REPLACES IT IS THE REFERENCE IMPLEMENTATION’S OWN ANSWER.
ops/firesnake.py:_align_SBS offers method='SBS_mean' for exactly
this case: the maximum across the base channels, normalised by a high
percentile and clipped, which turns four sparse spot channels into one
dense target. Measured on well A1 at two sites, cycles 2 to 11 against
cycle 1:
site 100 peak/mean 169 to 236 shift (-6..-27, 0..10) site 200 peak/mean 218 to 281 shift (-4..-25, 11..21)
20 of 20 cycles registered.
IT IS NOT A FALLBACK, IT IS THE BETTER CHANNEL. The tile axis on DAPI peaks at 23 to 85; this peaks at 169 to 281. Spots are punctate and abundant and nuclei are smooth and few, so losing the Hoechst costs nothing here.
AND THE OFFSET BELONGS TO THE SITE, NOT THE CYCLE. Site 100 sits at x = 0 to 10 across the eleven cycles and site 200 at x = 11 to 21. One rigid transform per cycle for a whole well would carry that difference into every field, so each site is registered against its own reference – which is also what the reference implementation does, one field’s cycle stack at a time.
Classes¶
One field's sequencing cycles, every channel moved into one frame. |
Functions¶
|
The cycles whose registration was believed, in order. |
|
Register one field's channels within each cycle, then its cycles. |
|
Place every cycle of one field against that field's reference. |
|
Turn one cycle's base channels into a single registration target. |
Module Contents¶
- class spacr.ops_cycles.AlignedField[source]¶
One field’s sequencing cycles, every channel moved into one frame.
- Variables:
stack –
(cycles, channels, Y, X)float32, one entry per cycle inkeptand in that order.kept – the cycle numbers the stack holds, ascending. The reference cycle is always among them.
refused – cycles whose registration against the reference was not accepted. They are left out of the stack, because base calls read at untrusted coordinates decode to a wrong barcode rather than to none.
missing – cycles offered with no planes at all – a file that could not be read, for instance.
channel_shifts –
cycle -> one (dy, dx) per channel, the shift that moved each channel onto the first channel of its cycle.cycle_shifts –
cycle -> (dy, dx), the shift that moved each kept cycle onto the reference; the reference’s own is(0, 0).refused_channels –
(cycle, channel)pairs whose within-cycle registration was refused and which were therefore not moved.
- spacr.ops_cycles.accepted_cycles(registrations: Mapping[int, spacr.ops_register.Registration]) Tuple[int, ...][source]¶
The cycles whose registration was believed, in order.
- Parameters:
registrations – the result of
register_cycles().- Returns:
the accepted cycle numbers, ascending.
- spacr.ops_cycles.align_field(planes: Mapping[int, Sequence[numpy.ndarray] | None], *, reference: int | None = None, tolerance: int = CYCLE_TOLERANCE, gpu: bool = True) AlignedField[source]¶
Register one field’s channels within each cycle, then its cycles.
Each base channel is first moved onto its cycle’s first channel, on the clipped cell background the channels share – on the measured plate they sat up to 14 px apart, which no cycle-to-cycle registration can see – and each cycle is then moved onto the reference with
sbs_mean_target(). A cycle offered asNoneor with a missing plane is reported inAlignedField.missingand one whose registration is refused inAlignedField.refused; the rest are still aligned, so one lost cycle does not cost the field.- Parameters:
planes –
cycle -> the base channels of that cycle, every plane one 2-D image of the same shape.reference – the cycle everything is moved onto. None takes the lowest cycle that has planes.
tolerance – how far a cycle may land from the reference and still be accepted, in pixels.
gpu – let the phase correlations run on the card.
- Returns:
the aligned field.
- Raises:
ValueError – when no cycle has planes, or when the reference cycle has none.
- spacr.ops_cycles.register_cycles(reference: numpy.ndarray, cycles: Mapping[int, numpy.ndarray], *, tolerance: int = CYCLE_TOLERANCE, **kwargs) Dict[int, spacr.ops_register.Registration][source]¶
Place every cycle of one field against that field’s reference.
EACH CYCLE AGAINST THE REFERENCE DIRECTLY, never against its predecessor. Chaining c1->c2->c3 saves one registration and makes every later cycle depend on every earlier one: a single bad link displaces the rest and the residual does not say which link failed. Registering each independently is what lets one cycle be dropped without costing the others – PART 9’s rule that a cycle which will not register must not cost the well.
- Parameters:
reference – the reference cycle’s target, from
sbs_mean_target().cycles – cycle number to that cycle’s target.
tolerance – how far a cycle may land from the reference and still be accepted, in pixels.
kwargs – passed to
spacr.ops_register.phase_correlate().
- Returns:
cycle number to its
Registration, including the refused ones – a caller reportingn_cyclesneeds to know a cycle was tried and refused, not merely that it is absent.
- spacr.ops_cycles.sbs_mean_target(planes: Sequence[numpy.ndarray], *, percentile: float = NORMALISE_PERCENTILE, cutoff: float = 1.0) numpy.ndarray[source]¶
Turn one cycle’s base channels into a single registration target.
THE MAXIMUM, NOT THE MEAN, over channels. A read is bright in exactly one channel per cycle – that is what a base call is – so averaging the four divides every spot by four and leaves the background where it was. The maximum keeps each spot at its own brightness whichever channel carried it.
- Parameters:
planes – the base channels for one cycle of one field.
percentile – the percentile the result is divided by.
cutoff – the value the result is clipped at afterwards, so a saturated spot cannot dominate the correlation on its own.
- Returns:
a float32 image, the same shape as one plane.
- Raises:
ValueError – when no planes are given, or they disagree in shape.