Reference#
Testing#
- spicyr.spicy(cells, condition=None, subject=None, covariates=None, image_id='imageID', cell_type='cellType', spatial_coords=('x', 'y'), r=None, from_=None, to=None, method='cell', effect='allocation', k=None, combine='maxT', adjust_abundance=False, variance='cr2', ref=None, cores=1, survival=None, table_key='table', image_info=None, **kwargs)#
Test whether the co-localisation of cell types differs between conditions, or is associated with survival.
Every ordered pair of cell types
from_ -> tois tested: aretocells placed nearfromcells more than other cells are?In each image, the share of
tocells with at least onefromcell withinris compared with its exact expectation q if thetocells were a random choice among the cells that are notfromcells (random labelling of the observed cells). The effect (effect="allocation", the default) is the fraction oftocells placed next to (or kept away from)fromcells. For a pair that attracts (moretocells next tofromcells than q over all images together) it is (observed share - q) / (1 - q): if a fraction f of thetocells were moved next tofromcells, the effect is f. For a pair that avoids it is (observed share - q) / q: if a fraction f of thetocells that would have afromcell nearby were moved away, the effect is -f. Either way it does not depend on how manyfromcells there are or how densely they are packed. The side is chosen once per pair from all images, without the conditions, and is reported in thesidecolumn.effect="count"gives the number of extrafromcells withinrof eachtocell instead; it also reflects how manyfromcells surround atocell (depth of infiltration), but it grows with how densely thefromcells are packed. Images are combined within patients (subject) and patients within conditions by a frailty GEE with a second random effect for the images of a patient (each image is weighted by 1 / (its sampling variance + the between-image variance), so one large image cannot outweigh the patient’s other images), and the difference is tested with a CR2 variance on Satterthwaite degrees of freedom, with patients as the units. The difference is adjusted for anycovariatesand, withadjust_abundance=True, for the log share of thefromtype in each image; the unadjusted test is then reported alongside (unadjusted_*columns). When nearly every cell has afromcell withinr(q close to 1), there is little room for attraction and an attracting pair’s images carry little information; a smallerris more informative.fromis spelledfrom_becausefromis a Python keyword (**{"from": ...}also works).- Parameters:
cells – A pandas DataFrame (one row per cell), an AnnData object (cells as observations; coordinates in
obsm["spatial"]or obs columns), a SpatialData object (its annotation tabletable_key), or the path of a SpatialData store (.zarr) or of an AnnData zarr store. A store is read lazily: the image and cell-type columns are loaded once as integer codes, the coordinates (obsm["spatial"], or the obs columnsspatial_coords) a batch of whole images at a time, and the condition, subject and covariates once per image, so the data never need to fit in memory. Reading is fastest when the rows are grouped by image (as spatialdata writes a table sorted by region); categorical image and cell-type columns keep the codes small.condition – Column of the image-level condition (two or more groups).
subject – Column of the patient of each image. Images of one patient are combined; by default each image is a patient.
covariates – Image- or patient-level columns to adjust for. The effect of each is reported as
<column>_effectand<column>_p_value(one column per level after the first for a categorical covariate).r – Radius, or several radii combined by
combine(“maxT”, up to 6 radii; “davies”, Davies’ bound for the same maximum, for many radii; or “cauchy”). Default 50. The max-T p-value is the multivariate normal probability of the largest absolute z, computed by the quasi-Monte Carlo method of Genz and Bretz with an absolute error of about 1e-4 (by quadrature for two radii); the same inputs always give the same value.from_ – Cell types to test (all ordered pairs by default).
to – Cell types to test (all ordered pairs by default).
method – “cell” (spicyR Cell). The image-level method of spicyR is not yet available in Python.
effect – “allocation” (default): the fraction of
tocells moved next to (or away from)fromcells withinr; “count”: the number of extrafromcells withinrof eachtocell. Withk, “withinr” means among the cell’sknearest neighbours.k – Use the
knearest neighbours instead of a radius.adjust_abundance – Adjust the test for the log share of the
fromtype in each image (defaultFalse). Its effect is reported asabundance_effect. It does not separate morefromcells from more densely packed ones, and it removes real effects when the share tracks the condition.variance – “cr2” (default: CR2 on Satterthwaite df) or “hartung_knapp” (the model-based variance, scaled by the Pearson statistic when that exceeds its df and never below CR2, on m - 2 df). The variance used is in
.varianceof the result.survival – A survival outcome:
(time_column, event_column), one value per patient (the R package’sSurv(time, event)). Leaveconditionempty. (Older form:condition=time_column, survival=event_column.)image_id – Columns of the image, the cell type and the coordinates. For SpatialData, images are the table’s regions (its region_key column) unless
image_idnames another column.cell_type – Columns of the image, the cell type and the coordinates. For SpatialData, images are the table’s regions (its region_key column) unless
image_idnames another column.spatial_coords – Columns of the image, the cell type and the coordinates. For SpatialData, images are the table’s regions (its region_key column) unless
image_idnames another column.cores – Threads. Batches of whole images are read and summarised in parallel; results do not depend on it.
table_key – The annotation table of a SpatialData object or store.
image_info – A table with one row per image, for
condition,subject, covariates or the survival columns that are not columns of the cell table: a DataFrame, an AnnData object (its obs), or the key of a table of the SpatialData object or store. Itsimage_idcolumn, or else its index, gives the image IDs. Every image of the cells needs a row, and every row an image.
- Return type:
Writing a store#
- spicyr.write_cell_store(cells, path, image_id='imageID', spatial_coords=('x', 'y'), table_key='table', image_info=None, info_key='images', chunk_rows=1048576)#
Write cells as the cell table of a SpatialData Zarr store.
The store holds the cells as an AnnData table under
tables/(Zarr v3), whichspicy()reads a block of rows at a time andspatialdata.read_zarr()reads as a SpatialData object. The coordinates become theobsmarray"spatial"and the other columns the table’sobs(categorical columns stay categorical). The image column is the table’s region key: a categorical column whose categories are the images in order of first appearance, unless it is categorical already. A column"instance_id"numbers the cells from 0 (unsigned integers of 16 bits at least). A table with one row per image can be added as a second table. Every array of the length of the table is written in chunks ofchunk_rowsrows compressed with zstd, one chunk at a time, so writing needs little memory beyond that ofcells, however many cells it has.- Parameters:
cells – A pandas DataFrame with one row per cell, or an AnnData object (cells as observations; its
obsis written, with the coordinates from the obs columnsspatial_coordsor else fromobsm["spatial"]). Columns are categorical, strings, integers, floats or booleans (pandas’ nullable types included).path – The directory of the store (replaced if it exists).
image_id – The column of the image.
spatial_coords – The two columns of the coordinates. They are written as float64 (float32 coordinates stay float32).
table_key – The name of the cell table.
image_info – Optional: a DataFrame (or an AnnData object, its
obs) with one row per image, written as the tableinfo_key. Itsimage_idcolumn, or else its index, gives the image IDs.info_key – The name of the per-image table.
chunk_rows – Rows per chunk of every array of the length of a table.
- Return type:
The path of the store.
Examples
>>> import numpy as np, pandas as pd >>> rng = np.random.default_rng(1) >>> cells = pd.DataFrame({"imageID": pd.Categorical(np.repeat(["a", "b"], 50)), ... "cellType": pd.Categorical(np.tile(["T", "B"], 50)), ... "x": rng.uniform(0, 100, 100), "y": rng.uniform(0, 100, 100)}) >>> path = write_cell_store(cells, "cells.zarr")
Results#
- class spicyr.SpicyResults(cell_results, levels, survival, radius_results=None, image_ids=<factory>, condition=None, subject=None, pairwise_assoc=<factory>, image_weights=<factory>, r=None, k=None, method='cell', effect='allocation', variance=None)#
Results of
spicyr.spicy().cell_resultsis the full table, one row per pair (and per level when there are more than two conditions): for the allocation effect the pair’sside(“attract” or “avoid”, which sets its scale), the effect (effect: “allocation”, the fraction oftocells moved next to or away fromfromcells withinr, or “count”, the extrafromcells pertocell) in the reference condition (excess_ref) and the comparison condition, the difference, its standard error, Satterthwaite df, p-value and BH-adjusted p-value, the frailty variancetau2, what the test was adjusted for (adjusted_for), the effect and p-value of each adjustment (abundance_effect,<covariate>_effect, …) and the unadjusted test (unadjusted_*).image_weightsgives, for every pair, each image’s share of its condition’s information. For survival: the score test (score_coefficient,p_value) and the hazard ratio per SD of the shrunken excess.- bind(pair=None)#
Per-image excess of every pair (or one
"from__to"pair) with the image’s condition and subject.- Return type:
DataFrame
- box_plot(from_, to, ax=None, interactive=False)#
Per-image excess of one pair by condition, with a point per image behind each box.
The Python version of spicyR’s
spicyBoxPlot().Each point is sized by how much the image contributes to the test (its weight in the frailty model, relative to the average image of its condition). With
interactive=Truethe result is a plotly figure: hover over a point to see its image, patient, excess and weight, which helps to find images worth looking at withspicyr.plot_image(). Images in which the pair was not tested are not shown.
- signif_plot(fdr=False, breaks=None, comparison_group=None, colours=('#4575B4', 'white', '#D73027'), marks_to_plot=None, cutoff=0.05, ax=None)#
Bubble plot of every pair, as spicyR’s
signifPlot().Each pair is a disc at (to, from). Its left half is coloured by the excess in the reference condition and its right half by the excess in the comparison condition; the radius grows with -log10 p (the BH-adjusted p with
fdr=True), and a black ring marks p (or, withfdr=True, the BH-adjusted p) belowcutoff.breaksis(low, high, step)for the colour scale. For survival results each disc is one colour: the log hazard ratio per SD.
- top_pairs(n=10, coef=None, adj='fdr', cutoff=None, figures=None)#
The most significant pairs, as spicyR’s
topPairs().- Return type:
DataFrame
The attributes of a results object:
Attribute |
Contents |
|---|---|
|
one row per pair (and per group with more than two groups): |
|
with several radii, one row per pair and radius |
|
the effect of every pair in every image (what |
|
the weight of every image in the test of every pair: its share of its group’s information (the point sizes of |
|
the groups, images and settings of the analysis ( |
Proportions#
- spicyr.get_prop(cells, feature='cellType', image_id='imageID')#
The proportion of each level of
featurein each image, as spicyR’sgetProp().- Parameters:
cells – A pandas DataFrame or an AnnData object with one row per cell.
feature – The column whose proportions are computed, e.g. cell types or regions.
image_id – The column of the units: images, or patients to pool the images of each patient.
- Return type:
DataFrame
- spicyr.col_test(df, condition, type=None, feature=None, image_id='imageID')#
Test each column of a table, such as proportions per image, as spicyR’s
colTest().Each column is tested for a difference between two groups (Wilcoxon or Welch t-test) or for an association with survival (Cox model).
- Parameters:
df – A DataFrame with one row per image (or patient) and one column per feature, such as the output of
get_prop(). Withfeaturegiven,dfis instead a table of cells (a DataFrame or an AnnData object), and the proportions offeaturein eachimage_idare computed first.condition – The group of each row of
df(a sequence or Series in its row order), or two columns(time, event)for survival. Withfeature, the name of the cells’ group column.type –
"wilcox","ttest"or"survival"; by default"ttest"for one condition and"survival"for two columns.feature – The column of the cells whose proportions are tested, e.g. cell types or regions.
image_id – With
feature: the units, images or patients (to pool the images of each patient).
- Return type:
DataFrame- Returns:
A DataFrame with one row per column of ``df``, ordered by p-value (the group means (t-test), the test)
statistic (
tval.W,tval.t) or the Cox coefficient and its standard error (survival), the p-value(
pval), the Benjamini-Hochberg adjusted p-value (adjPval) and the column name (cluster), allrounded to two significant digits as in R.
Plotting an image#
- spicyr.plot_image(cells, image, from_, to, r=None, image_id='imageID', cell_type='cellType', spatial_coords=('x', 'y'), table_key='table', ax=None, **kwargs)#
Plot one image, showing the
from_andtocells of a pair.The density of all cells is shown in blue, with the
from_cells (gold) andtocells (dark red) on top. Withr, a circle of radiusris drawn around eachtocell: thefrom_cells inside the circles are those thatspicyr.spicy()counts.- Parameters:
cells – A pandas DataFrame, AnnData or SpatialData object, as for
spicyr.spicy().image – The image to plot (a value of the
image_idcolumn).from_ – The two cell types (
fromalso works as a keyword).to – The two cell types (
fromalso works as a keyword).r – Optional radius of the circles around the
tocells, in the units of the coordinates.
- Return type:
The matplotlib axes.
Data#
- spicyr.datasets.metabric_ali2020(path=None, as_anndata=False)#
Imaging mass cytometry of 483 breast tumours from the METABRIC cohort (Ali et al., Nature Cancer 2020).
One row per cell (433,001 cells): the core (
file_id), the patient (metabricId), the cell type assigned by the authors (description), the coordinates in micrometres (x,y) and the patient’s clinical data, including ER status (ER.Status) and relapse-free survival (timeRFS,eventRFS).The file (130 MB) is downloaded once from Bioconductor’s ExperimentHub, where the R package SpatialDatasets gets it (
spe_Ali_2020), and cached in~/.cache/spicyr(or$SPICYR_CACHE). Reading it needs therds2pypackage (pip install "spicyr[data]").With
as_anndata=Truethe cells are returned as an AnnData object: the table asobsand the coordinates inobsm["spatial"](needsanndata).
- spicyr.datasets.schurch2020(path=None, as_anndata=False)#
CODEX imaging of colorectal cancer (Schürch et al., Cell 2020): 35 patients, four tissue cores each.
One row per cell (258,385 cells) with the core (
imageID), the patient (patient), the cell type (cellType), the coordinates (x,y) and the patient group (group: 1 = Crohn’s-like reaction, 2 = diffuse inflammatory infiltration). Downloaded from ExperimentHub asspe_Schurch_2020of the R package SpatialDatasets (82 MB), and cached as formetabric_ali2020().as_anndataas formetabric_ali2020().
- spicyr.datasets.example_cells()#
A small simulated data set: 14 patients (7 per condition, A and B), two images each, six cell types.
In condition B, about a third of the T cells were moved next to tumour cells. Both directions change;
tumour -> T(are T cells placed near tumour cells? tumour cells counted around each T cell, the recruited type at the centre) is the direction whose excess does not depend on how common tumour cells are.- Return type:
DataFrame
- spicyr.format_data(cells, image_id='imageID', cell_type='cellType', spatial_coords=('x', 'y'), table_key='table')#
One row per cell with columns imageID, cellType, x, y, and every other column kept.
Rows are ordered by image in order of first appearance, as spicyR’s
.format_data().