spatialproteomics 0.8.5__tar.gz → 0.8.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {spatialproteomics-0.8.5/spatialproteomics.egg-info → spatialproteomics-0.8.6}/PKG-INFO +5 -2
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/README.md +1 -1
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/pyproject.toml +3 -1
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/la/label.py +3 -1
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/tl/__init__.py +2 -1
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/tl/tool.py +169 -2
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/tl/utils.py +38 -1
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6/spatialproteomics.egg-info}/PKG-INFO +5 -2
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics.egg-info/requires.txt +4 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/LICENSE +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/setup.cfg +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/__init__.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/base_logger.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/constants.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/container.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/image_container/ImageContainer.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/image_container/__init__.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/la/__init__.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/la/utils.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/nh/__init__.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/nh/neighborhood.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/nh/utils.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/pl/__init__.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/pl/plot.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/pl/utils.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/pp/__init__.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/pp/intensity.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/pp/preprocessing.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/pp/utils.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/sd/__init__.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/sd/utils.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics.egg-info/SOURCES.txt +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics.egg-info/dependency_links.txt +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics.egg-info/top_level.txt +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/tests/test_container.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/tests/test_integration.py +0 -0
- {spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/tests/test_to_zarr.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spatialproteomics
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.6
|
|
4
4
|
Summary: Spatialproteomics is an interoperable toolbox for analyzing highly multiplexed fluorescence image data
|
|
5
5
|
Author: Matthias Meyer-Bender, Harald Vohringer
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -33,6 +33,8 @@ Provides-Extra: anndata
|
|
|
33
33
|
Requires-Dist: anndata; extra == "anndata"
|
|
34
34
|
Provides-Extra: astir
|
|
35
35
|
Requires-Dist: astir>=0.1.5; extra == "astir"
|
|
36
|
+
Provides-Extra: spotiflow
|
|
37
|
+
Requires-Dist: spotiflow; extra == "spotiflow"
|
|
36
38
|
Provides-Extra: dev
|
|
37
39
|
Requires-Dist: pytest>=7.1.2; extra == "dev"
|
|
38
40
|
Requires-Dist: pytest-cov>=3.0.0; extra == "dev"
|
|
@@ -41,6 +43,7 @@ Requires-Dist: isort>=5.10.1; extra == "dev"
|
|
|
41
43
|
Requires-Dist: flake8>=5.0.4; extra == "dev"
|
|
42
44
|
Requires-Dist: bandit>=1.7.4; extra == "dev"
|
|
43
45
|
Requires-Dist: safety>=2.1.1; extra == "dev"
|
|
46
|
+
Requires-Dist: typing_extensions>=4.16; extra == "dev"
|
|
44
47
|
Provides-Extra: all
|
|
45
48
|
Requires-Dist: spatialdata; extra == "all"
|
|
46
49
|
Requires-Dist: cellpose; extra == "all"
|
|
@@ -60,7 +63,7 @@ Dynamic: license-file
|
|
|
60
63
|
|
|
61
64
|
## Principles
|
|
62
65
|
|
|
63
|
-
Multiplexed imaging data comprises at least 3 dimensions (i.e. `channels`, `x`, and `y`) and
|
|
66
|
+
Multiplexed imaging data comprises at least 3 dimensions (i.e. `channels`, `x`, and `y`) and often contains additional data such as segmentation masks or cell type annotations associated with it. In `spatialproteomics`, we use `xarray` to create a data structure that keeps all of these data dimension in sync. This data structure can then be used to apply all sorts of operations to the data. Users can segment cells, perform different image processing steps, quantify protein expression, predict cell types, and plot their data in various ways. By providing researchers with those tools, `spatialproteomics` can be used to quickly explore highly multiplexed spatial proteomics data directly within jupyter notebooks.
|
|
64
67
|
|
|
65
68
|
<p align="center" width="100%">
|
|
66
69
|
<img src="docs/_static/img/supplementary_figure_1.png" alt="The spatialproteomics data structure enables synchronized subsetting across shared dimensions." style="width:70%;">
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
## Principles
|
|
12
12
|
|
|
13
|
-
Multiplexed imaging data comprises at least 3 dimensions (i.e. `channels`, `x`, and `y`) and
|
|
13
|
+
Multiplexed imaging data comprises at least 3 dimensions (i.e. `channels`, `x`, and `y`) and often contains additional data such as segmentation masks or cell type annotations associated with it. In `spatialproteomics`, we use `xarray` to create a data structure that keeps all of these data dimension in sync. This data structure can then be used to apply all sorts of operations to the data. Users can segment cells, perform different image processing steps, quantify protein expression, predict cell types, and plot their data in various ways. By providing researchers with those tools, `spatialproteomics` can be used to quickly explore highly multiplexed spatial proteomics data directly within jupyter notebooks.
|
|
14
14
|
|
|
15
15
|
<p align="center" width="100%">
|
|
16
16
|
<img src="docs/_static/img/supplementary_figure_1.png" alt="The spatialproteomics data structure enables synchronized subsetting across shared dimensions." style="width:70%;">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "spatialproteomics"
|
|
3
|
-
version = "0.8.
|
|
3
|
+
version = "0.8.6"
|
|
4
4
|
description = "Spatialproteomics is an interoperable toolbox for analyzing highly multiplexed fluorescence image data"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -40,6 +40,7 @@ cellpose = ["cellpose>=3.1.0"]
|
|
|
40
40
|
stardist = ["stardist>=0.9.1"]
|
|
41
41
|
anndata = ["anndata"]
|
|
42
42
|
astir = ["astir>=0.1.5"]
|
|
43
|
+
spotiflow = ["spotiflow"]
|
|
43
44
|
dev = [
|
|
44
45
|
"pytest>=7.1.2",
|
|
45
46
|
"pytest-cov>=3.0.0",
|
|
@@ -48,6 +49,7 @@ dev = [
|
|
|
48
49
|
"flake8>=5.0.4",
|
|
49
50
|
"bandit>=1.7.4",
|
|
50
51
|
"safety>=2.1.1",
|
|
52
|
+
"typing_extensions>=4.16", # to avoid anndata issues
|
|
51
53
|
]
|
|
52
54
|
all = ["spatialdata", "cellpose", "stardist", "astir"]
|
|
53
55
|
|
|
@@ -797,6 +797,7 @@ class LabelAccessor:
|
|
|
797
797
|
cell_col: str = "cell",
|
|
798
798
|
label_col: str = "label",
|
|
799
799
|
min_intensity: float = 0.0,
|
|
800
|
+
ignore_neighborhoods: bool = False,
|
|
800
801
|
):
|
|
801
802
|
"""
|
|
802
803
|
Predicts cell types based on the argmax classification of marker intensities.
|
|
@@ -808,6 +809,7 @@ class LabelAccessor:
|
|
|
808
809
|
cell_col (str, optional): The name of the column to store cell IDs in the output dataframe. Defaults to "cell".
|
|
809
810
|
label_col (str, optional): The name of the column to store predicted cell types in the output dataframe. Defaults to "label".
|
|
810
811
|
min_intensity (float, optional): The minimum intensity threshold for assigning cells to a type. Defaults to 0.0.
|
|
812
|
+
ignore_neighborhoods (bool, optional): Whether to remove existing neighborhoods when predicting cell types. Defaults to False.
|
|
811
813
|
|
|
812
814
|
Returns:
|
|
813
815
|
xr.Dataset: A new spatialproteomics object with the predicted cell types added as labels.
|
|
@@ -869,7 +871,7 @@ class LabelAccessor:
|
|
|
869
871
|
obj = obj.pp.drop_layers(Layers.LA_PROPERTIES)
|
|
870
872
|
|
|
871
873
|
# adding the new labels
|
|
872
|
-
return obj.la.add_labels_from_dataframe(celltype_prediction_df)
|
|
874
|
+
return obj.la.add_labels_from_dataframe(celltype_prediction_df, ignore_neighborhoods=ignore_neighborhoods)
|
|
873
875
|
|
|
874
876
|
def _threshold_label(
|
|
875
877
|
self, channel: str, threshold: float, layer_key: str = Layers.INTENSITY, label: Optional[str] = None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .tool import ToolAccessor, astir, cellpose, mesmer, stardist
|
|
1
|
+
from .tool import ToolAccessor, astir, cellpose, mesmer, spotiflow, stardist
|
|
2
2
|
|
|
3
3
|
__all__ = [
|
|
4
4
|
"ToolAccessor",
|
|
@@ -6,4 +6,5 @@ __all__ = [
|
|
|
6
6
|
"mesmer",
|
|
7
7
|
"stardist",
|
|
8
8
|
"astir",
|
|
9
|
+
"spotiflow",
|
|
9
10
|
]
|
|
@@ -7,7 +7,12 @@ import xarray as xr
|
|
|
7
7
|
|
|
8
8
|
from ..base_logger import logger
|
|
9
9
|
from ..constants import Dims, Features, Layers, Props, SDLayers
|
|
10
|
-
from ..sd.utils import
|
|
10
|
+
from ..sd.utils import (
|
|
11
|
+
_get_channels_spatialdata,
|
|
12
|
+
_process_adata,
|
|
13
|
+
_process_image,
|
|
14
|
+
_process_segmentation,
|
|
15
|
+
)
|
|
11
16
|
from .utils import (
|
|
12
17
|
_astir,
|
|
13
18
|
_cellpose,
|
|
@@ -15,6 +20,7 @@ from .utils import (
|
|
|
15
20
|
_convert_masks_to_data_array,
|
|
16
21
|
_get_channels,
|
|
17
22
|
_mesmer,
|
|
23
|
+
_spotiflow,
|
|
18
24
|
_stardist,
|
|
19
25
|
)
|
|
20
26
|
|
|
@@ -262,6 +268,96 @@ def astir(
|
|
|
262
268
|
return sdata
|
|
263
269
|
|
|
264
270
|
|
|
271
|
+
def spotiflow(
|
|
272
|
+
sdata,
|
|
273
|
+
channel: Optional[str] = None,
|
|
274
|
+
image_key: str = SDLayers.IMAGE,
|
|
275
|
+
segmentation_key: str = SDLayers.SEGMENTATION,
|
|
276
|
+
table_key: str = SDLayers.TABLE,
|
|
277
|
+
key_added: str = "spotiflow",
|
|
278
|
+
key_added_suffix: str = "_spots",
|
|
279
|
+
pretrained_name: str = "general",
|
|
280
|
+
model_kwargs: Optional[dict] = {"verbose": False},
|
|
281
|
+
predict_kwargs: Optional[dict] = {"verbose": False},
|
|
282
|
+
copy: bool = False,
|
|
283
|
+
):
|
|
284
|
+
"""
|
|
285
|
+
This function applies the Spotiflow algorithm to detect spots in the provided image data.
|
|
286
|
+
It extracts the image data from the spatialdata object, applies the Spotiflow algorithm,
|
|
287
|
+
and adds the detected spots to the spatialdata object.
|
|
288
|
+
The detected spots are stored in the points attribute of the spatialdata object.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
sdata (spatialdata.SpatialData): The spatialdata object containing the image data.
|
|
292
|
+
channel (Optional[str]): The channel(s) to be used for spot detection. If None, all channels will be used.
|
|
293
|
+
image_key (str, optional): The key for the image data in the spatialdata object. Defaults to "image".
|
|
294
|
+
segmentation_key (str, optional): The key for the segmentation mask in the spatialdata object. Defaults to "segmentation".
|
|
295
|
+
table_key (str, optional): The key for the table in the spatialdata object. Defaults to "table".
|
|
296
|
+
key_added (str, optional): The key under which the detected spots will be stored in the points attribute of the spatialdata object. Defaults to "spotiflow".
|
|
297
|
+
key_added_suffix (str, optional): The suffix to be added to the channel names in the detected spots. Defaults to "_spots".
|
|
298
|
+
pretrained_name (str, optional): The name of the pretrained model to be used for spot detection. Defaults to "general".
|
|
299
|
+
model_kwargs (Optional[dict], optional): Additional keyword arguments to be passed to the Spotiflow model. Defaults to {'verbose': False}.
|
|
300
|
+
predict_kwargs (Optional[dict], optional): Additional keyword arguments to be passed to the Spotiflow prediction method. Defaults to {'verbose': False}.
|
|
301
|
+
copy (bool, optional): Whether to create a copy of the spatialdata object. Defaults to False.
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
spatialdata.SpatialData: The spatialdata object with the detected spots added to the points attribute.
|
|
305
|
+
"""
|
|
306
|
+
import spatialdata as sd
|
|
307
|
+
from spatialdata.transformations import get_transformation, set_transformation
|
|
308
|
+
|
|
309
|
+
assert image_key in sdata, f"Image key {image_key} not found in the object."
|
|
310
|
+
assert segmentation_key in sdata, f"Segmentation key {segmentation_key} not found in the object."
|
|
311
|
+
assert table_key in sdata, f"Table key {table_key} not found in the object."
|
|
312
|
+
|
|
313
|
+
if copy:
|
|
314
|
+
sdata = cp.deepcopy(sdata)
|
|
315
|
+
|
|
316
|
+
channels = _get_channels_spatialdata(channel)
|
|
317
|
+
img = _process_image(sdata, channels=channel, image_key=image_key, key_added=None)
|
|
318
|
+
adata = _process_adata(sdata, table_key=table_key)
|
|
319
|
+
|
|
320
|
+
points_df = _spotiflow(
|
|
321
|
+
img,
|
|
322
|
+
channel_names=channels,
|
|
323
|
+
pretrained_name=pretrained_name,
|
|
324
|
+
model_kwargs=model_kwargs,
|
|
325
|
+
predict_kwargs=predict_kwargs,
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
seg = _process_segmentation(sdata, segmentation_key=segmentation_key)
|
|
329
|
+
yy = points_df["y"].round().astype(int).clip(0, seg.shape[0] - 1)
|
|
330
|
+
xx = points_df["x"].round().astype(int).clip(0, seg.shape[1] - 1)
|
|
331
|
+
points_df["cell_id"] = seg[yy, xx]
|
|
332
|
+
points_df = points_df[points_df["cell_id"] > 0] # drop background detections
|
|
333
|
+
|
|
334
|
+
# --- counts per cell, per channel -------------------------------------
|
|
335
|
+
counts = points_df.groupby(["cell_id", "channel"]).size().unstack(fill_value=0)
|
|
336
|
+
counts.columns = [f"{ch}{key_added_suffix}" for ch in counts.columns]
|
|
337
|
+
|
|
338
|
+
# --- counts per cell, per channel -------------------------------------
|
|
339
|
+
counts = points_df.groupby(["cell_id", "channel"]).size().unstack(fill_value=0)
|
|
340
|
+
counts.columns = [f"{ch}{key_added_suffix}" for ch in counts.columns]
|
|
341
|
+
new_cols = counts.columns.tolist() # remember which columns are new
|
|
342
|
+
|
|
343
|
+
# get transformations
|
|
344
|
+
transformation = get_transformation(sdata[image_key])
|
|
345
|
+
|
|
346
|
+
# write points to spatialdata
|
|
347
|
+
sdata.points[key_added] = sd.models.PointsModel.parse(points_df, coordinates={"x": "x", "y": "y"})
|
|
348
|
+
set_transformation(sdata.points[key_added], transformation)
|
|
349
|
+
|
|
350
|
+
# merge counts to existing obs
|
|
351
|
+
obs = adata.obs
|
|
352
|
+
obs = obs.merge(counts, left_on="id", right_index=True, how="left")
|
|
353
|
+
obs[new_cols] = obs[new_cols].fillna(0).astype(int) # only fill the newly merged columns
|
|
354
|
+
|
|
355
|
+
sdata.tables[table_key].obs = obs
|
|
356
|
+
|
|
357
|
+
if copy:
|
|
358
|
+
return sdata
|
|
359
|
+
|
|
360
|
+
|
|
265
361
|
# === SPATIALPROTEOMICS ACCESSOR ===
|
|
266
362
|
@xr.register_dataset_accessor("tl")
|
|
267
363
|
class ToolAccessor:
|
|
@@ -418,7 +514,7 @@ class ToolAccessor:
|
|
|
418
514
|
self._obj.pp[channels]._image.values,
|
|
419
515
|
scale=scale,
|
|
420
516
|
n_tiles=n_tiles,
|
|
421
|
-
normalize=
|
|
517
|
+
normalize=normalize,
|
|
422
518
|
predict_big=predict_big,
|
|
423
519
|
postprocess_func=postprocess_func,
|
|
424
520
|
**kwargs,
|
|
@@ -583,6 +679,77 @@ class ToolAccessor:
|
|
|
583
679
|
assigned_cell_types, cell_col=cell_id_col, label_col=cell_type_col
|
|
584
680
|
)
|
|
585
681
|
|
|
682
|
+
def spotiflow(
|
|
683
|
+
self,
|
|
684
|
+
channel: Optional[str] = None,
|
|
685
|
+
image_key: str = Layers.IMAGE,
|
|
686
|
+
segmentation_key: str = Layers.SEGMENTATION,
|
|
687
|
+
key_added_suffix: str = "_spots",
|
|
688
|
+
pretrained_name: str = "general",
|
|
689
|
+
return_spots: bool = False,
|
|
690
|
+
model_kwargs: Optional[dict] = {"verbose": False},
|
|
691
|
+
predict_kwargs: Optional[dict] = {"verbose": False},
|
|
692
|
+
):
|
|
693
|
+
"""
|
|
694
|
+
This method detects spots in the image using the Spotiflow algorithm and counts the number of spots per cell, per channel.
|
|
695
|
+
|
|
696
|
+
Parameters
|
|
697
|
+
----------
|
|
698
|
+
channel : str, optional
|
|
699
|
+
Channel to use for spot detection. If None, all channels are used.
|
|
700
|
+
image_key : str, optional
|
|
701
|
+
Key to the image layer in the spatialproteomics object. Default is 'image'.
|
|
702
|
+
segmentation_key : str, optional
|
|
703
|
+
Key to the segmentation layer in the spatialproteomics object. Default is 'segmentation'.
|
|
704
|
+
key_added_suffix : str, optional
|
|
705
|
+
Suffix to add to the channel names in the resulting counts. Default is '_spots'.
|
|
706
|
+
pretrained_name : str, optional
|
|
707
|
+
Name of the pretrained model to use for spot detection. Default is 'general'.
|
|
708
|
+
return_spots : bool, optional
|
|
709
|
+
Whether to return the detected spots as a DataFrame. Default is False.
|
|
710
|
+
model_kwargs : dict, optional
|
|
711
|
+
Additional keyword arguments to pass to the Spotiflow model. Default is {'verbose': False}.
|
|
712
|
+
predict_kwargs : dict, optional
|
|
713
|
+
Additional keyword arguments to pass to the Spotiflow prediction method. Default is {'verbose': False}.
|
|
714
|
+
|
|
715
|
+
Returns
|
|
716
|
+
-------
|
|
717
|
+
xr.Dataset
|
|
718
|
+
Dataset containing the counts of spots per cell, per channel. If return_spots is True, also returns a DataFrame of the detected spots with their coordinates and assigned cell IDs.
|
|
719
|
+
"""
|
|
720
|
+
assert image_key in self._obj, f"Image key {image_key} not found in the object."
|
|
721
|
+
assert segmentation_key in self._obj, f"Segmentation key {segmentation_key} not found in the object."
|
|
722
|
+
channels = _get_channels(self._obj, key_added=None, channel=channel)
|
|
723
|
+
img = self._obj.pp[channels][image_key].values
|
|
724
|
+
points_df = _spotiflow(
|
|
725
|
+
img,
|
|
726
|
+
channel_names=channels,
|
|
727
|
+
pretrained_name=pretrained_name,
|
|
728
|
+
model_kwargs=model_kwargs,
|
|
729
|
+
predict_kwargs=predict_kwargs,
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
# assign each point to a cell via the segmentation mask
|
|
733
|
+
seg = self._obj[segmentation_key].values
|
|
734
|
+
yy = points_df["y"].round().astype(int).clip(0, seg.shape[0] - 1)
|
|
735
|
+
xx = points_df["x"].round().astype(int).clip(0, seg.shape[1] - 1)
|
|
736
|
+
points_df["cell_id"] = seg[yy, xx]
|
|
737
|
+
points_df = points_df[points_df["cell_id"] > 0] # drop background detections
|
|
738
|
+
|
|
739
|
+
# count points per cell, per channel
|
|
740
|
+
counts = (
|
|
741
|
+
points_df.groupby(["cell_id", "channel"])
|
|
742
|
+
.size()
|
|
743
|
+
.unstack(fill_value=0)
|
|
744
|
+
.reindex(index=self._obj.cells.values, columns=channels, fill_value=0)
|
|
745
|
+
)
|
|
746
|
+
counts.columns = [f"{ch}{key_added_suffix}" for ch in counts.columns]
|
|
747
|
+
|
|
748
|
+
if return_spots:
|
|
749
|
+
return self._obj.pp.add_obs_from_dataframe(counts.reset_index(drop=True)), points_df
|
|
750
|
+
|
|
751
|
+
return self._obj.pp.add_obs_from_dataframe(counts.reset_index(drop=True))
|
|
752
|
+
|
|
586
753
|
def convert_to_anndata(
|
|
587
754
|
self,
|
|
588
755
|
expression_matrix_key: str = Layers.INTENSITY,
|
|
@@ -12,7 +12,7 @@ from ..pp.utils import _normalize
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def _get_channels(obj, key_added, channel):
|
|
15
|
-
if key_added in obj:
|
|
15
|
+
if key_added is not None and key_added in obj:
|
|
16
16
|
raise KeyError(f'The key "{key_added}" already exists. Please choose another key.')
|
|
17
17
|
|
|
18
18
|
if channel is not None:
|
|
@@ -248,6 +248,43 @@ def _astir(
|
|
|
248
248
|
return assigned_cell_types
|
|
249
249
|
|
|
250
250
|
|
|
251
|
+
def _spotiflow(
|
|
252
|
+
img,
|
|
253
|
+
channel_names,
|
|
254
|
+
pretrained_name: str = "general",
|
|
255
|
+
model_kwargs: dict = None,
|
|
256
|
+
predict_kwargs: dict = None,
|
|
257
|
+
):
|
|
258
|
+
model_kwargs = model_kwargs or {}
|
|
259
|
+
predict_kwargs = predict_kwargs or {}
|
|
260
|
+
|
|
261
|
+
from spotiflow.model import Spotiflow
|
|
262
|
+
|
|
263
|
+
if img.ndim not in [2, 3]:
|
|
264
|
+
raise ValueError(f"Input image must be 2D or 3D, got {img.ndim}.")
|
|
265
|
+
|
|
266
|
+
if img.ndim == 2:
|
|
267
|
+
img = img[np.newaxis, :, :]
|
|
268
|
+
channel_names = [channel_names] if np.isscalar(channel_names) else channel_names
|
|
269
|
+
|
|
270
|
+
assert img.shape[0] == len(channel_names), "Number of channels in image does not match number of channel names."
|
|
271
|
+
|
|
272
|
+
model = Spotiflow.from_pretrained(pretrained_name, **model_kwargs)
|
|
273
|
+
|
|
274
|
+
dfs = []
|
|
275
|
+
for ch_idx, ch_name in enumerate(channel_names):
|
|
276
|
+
single_image = img[ch_idx]
|
|
277
|
+
points, _ = model.predict(single_image, **predict_kwargs)
|
|
278
|
+
# spotiflow returns points as (row, col) == (y, x)
|
|
279
|
+
df = pd.DataFrame(points, columns=["y", "x"])
|
|
280
|
+
df["channel"] = ch_name
|
|
281
|
+
dfs.append(df)
|
|
282
|
+
|
|
283
|
+
df = pd.concat(dfs, ignore_index=True)
|
|
284
|
+
df.index.name = "points"
|
|
285
|
+
return df
|
|
286
|
+
|
|
287
|
+
|
|
251
288
|
def _compute_transformation(x_coords, y_coords):
|
|
252
289
|
from spatialdata.transformations import Affine
|
|
253
290
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spatialproteomics
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.6
|
|
4
4
|
Summary: Spatialproteomics is an interoperable toolbox for analyzing highly multiplexed fluorescence image data
|
|
5
5
|
Author: Matthias Meyer-Bender, Harald Vohringer
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -33,6 +33,8 @@ Provides-Extra: anndata
|
|
|
33
33
|
Requires-Dist: anndata; extra == "anndata"
|
|
34
34
|
Provides-Extra: astir
|
|
35
35
|
Requires-Dist: astir>=0.1.5; extra == "astir"
|
|
36
|
+
Provides-Extra: spotiflow
|
|
37
|
+
Requires-Dist: spotiflow; extra == "spotiflow"
|
|
36
38
|
Provides-Extra: dev
|
|
37
39
|
Requires-Dist: pytest>=7.1.2; extra == "dev"
|
|
38
40
|
Requires-Dist: pytest-cov>=3.0.0; extra == "dev"
|
|
@@ -41,6 +43,7 @@ Requires-Dist: isort>=5.10.1; extra == "dev"
|
|
|
41
43
|
Requires-Dist: flake8>=5.0.4; extra == "dev"
|
|
42
44
|
Requires-Dist: bandit>=1.7.4; extra == "dev"
|
|
43
45
|
Requires-Dist: safety>=2.1.1; extra == "dev"
|
|
46
|
+
Requires-Dist: typing_extensions>=4.16; extra == "dev"
|
|
44
47
|
Provides-Extra: all
|
|
45
48
|
Requires-Dist: spatialdata; extra == "all"
|
|
46
49
|
Requires-Dist: cellpose; extra == "all"
|
|
@@ -60,7 +63,7 @@ Dynamic: license-file
|
|
|
60
63
|
|
|
61
64
|
## Principles
|
|
62
65
|
|
|
63
|
-
Multiplexed imaging data comprises at least 3 dimensions (i.e. `channels`, `x`, and `y`) and
|
|
66
|
+
Multiplexed imaging data comprises at least 3 dimensions (i.e. `channels`, `x`, and `y`) and often contains additional data such as segmentation masks or cell type annotations associated with it. In `spatialproteomics`, we use `xarray` to create a data structure that keeps all of these data dimension in sync. This data structure can then be used to apply all sorts of operations to the data. Users can segment cells, perform different image processing steps, quantify protein expression, predict cell types, and plot their data in various ways. By providing researchers with those tools, `spatialproteomics` can be used to quickly explore highly multiplexed spatial proteomics data directly within jupyter notebooks.
|
|
64
67
|
|
|
65
68
|
<p align="center" width="100%">
|
|
66
69
|
<img src="docs/_static/img/supplementary_figure_1.png" alt="The spatialproteomics data structure enables synchronized subsetting across shared dimensions." style="width:70%;">
|
|
@@ -32,6 +32,7 @@ isort>=5.10.1
|
|
|
32
32
|
flake8>=5.0.4
|
|
33
33
|
bandit>=1.7.4
|
|
34
34
|
safety>=2.1.1
|
|
35
|
+
typing_extensions>=4.16
|
|
35
36
|
|
|
36
37
|
[docs]
|
|
37
38
|
Sphinx>=7.0.0
|
|
@@ -44,5 +45,8 @@ IPython>=8.0.0
|
|
|
44
45
|
[spatialdata]
|
|
45
46
|
spatialdata>=0.4.0
|
|
46
47
|
|
|
48
|
+
[spotiflow]
|
|
49
|
+
spotiflow
|
|
50
|
+
|
|
47
51
|
[stardist]
|
|
48
52
|
stardist>=0.9.1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics/image_container/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{spatialproteomics-0.8.5 → spatialproteomics-0.8.6}/spatialproteomics.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|