Python API¶
The pure-compute layer of napari-colocalization is independent of napari
and Qt - you can import the metric, masking, and analysis functions from
a script or notebook and use them on plain ndarrays.
The function reference below is generated directly from the source
docstrings. The narrative and examples on this page are written by hand;
the ::: blocks are filled in automatically by mkdocstrings at build
time.
Module layout¶
napari_colocalization
├── _metrics.py pearson, spearman, li_icq, manders, overlap,
│ costes_threshold, costes_regression
├── _masking.py shapes_to_label_mask, labels_to_label_mask, iter_regions
├── _analysis.py analyse_pairwise, analyse_all_to_all, COLUMNS
├── _diagnostics.py costes_randomization, van_steensel_ccf, li_ica
├── _objects.py label_objects, object_table, object_centroids,
│ nearest_neighbour_vectors
├── _sample_data.py make_sample_data, make_sample_data_3d,
│ make_sample_data_cbs006rbm, make_sample_data_coloc
└── _widget.py ColocalizationWidget (Qt-only)
The leading underscore is a convention from the napari plugin template; the symbols below are stable and intended to be imported.
Metrics - napari_colocalization._metrics¶
Pure-numpy colocalization metrics.
No napari / qtpy imports here - every function in this module operates on ndarrays so it can be tested headlessly and reused from scripts. PCC and Manders delegate to scikit-image; SRCC uses scipy.stats; Costes auto-threshold is implemented locally because scikit-image does not provide it.
pearson ¶
Pearson correlation coefficient and two-tailed p-value.
Wraps skimage.measure.pearson_corr_coeff. Returns
(nan, nan) for inputs with fewer than two samples or zero
variance in either channel - both edge cases for which PCC is
mathematically undefined.
| PARAMETER | DESCRIPTION |
|---|---|
a
|
Same-shape intensity arrays of any dimensionality.
TYPE:
|
b
|
Same-shape intensity arrays of any dimensionality.
TYPE:
|
mask
|
Boolean array with the same shape as
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
pcc
|
The Pearson correlation coefficient in
TYPE:
|
p_value
|
Two-tailed p-value for the null hypothesis that the
coefficient is zero.
TYPE:
|
Examples:
spearman ¶
Spearman rank correlation coefficient and p-value.
Uses scipy.stats.spearmanr on the masked, flattened
intensities. Robust to monotonic non-linearity and outliers.
| PARAMETER | DESCRIPTION |
|---|---|
a
|
Same-shape intensity arrays of any dimensionality.
TYPE:
|
b
|
Same-shape intensity arrays of any dimensionality.
TYPE:
|
mask
|
Boolean array with the same shape as
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
rho
|
Spearman's rank correlation coefficient in
TYPE:
|
p_value
|
Two-tailed p-value for the rank correlation, or
TYPE:
|
Examples:
li_icq ¶
Li's Intensity Correlation Quotient (ICQ).
For each pixel i, form the covariance contribution
P_i = (a_i - mean(a)) * (b_i - mean(b)). The ICQ is the
fraction of pixels for which this product is positive,
re-centred to lie on [-0.5, 0.5]:
.. math:: \mathrm{ICQ} = \frac{|{i : P_i > 0}|}{N} - 0.5
Following Li et al. (2004), values close to +0.5 indicate
dependent (co-varying) staining, 0 indicates random
staining, and -0.5 indicates segregated (anti-varying)
staining.
| PARAMETER | DESCRIPTION |
|---|---|
a
|
Same-shape intensity arrays of any dimensionality.
TYPE:
|
b
|
Same-shape intensity arrays of any dimensionality.
TYPE:
|
mask
|
Boolean array with the same shape as
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
icq
|
Value in
TYPE:
|
Notes
Pixels with P_i == 0 (typically because one channel
equals its mean exactly at that pixel) are excluded from the
fraction's numerator and denominator, mirroring the
convention adopted by ImageJ's Coloc 2 plugin.
References
Li, Q. et al. (2004). A Syntaxin 1, Galpha(o), and N-type Calcium Channel Complex at a Presynaptic Nerve Terminal: Analysis by Quantitative Immunocolocalization. J. Neurosci. 24(16), 4070-4081.
Examples:
manders ¶
Manders' colocalization coefficients M1 and M2.
M1 is the fraction of the channel-A intensity that lies in
pixels where channel B is above threshold_b. M2 is the
symmetric counterpart for channel B above threshold_a.
Asymmetry between the two is meaningful - it reflects the
difference in how much of each channel co-occurs with the
other.
Wraps skimage.measure.manders_coloc_coeff, which
expects a binary mask for the second image; we threshold
internally and then call it twice.
| PARAMETER | DESCRIPTION |
|---|---|
a
|
Same-shape, non-negative intensity arrays.
TYPE:
|
b
|
Same-shape, non-negative intensity arrays.
TYPE:
|
threshold_a
|
Per-channel thresholds. Use
TYPE:
|
threshold_b
|
Per-channel thresholds. Use
TYPE:
|
mask
|
Boolean array selecting the analysed region.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
m1, m2 : float
|
Each in |
Examples:
overlap ¶
Manders' overlap coefficient r and split coefficients k1, k2.
These threshold-free measures (Manders et al. 1992) quantify
co-occurrence from the raw intensity products, complementing
the threshold-dependent M1/M2 from manders:
.. math:: r = \frac{\sum_i a_i b_i} {\sqrt{\sum_i a_i^2 \; \sum_i b_i^2}}, \quad k_1 = \frac{\sum_i a_i b_i}{\sum_i a_i^2}, \quad k_2 = \frac{\sum_i a_i b_i}{\sum_i b_i^2}
r lies in [0, 1] for non-negative intensities and is
insensitive to a difference in mean brightness between the two
channels. k1 and k2 split that co-occurrence per
channel and are sensitive to such differences - their
asymmetry is informative.
r is delegated to
skimage.measure.manders_overlap_coeff. The split
coefficients k1/k2 have no scikit-image equivalent
(skimage.measure.manders_coloc_coeff computes the
threshold-gated M1/M2 used by manders, a different
quantity), so they are derived from the same intensity sums
here.
| PARAMETER | DESCRIPTION |
|---|---|
a
|
Same-shape, non-negative intensity arrays.
TYPE:
|
b
|
Same-shape, non-negative intensity arrays.
TYPE:
|
mask
|
Boolean array selecting the analysed region.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
r, k1, k2 : float
|
The overlap coefficient and the two split coefficients.
Any coefficient whose denominator is zero (an all-zero
channel within the region) is returned as |
References
Manders, E.M.M. et al. (1992). Dynamics of three-dimensional replication patterns during the S-phase, analysed by double labelling of DNA and confocal microscopy. J. Cell Sci. 103, 857-862.
Examples:
costes_threshold ¶
Costes' iterative auto-threshold for Manders' M1 / M2.
Follows Fiji Coloc 2 (AutoThresholdRegression):
- Fit the
costes_regressionorthogonal lineb = m*a + c. - Step a candidate threshold by bisection. The threshold
pair always lies on the line; the channel that is stepped
is the one giving finer resolution - channel A when
|m| < 1(thenT_b = m*T_a + c) else channel B (thenT_a = (T_b - c)/m). - At each candidate, compute the Pearson correlation of the
below-threshold pixels (
a < T_aorb < T_b). Bisect downward while that correlation is positive and upward when it is non-positive (or undefined), converging on the threshold where the background pixels stop correlating.
| PARAMETER | DESCRIPTION |
|---|---|
a
|
Same-shape intensity arrays.
TYPE:
|
b
|
Same-shape intensity arrays.
TYPE:
|
mask
|
Restrict the regression and search to this region.
TYPE:
|
max_iter
|
Maximum bisection iterations (Coloc 2 default); the search also stops once the step falls below one intensity unit.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
threshold_a, threshold_b : float
|
Per-channel thresholds for |
References
Costes, S.V. et al. (2004). Automatic and quantitative measurement of protein-protein colocalization in live cells. Biophys. J. 86(6), 3993-4003.
costes_regression ¶
Orthogonal-regression line b = slope * a + intercept.
This is the line costes_threshold walks along; it is
exposed separately so callers (e.g. the cytofluorogram) can
draw the same line. To match Fiji's Coloc 2 we use
orthogonal (total-least-squares) regression rather than an
ordinary least-squares fit - the relationship is symmetric
(neither channel is the independent variable), and OLS would
bias the slope when the predictor channel is noisy. The slope
is the principal axis of the intensity covariance:
.. math:: m = \frac{\sigma_b^2 - \sigma_a^2 + \sqrt{(\sigma_b^2 - \sigma_a^2)^2 + 4\sigma_{ab}^2}} {2\sigma_{ab}}, \quad c = \bar b - m\,\bar a
| PARAMETER | DESCRIPTION |
|---|---|
a
|
Same-shape intensity arrays.
TYPE:
|
b
|
Same-shape intensity arrays.
TYPE:
|
mask
|
Restrict the regression to this region.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
slope, intercept : float
|
Regression coefficients, or |
References
Costes, S.V. et al. (2004). Automatic and quantitative
measurement of protein-protein colocalization in live cells.
Biophys. J. 86(6), 3993-4003. Implementation matched to Fiji
Coloc 2 AutoThresholdRegression.
Masking - napari_colocalization._masking¶
Region-of-interest helpers.
These functions convert a napari Shapes or Labels layer into an integer label mask (0 = background, 1..N = regions) and iterate over the non-zero regions. The helpers duck-type the layer interface - they do not import napari - so they can be tested with simple stand-in objects.
shapes_to_label_mask ¶
Rasterise a napari Shapes layer to an integer label mask.
Uses Shapes.to_labels(labels_shape=image_shape). The
resulting mask has shape image_shape, with 0 outside any
shape and 1..N inside each shape (where shape i of
the layer maps to label i + 1).
| PARAMETER | DESCRIPTION |
|---|---|
shapes_layer
|
Any object that exposes
TYPE:
|
image_shape
|
The desired output shape, typically the spatial shape of the image being analysed.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
mask
|
Integer label image of shape
TYPE:
|
labels_to_label_mask ¶
Validate and return integer data from a napari Labels layer.
| PARAMETER | DESCRIPTION |
|---|---|
labels_layer
|
Any object that exposes a
TYPE:
|
image_shape
|
The expected shape;
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
mask
|
The label data, dtype-cast to
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If the layer's data shape does not match |
iter_regions ¶
Yield (label_id, bool_mask) for each non-zero region.
| PARAMETER | DESCRIPTION |
|---|---|
label_mask
|
Integer label image.
TYPE:
|
| YIELDS | DESCRIPTION |
|---|---|
label_id
|
The integer label value (1, 2, ...). When
TYPE::
|
bool_mask
|
Boolean mask of the same shape as
TYPE::
|
Examples:
Analysis - napari_colocalization._analysis¶
COLUMNS is the canonical column order shared by the table, the CSV
export, and the row dicts:
('region', 'slice', 'channel_a', 'channel_b', 'n_pixels',
'pcc', 'pcc_pvalue', 'srcc', 'srcc_pvalue',
'icq',
'overlap', 'k1', 'k2',
'm1', 'm2', 'threshold_a', 'threshold_b')
(slice is the plane index for per-Z-slice runs, and NaN otherwise.)
High-level orchestrators that produce a result row per region.
These accept ndarrays plus a label mask, walk every non-zero region, compute the requested metrics, and return a list of dicts suitable for direct insertion into a table or a CSV.
Failure policy: conditions that make the whole request invalid
(shape mismatch, unknown options, missing manual thresholds) raise
ValueError so the caller can surface the reason. Per-region
degeneracies - a single ROI too small or with a constant/empty
channel - are not errors in a multi-region run; the affected
metrics stay NaN (a visible blank cell), and a human-readable
reason is appended to the optional region_warnings collector so
the caller can summarise how many regions were skipped and why.
analyse_pairwise ¶
analyse_pairwise(a, b, *, label_mask=None, metrics=ALL_METRICS, threshold_method='costes', threshold_a=None, threshold_b=None, channel_a='A', channel_b='B', slice_axis=None, region_warnings=None)
Compute selected metrics for each region of two grayscale arrays.
Walks every non-zero region of label_mask (or analyses the
whole image when label_mask is None) and computes the
requested metrics within each region. Missing metrics are
written as NaN so the output schema is constant.
| PARAMETER | DESCRIPTION |
|---|---|
a
|
Same-shape intensity arrays (2D or 3D).
TYPE:
|
b
|
Same-shape intensity arrays (2D or 3D).
TYPE:
|
label_mask
|
Integer label image (0 = background, 1..N = regions).
TYPE:
|
metrics
|
Which metrics to compute. Defaults to all.
TYPE:
|
threshold_method
|
Only used when
TYPE:
|
threshold_a
|
Required when
TYPE:
|
threshold_b
|
Required when
TYPE:
|
channel_a
|
Display names for the two channels - written into the result rows so they round-trip into the table and CSV.
TYPE:
|
channel_b
|
Display names for the two channels - written into the result rows so they round-trip into the table and CSV.
TYPE:
|
slice_axis
|
If given, analyse each plane along this axis separately
(JACoP B's "consider Z slices separately") rather than the
whole volume: every region is reported once per slice, with
the plane index in the
TYPE:
|
region_warnings
|
If provided, a human-readable string is appended for each
region where a requested metric could not be computed
(too few pixels, or a constant/empty channel). The metric
cell itself stays
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
rows
|
One row per region. Each row has the keys listed in
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If |
Examples:
analyse_all_to_all ¶
analyse_all_to_all(image, channel_axis, *, label_mask=None, metrics=ALL_METRICS, threshold_method='costes', threshold_a=None, threshold_b=None, channel_names=None, region_warnings=None)
Compute metrics for every channel pair (i, j), i < j.
Iterates over each unordered pair of channels along
channel_axis and dispatches to analyse_pairwise.
For N channels this produces N*(N-1)/2 × R rows,
where R is the number of non-zero regions in label_mask
(or 1 for the whole image).
| PARAMETER | DESCRIPTION |
|---|---|
image
|
N-dimensional array with one channel axis. The remaining axes are spatial (the plugin supports up to 3 spatial axes, i.e. 4D total).
TYPE:
|
channel_axis
|
Axis index along which channels are enumerated.
TYPE:
|
label_mask
|
Integer label image whose shape matches
TYPE:
|
metrics
|
Forwarded to
TYPE:
|
threshold_method
|
Forwarded to
TYPE:
|
threshold_a
|
Forwarded to
TYPE:
|
threshold_b
|
Forwarded to
TYPE:
|
channel_names
|
One name per channel along
TYPE:
|
region_warnings
|
Forwarded to
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
rows
|
Concatenation of the per-pair results from
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If |
Diagnostics - napari_colocalization._diagnostics¶
Curve/distribution producers behind the Diagnostics tab. Unlike the
metrics, a degenerate whole input raises ValueError rather than
returning NaN.
Pure-compute colocalization diagnostics.
Unlike _metrics, whose functions return a scalar per region,
these produce a curve or a distribution - the payloads behind the
widget's Diagnostics tab. As in _metrics there are no
napari/qtpy imports here, so every function operates on ndarrays and
can be tested headlessly. The scalar summaries (peak shift, ICQ,
p-value) are returned alongside the arrays so the widget can drop them
into a label while the arrays go to the plot.
Failure policy matches the rest of the package: a degenerate whole
input (shape mismatch, too few pixels, an out-of-range parameter)
raises ValueError for the widget to surface as a napari warning,
rather than returning a silently meaningless result.
costes_randomization ¶
Costes' randomization significance test for Pearson's PCC.
Scrambles channel b in blocks n_iter times - destroying
spatial co-occurrence while preserving each channel's intensity
histogram and local texture - and recomputes the PCC each time to
build a null distribution. The observed PCC is then placed against
that null (Costes et al. 2004). A high observed PCC that sits far
above the null (small p-value) is evidence of genuine
colocalisation rather than chance overlap.
Works for 2D or 3D images; the arrays are cropped to a whole number of blocks in each dimension before scrambling.
| PARAMETER | DESCRIPTION |
|---|---|
a
|
Same-shape 2D or 3D intensity arrays.
TYPE:
|
b
|
Same-shape 2D or 3D intensity arrays.
TYPE:
|
mask
|
Region of interest; cropped alongside
TYPE:
|
n_iter
|
Number of scrambles forming the null distribution.
TYPE:
|
block_size
|
Side length (px) of the scrambled blocks. Should approximate the point-spread-function width of the acquisition.
TYPE:
|
seed
|
Seed for the random generator, for reproducibility.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict
|
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
On shape mismatch, |
van_steensel_ccf ¶
Van Steensel's cross-correlation function (CCF).
Shifts b relative to a by every integer offset in
[-max_shift, +max_shift] along axis and computes Pearson's
coefficient at each shift (Van Steensel et al. 1996). Genuinely
colocalised channels give a CCF that peaks at shift 0; mutually
excluded channels give a trough at 0 with side peaks.
| PARAMETER | DESCRIPTION |
|---|---|
a
|
Same-shape intensity arrays.
TYPE:
|
b
|
Same-shape intensity arrays.
TYPE:
|
mask
|
Region of interest passed through to
TYPE:
|
max_shift
|
Largest pixel shift to evaluate in each direction.
TYPE:
|
axis
|
Axis along which
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
shifts
|
Integer offsets
TYPE:
|
ccf
|
Pearson coefficient at each shift;
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If |
li_ica ¶
Li's Intensity Correlation Analysis (ICA) payload.
Returns the per-pixel covariance products
P_i = (a_i - mean a)(b_i - mean b) together with the paired
intensities, so the widget can draw the two ICA scatter panels
(intensity vs P) for channels A and B. The scalar ICQ - the
fraction of positive P re-centred to [-0.5, 0.5] - is
included for the summary line.
| PARAMETER | DESCRIPTION |
|---|---|
a
|
Same-shape intensity arrays.
TYPE:
|
b
|
Same-shape intensity arrays.
TYPE:
|
mask
|
Region of interest.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict
|
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If |
Object-based - napari_colocalization._objects¶
Object-level colocalization: from two labelled images, report
centre-particle coincidence and object overlap per object, plus
centroids and nearest-neighbour links for viewer overlays. Objects can
be supplied directly or obtained with label_objects (threshold +
connected components).
Pure-compute object-based colocalization.
Where _metrics works on pixel intensities, this works on
segmented objects: two labelled images (objects in channel A,
objects in channel B) are compared by
- centre-particle coincidence - does an object's centroid fall inside an object of the other channel?
- object overlap - do an object's pixels touch any object of the other channel?
It also exposes object centroids and nearest-neighbour links so the
widget can draw Points / Vectors overlays. As elsewhere there are no
napari/qtpy imports here, so everything operates on ndarrays and is
testable headlessly. Objects can be supplied directly (a Labels
layer) or obtained with label_objects (threshold + connected
components).
label_objects ¶
Threshold an intensity image and label its connected components.
| PARAMETER | DESCRIPTION |
|---|---|
image
|
Intensity image (2D or 3D).
TYPE:
|
threshold_method
|
Auto-threshold name from the
TYPE:
|
mask
|
Restrict object detection to this region.
TYPE:
|
min_size
|
Drop connected components smaller than this many pixels.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
numpy.ndarray of int
|
Integer label image (0 = background, 1..N = objects). All zeros when the channel has no defined threshold (constant). |
object_table ¶
Object-based colocalization between two labelled images.
Reports, for every object in each channel, whether its centroid is coincident with an object of the other channel and whether it overlaps one.
| PARAMETER | DESCRIPTION |
|---|---|
labels_a
|
Same-shape integer label images (0 = background).
TYPE:
|
labels_b
|
Same-shape integer label images (0 = background).
TYPE:
|
name_a
|
Channel display names written into the
TYPE:
|
name_b
|
Channel display names written into the
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
rows
|
One row per object, with the keys in
TYPE:
|
summary
|
Object counts and coincident/overlap counts and fractions per channel.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If the two label images differ in shape. |
nearest_neighbour_vectors ¶
Vectors from each A centroid to its nearest B centroid.
Returned as napari Vectors data (N, 2, ndim) - [start,
direction] pairs. Empty when either set has no objects.
Sample data - napari_colocalization._sample_data¶
make_sample_data_cbs006rbm downloads the CBS006RBM benchmark image
from the Colocalization Benchmark Source
on first use and caches it under ~/.cache/napari-colocalization/.
Synthetic two-channel sample data for colocalization.
Synthetic samples (2D, 3D): gaussian blobs with channel B copying 60 % of channel A's blobs plus independent blobs and noise, giving PCC ~ 0.7 and Manders M1/M2 ~ 0.6.
CBS006RBM: red and blue channels with ~50 % colocalization, from the Colocalization Benchmark Source. The TIFF is downloaded once and cached in ~/.cache/napari-colocalization/.
colocsample1bRGB: a confocal Z-stack (33 x 152 x 172) with red and green dyes that strongly colocalise. Downloaded once from the Fiji sample server and cached under ~/.cache/napari-colocalization/; this is the image used by the ROI colocalization tutorial.
make_sample_data_3d ¶
3D sample: 32x128x128 (Z, Y, X) volumes of gaussian blobs.
make_sample_data_cbs006rbm ¶
2D sample from the Colocalization Benchmark Source (CBS006RBM).
Red and blue channels with ~50 % colocalization. Downloaded once and cached under ~/.cache/napari-colocalization/.
Source: https://colocalization-benchmark.com/
make_sample_data_coloc ¶
2D-stack sample: red and green confocal dyes that colocalise.
The colocsample1bRGB_BG.tif confocal Z-stack (33 x 152 x 172),
downloaded once from the Fiji sample server and cached locally, split
into its red and green channels. The two dyes strongly colocalise
(whole-stack PCC ~ 0.75).
Putting it together: scripted analysis¶
import numpy as np
import pandas as pd
from napari_colocalization._analysis import analyse_pairwise, COLUMNS
a = np.load('channel_a.npy')
b = np.load('channel_b.npy')
mask = np.load('cell_labels.npy') # 0 = bg, 1..N = cells
rows = analyse_pairwise(
a, b,
label_mask=mask,
metrics=('pcc', 'srcc', 'mcc'),
threshold_method='costes',
channel_a='dna', channel_b='tubulin',
)
df = pd.DataFrame(rows, columns=COLUMNS)
df.to_csv('colocalization_per_cell.csv', index=False)
print(df.describe())
Stability¶
- The function signatures, return shapes and
COLUMNStuple above are intended to be stable across point releases. - Internal helpers prefixed with
_(private functions inside each module) may change without notice. ColocalizationWidget(_widget.py) is the GUI surface and not part of the scripting API; for scripts, driveanalyse_*directly.