diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 61fbd30..8f35862 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.15.6 + rev: v0.16.1 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/setup.py b/setup.py index 1012362..2c68653 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ if __name__ == "__main__": try: setup(use_scm_version={"version_scheme": "no-guess-dev"}) - except: # noqa + except: print( "\n\nAn error occurred while building the project, " "please ensure you have the most updated version of setuptools, " diff --git a/src/spatialfeatureexperiment/aligned_spatialimage.py b/src/spatialfeatureexperiment/aligned_spatialimage.py index 5c121f0..dec2895 100644 --- a/src/spatialfeatureexperiment/aligned_spatialimage.py +++ b/src/spatialfeatureexperiment/aligned_spatialimage.py @@ -1,7 +1,7 @@ import math import os from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any from warnings import warn import biocutils as ut @@ -16,7 +16,7 @@ __license__ = "MIT" -def _validate_extent(extent: Dict[str, float]): +def _validate_extent(extent: dict[str, float]): required_keys = ["xmin", "xmax", "ymin", "ymax"] if not all(k in extent for k in required_keys): raise ValueError(f"Extent must contain keys: {', '.join(required_keys)}.") @@ -25,7 +25,7 @@ def _validate_extent(extent: Dict[str, float]): raise ValueError("Invalid extent: xmin must be < xmax and ymin must be < ymax.") -def _transform_extent(extent: Dict[str, float], affine_matrix: Optional[np.ndarray] = None) -> Dict[str, float]: +def _transform_extent(extent: dict[str, float], affine_matrix: np.ndarray | None = None) -> dict[str, float]: """Transforms an extent (bounding box) by an affine matrix. If no matrix is provided, returns the original extent. @@ -79,7 +79,7 @@ class AlignedSpatialImage(VirtualSpatialImage): All images in `SpatialFeatureExperiment` have an extent in spatial coordinates. """ - def __init__(self, metadata: Optional[dict] = None): + def __init__(self, metadata: dict | None = None): """Initializes the AlignedSpatialImage. Args: @@ -89,7 +89,7 @@ def __init__(self, metadata: Optional[dict] = None): super().__init__(metadata=metadata) self._extent = {} - def get_extent(self) -> Dict[str, float]: + def get_extent(self) -> dict[str, float]: """Get the spatial extent of the image. Subclasses must implement this to return their specific extent. @@ -99,7 +99,7 @@ def get_extent(self) -> Dict[str, float]: """ raise NotImplementedError("Subclasses must implement `get_extent`") - def set_extent(self, extent: Dict[str, float], in_place: bool = False) -> "AlignedSpatialImage": + def set_extent(self, extent: dict[str, float], in_place: bool = False) -> "AlignedSpatialImage": """Set the spatial extent of the image. Subclasses must implement this. @@ -118,12 +118,12 @@ def set_extent(self, extent: Dict[str, float], in_place: bool = False) -> "Align raise NotImplementedError("Subclasses must implement `set_extent`") @property - def extent(self) -> Dict[str, float]: + def extent(self) -> dict[str, float]: """Alias for :py:meth:`~get_extent`.""" return self.get_extent() @extent.setter - def extent(self, value: Dict[str, float]): + def extent(self, value: dict[str, float]): """Alias for :py:attr:`~set_extent` with ``in_place = True``. As this mutates the original object, a warning is raised. @@ -144,9 +144,9 @@ class SpatRasterImage(AlignedSpatialImage): def __init__( self, - image: Union[rasterio.DatasetReader, np.ndarray], - extent: Optional[Dict[str, float]] = None, - metadata: Optional[dict] = None, + image: rasterio.DatasetReader | np.ndarray, + extent: dict[str, float] | None = None, + metadata: dict | None = None, ): """Initialize a `SpatRasterImage`. @@ -164,9 +164,9 @@ def __init__( metadata: Additional image metadata. Defaults to None. """ super().__init__(metadata=metadata) - self._src: Optional[rasterio.DatasetReader] = None + self._src: rasterio.DatasetReader | None = None self._in_memory: bool = False - self._img_source: Optional[str] = None + self._img_source: str | None = None if isinstance(image, np.ndarray): if extent is None: @@ -226,7 +226,7 @@ def __init__( else: raise ValueError("img must be a rasterio.DatasetReader or numpy.ndarray.") - def _numpy_array_to_rasterio(self, array: np.ndarray, extent: Dict[str, float]) -> rasterio.io.MemoryFile: + def _numpy_array_to_rasterio(self, array: np.ndarray, extent: dict[str, float]) -> rasterio.io.MemoryFile: """Converts a numpy array to an in-memory rasterio dataset.""" from rasterio.io import MemoryFile @@ -307,7 +307,7 @@ def __str__(self) -> str: output += f"in_memory: {self._in_memory}\n" if self._img_source: output += f"img_source: {self._img_source}\n" - output += f"metadata({str(len(self.metadata))}): {ut.print_truncated_list(list(self.metadata.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" + output += f"metadata({len(self.metadata)!s}): {ut.print_truncated_list(list(self.metadata.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" return output @@ -315,7 +315,7 @@ def __str__(self) -> str: ######>> accessors <<###### ########################### - def img_source(self, as_path: bool = False) -> Optional[str]: + def img_source(self, as_path: bool = False) -> str | None: """Get the source file path if available.""" if ( self._in_memory @@ -327,11 +327,11 @@ def img_source(self, as_path: bool = False) -> Optional[str]: return self._img_source - def get_extent(self) -> Dict[str, float]: + def get_extent(self) -> dict[str, float]: """Get the extent of the image.""" return self._extent.copy() - def set_extent(self, extent: Dict[str, float], in_place: bool = False) -> "SpatRasterImage": + def set_extent(self, extent: dict[str, float], in_place: bool = False) -> "SpatRasterImage": """Set the extent of the image.""" _validate_extent(extent) @@ -380,8 +380,8 @@ def copy(self) -> "SpatRasterImage": def img_raster( self, - window: Optional[rasterio.windows.Window] = None, - out_shape: Optional[Tuple[int, int, int]] = None, + window: rasterio.windows.Window | None = None, + out_shape: tuple[int, int, int] | None = None, resampling_method_str: str = "nearest", ) -> np.ndarray: """Load the image data as a numpy array. @@ -412,14 +412,14 @@ def img_raster( raise RuntimeError("Image source (_src) is not available.") @property - def shape(self) -> Tuple[int, int, int]: + def shape(self) -> tuple[int, int, int]: """Get the shape of the image (height, width, channels/bands). This matches common numpy/PIL dimension order after loading. """ return self.get_dimensions() - def get_dimensions(self) -> Tuple[int, int, int]: + def get_dimensions(self) -> tuple[int, int, int]: """Get the dimensions of the image (height, width, channels/count). Returns: @@ -451,9 +451,7 @@ def array(self) -> np.ndarray: raise RuntimeError("Image source (_src) is not available.") - def to_ext_image( - self, maxcell: Optional[int] = None, channel: Optional[Union[int, List[int]]] = None - ) -> "ExtImage": + def to_ext_image(self, maxcell: int | None = None, channel: int | list[int] | None = None) -> "ExtImage": """Convert this `SpatRasterImage` to an `ExtImage` (in-memory PIL/numpy based). Args: @@ -485,12 +483,12 @@ def to_ext_image( f"Image downsampled from {current_width}x{current_height} to {target_width}x{target_height} to meet maxcell={maxcell}" ) - out_shape: Optional[Tuple[int, int, int]] = None + out_shape: tuple[int, int, int] | None = None if target_height != current_height or target_width != current_width: out_shape = (num_channels, target_height, target_width) # Select channels - bands_to_read: Optional[Union[int, List[int]]] = None + bands_to_read: int | list[int] | None = None if channel is not None: if isinstance(channel, int): bands_to_read = channel + 1 @@ -529,12 +527,12 @@ class BioFormatsImage(AlignedSpatialImage): def __init__( self, - path: Union[str, Path], - extent: Optional[Dict[str, float]] = None, + path: str | Path, + extent: dict[str, float] | None = None, is_full: bool = True, - origin: Optional[List[float]] = None, - transformation: Optional[Union[List[Dict[str, Any]], np.ndarray]] = None, - metadata: Optional[dict] = None, + origin: list[float] | None = None, + transformation: list[dict[str, Any]] | np.ndarray | None = None, + metadata: dict | None = None, validate: bool = True, ): """Initialize the BioFormatsImage. @@ -572,8 +570,8 @@ def __init__( self._is_full = is_full self._origin = [0.0, 0.0] if origin is None else origin - self._transformation_list: List[Dict[str, Any]] = [] - self._combined_affine_matrix: Optional[np.ndarray] = None + self._transformation_list: list[dict[str, Any]] = [] + self._combined_affine_matrix: np.ndarray | None = None if transformation is not None: if isinstance(transformation, np.ndarray): @@ -612,7 +610,7 @@ def _get_aicsimage(self): raise RuntimeError(f"Error initializing AICSImage for {self._path}: {e}") # method written by llm - def _infer_full_extent(self) -> Dict[str, float]: + def _infer_full_extent(self) -> dict[str, float]: """Infers the full spatial extent from image metadata using aicsimageio.""" try: img = self._get_aicsimage() @@ -675,7 +673,7 @@ def _infer_full_extent(self) -> Dict[str, float]: def __repr__(self): dims = self.get_dimensions() # X, Y, C, Z, T dim_str = f"X:{dims[0]}, Y:{dims[1]}, C:{dims[2]}, Z:{dims[3]}, T:{dims[4]}" - output = f"{type(self).__name__}(path='{str(self._path)}', dims=({dim_str})" + output = f"{type(self).__name__}(path='{self._path!s}', dims=({dim_str})" if len(self.metadata) > 0: output += ", metadata=" + ut.print_truncated_dict(self.metadata) @@ -685,7 +683,7 @@ def __repr__(self): def __str__(self) -> str: output = f"class: {type(self).__name__}\n" - output += f"path: {str(self._path)}\n" + output += f"path: {self._path!s}\n" dims = self.get_dimensions() output += f"dimensions (X,Y,C,Z,T): {dims[0]}, {dims[1]}, {dims[2]}, {dims[3]}, {dims[4]}\n" @@ -700,7 +698,7 @@ def __str__(self) -> str: if self._combined_affine_matrix is not None: output += f"combined_affine_matrix: {self._combined_affine_matrix.tolist()}\n" - output += f"metadata({str(len(self.metadata))}): {ut.print_truncated_list(list(self.metadata.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" + output += f"metadata({len(self.metadata)!s}): {ut.print_truncated_list(list(self.metadata.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" return output @@ -727,7 +725,7 @@ def img_source(self, as_path: bool = False) -> str: """Get the source file path.""" return str(self._path) - def get_extent(self) -> Dict[str, float]: + def get_extent(self) -> dict[str, float]: """Get the spatial extent of the image, applying stored transformations to the base extent.""" if self._combined_affine_matrix is not None: return _transform_extent(self._base_extent, self._combined_affine_matrix) @@ -739,7 +737,7 @@ def get_extent(self) -> Dict[str, float]: return self._base_extent.copy() - def set_extent(self, extent: Dict[str, float], in_place: bool = False) -> "BioFormatsImage": + def set_extent(self, extent: dict[str, float], in_place: bool = False) -> "BioFormatsImage": """Set the base spatial extent of the image (pre-transformation). To change transformations, use the `transformation` property or specific methods. @@ -764,12 +762,12 @@ def is_full(self, value: bool): self._is_full = value @property - def origin(self) -> List[float]: + def origin(self) -> list[float]: """Spatial coordinates [x, y] of the image's own origin.""" return self._origin @origin.setter - def origin(self, value: List[float]): + def origin(self, value: list[float]): """Set the spatial origin [x,y].""" if not (isinstance(value, list) and len(value) == 2 and all(isinstance(x, (int, float)) for x in value)): raise ValueError("Origin must be a list/tuple of two numbers [x, y].") @@ -777,7 +775,7 @@ def origin(self, value: List[float]): self._origin = value @property - def transformation(self) -> Optional[Union[List[Dict[str, Any]], np.ndarray]]: + def transformation(self) -> list[dict[str, Any]] | np.ndarray | None: """Stored transformation(s) to be applied. Returns: @@ -793,7 +791,7 @@ def transformation(self) -> Optional[Union[List[Dict[str, Any]], np.ndarray]]: def transformation(self): raise NotImplementedError("Setting transformations are not supported.") - def get_dimensions(self) -> Tuple[int, int, int, int, int]: + def get_dimensions(self) -> tuple[int, int, int, int, int]: """Get the dimensions of the image (X, Y, C, Z, T) from metadata. This refers to the dimensions of the source image file, not affected by transformations. @@ -816,15 +814,15 @@ def get_dimensions(self) -> Tuple[int, int, int, int, int]: return (0, 0, 0, 0, 0) @property - def shape(self) -> Tuple[int, int, int, int, int]: + def shape(self) -> tuple[int, int, int, int, int]: """Alias for get_dimensions, returning (X,Y,C,Z,T).""" return self.get_dimensions() def img_raster( self, - resolution: Optional[int] = None, - scene: Optional[int] = 0, - channel: Optional[Union[int, List[int]]] = None, + resolution: int | None = None, + scene: int | None = 0, + channel: int | list[int] | None = None, **kwargs, ) -> Image.Image: """Load the image data as a PIL Image, applying transformations. @@ -845,9 +843,9 @@ class ExtImage(AlignedSpatialImage): def __init__( self, - image: Union[Image.Image, np.ndarray], - extent: Optional[Dict[str, float]] = None, - metadata: Optional[dict] = None, + image: Image.Image | np.ndarray, + extent: dict[str, float] | None = None, + metadata: dict | None = None, ): """Initialize an ExtImage. @@ -866,7 +864,7 @@ def __init__( if isinstance(image, np.ndarray): self._array: np.ndarray = image.copy() - self._pil_image_cache: Optional[Image.Image] = None + self._pil_image_cache: Image.Image | None = None elif isinstance(image, Image.Image): self._array: np.ndarray = np.array(image) self._pil_image_cache = image.copy() @@ -922,7 +920,7 @@ def __str__(self) -> str: ) output += f"dimensions: {shape_str}\n" output += f"extent: xmin={self._extent['xmin']:.2f}, xmax={self._extent['xmax']:.2f}, ymin={self._extent['ymin']:.2f}, ymax={self._extent['ymax']:.2f}\n" - output += f"metadata({str(len(self.metadata))}): {ut.print_truncated_list(list(self.metadata.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" + output += f"metadata({len(self.metadata)!s}): {ut.print_truncated_list(list(self.metadata.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" return output @@ -936,13 +934,13 @@ def copy(self) -> "ExtImage": def img_source(self, as_path: bool = False) -> None: """Get the source file path (always None for in-memory ExtImage).""" - return None + return - def get_extent(self) -> Dict[str, float]: + def get_extent(self) -> dict[str, float]: """Get the extent of the image.""" return self._extent.copy() - def set_extent(self, extent: Dict[str, float], in_place: bool = False) -> "ExtImage": + def set_extent(self, extent: dict[str, float], in_place: bool = False) -> "ExtImage": """Set the extent of the image.""" _validate_extent(extent) obj = self if in_place else self.copy() @@ -955,11 +953,11 @@ def array(self) -> np.ndarray: return self._array @property - def shape(self) -> Tuple[int, ...]: + def shape(self) -> tuple[int, ...]: """Get the shape of the image array (height, width, channels) or (height, width).""" return self._array.shape - def get_dimensions(self) -> Tuple[int, ...]: + def get_dimensions(self) -> tuple[int, ...]: """Get the dimensions of the image array (height, width, channels) or (height, width).""" return self._array.shape diff --git a/src/spatialfeatureexperiment/coercions.py b/src/spatialfeatureexperiment/coercions.py index a21de59..22dc59e 100644 --- a/src/spatialfeatureexperiment/coercions.py +++ b/src/spatialfeatureexperiment/coercions.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Literal, Optional, Union +from typing import Any, Literal from warnings import warn import geopandas as gpd @@ -25,7 +25,7 @@ def dataframe_to_geopandas( spatial_coordinates_names: list = None, spot_diameter: float = None, buffer_radius: float = 1.0, - vertices_col: Optional[str] = None, # specifically for POLYGON/MULTIPOINT from lists of coords + vertices_col: str | None = None, # specifically for POLYGON/MULTIPOINT from lists of coords geometry_type: Literal["POINT", "POLYGON", "MULTIPOINT"] = "POINT", end_cap_style: Literal["ROUND", "FLAT", "SQUARE"] = "ROUND", ) -> gpd.GeoDataFrame: @@ -134,9 +134,9 @@ def df_dict_to_gdf_dict( geometry_type: Literal["POINT", "POLYGON", "MULTIPOINT"] = "POINT", spot_diameter: float = None, buffer_radius: float = 1.0, - vertices_col: Optional[str] = None, + vertices_col: str | None = None, end_cap_style: Literal["ROUND", "FLAT", "SQUARE"] = "ROUND", -) -> Dict[str, gpd.GeoDataFrame]: +) -> dict[str, gpd.GeoDataFrame]: """Convert a list of DataFrames to a list of GeoPandas DataFrames. Args: @@ -230,17 +230,17 @@ def spatial_coords_to_col_geometries( def spe_to_sfe( spe: SpatialExperiment, - row_geometries: Optional[Dict[str, gpd.GeoDataFrame]] = None, - column_geometries: Optional[Dict[str, gpd.GeoDataFrame]] = None, - annotation_geometries: Optional[Dict[str, gpd.GeoDataFrame]] = None, + row_geometries: dict[str, gpd.GeoDataFrame] | None = None, + column_geometries: dict[str, gpd.GeoDataFrame] | None = None, + annotation_geometries: dict[str, gpd.GeoDataFrame] | None = None, spatial_coordinates_names: list = None, row_geometry_type: Literal["POINT", "POLYGON", "MULTIPOINT"] = "POINT", annotation_geometry_type: Literal["POINT", "POLYGON", "MULTIPOINT"] = "POLYGON", - vertices_col_row: Optional[str] = None, - vertices_col_annot: Optional[str] = None, + vertices_col_row: str | None = None, + vertices_col_annot: str | None = None, buffer_radius_row: float = 1.0, buffer_radius_annot: float = 1.0, - spatial_graphs: Optional[Dict[str, Union[Graph, Any]]] = None, + spatial_graphs: dict[str, Graph | Any] | None = None, spot_diameter: float = None, unit: str = None, end_cap_style: Literal["ROUND", "FLAT", "SQUARE"] = "ROUND", diff --git a/src/spatialfeatureexperiment/sfe.py b/src/spatialfeatureexperiment/sfe.py index 3111bf8..4ebdb96 100644 --- a/src/spatialfeatureexperiment/sfe.py +++ b/src/spatialfeatureexperiment/sfe.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any from warnings import warn import biocutils as ut @@ -39,7 +39,7 @@ def _sanitize_spatial_graphs(spatial_graph, sample_ids): return spatial_graph -def _validate_geometries(geometries: Dict[str, gpd.GeoDataFrame], prop_name: str): +def _validate_geometries(geometries: dict[str, gpd.GeoDataFrame], prop_name: str): """Validate geometry objects.""" if geometries is None or len(geometries) == 0: return @@ -101,26 +101,26 @@ class SpatialFeatureExperiment(SpatialExperiment): def __init__( self, - assays: Dict[str, Any] = None, - row_ranges: Optional[GRangesOrGRangesList] = None, - row_data: Optional[BiocFrame] = None, - column_data: Optional[BiocFrame] = None, - row_names: Optional[List[str]] = None, - column_names: Optional[List[str]] = None, - metadata: Optional[Union[Dict[str, Any], ut.NamedList]] = None, - reduced_dims: Optional[Dict[str, Any]] = None, - main_experiment_name: Optional[str] = None, - alternative_experiments: Optional[Dict[str, Any]] = None, + assays: dict[str, Any] = None, + row_ranges: GRangesOrGRangesList | None = None, + row_data: BiocFrame | None = None, + column_data: BiocFrame | None = None, + row_names: list[str] | None = None, + column_names: list[str] | None = None, + metadata: dict[str, Any] | ut.NamedList | None = None, + reduced_dims: dict[str, Any] | None = None, + main_experiment_name: str | None = None, + alternative_experiments: dict[str, Any] | None = None, alternative_experiment_check_dim_names: bool = True, - row_pairs: Optional[Any] = None, - column_pairs: Optional[Any] = None, - spatial_coords: Optional[Union[BiocFrame, np.ndarray]] = None, - img_data: Optional[BiocFrame] = None, + row_pairs: Any | None = None, + column_pairs: Any | None = None, + spatial_coords: BiocFrame | np.ndarray | None = None, + img_data: BiocFrame | None = None, # SFE args - col_geometries: Optional[Dict[str, gpd.GeoDataFrame]] = None, - row_geometries: Optional[Dict[str, gpd.GeoDataFrame]] = None, - annot_geometries: Optional[Dict[str, gpd.GeoDataFrame]] = None, - spatial_graphs: Optional[Dict[str, Union[Graph, Any]]] = None, + col_geometries: dict[str, gpd.GeoDataFrame] | None = None, + row_geometries: dict[str, gpd.GeoDataFrame] | None = None, + annot_geometries: dict[str, gpd.GeoDataFrame] | None = None, + spatial_graphs: dict[str, Graph | Any] | None = None, unit: str = "full_res_image_pixel", _validate: bool = True, **kwargs, @@ -427,19 +427,19 @@ def __str__(self) -> str: output += "\nGeometries:\n" if col_geoms: - output += f"col_geometries({str(len(col_geoms))}): {ut.print_truncated_list(list(col_geoms.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" + output += f"col_geometries({len(col_geoms)!s}): {ut.print_truncated_list(list(col_geoms.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" if row_geoms: - output += f"row_geometries({str(len(row_geoms))}): {ut.print_truncated_list(list(row_geoms.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" + output += f"row_geometries({len(row_geoms)!s}): {ut.print_truncated_list(list(row_geoms.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" if annot_geoms: - output += f"annot_geometries({str(len(annot_geoms))}): {ut.print_truncated_list(list(annot_geoms.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" + output += f"annot_geometries({len(annot_geoms)!s}): {ut.print_truncated_list(list(annot_geoms.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" # Add graphs info graphs = self._spatial_graphs if graphs is not None: output += "Graphs:" - output += f"spatial_graphs({str(len(graphs))}):{ut.print_truncated_list(list(graphs.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" + output += f"spatial_graphs({len(graphs)!s}):{ut.print_truncated_list(list(graphs.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" return output @@ -489,20 +489,20 @@ def unit(self, unit: str): #####>> geoms <<##### ##################### - def get_col_geometries(self) -> Dict[str, gpd.GeoDataFrame]: + def get_col_geometries(self) -> dict[str, gpd.GeoDataFrame]: """Get column geometries.""" return self._col_geometries - def get_row_geometries(self) -> Dict[str, gpd.GeoDataFrame]: + def get_row_geometries(self) -> dict[str, gpd.GeoDataFrame]: """Get row geometries.""" return self._row_geometries - def get_annot_geometries(self) -> Dict[str, gpd.GeoDataFrame]: + def get_annot_geometries(self) -> dict[str, gpd.GeoDataFrame]: """Get annotation geometries.""" return self._annot_geometries def set_col_geometries( - self, geometries: Dict[str, gpd.GeoDataFrame], in_place: bool = False + self, geometries: dict[str, gpd.GeoDataFrame], in_place: bool = False ) -> SpatialFeatureExperiment: """Set column geometries. @@ -524,7 +524,7 @@ def set_col_geometries( return output def set_row_geometries( - self, geometries: Dict[str, gpd.GeoDataFrame], in_place: bool = False + self, geometries: dict[str, gpd.GeoDataFrame], in_place: bool = False ) -> SpatialFeatureExperiment: """Set row geometries. @@ -546,7 +546,7 @@ def set_row_geometries( return output def set_annot_geometries( - self, geometries: Dict[str, gpd.GeoDataFrame], in_place: bool = False + self, geometries: dict[str, gpd.GeoDataFrame], in_place: bool = False ) -> SpatialFeatureExperiment: """Set annotation geometries. @@ -570,12 +570,12 @@ def set_annot_geometries( return output @property - def col_geometries(self) -> Dict[str, gpd.GeoDataFrame]: + def col_geometries(self) -> dict[str, gpd.GeoDataFrame]: """Get column geometries.""" return self.get_col_geometries() @col_geometries.setter - def col_geometries(self, geometries: Dict[str, gpd.GeoDataFrame]): + def col_geometries(self, geometries: dict[str, gpd.GeoDataFrame]): """Set column geometries.""" warn( "Setting property 'col_geometries' is an in-place operation, use 'set_col_geometries' instead.", @@ -584,12 +584,12 @@ def col_geometries(self, geometries: Dict[str, gpd.GeoDataFrame]): self.set_col_geometries(geometries, in_place=True) @property - def row_geometries(self) -> Dict[str, gpd.GeoDataFrame]: + def row_geometries(self) -> dict[str, gpd.GeoDataFrame]: """Get row geometries.""" return self.get_row_geometries() @row_geometries.setter - def row_geometries(self, geometries: Dict[str, gpd.GeoDataFrame]): + def row_geometries(self, geometries: dict[str, gpd.GeoDataFrame]): """Set row geometries.""" warn( "Setting property 'row_geometries' is an in-place operation, use 'set_row_geometries' instead.", @@ -598,12 +598,12 @@ def row_geometries(self, geometries: Dict[str, gpd.GeoDataFrame]): self.set_row_geometries(geometries, in_place=True) @property - def annot_geometries(self) -> Dict[str, gpd.GeoDataFrame]: + def annot_geometries(self) -> dict[str, gpd.GeoDataFrame]: """Get annotation geometries.""" return self.get_annot_geometries() @annot_geometries.setter - def annot_geometries(self, geometries: Dict[str, gpd.GeoDataFrame]): + def annot_geometries(self, geometries: dict[str, gpd.GeoDataFrame]): """Set annotation geometries.""" warn( "Setting property 'annot_geometries' is an in-place operation, use 'set_annot_geometries' instead.", @@ -615,11 +615,11 @@ def annot_geometries(self, geometries: Dict[str, gpd.GeoDataFrame]): #####>> spatial_graphs <<##### ############################## - def get_spatial_graphs(self) -> Optional[BiocFrame]: + def get_spatial_graphs(self) -> BiocFrame | None: """Get spatial neighborhood graphs.""" return self._spatial_graphs - def set_spatial_graphs(self, graphs: Optional[BiocFrame], in_place: bool = False) -> SpatialFeatureExperiment: + def set_spatial_graphs(self, graphs: BiocFrame | None, in_place: bool = False) -> SpatialFeatureExperiment: """Set spatial neighborhood graphs. Args: @@ -641,12 +641,12 @@ def set_spatial_graphs(self, graphs: Optional[BiocFrame], in_place: bool = False return output @property - def spatial_graphs(self) -> Optional[BiocFrame]: + def spatial_graphs(self) -> BiocFrame | None: """Get spatial graphs.""" return self.get_spatial_graphs() @spatial_graphs.setter - def spatial_graphs(self, graphs: Optional[BiocFrame]): + def spatial_graphs(self, graphs: BiocFrame | None): """Set spatial graphs.""" warn( "Setting property 'spatial_graphs' is an in-place operation, use 'set_spatial_graphs' instead.", @@ -660,8 +660,8 @@ def spatial_graphs(self, graphs: Optional[BiocFrame]): def get_slice( self, - rows: Optional[Union[str, int, bool, List]] = None, - columns: Optional[Union[str, int, bool, List]] = None, + rows: str | int | bool | list | None = None, + columns: str | int | bool | list | None = None, ) -> SpatialFeatureExperiment: """Get a slice of the experiment. @@ -747,7 +747,7 @@ def get_slice( def set_column_data( self, - cols: Optional[BiocFrame], + cols: BiocFrame | None, replace_column_names: bool = False, in_place: bool = False, ) -> SpatialFeatureExperiment: @@ -796,7 +796,7 @@ def set_column_data( def to_anndata( self, include_alternative_experiments: bool = False - ) -> Tuple["anndata.AnnData", Dict[str, "anndata.AnnData"]]: + ) -> tuple[anndata.AnnData, dict[str, anndata.AnnData]]: """Transform :py:class:`~SpatialFeatureExperiment`-like into a :py:class:`~anndata.AnnData` representation. This method extends the :py:meth:`~SpatialExperiment.to_anndata` method from the parent class @@ -833,9 +833,9 @@ def to_anndata( def from_spatial_experiment( cls, input: SpatialExperiment, - row_geometries: Optional[Dict[str, gpd.GeoDataFrame]] = None, - column_geometries: Optional[Dict[str, gpd.GeoDataFrame]] = None, - annotation_geometries: Optional[Dict[str, gpd.GeoDataFrame]] = None, + row_geometries: dict[str, gpd.GeoDataFrame] | None = None, + column_geometries: dict[str, gpd.GeoDataFrame] | None = None, + annotation_geometries: dict[str, gpd.GeoDataFrame] | None = None, spatial_coordinates_names: list = None, annotation_geometry_type: str = "POLYGON", spatial_graphs: BiocFrame = None,