radiens_qc.units
Read the units a clustered sort found in a recording.
Distinct from :mod:radiens_qc.events, which reads threshold crossings. The two
come from different scrapes of the same recording and neither substitutes for
the other -- see :mod:radiens_qc.spikes. A crossing is a site detecting
something; a unit is a cell the sorter clustered across a neighborhood, and the
question this level answers is what cells are here rather than what each site saw.
Nothing here is archived on a :class:~radiens_qc.report.QualityReport, for the
same reason an excerpt is not: a report is a measurement the KPI pass produced,
while this is a view into the recording, fetched when a figure is drawn. The sort
is the caller's, named by spikes_id; see :mod:radiens_qc.spikes.
Waveforms are the largest thing the package moves, so they are fetched
separately -- :func:fetch_unit_waveforms reads a bounded sample of spikes,
which :meth:SortedUnits.with_waveforms attaches to the units it read them for.
:func:fetch_units never fetches them, and nothing caches them. The figures
reporting amplitude find it there, and say so when it is absent.
Classes
SortedUnits
dataclass
Every unit a clustered sort found in one recording.
Attributes:
| Name | Type | Description |
|---|---|---|
base_name |
str
|
Recording identifier. |
sampling_rate |
float
|
Sampling rate in Hz. |
time_range_sec |
tuple[float, float]
|
|
geometry |
DataFrame
|
Per-channel probe geometry, indexed by |
units |
DataFrame
|
One row per unit, indexed by integer label, carrying the primary
site, spike count and rate, SNR, and probe coordinates. Those
coordinates are the primary site's, copied: the sorter reports no
position of its own, so they carry nothing |
spikes |
dict[int, NDArray[float64]]
|
|
spikes_id |
str
|
Fileset the units were read from, so a caller wanting waveforms reads them from the same sort. |
waveforms |
dict[int, UnitFootprint]
|
|
Attributes
Methods:
amplitudes_uv
label -> µV peak of each unit's mean waveform at its detecting site.
Measured from the waveforms because the sorter reports no amplitude of its own. The same quantity the channel level maps as event amplitude -- the mean absolute peak of an event, at the site that saw it best -- so the two share a color scale and a unit map can be read against the site map beneath it.
Peak of the mean rather than peak-to-peak: peak-to-peak is roughly twice as large, and drawing it against the channel level's scale would put every unit at the top of a ramp that means something else.
Empty when no waveforms are attached, and a unit whose footprint omits its own detecting site is skipped rather than reported at a neighbor's amplitude.
depth_order
Row order for a unit raster: by where the cell sits, not by label.
A unit's probe coordinates are its primary site's, copied -- the sorter
reports no position of its own -- so units sharing a site tie exactly.
Descending spike count breaks the tie, which puts the site's dominant cell
first and matches how :func:_unit_table picks the listing every other
per-unit field is read from.
with_waveforms
A copy carrying waveforms, as read by :func:fetch_unit_waveforms.
Separate from the fetch so the read stays a read: waveforms are the largest payload the package moves, and whether to pay for them is the caller's decision, not something reading the units settles.
UnitFootprint
dataclass
One unit's spikes as the probe saw them, across a neighborhood at once.
Attributes:
| Name | Type | Description |
|---|---|---|
detecting_ntv_idx |
int
|
The site these spikes were detected on -- the one that saw the unit most, among the sites that detected it at all. |
site_ntv_idx |
list[int]
|
The site each column of :attr: |
waveforms |
NDArray[float64]
|
|
spike_count |
int
|
Spikes the unit fired on the detecting site over the read span, before any sampling -- so a sampled footprint still reports what it is a sample of. |
Functions:
fetch_unit_waveforms
Each unit's spikes, each one carrying every site that saw it.
Read by channel rather than by neuron. A neuron-keyed read attributes a whole channel's rows to every neuron on it, so a site carrying two cells reports the same waveforms for both. Reading by channel and selecting the rows whose label is the unit's keeps a unit's spikes its own.
A spike is kept only on the site that saw its largest peak, and it carries that site's detection neighborhood alongside. Taking one detecting site's spikes therefore gives a footprint whose traces are all the same spikes seen in different places -- which is what makes the spatial spread readable. Pooling across detecting sites would not: those are disjoint sets of spikes, so each site's mean would be over different events, and a unit whose peak wandered would read as one that was wide.
The detecting site is the one that saw the unit most. A unit is listed under several only when its extremum moved between them, which happens to the marginal, low-count units rather than the well-isolated ones.
Read from the fileset the units came from. Sampling bounds the payload: a unit firing at 20 Hz for half an hour has 36,000 spikes, and a mean is converged long before that.
Returns:
| Type | Description |
|---|---|
dict[int, UnitFootprint]
|
|
fetch_units
Read every unit a clustered sort found in the recording.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vc
|
VidereClient
|
Client connected to the server holding the recording. |
required |
data
|
DatasetMetadata | Path
|
An already-linked recording, or a path to link. |
required |
spikes_id
|
str
|
Clustered fileset to read. |
required |
channels
|
Sequence[int] | None
|
Amplifier |
None
|
Returns:
| Type | Description |
|---|---|
SortedUnits
|
The units, with the site geometry needed to draw the probe they sit on. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no amplifier channels are selected, or the fileset is detect-only or lacks a selected channel. |