11from __future__ import annotations
22
3- import warnings
3+ from collections . abc import Mapping
44from typing import TYPE_CHECKING
55
66import numpy as np
1212 to_circles ,
1313)
1414from spatialdata ._core .operations ._utils import transform_to_data_extent
15+ from spatialdata ._logging import logger
1516from spatialdata .models import Image2DModel , ShapesModel , TableModel , get_table_keys
1617from spatialdata .transformations import Identity , Scale
1718
@@ -250,6 +251,7 @@ def from_legacy_anndata(adata: AnnData) -> SpatialData:
250251 IMAGES = "images"
251252 HIRES = "hires"
252253 LOWRES = "lowres"
254+ DEFAULT_SCALE_FACTOR = 1.0
253255
254256 # SpatialData keys
255257 REGION = "locations"
@@ -265,72 +267,77 @@ def from_legacy_anndata(adata: AnnData) -> SpatialData:
265267 if SPATIAL in adata .uns :
266268 dataset_ids = list (adata .uns [SPATIAL ].keys ())
267269 for dataset_id in dataset_ids :
268- # read the image data and the scale factors for the shapes
269- keys = set (adata .uns [SPATIAL ][dataset_id ].keys ())
270- tissue_hires_scalef = None
271- tissue_lowres_scalef = None
272- hires = None
273- lowres = None
274- if SCALEFACTORS in keys :
275- scalefactors = adata .uns [SPATIAL ][dataset_id ][SCALEFACTORS ]
276- if TISSUE_HIRES_SCALEF in scalefactors :
277- tissue_hires_scalef = scalefactors [TISSUE_HIRES_SCALEF ]
278- if TISSUE_LOWRES_SCALEF in scalefactors :
279- tissue_lowres_scalef = scalefactors [TISSUE_LOWRES_SCALEF ]
280- if SPOT_DIAMETER_FULLRES in scalefactors :
281- spot_diameter_fullres_list .append (scalefactors [SPOT_DIAMETER_FULLRES ])
282- if IMAGES in keys :
283- image_data = adata .uns [SPATIAL ][dataset_id ][IMAGES ]
284- if HIRES in image_data :
285- hires = image_data [HIRES ]
286- if LOWRES in image_data :
287- lowres = image_data [LOWRES ]
288-
289- # construct the spatialdata elements
290- if hires is not None :
291- # prepare the hires image
292- assert tissue_hires_scalef is not None , (
293- "tissue_hires_scalef is required when an the hires image is present"
270+ dataset_data = adata .uns [SPATIAL ][dataset_id ]
271+ keys = set (dataset_data .keys ())
272+ scalefactors_raw = dataset_data .get (SCALEFACTORS , {}) if isinstance (dataset_data , Mapping ) else {}
273+ scalefactors = scalefactors_raw if isinstance (scalefactors_raw , Mapping ) else {}
274+
275+ if SPOT_DIAMETER_FULLRES in scalefactors :
276+ spot_diameter_fullres_list .append (scalefactors [SPOT_DIAMETER_FULLRES ])
277+
278+ image_data = dataset_data .get (IMAGES , {}) if IMAGES in keys and isinstance (dataset_data , Mapping ) else {}
279+ if not isinstance (image_data , Mapping ):
280+ image_data = {}
281+ for image_key , image_value in image_data .items ():
282+ if image_key not in (HIRES , LOWRES ):
283+ logger .warning (
284+ "Found non-standard image key '%s' in dataset '%s' - attempting to parse." ,
285+ image_key ,
286+ dataset_id ,
287+ )
288+ # prefer scalefactors keyed by the image name, fall back to tissue_<image_key>_scalef
289+ # then to legacy hires/lowres names, finally default to 1.0.
290+ scalefactor = None
291+ scalefactor_source = None
292+ if image_key in scalefactors :
293+ scalefactor = scalefactors [image_key ]
294+ scalefactor_source = image_key
295+ elif f"tissue_{ image_key } _scalef" in scalefactors :
296+ scalefactor = scalefactors [f"tissue_{ image_key } _scalef" ]
297+ scalefactor_source = f"tissue_{ image_key } _scalef"
298+ elif image_key == HIRES and TISSUE_HIRES_SCALEF in scalefactors :
299+ scalefactor = scalefactors [TISSUE_HIRES_SCALEF ]
300+ scalefactor_source = TISSUE_HIRES_SCALEF
301+ elif image_key == LOWRES and TISSUE_LOWRES_SCALEF in scalefactors :
302+ scalefactor = scalefactors [TISSUE_LOWRES_SCALEF ]
303+ scalefactor_source = TISSUE_LOWRES_SCALEF
304+
305+ if scalefactor is None :
306+ scalefactor = DEFAULT_SCALE_FACTOR
307+ logger .warning (
308+ "Scale factor missing for image '%s' in dataset '%s'; defaulting to %s" ,
309+ image_key ,
310+ dataset_id ,
311+ DEFAULT_SCALE_FACTOR ,
312+ )
313+ else :
314+ logger .debug (
315+ "Using scalefactor '%s' for image '%s' in dataset '%s'" ,
316+ scalefactor_source ,
317+ image_key ,
318+ dataset_id ,
319+ )
320+
321+ transform_name = f"{ dataset_id } _{ image_key } "
322+ image_name = f"{ dataset_id } _{ image_key } "
323+ images [image_name ] = Image2DModel .parse (
324+ image_value , dims = ("y" , "x" , "c" ), transformations = {transform_name : Identity ()}
294325 )
295- hires_image = Image2DModel .parse (
296- hires , dims = ("y" , "x" , "c" ), transformations = {f"{ dataset_id } _downscaled_hires" : Identity ()}
297- )
298- images [f"{ dataset_id } _hires_image" ] = hires_image
299-
300- # prepare the transformation to the hires image for the shapes
301- scale_hires = Scale ([tissue_hires_scalef , tissue_hires_scalef ], axes = ("x" , "y" ))
302- shapes_transformations [f"{ dataset_id } _downscaled_hires" ] = scale_hires
303- if lowres is not None :
304- # prepare the lowres image
305- assert tissue_lowres_scalef is not None , (
306- "tissue_lowres_scalef is required when an the lowres image is present"
307- )
308- lowres_image = Image2DModel .parse (
309- lowres , dims = ("y" , "x" , "c" ), transformations = {f"{ dataset_id } _downscaled_lowres" : Identity ()}
310- )
311- images [f"{ dataset_id } _lowres_image" ] = lowres_image
312-
313- # prepare the transformation to the lowres image for the shapes
314- scale_lowres = Scale ([tissue_lowres_scalef , tissue_lowres_scalef ], axes = ("x" , "y" ))
315- shapes_transformations [f"{ dataset_id } _downscaled_lowres" ] = scale_lowres
326+ shapes_transformations [transform_name ] = Scale ([scalefactor , scalefactor ], axes = ("x" , "y" ))
316327
317328 # validate the spot_diameter_fullres value
318329 if len (spot_diameter_fullres_list ) > 0 :
319330 d = np .array (spot_diameter_fullres_list )
320331 if not np .allclose (d , d [0 ]):
321- warnings . warn (
332+ logger . warning (
322333 "spot_diameter_fullres is not constant across datasets. Using the average value." ,
323- UserWarning ,
324- stacklevel = 2 ,
325334 )
326335 spot_diameter_fullres = d .mean ()
327336 else :
328337 spot_diameter_fullres = d [0 ]
329338 else :
330- warnings . warn (
339+ logger . warning (
331340 f"spot_diameter_fullres is not present. Using { SPOT_DIAMETER_FULLRES_DEFAULT } as default value." ,
332- UserWarning ,
333- stacklevel = 2 ,
334341 )
335342 spot_diameter_fullres = SPOT_DIAMETER_FULLRES_DEFAULT
336343
0 commit comments