Skip to content

Commit 256a8e2

Browse files
Merge pull request #91 from scverse/fix/visium_no_dataset_id
Fixed visium() to support file counts without dataset_id
2 parents 28af0f9 + de93257 commit 256a8e2

2 files changed

Lines changed: 35 additions & 22 deletions

File tree

src/spatialdata_io/readers/_utils/_utils.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ def _read_counts(
2929
) -> tuple[AnnData, str]:
3030
path = Path(path)
3131
if counts_file.endswith(".h5"):
32-
print(counts_file)
3332
adata: AnnData = _read_10x_h5(path / counts_file, **kwargs)
3433
with File(path / counts_file, mode="r") as f:
3534
attrs = dict(f.attrs)
@@ -50,9 +49,8 @@ def _read_counts(
5049
adata.uns["spatial"][library_id]["metadata"][key] = metadata
5150

5251
return adata, library_id
53-
5452
if library_id is None:
55-
raise ValueError("Please explicitly specify library id.")
53+
raise ValueError("Please explicitly specify `library id`.")
5654

5755
if counts_file.endswith((".csv", ".txt")):
5856
adata = read_text(path / counts_file, **kwargs)

src/spatialdata_io/readers/visium.py

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def visium(
4242
4343
This function reads the following files:
4444
45-
- ``{vx.COUNTS_FILE!r}``: Counts and metadata file.
45+
- ``(<dataset_id>_)`{vx.COUNTS_FILE!r}```: Counts and metadata file.
4646
- ``{vx.IMAGE_HIRES_FILE!r}``: High resolution image.
4747
- ``{vx.IMAGE_LOWRES_FILE!r}``: Low resolution image.
4848
- ``{vx.SCALEFACTORS_FILE!r}``: Scalefactors file.
@@ -59,8 +59,8 @@ def visium(
5959
path
6060
Path to the directory containing the data.
6161
dataset_id
62-
Dataset identifier. If not given will be determined automatically
63-
from the ``{vx.COUNTS_FILE!r}`` file.
62+
Dataset identifier to name the constructed `SpatialData` elements. The reader will try to infer it from the
63+
``{vx.COUNTS_FILE!r}`` file name. If the file name does not contain the dataset id, it will try to infer it from the metadata, it needs to be provided.
6464
counts_file
6565
Name of the counts file. Use only if counts is not in `h5` format.
6666
fullres_image_file
@@ -81,39 +81,53 @@ def visium(
8181
path = Path(path)
8282
imread_kwargs = dict(imread_kwargs)
8383
image_models_kwargs = dict(image_models_kwargs)
84-
# get library_id
84+
# try to infer library_id from the counts file
85+
library_id = None
8586
try:
8687
patt = re.compile(f".*{VisiumKeys.COUNTS_FILE}")
8788
first_file = [i for i in os.listdir(path) if patt.match(i)][0]
8889

8990
if f"_{VisiumKeys.COUNTS_FILE}" in first_file:
9091
library_id = first_file.replace(f"_{VisiumKeys.COUNTS_FILE}", "")
92+
counts_file = f"{library_id}_{VisiumKeys.COUNTS_FILE}"
93+
elif VisiumKeys.COUNTS_FILE == first_file:
94+
library_id = None
95+
counts_file = VisiumKeys.COUNTS_FILE
9196
else:
9297
raise ValueError(
93-
f"Cannot determine the library_id. Expecting a file with format <library_id>_{VisiumKeys.COUNTS_FILE}. Has "
94-
f"the files been renamed?"
98+
f"Cannot determine the library_id. Expecting a file with format (<library_id>_){VisiumKeys.COUNTS_FILE}"
99+
f". If the files have been renamed you may need to specify their file names (not their paths), with "
100+
f"some of the following arguments: `counts_file`, `fullres_image_file`, `tissue_positions_file`, "
101+
f"`scalefactors_file` arguments."
95102
)
96-
counts_file = f"{library_id}_{VisiumKeys.COUNTS_FILE}"
97103
except IndexError as e:
98-
logger.error(
99-
f"{e}. \nError is due to the fact that the library id could not be found, this is the case when the `counts_file` is `.mtx`.",
100-
)
101-
if dataset_id is None:
102-
raise ValueError("Cannot determine the `library_id`. Please provide `dataset_id`.")
103-
library_id = dataset_id
104104
if counts_file is None:
105-
raise ValueError("Cannot determine the library_id. Please provide `counts_file`.")
105+
logger.error(
106+
f"{e}. \nError is due to the fact that the library id could not be found, if the counts file is `.mtx` (or else), Please provide a `counts_file`.",
107+
)
108+
raise e
109+
assert counts_file is not None
110+
111+
if library_id is None and dataset_id is None:
112+
raise ValueError("Cannot determine the `library_id`. Please provide `dataset_id`.")
106113

107114
if dataset_id is not None:
108-
if dataset_id != library_id:
115+
if dataset_id != library_id and library_id is not None:
109116
logger.warning(
110117
f"`dataset_id: {dataset_id}` does not match `library_id: {library_id}`. `dataset_id: {dataset_id}` "
111118
f"will be used to build SpatialData."
112119
)
120+
library_id = dataset_id
113121
else:
114122
dataset_id = library_id
123+
assert dataset_id is not None
115124

116-
adata, dataset_id = _read_counts(path, counts_file=counts_file, library_id=dataset_id, **kwargs)
125+
# Yhe second element of the returned tuple is the full library as contained in the metadata of
126+
# VisiumKeys.COUNTS_FILE. For instance for the spatialdata-sandbox/visium dataset it is:
127+
# spaceranger100_count_30458_ST8059048_mm10-3_0_0_premrna
128+
# We discard this value and use the one inferred from the filename of VisiumKeys.COUNTS_FILE, or the one provided by
129+
# the user in dataset_id
130+
adata, _ = _read_counts(path, counts_file=counts_file, library_id=library_id, **kwargs)
117131

118132
if (path / "spatial" / VisiumKeys.SPOTS_FILE_1).exists() or (
119133
tissue_positions_file is not None and str(VisiumKeys.SPOTS_FILE_1) in str(tissue_positions_file)
@@ -142,6 +156,7 @@ def visium(
142156
adata.obs = pd.merge(adata.obs, coords, how="left", left_index=True, right_index=True)
143157
coords = adata.obs[[VisiumKeys.SPOTS_X, VisiumKeys.SPOTS_Y]].values
144158
adata.obsm["spatial"] = coords
159+
adata.obs = pd.DataFrame(adata.obs)
145160
adata.obs.drop(columns=[VisiumKeys.SPOTS_X, VisiumKeys.SPOTS_Y], inplace=True)
146161
adata.obs["spot_id"] = np.arange(len(adata))
147162
adata.var_names_make_unique()
@@ -187,7 +202,7 @@ def visium(
187202

188203
ImagePIL.MAX_IMAGE_PIXELS = imread_kwargs.pop("MAX_IMAGE_PIXELS")
189204
full_image = imread(fullres_image_file, **imread_kwargs).squeeze().transpose(2, 0, 1)
190-
full_image = DataArray(full_image, dims=("c", "y", "x"), name=dataset_id)
205+
full_image = DataArray(full_image, dims=("c", "y", "x"))
191206
images[dataset_id + "_full_image"] = Image2DModel.parse(
192207
full_image,
193208
scale_factors=[2, 2, 2, 2],
@@ -199,13 +214,13 @@ def visium(
199214

200215
if (path / VisiumKeys.IMAGE_HIRES_FILE).exists():
201216
image_hires = imread(path / VisiumKeys.IMAGE_HIRES_FILE, **imread_kwargs).squeeze().transpose(2, 0, 1)
202-
image_hires = DataArray(image_hires, dims=("c", "y", "x"), name=dataset_id)
217+
image_hires = DataArray(image_hires, dims=("c", "y", "x"))
203218
images[dataset_id + "_hires_image"] = Image2DModel.parse(
204219
image_hires, transformations={"downscaled_hires": Identity()}
205220
)
206221
if (path / VisiumKeys.IMAGE_LOWRES_FILE).exists():
207222
image_lowres = imread(path / VisiumKeys.IMAGE_LOWRES_FILE, **imread_kwargs).squeeze().transpose(2, 0, 1)
208-
image_lowres = DataArray(image_lowres, dims=("c", "y", "x"), name=dataset_id)
223+
image_lowres = DataArray(image_lowres, dims=("c", "y", "x"))
209224
images[dataset_id + "_lowres_image"] = Image2DModel.parse(
210225
image_lowres, transformations={"downscaled_lowres": Identity()}
211226
)

0 commit comments

Comments
 (0)