radiens_qc
radiens-qc turns a Radiens recording into an answerable question: is this data good enough to use?
Point it at a recording and a :class:~radiens_core.VidereClient; it configures
the stage-2 filters and detection threshold, walks the recording in windows, and returns a
:class:~radiens_qc.report.QualityReport -- per-channel SNR / noise / event
rate, an electrode-integrity grade, and whether the detector fired::
from pathlib import Path
from radiens_core import VidereClient
from radiens_qc import compute_report, save_report
vc = VidereClient()
report = compute_report(vc, Path("/data/rec01.xdat"), source="exp/day3")
print(report.integrity_counts()) # {"ok": 15, "noisy": 1, "dead": 0}
print(report.event_counts()) # {"present": 9, "absent": 7}
save_report(report, Path("reports"))
The package never learns where recordings are stored: hand it a local path (it
links the file itself -- linking is idempotent) or an already-linked
:class:~radiens_core.models.DatasetMetadata. Fetching bytes from Drive, S3, or
a share stays the caller's job.
Classes
DetectionSettings
dataclass
What to configure on a datasource before measuring it.
The two travel together because they are never independently meaningful: a
threshold is in multiples of a noise floor measured through the filters, and
an event_rate states nothing without both. Passing one object is also
what keeps a report and the raw-signal figures drawn beside it describing the
same signal, which two loose arguments left to a caller to keep in sync.
Attributes:
| Name | Type | Description |
|---|---|---|
dsp_params |
Sequence[DSPParam] | None
|
Filters applied at stage 2, in order. Any param that does not
name a |
threshold_sd |
float
|
Symmetric event-detection threshold in noise-SD multiples,
applied as |
EventTrains
dataclass
Every threshold crossing in one recording, per channel.
Attributes:
| Name | Type | Description |
|---|---|---|
base_name |
str
|
Recording identifier. |
sampling_rate |
float
|
Sampling rate in Hz. |
time_range_sec |
tuple[float, float]
|
|
channel_indices |
tuple[int, ...]
|
Amplifier |
geometry |
DataFrame
|
Per-channel probe geometry, indexed by |
crossings |
dict[int, NDArray[float64]]
|
|
detection |
ResolvedDetection
|
Stage-2 filters and threshold the crossings were found at. |
spikes_id |
str
|
Fileset the crossings were read from. Carried so a caller wanting waveforms for these same events reads the fileset that produced them rather than whichever the dataset offers by default. |
Attributes
Methods:
depth_order
Row order for the raster: shank, then depth.
See :func:~radiens_qc._dataset.depth_order. This level takes depth
rather than the SNR rank the report's panels share, because what it is
drawn to show -- an array-wide stripe, a burst confined to one shank --
is spatial structure that a quality ranking scatters.
Excerpt
dataclass
One slice of the recording, read twice through different filter stages.
wideband and filtered are (n_channels, n_samples) in the channel
order of the owning :class:RawSignal, and cover the same samples: the pair
is what makes "did the DSP chain do what we think" answerable.
FigureSources
dataclass
The objects the figures are drawn from, however the caller came by them.
Every field is optional because which ones are needed depends on what was
selected, and because a report read off disk carries no live recording.
:func:render skips a figure whose source is absent rather than failing:
drawing what a saved report can support is a normal thing to do.
FigureSpec
dataclass
One figure: what it is called, what it shows, and how to draw it.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Unique across the whole registry, not merely within a level -- selection and the rendered mapping are both keyed by it, so two figures sharing a name could not be asked for separately. |
level |
Level
|
Which level of the data the figure shows. |
source |
Source
|
Which of the package's objects :attr: |
build |
_Build
|
Draws the figure from a :class: |
caption |
str
|
One line saying what the reader is looking at. |
needs_waveforms |
bool
|
Whether the figure reports unit amplitude, which is
measured from spike waveforms and has no other source. What decides
whether :func: |
QualityReport
dataclass
Self-contained quality report for a single recording.
Attributes:
| Name | Type | Description |
|---|---|---|
base_name |
str
|
Recording identifier. |
source |
str
|
Caller-supplied provenance string describing where the recording came from (a Drive path, an experiment id, a bare filesystem path). Opaque to this package -- it is recorded and displayed, never parsed. |
recorded_at |
datetime | None
|
Wall-clock recording start (UTC), or |
duration_sec |
float
|
Recording duration in seconds. |
sampling_rate |
float
|
Sampling rate in Hz. |
num_channels |
int
|
Number of amplifier channels analyzed. |
probe_ids |
list[str]
|
Distinct probe identifiers present. |
headstage_ids |
list[str]
|
Distinct headstage identifiers present. |
window_sec |
float
|
Window width used for the temporal analysis. |
metrics |
list[str]
|
Metric names in column order -- the ones the server returned,
followed by the ratios :func: |
thresholds |
QualityThresholds
|
Quality thresholds used for channel classification. |
channels |
DataFrame
|
One row per channel, indexed by native channel index
( The two are deliberately not symmetric. |
window_centers_sec |
NDArray[float64]
|
Window center times, on the dataset's own time base, which does not generally start at zero. |
detection |
ResolvedDetection
|
Stage-2 filters and detection threshold the KPIs were measured
through (provenance). Required, because |
matrices |
dict[str, NDArray[float64]]
|
|
Methods:
ap_band_rms_uv
Median spike-band RMS across channels (µV), or None if not measurable.
A whole-recording noise judgment, and the one that catches what the
per-channel outlier test structurally cannot: a uniformly noisy recording
has no outliers, because every channel is equally bad. Compare against
:attr:QualityThresholds.ap_band_rms_max_uv.
Returns None unless a bandpass appears in the applied filters. The
rms metric is only a spike-band RMS because the KPI engine read
through a bandpass; with no filter established this is the RMS of
whatever the server happened to be applying, which is not a quantity any
threshold describes.
crest_factor
Median peak-excursion-over-noise across channels, or None if not measured.
A whole-recording artifact reading: movement, stim and chewing all put a sample far above what the channel's quiet samples do, and this is how far. Built from two ungated metrics, so unlike SNR it still reports through the epochs an offset makes detection unreliable.
Only comparable against a stated window width. Its numerator is an
extremum, which grows with the width of the fold, so the same recording
read at one window and at another does not give the same number --
:attr:window_sec is the width this one was measured at.
depth_order
Channel positions ordered by shank, then depth.
The report's one display order. Every panel that lists channels -- the per-channel profiles and every channel x time heatmap -- uses this array, so a given row is the same physical site across all of them and against the site maps, which draw the same probe.
Depth rather than metric rank because channel defects are spatially
structured: a damaged shank, a bad connector block and a lifted probe
each occupy a contiguous run of sites, and any metric ordering scatters
exactly that signature across the panel. See
:func:~radiens_qc._dataset.depth_order.
event_counts
Number of channels on which the detector did and did not fire (present/absent).
in_event_fraction
Median share of samples falling inside a detected event, or None.
Near zero on a normally spiking channel: an event occupies a millisecond or two and they are seconds apart. A channel well above that is not spiking -- it is ringing, oscillating, or detecting against a threshold that has collapsed onto its own noise.
integrity_counts
Number of channels in each electrode-integrity tier (ok/noisy/dead).
noise_cutoff_uv
Noise floor (µV) above which this report graded a channel noisy.
The bar the integrity column was actually held to, recoverable from
the report rather than left inside the classifier -- provenance for the
grade, in the same sense as :attr:detection.
Returns None when the report has no noise column, or when no channel
was live and there is therefore no cutoff to state.
shank_ids
Shank of each channel, numbered from the leftmost, aligned to channels.index.
The grouping :meth:depth_order sorts by, for callers that compare sites
within a shank. See :func:~radiens_qc._dataset.shank_ids.
QualityThresholds
dataclass
Heuristic thresholds for classifying per-channel signal quality.
These are deliberately conservative, adjustable defaults — tune them to your probe and preparation rather than treating them as universal.
Attributes:
| Name | Type | Description |
|---|---|---|
dead_noise_uv |
float
|
Channels whose noise floor falls below this (µV) are
treated as |
noisy_mad_multiplier |
float
|
How many robust standard deviations above the
array's median noise floor a channel must sit to be flagged
|
noisy_scale_floor_frac |
float
|
Lower bound on that robust scale, as a fraction of the array's median noise floor. Keeps the cutoff from collapsing onto the median when more than half the channels share an identical value (quantized readings, or a near-uniform probe), which would otherwise flag every channel above it. Relative rather than absolute so it carries no assumption about a particular rig's noise level. |
ap_band_rms_max_uv |
float
|
Upper bound on the array's median spike-band RMS
(µV), a whole-recording judgment rather than a per-channel one: it
catches a uniformly noisy recording, which by definition has no
outliers for |
snr_scale_min |
float
|
Lower bound of the fixed SNR color scale used by the spatial map and stability heatmap. |
snr_scale_max |
float
|
Upper bound of the fixed SNR color scale used by the spatial map and stability heatmap. These scales are intentionally not autoscaled to each report's own min/max -- a probe that's uniformly excellent would otherwise still show "red" at the low end of its own compressed range, giving a false impression of poor sites. |
noise_scale_min_uv |
float
|
Lower bound of the fixed noise-floor color scale used by the spatial map. |
noise_scale_max_uv |
float
|
Upper bound of the fixed noise-floor color scale used by the spatial map, for the same reason. |
event_rate_scale_max_hz |
float
|
Upper bound of the fixed activity/event-rate color scale used by the spatial map, for the same reason. |
amplitude_scale_max_uv |
float
|
Upper bound of the fixed mean-event-amplitude color scale, for the same reason. |
crest_scale_max |
float
|
Upper bound of the fixed peak-over-noise color scale.
A clean spike-band channel sits a few noise SDs up, since detection
itself runs at |
in_event_scale_max |
float
|
Upper bound of the fixed in-event-fraction color scale. Ordinary spiking occupies well under a percent of a window -- a millisecond or two per event, seconds apart -- so a scale ending here spends its range where the interesting values are. |
RawSignal
dataclass
Excerpts, crossings, geometry and whole-file spectra for raw-signal figures.
Attributes:
| Name | Type | Description |
|---|---|---|
base_name |
str
|
Recording identifier. |
sampling_rate |
float
|
Sampling rate in Hz. |
duration_sec |
float
|
Recording duration in seconds. |
channel_indices |
tuple[int, ...]
|
Amplifier |
geometry |
DataFrame
|
Per-channel probe geometry, indexed by |
excerpts |
tuple[Excerpt, ...]
|
One per entry of :data: |
crossings |
dict[int, NDArray[float64]]
|
|
detection |
ResolvedDetection
|
Stage-2 filters and detection threshold the excerpts were read through and the crossings found at. |
freqs |
NDArray[float64]
|
Frequency axis in Hz for whole-file spectral estimates. |
psd_wideband |
NDArray[float64]
|
Whole-file wideband Welch power spectral density,
|
psd_filtered |
NDArray[float64]
|
Whole-file stage-2 filtered Welch power spectral density,
|
Methods:
depth_order
Row order that puts spatially adjacent sites next to each other.
See :func:~radiens_qc._dataset.depth_order.
window_crossings
Crossing times on ntv_idx inside the drawn window, on the dataset's own time base.
window_slice
Sample slice of the centered window_sec of excerpt.
RenderOptions
dataclass
Drawing choices a run makes, for the figures that have one to make.
Reaches every figure; one with no choice to make ignores it. That is what keeps a run-wide choice from having to be repeated per row, and what lets a row be added without a caller learning a new argument.
Attributes:
| Name | Type | Description |
|---|---|---|
smooth_sec |
float | None
|
Gaussian time kernel, in seconds, for the figures drawn from
the report's window series -- the stability trend, The rasters deliberately do not take it. Their kernel is already fixed
in seconds rather than scaled to the span, so they need no pinning to
compare, and their panel exists to show bursts -- a width suiting a
drift readout smears the structure they are drawn for. A raster
bandwidth is set by calling :func: |
ResolvedDetection
dataclass
What was applied to a particular recording, recorded as provenance.
Distinct from :class:DetectionSettings so that a report describes the
filters that ran rather than the request that produced them: ports are
expanded, stage is injected, and the mapping form is gone. An
empty dsp_params means no DSP was configured, so the measurement rode on
whatever the server already held -- which is why
:meth:~radiens_qc.report.QualityReport.ap_band_rms_uv declines to answer.
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:
amp_ports
Distinct hardware ports the recording's amplifier channels occupy, in channel order.
A DSP filter targets one port, so filters must be replicated across every port present. Falls back to port A when no channel reports one.
apply_detection_settings
Configure dataset's stage-2 filters and detection threshold, and report what was applied.
No data files are rewritten -- stage 2 is read-time filtering.
The server auto-clears and recomputes the KPI cache when either changes, but
that recompute is asynchronous. Callers must therefore trigger and await KPI
computation (:meth:VidereClient.kpi_calculate) after this returns, before
reading metrics, or get_kpi_metrics_series may return stale/partial values.
:func:~radiens_qc.compute.compute_report handles that ordering for you.
Returns:
| Type | Description |
|---|---|
ResolvedDetection
|
The settings as applied, for recording as provenance. |
cached_key
The cache key save_report recorded here, or None if there is none.
None for a directory that does not exist, holds no meta.json, or was
written without a key -- all of which read as "cannot be reused".
check_crossings_fileset
Refuse a fileset whose crossings are not the per-site events the report counted.
Raises:
| Type | Description |
|---|---|
ValueError
|
If the fileset detected sites together, at another threshold
on any site, or without some of |
check_units_fileset
Refuse a fileset that no sort labeled, or that lacks a requested channel.
Raises:
| Type | Description |
|---|---|
ValueError
|
If the fileset's provenance has no sort, or it lacks some of |
compute_or_load_report
compute_or_load_report(
vc,
data,
out_dir,
*,
force=False,
source=None,
window_sec=None,
channels=None,
metrics=DEFAULT_METRICS,
thresholds=None,
detection=DEFAULT_DETECTION,
)
Load out_dir's report for this recording, or compute and save it.
A hit still applies thresholds to the loaded report, since thresholds are
not part of the key -- so changing a grading bar regrades in-process instead
of costing a recompute.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vc
|
VidereClient
|
Client connected to the server that would do the computation. |
required |
data
|
DatasetMetadata | Path
|
An already-linked recording, or a path to link. Linking is idempotent and is the one server call a cache hit still makes; it is what yields the identity the key is built from. |
required |
out_dir
|
Path
|
Parent directory holding one subdirectory per recording, as
:func: |
required |
force
|
bool
|
Recompute and overwrite even when the key matches. |
False
|
source
|
str | None
|
See :func: |
None
|
window_sec
|
float | None
|
See :func: |
None
|
channels
|
Sequence[int] | None
|
See :func: |
None
|
metrics
|
Sequence[FlexKpiMetricId]
|
See :func: |
DEFAULT_METRICS
|
thresholds
|
QualityThresholds | None
|
Channel-classification thresholds, applied on load as well as on compute. |
None
|
detection
|
DetectionSettings
|
Stage-2 filters and detection threshold. Part of the key. |
DEFAULT_DETECTION
|
Returns:
| Type | Description |
|---|---|
QualityReport
|
The loaded or freshly computed report. |
compute_report
compute_report(
vc,
data,
*,
source=None,
window_sec=None,
channels=None,
metrics=DEFAULT_METRICS,
thresholds=None,
detection=DEFAULT_DETECTION,
)
Compute a quality report for one recording.
Links the recording if needed, selects the channels to analyze, configures the stage-2 filters and detection threshold so the KPIs reflect them, triggers KPI computation, then reads the whole per-channel metric timeseries in one request. Whole-recording per-channel values are the mean across windows; the full per-window matrices are retained for temporal-stability panels.
Leaves channels selected on the datasource when it returns. Selection is
shared server-side state, so other clients viewing the same datasource see
the change -- as they already do for the DSP group and detection threshold
this configures.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vc
|
VidereClient
|
Client connected to the server that will do the computation. |
required |
data
|
DatasetMetadata | Path
|
An already-linked recording, or a local filesystem path to link.
A path is linked via |
required |
source
|
str | None
|
Provenance string recorded on the report (e.g. the Drive folder or experiment the recording came from). Defaults to the dataset's own path. Never parsed by this package. |
None
|
window_sec
|
float | None
|
Requested width of each analysis window, in seconds. The
server bins its KPI packets, so actual windows are quantized to the
packet duration and the last one may be shorter; a trailing window
under half the resolved width is dropped rather than averaged in.
|
None
|
channels
|
Sequence[int] | None
|
Amplifier |
None
|
metrics
|
Sequence[FlexKpiMetricId]
|
KPI metric names to compute (e.g. |
DEFAULT_METRICS
|
thresholds
|
QualityThresholds | None
|
Channel-classification thresholds; defaults to
|
None
|
detection
|
DetectionSettings
|
Stage-2 filters and detection threshold to measure through,
applied before KPI computation and recorded on the report. Hand the
same object to :func: |
DEFAULT_DETECTION
|
Returns:
| Type | Description |
|---|---|
QualityReport
|
The computed report. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
fetch_events
Read every threshold crossing in the recording from a detect-only fileset.
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
|
Detect-only fileset to read, detected at |
required |
channels
|
Sequence[int] | None
|
Amplifier |
None
|
detection
|
DetectionSettings
|
Stage-2 filters and detection threshold. Pass the same object
given to :func: |
DEFAULT_DETECTION
|
Returns:
| Type | Description |
|---|---|
EventTrains
|
The crossings, with the geometry needed to order them by depth. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no amplifier channels are selected, or the fileset does not
hold per-site crossings at |
fetch_figure_sources
fetch_figure_sources(
vc,
dataset,
specs,
*,
report,
detection=DEFAULT_DETECTION,
crossings_spikes_id=None,
units_spikes_id=None,
)
Fetch what specs need from the recording, each source at most once.
A source no selected figure asks for is not fetched: each is several requests
and tens of megabytes. Without crossings_spikes_id the events source is
left out and the raw traces carry no crossings; without units_spikes_id
the units source is left out. :func:render skips what is missing.
Waveforms are fetched with the units whenever a selected figure reports amplitude. There is no other source for it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
report
|
QualityReport
|
The measurement the report-backed figures are drawn from.
Computed by the caller, since how it is cached is the caller's
business -- see :func: |
required |
detection
|
DetectionSettings
|
Filters and threshold to read the raw signal and events at. Pass the settings the report was computed with, or the figures describe a differently-detected recording than the report beside them. |
DEFAULT_DETECTION
|
crossings_spikes_id
|
str | None
|
Detect-only fileset for the raw and events levels; see
:mod: |
None
|
units_spikes_id
|
str | None
|
Clustered fileset for the units level. |
None
|
fetch_raw_signal
fetch_raw_signal(
vc,
data,
*,
channels=None,
fractions=EXCERPT_FRACTIONS,
excerpt_sec=EXCERPT_SEC,
detection=DEFAULT_DETECTION,
crossings_spikes_id=None,
with_spectra=True,
)
Read paired wideband/filtered excerpts, crossings, and whole-file Welch spectra.
Configures read-time DSP and the detection threshold first, so the filtered
excerpt is the signal the KPI engine measured. Whole-file Welch spectra are queried via
radiens-core's spectral analysis API for both wideband and stage-2
filtered signals.
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 |
channels
|
Sequence[int] | None
|
Amplifier |
None
|
fractions
|
Sequence[float]
|
Where in the recording to place excerpts. |
EXCERPT_FRACTIONS
|
excerpt_sec
|
float
|
Seconds fetched per excerpt. |
EXCERPT_SEC
|
detection
|
DetectionSettings
|
Stage-2 filters and detection threshold to read through. Pass
the same object given to :func: |
DEFAULT_DETECTION
|
crossings_spikes_id
|
str | None
|
Detect-only fileset to mark crossings from, detected at
|
None
|
with_spectra
|
bool
|
Whether to fetch whole-file Welch spectra via |
True
|
Returns:
| Type | Description |
|---|---|
RawSignal
|
The fetched excerpts, crossings, and whole-file spectra. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the recording is shorter than :data: |
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. |
load_report
Load a report previously written by :func:save_report.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
report_dir
|
Path
|
A report directory as written by :func: |
required |
thresholds
|
QualityThresholds | None
|
Regrade the channel table against these instead of the ones the report was saved with. Classification is pure over the stored metrics, so this costs no server work -- which is why thresholds are not part of the cache key. |
None
|
Returns:
| Type | Description |
|---|---|
QualityReport
|
The reconstructed report. |
plot_channel_profiles
Every site's SNR, event amplitude, noise floor and event rate, one row per site.
Bars carry the integrity tier rather than event detection, because integrity is the axis with a severity ordering. A shared row order is what lets an unremarkable SNR be read as a weak signal or a large noise floor.
plot_event_raster
Raster over per-channel rate traces, on one shared time axis.
Stacked rather than overlaid: the two carry different units, so co-locating them needs a twin y axis that leaves neither labelable, and puts the rate lines over the channels being inspected exactly during the burst being inspected. Sharing x is what makes the comparison work, and both panels order channels by depth and color them alike, so a row in one is findable in the other.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
events
|
EventTrains
|
The fetched crossings. |
required |
span_sec
|
tuple[float, float] | None
|
Time range to draw. |
None
|
columns
|
int | None
|
Time bins across the panel. |
None
|
smooth_sec
|
float | None
|
Kernel the rate traces are estimated with, in seconds. Fixed
rather than derived from the span, for the reason the module docstring
gives. Never narrower than one bin, and |
None
|
Returns:
| Type | Description |
|---|---|
Figure
|
The figure, with the raster above and the rate lines below. |
plot_metric_over_time
One channel x window heatmap, rows in depth order.
metric names one of the report's metrics, and only those with a color
scale defined can be drawn -- :data:~radiens_qc.figures.FIGURES holds one
entry per such metric. smooth_sec pins the Gaussian kernel along time, in
seconds; the default sizes it from the duration drawn (see
:func:~radiens_qc._smooth.time_sigma_sec). A pinned width narrower than the
report's window is widened to it -- the windows are what the metric was
measured over, so nothing finer is there to draw -- and 0 draws the image
window for window. Either way the time axis names the width applied.
Raises:
| Type | Description |
|---|---|
KeyError
|
If no heatmap scale is defined for |
plot_raw_spectra
Per-channel power spectra of the wideband recording, overlaid and as a site map.
Computed over the full recording on the wideband signal via radiens-core's
spectral API: the filtered signal has the notch and bandpass already applied,
so line noise is absent from it by construction and a spectrum of it would
show the filter rather than the recording. The filtered median is drawn
alongside as one line, which is what makes the passband visible.
The left panel overlays every channel, where a line-noise peak and its harmonics stand out. The right panel is the same data as channel x frequency in depth order, where a site unlike its neighbors does.
plot_raw_traces
Wideband and stage-2-filtered traces, side by side, one row per excerpt.
The two columns share their channel axis so a site sits at the same height in both -- seeing what the DSP chain removed is the comparison, and it only reads if the pair lines up. Each column carries its own amplitude scale: wideband and filtered legitimately differ by an order of magnitude, and one shared scale would flatten the filtered column to a line.
Crossing ticks go on the filtered column only, since that is the signal detection ran on.
plot_signal_integrity
Artifact and detector saturation over time, as two stacked channel x window rows.
One figure rather than two because the pair is read together: a burst of peak excursion with no rise in in-event samples is an artifact the detector rode out, while the two rising together is the detector firing on it. A shared x-axis, so a band in one panel lines up with the same instant in the other.
smooth_sec pins the Gaussian kernel along time, in seconds; the default
sizes it from the duration drawn. A pinned width narrower than the report's
window is widened to it, and 0 draws both rows window for window.
plot_site_maps
SNR, noise floor, event rate and event amplitude at each site, on the probe's lattice.
One figure rather than four: the maps share a row axis, so reading a site's four values off the same height is the point of drawing them together. Sized from the site lattice, so a two-column probe yields narrow ribbons and a planar array wide panels, at the same width per site.
plot_stability
Every array-wide metric over time, each against its own opening value.
smooth_sec pins the Gaussian kernel, in seconds; the default sizes it
from the duration drawn (see :func:~radiens_qc._smooth.time_sigma_sec). A
pinned width narrower than the report's window is widened to it, and 0
draws the trend unfiltered.
plot_unit_footprints
Every unit's footprint on the site lattice: where the cell is, and how it fades.
A panel per unit, in depth order, each one the probe's own site lattice cropped around the site that detected the unit. Cell color carries the unit's amplitude at that site and the waveform drawn inside carries its shape, so a panel answers where the cell sits, what it looks like, and how far across the array it was still visible.
The lattice is what makes that readable on any probe. Space is spent per site rather than per micron, so a stagger, a shank gutter and a planar grid all give a waveform the same box to be drawn in, and the fade is read across true adjacency rather than down one column.
Each panel is scaled to its own unit and states its µV per cell, so a weak cell is legible as a shape instead of being drawn as the flat line one shared scale would make of it. Each also carries a locator: the whole probe as one strip, with the crop and the detecting site marked on it, which is what says where on the array the panel is looking.
Every unit gets a panel. The waveforms are the ones attached to units by
:meth:~radiens_qc.units.SortedUnits.with_waveforms; a unit with none among
them is drawn as an empty panel rather than skipped, so the grid stays a
census of the sort.
plot_unit_inventory
How many cells the sort found, and how their rate, amplitude and SNR are spread.
Descriptive rather than a grade: it says what is here, and leaves whether that is enough to the person who knows what they were recording.
Amplitude is measured from the waveforms attached to units; with none
attached that one panel says "not reported" rather than drawing a single bar
at zero.
plot_unit_raster
Unit rasters over per-unit rate traces, on one shared time axis.
The same figure the events level draws, with a unit per row instead of a site. Rows are ordered by unit depth, so a burst confined to one stretch of the probe still reads as a contiguous band.
smooth_sec pins the rate kernel exactly as it does for
:func:~radiens_qc.plot_events.plot_event_raster, so the two stay comparable.
plot_unit_yield
Where on the array cells were found, how clean they are, and how fast they fire.
The only units figure that is array-wide. The others are per-unit -- a footprint panel, a raster row, a histogram bar -- so which stretches of the probe produced cells and which produced none has nowhere else to be read.
Yield is a property of the recording rather than of the sort: a dead stretch of electrode yields no cells however the sorter was parameterized. That is what keeps this figure on the right side of the line this module's docstring draws around sort quality.
Drawn on the channel level's site lattice, and on the same four panels
:func:~radiens_qc.plot_quality.plot_site_maps draws, so a site's yield here and its
SNR on the channel maps are read off the same cell in the same place. Sites
carrying several cells read as a count above one, which is what the sorter's
lack of a position of its own otherwise hides.
Amplitude is measured from the waveforms attached to units; with none
attached that one panel says "not reported" rather than mapping zeros, and
the other three are unaffected.
render
Draw each figure whose source sources holds, in registry order.
A figure whose source is absent is skipped rather than raising, because
drawing what a saved report directory supports is a normal mode. The skip is
not silent by construction: the caller has the same predicate, so
[s for s in specs if not sources.has(s.source)] is what was left out.
options reaches every figure; one with no choice to make ignores it.
Keyed by the spec rather than by name so the level and the caption travel
with the figure; {s.name: f for s, f in rendered.items()} is the
one-liner when only names are wanted.
report_cache_key
Digest identifying the pipeline run a saved report came from.
Adding a field here invalidates every existing key, which is the correct behavior: a key that does not cover something the server acts on is a key that can hand back the wrong report.
resolve_dsp_params
Coerce the mapping form, inject STAGE2, and expand port-less entries.
An entry that names a port is left on that port -- a caller who targeted one port meant it, and silently fanning it out would apply filtering they did not ask for.
save_figures
Write each figure to <out_dir>/<level>/<name>.png and release it.
Cropped to content, since each figure is sized for what it draws rather than laid out on a fixed sheet. Figures are cleared once written: they are built outside pyplot and so are not registered anywhere, but a full run holds every one of them in memory at once otherwise.
save_report
Persist report to <out_dir>/<report.base_name>/.
Data only. Figures are drawn from a report, not stored beside one, so nothing here renders.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
report
|
QualityReport
|
Report to persist. |
required |
out_dir
|
Path
|
Parent directory; one subdirectory per recording is created. |
required |
cache_key
|
str | None
|
Digest of the pipeline run that produced |
None
|
Returns:
| Type | Description |
|---|---|
Path
|
The report's own directory. |