Skip to content

Commit 1326299

Browse files
committed
improve cosmx loading
1 parent 4cf0f63 commit 1326299

File tree

1 file changed

+51
-5
lines changed

1 file changed

+51
-5
lines changed

src/spatialdata_io/readers/cosmx.py

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from dask_image.imread import imread
1717
from scipy.sparse import csr_matrix
1818
from skimage.transform import estimate_transform
19-
from spatialdata import SpatialData
19+
from spatialdata import SpatialData, read_zarr
2020
from spatialdata._logging import logger
2121
from spatialdata.models import Image2DModel, Labels2DModel, PointsModel, TableModel
2222
from spatialdata.transformations.transformations import Affine, Identity
@@ -34,6 +34,7 @@ def cosmx(
3434
transcripts: bool = True,
3535
imread_kwargs: Mapping[str, Any] = MappingProxyType({}),
3636
image_models_kwargs: Mapping[str, Any] = MappingProxyType({}),
37+
output_path: str | Path | None = None,
3738
) -> SpatialData:
3839
"""
3940
Read *Cosmx Nanostring* data.
@@ -62,12 +63,20 @@ def cosmx(
6263
Keyword arguments passed to :func:`dask_image.imread.imread`.
6364
image_models_kwargs
6465
Keyword arguments passed to :class:`spatialdata.models.Image2DModel`.
66+
output_path
67+
Path where the output will be saved. If ``None``, the output will not be saved.
6568
6669
Returns
6770
-------
6871
:class:`spatialdata.SpatialData`
6972
"""
7073
path = Path(path)
74+
output_path = Path(output_path) if output_path is not None else None
75+
sdata = SpatialData()
76+
77+
# If output path is provided, save the empty SpatialData object to create directories and hierarchy
78+
if output_path is not None:
79+
sdata.write(output_path)
7180

7281
# tries to infer dataset_id from the name of the counts file
7382
if dataset_id is None:
@@ -151,6 +160,14 @@ def cosmx(
151160
inplace=True,
152161
)
153162

163+
# Add table to SpatialData object, write it and delete temporary objects to save memory
164+
sdata.tables["table"] = table
165+
if output_path is not None:
166+
sdata.write_element(element_name="table")
167+
del adata
168+
del table
169+
del sdata.tables
170+
154171
# prepare to read images and labels
155172
file_extensions = (".jpg", ".png", ".jpeg", ".tif", ".tiff")
156173
pat = re.compile(r".*_F(\d+)")
@@ -195,7 +212,14 @@ def cosmx(
195212
rgb=None,
196213
**image_models_kwargs,
197214
)
198-
images[f"{fov}_image"] = parsed_im
215+
image_name = f"{fov}_image"
216+
images[image_name] = parsed_im
217+
if output_path is not None:
218+
sdata.images[image_name] = parsed_im
219+
sdata.write_element(element_name=image_name)
220+
del parsed_im
221+
del images[image_name]
222+
del sdata.images[image_name]
199223
else:
200224
logger.warning(f"FOV {fov} not found in counts file. Skipping image {fname}.")
201225

@@ -218,7 +242,14 @@ def cosmx(
218242
dims=("y", "x"),
219243
**image_models_kwargs,
220244
)
221-
labels[f"{fov}_labels"] = parsed_la
245+
label_name = f"{fov}_labels"
246+
labels[label_name] = parsed_la
247+
if output_path is not None:
248+
sdata.labels[label_name] = parsed_la
249+
sdata.write_element(element_name=label_name)
250+
del parsed_la
251+
del labels[label_name]
252+
del sdata.labels[label_name]
222253
else:
223254
logger.warning(f"FOV {fov} not found in counts file. Skipping labels {fname}.")
224255

@@ -265,7 +296,8 @@ def cosmx(
265296
# we rename z because we want to treat the data as 2d
266297
sub_table.rename(columns={"z": "z_raw"}, inplace=True)
267298
if len(sub_table) > 0:
268-
points[f"{fov}_points"] = PointsModel.parse(
299+
point_name = f"{fov}_points"
300+
points[point_name] = PointsModel.parse(
269301
sub_table,
270302
coordinates={"x": CosmxKeys.X_LOCAL_TRANSCRIPT, "y": CosmxKeys.Y_LOCAL_TRANSCRIPT},
271303
feature_key=CosmxKeys.TARGET_OF_TRANSCRIPT,
@@ -276,6 +308,11 @@ def cosmx(
276308
"global_only_labels": aff,
277309
},
278310
)
311+
if output_path is not None:
312+
sdata.points[point_name] = points[point_name]
313+
sdata.write_element(element_name=point_name)
314+
del points[point_name]
315+
del sdata.points[point_name]
279316

280317
# TODO: what to do with fov file?
281318
# if fov_file is not None:
@@ -286,5 +323,14 @@ def cosmx(
286323
# except KeyError:
287324
# logg.warning(f"FOV `{str(fov)}` does not exist, skipping it.")
288325
# continue
289-
326+
if output_path is not None:
327+
return read_zarr(output_path)
290328
return SpatialData(images=images, labels=labels, points=points, table=table)
329+
330+
if __name__ == "__main__":
331+
cosmx(
332+
path="/Users/ldumont/git/cosmx_data",
333+
dataset_id="1",
334+
transcripts=True,
335+
output_path="/Users/ldumont/cosmx_data_output",
336+
)

0 commit comments

Comments
 (0)