diff --git a/bento/__init__.py b/bento/__init__.py index 305679d..16c5153 100644 --- a/bento/__init__.py +++ b/bento/__init__.py @@ -1,6 +1,7 @@ -from . import io -from . import plotting as pl -from . import tools as tl from . import _utils as ut from . import geometry as geo +from . import plotting as pl +from . import tools as tl +from . import io +from .io import prep from .plotting import _colors as colors diff --git a/bento/geometry/_geometry.py b/bento/geometry/_geometry.py index f06a953..f92963d 100644 --- a/bento/geometry/_geometry.py +++ b/bento/geometry/_geometry.py @@ -321,6 +321,7 @@ def set_points_metadata( sdata.points[points_key] = sdata.points[points_key].assign(**{name: series}) + def set_shape_metadata( sdata: SpatialData, shape_key: str, @@ -380,7 +381,7 @@ def _check_points_sync(sdata, points_key): points = sdata.points[points_key] if points.attrs["spatialdata_attrs"]["instance_key"] not in points.columns: raise ValueError( - f"Points {points_key} not synced to instance_key shape element. Run bento.io.format_sdata() to setup SpatialData object for bento-tools." + f"Points {points_key} not synced to instance_key shape element. Run bento.io.prep() to setup SpatialData object for bento-tools." ) @@ -407,5 +408,5 @@ def _check_shape_sync(sdata, shape_key, instance_key): and shape_key not in sdata.shapes[instance_key].columns ): raise ValueError( - f"Shape {shape_key} not synced to instance_key shape element. Run bento.io.format_sdata() to setup SpatialData object for bento-tools." + f"Shape {shape_key} not synced to instance_key shape element. Run bento.io.prep() to setup SpatialData object for bento-tools." ) diff --git a/bento/io/__init__.py b/bento/io/__init__.py index ab1950d..d9dbe4f 100644 --- a/bento/io/__init__.py +++ b/bento/io/__init__.py @@ -1 +1 @@ -from ._io import format_sdata \ No newline at end of file +from ._io import prep \ No newline at end of file diff --git a/bento/io/_io.py b/bento/io/_io.py index ae9e141..c532077 100644 --- a/bento/io/_io.py +++ b/bento/io/_io.py @@ -4,19 +4,21 @@ warnings.filterwarnings("ignore") from spatialdata._core.spatialdata import SpatialData -from spatialdata.models import ShapesModel, TableModel +from spatialdata.models import TableModel from ..geometry import sjoin_points, sjoin_shapes -def format_sdata( +def prep( sdata: SpatialData, points_key: str = "transcripts", - feature_key: str = "feature_name", + feature_key: str = "feature_name", instance_key: str = "cell_boundaries", shape_keys: List[str] = ["cell_boundaries", "nucleus_boundaries"], ) -> SpatialData: - """Converts shape indices to strings and indexes points to shapes and add as columns to `data.points[point_key]`. + """Computes spatial indices for elements in SpatialData to enable usage of bento-tools. + + Specifically, this function indexes points to shapes and joins shapes to the instance shape. It also computes a count table for the points. Parameters ---------- @@ -61,22 +63,22 @@ def format_sdata( shape_sjoin.append(shape_key) if len(point_sjoin) > 0: - sdata = sjoin_points( - sdata=sdata, points_key=points_key, shape_keys=point_sjoin - ) + sdata = sjoin_points(sdata=sdata, points_key=points_key, shape_keys=point_sjoin) if len(shape_sjoin) > 0: sdata = sjoin_shapes( sdata=sdata, instance_key=instance_key, shape_keys=shape_sjoin - ) + ) # Recompute count table - table = TableModel.parse(sdata.aggregate( - values=points_key, - instance_key=instance_key, - by=instance_key, - value_key=feature_key, - aggfunc="count", - ).table) + table = TableModel.parse( + sdata.aggregate( + values=points_key, + instance_key=instance_key, + by=instance_key, + value_key=feature_key, + aggfunc="count", + ).table + ) del sdata.table sdata.table = table diff --git a/bento/plotting/__init__.py b/bento/plotting/__init__.py index fae1e19..07910e9 100644 --- a/bento/plotting/__init__.py +++ b/bento/plotting/__init__.py @@ -1,5 +1,5 @@ -from ._multidimensional import flux_summary, obs_stats +from ._multidimensional import flux_summary, shape_stats from ._lp import lp_diff_discrete, lp_dist, lp_genes from ._plotting import points, density, shapes, flux, fluxmap, fe -from ._signatures import colocation, factor \ No newline at end of file +from ._signatures import colocation, factor diff --git a/bento/plotting/_lp.py b/bento/plotting/_lp.py index 47e61fa..805c60c 100644 --- a/bento/plotting/_lp.py +++ b/bento/plotting/_lp.py @@ -120,8 +120,8 @@ def lp_genes( @savefig def lp_diff_discrete(sdata: SpatialData, phenotype: str, fname: str = None): - """Visualize gene pattern frequencies between groups of cells by plotting - log2 fold change and -log10p, similar to volcano plot. Run after :func:`bento.tl.lp_diff()` + """Visualize gene pattern frequencies between groups of cells. Plots the + log2 fold change and -log10 p-value of each gene, similar to volcano plot. Run after :func:`bento.tl.lp_diff_discrete()` Parameters ---------- diff --git a/bento/plotting/_plotting.py b/bento/plotting/_plotting.py index 02e0125..bca7b34 100644 --- a/bento/plotting/_plotting.py +++ b/bento/plotting/_plotting.py @@ -67,6 +67,46 @@ def points( fname=None, **kwargs, ): + """ + Plot points scatter. + + Parameters + ---------- + data : SpatialData + Spatial formatted SpatialData object + hue : str, optional + Variable name to color points by, by default None + hue_order : list, optional + Order of hue levels, by default None + size : str, optional + Variable name to size points by, by default None + style : str, optional + Variable name to style points by, by default None + shapes : list, optional + List of shape names to plot, by default None. If None, will plot cell and nucleus shapes by default. + hide_outside : bool, optional + Whether to hide molecules outside of cells, by default True + title : str, optional + Title of plot, by default None + dx : float, optional + Size of scalebar in units, by default 0.1 + units : str, optional + Units of scalebar, by default "um" + square : bool, optional + Whether to make axis square, by default False + axis_visible : bool, optional + Whether to show axis, by default False + frame_visible : bool, optional + Whether to show frame, by default True + ax : matplotlib.axes.Axes, optional + Axis to plot on, by default None. If None, will use current axis. + sync_shapes : bool, optional + Whether to synchronize shapes with points, by default True + shapes_kws : dict, optional + Keyword arguments for shapes, by default {} + fname : str, optional + Filename to save figure to, by default None. If None, will not save figure. + """ points = _prepare_points_df( sdata, @@ -108,6 +148,44 @@ def density( fname=None, **kwargs, ): + """ + Plot points as 2D density. + + Parameters + ---------- + data : SpatialData + Spatial formatted SpatialData object + kind : str, optional + Type of density plot, by default "hist". Options: "hist", "kde" + hue : str, optional + Variable name to color points by, by default None + hue_order : list, optional + Order of hue levels, by default None + shapes : list, optional + List of shape names to plot, by default None. If None, will plot cell and nucleus shapes by default. + hide_outside : bool, optional + Whether to hide molecules outside of cells, by default True + title : str, optional + Title of plot, by default None + dx : float, optional + Size of scalebar in units, by default 0.1 + units : str, optional + Units of scalebar, by default "um" + square : bool, optional + Whether to make axis square, by default False + axis_visible : bool, optional + Whether to show axis, by default False + frame_visible : bool, optional + Whether to show frame, by default True + ax : matplotlib.axes.Axes, optional + Axis to plot on, by default None. If None, will use current axis. + sync_shapes : bool, optional + Whether to synchronize shapes with points, by default True + shape_kws : dict, optional + Keyword arguments for shapes, by default {} + fname : str, optional + Filename to save figure to, by default None. If None, will not save figure. + """ points = _prepare_points_df( sdata, @@ -147,6 +225,39 @@ def shapes( fname=None, **kwargs, ): + """Plot shape layers. + + Parameters + ---------- + data : SpatialData + Spatial formatted SpatialData + shapes : list, optional + List of shapes to plot, by default None. If None, will plot cell and nucleus shapes by default. + color : str, optional + Color name, by default None. If None, will use default theme color. + color_style : "outline" or "fill" + Whether to color the outline or fill of the shape, by default "outline". + hide_outside : bool, optional + Whether to hide molecules outside of cells, by default True. + dx : float, optional + Size of scalebar in units, by default 0.1. + units : str, optional + Units of scalebar, by default "um". + axis_visible : bool, optional + Whether to show axis, by default False. + frame_visible : bool, optional + Whether to show frame, by default True. + title : str, optional + Title of plot, by default None. + square : bool, optional + Whether to make axis square, by default False. + ax : matplotlib.axes.Axes, optional + Axis to plot on, by default None. If None, will use current axis. + sync_shapes : bool, optional + Whether to synchronize shapes with points, by default True. + fname : str, optional + Filename to save figure to, by default None. If None, will not save figure. + """ if shapes and not isinstance(shapes, list): shapes = [shapes] @@ -176,23 +287,6 @@ def _shapes( ax=None, **kwargs, ): - """Plot layer(s) of shapes. - - Parameters - ---------- - data : SpatialData - Spatial formatted SpatialData - shapes : list, optional - List of shapes to plot, by default None. If None, will plot cell and nucleus shapes by default. - color : str, optional - Color name, by default None. If None, will use default theme color. - color_style : "outline" or "fill" - Whether to color the outline or fill of the shape, by default "outline". - hide_outside : bool, optional - Whether to hide molecules outside of cells, by default True. - ax : matplotlib.axes.Axes, optional - Axis to plot on, by default None. If None, will use current axis. - """ if shapes is None: shapes = [instance_key, nucleus_key] @@ -271,6 +365,39 @@ def flux( fname=None, **kwargs, ): + """Plot colorized representation of RNAflux embedding. + + Parameters + ---------- + data : SpatialData + Spatial formatted SpatialData + res : float, optional + Resolution of fluxmap, by default 0.05 + shapes : list, optional + List of shapes to plot, by default None. If None, will plot cell and nucleus shapes by default. + hide_outside : bool, optional + Whether to hide molecules outside of cells, by default True. + axis_visible : bool, optional + Whether to show axis, by default False. + frame_visible : bool, optional + Whether to show frame, by default True. + title : str, optional + Title of plot, by default None. + dx : float, optional + Size of scalebar in units, by default 0.1. + units : str, optional + Units of scalebar, by default "um". + square : bool, optional + Whether to make axis square, by default False. + ax : matplotlib.axes.Axes, optional + Axis to plot on, by default None. If None, will use current axis. + sync_shapes : bool, optional + Whether to synchronize shapes with points, by default True. + shape_kws : dict, optional + Keyword arguments for shapes, by default {}. + fname : str, optional + Filename to save figure to, by default None. If None, will not save figure. + """ if ax is None: ax = plt.gca() @@ -301,6 +428,45 @@ def fe( fname=None, **kwargs, ): + """Plot spatial heatmap of flux enrichment scores. + + Parameters + ---------- + data : SpatialData + Spatial formatted SpatialData + gs : str + Gene set name + res : float, optional + Resolution of fluxmap, by default 0.05 + shapes : list, optional + List of shape names to plot, by default None. If None, will plot cell and nucleus shapes by default. + cmap : str, optional + Colormap, by default None. If None, will use red2blue colormap. + cbar : bool, optional + Whether to show colorbar, by default True + hide_outside : bool, optional + Whether to hide molecules outside of cells, by default True. + axis_visible : bool, optional + Whether to show axis, by default False. + frame_visible : bool, optional + Whether to show frame, by default True. + title : str, optional + Title of plot, by default None. + dx : float, optional + Size of scalebar in units, by default 0.1. + units : str, optional + Units of scalebar, by default "um". + square : bool, optional + Whether to make axis square, by default False. + ax : matplotlib.axes.Axes, optional + Axis to plot on, by default None. If None, will use current axis. + sync_shapes : bool, optional + Whether to synchronize shapes with points, by default True. + shape_kws : dict, optional + Keyword arguments for shapes, by default {}. + fname : str, optional + Filename to save figure to, by default None. If None, will not save figure. + """ if ax is None: ax = plt.gca() diff --git a/bento/tools/__init__.py b/bento/tools/__init__.py index 8133f7d..b973494 100644 --- a/bento/tools/__init__.py +++ b/bento/tools/__init__.py @@ -1,13 +1,39 @@ from ._colocation import coloc_quotient, colocation -from ._composition import comp_diff +from ._composition import comp, comp_diff from ._flux import flux, fluxmap from ._flux_enrichment import fe, fe_fazal2019, fe_xia2019, gene_sets, load_gene_sets from ._lp import lp, lp_stats, lp_diff_discrete, lp_diff_continuous -from ._point_features import analyze_points, list_point_features, register_point_feature +from ._point_features import ( + analyze_points, + list_point_features, + register_point_feature, + PointFeature, + ShapeProximity, + ShapeAsymmetry, + PointDispersionNorm, + ShapeDispersionNorm, + ShapeDistance, + ShapeOffset, + PointDispersion, + ShapeDispersion, + RipleyStats, + ShapeEnrichment, + +) from ._shape_features import ( analyze_shapes, - obs_stats, + shape_stats, register_shape_feature, list_shape_features, + area, + aspect_ratio, + bounds, + density, + opening, + perimeter, + radius, + raster, + second_moment, + span, ) from ._decomposition import decompose \ No newline at end of file diff --git a/bento/tools/_colocation.py b/bento/tools/_colocation.py index 6017915..8cdf563 100644 --- a/bento/tools/_colocation.py +++ b/bento/tools/_colocation.py @@ -9,7 +9,7 @@ from kneed import KneeLocator from tqdm.auto import tqdm -from bento.geometry import get_points +from ..geometry import get_points from ._neighborhoods import _count_neighbors from ._decomposition import decompose diff --git a/bento/tools/_composition.py b/bento/tools/_composition.py index b079556..831fcff 100644 --- a/bento/tools/_composition.py +++ b/bento/tools/_composition.py @@ -5,7 +5,7 @@ import numpy as np from ..geometry import get_points -#from .._utils import track +# from .._utils import track from spatialdata._core.spatialdata import SpatialData @@ -57,9 +57,26 @@ def _get_compositions(points: pd.DataFrame, shape_names: list) -> pd.DataFrame: return comp_stats -def comp_diff( - sdata: SpatialData, shape_names: list, groupby: str, ref_group: str -): +def comp(sdata: SpatialData, shape_names: list): + """Calculate the average gene composition for shapes across all cells. + + Parameters + ---------- + sdata : spatialdata.SpatialData + Spatial formatted SpatialData object. + shape_names : list of str + Names of shapes to calculate compositions for. + + """ + points = get_points(sdata, astype="pandas") + + # Get average gene compositions for each batch + comp_stats = _get_compositions(points, shape_names) + + sdata.table.uns["comp_stats"] = comp_stats + + +def comp_diff(sdata: SpatialData, shape_names: list, groupby: str, ref_group: str): """Calculate the average difference in gene composition for shapes across batches of cells. Uses the Wasserstein distance. Parameters diff --git a/bento/tools/_flux.py b/bento/tools/_flux.py index 522b17c..b6e011b 100644 --- a/bento/tools/_flux.py +++ b/bento/tools/_flux.py @@ -41,7 +41,7 @@ def flux( recompute: bool = False, ): """ - RNAflux: Embedding each pixel as normalized local composition normalized by cell composition. + Compute RNAflux embeddings of each pixel as local composition normalized by cell composition. For k-nearest neighborhoods or "knn", method, specify n_neighbors. For radius neighborhoods, specify radius. The default method is "radius" with radius = 1/2 of cell radius. RNAflux requires a minimum of 4 genes per cell to compute all embeddings properly. diff --git a/bento/tools/_flux_enrichment.py b/bento/tools/_flux_enrichment.py index d28b3ac..999be1a 100644 --- a/bento/tools/_flux_enrichment.py +++ b/bento/tools/_flux_enrichment.py @@ -4,11 +4,8 @@ import numpy as np import pandas as pd -import dask.dataframe as dd -import pkg_resources from scipy import sparse from spatialdata._core.spatialdata import SpatialData -from spatialdata.models import PointsModel from ..geometry import get_points, set_points_metadata @@ -62,7 +59,7 @@ def fe( min_n: int = 0, ): """ - Perform functional enrichment on point embeddings. Wrapper for decoupler wsum function. + Perform functional enrichment of RNAflux embeddings. Uses decoupler wsum function. Parameters ---------- @@ -165,7 +162,7 @@ def _fe_stats( def load_gene_sets(name): - """Load a gene set from bento. + """Load a gene set; list available ones with `bento.tl.gene_sets`. Parameters ---------- diff --git a/bento/tools/_point_features.py b/bento/tools/_point_features.py index 45f2118..c2de5d9 100644 --- a/bento/tools/_point_features.py +++ b/bento/tools/_point_features.py @@ -29,7 +29,7 @@ def analyze_points( recompute=False, progress: bool = False, ): - """Calculate the set of specified `features` for each point group. Groups are within each cell. + """Calculate features for each point group. Groups are always within each cell. When creating the points_df, it first grabs sdata.points[points_key] and joins shape polygons from sdata.shapes[shape_keys]. The second join is to sdata.shapes[instance_key] to pull in cell polygons and cell features. diff --git a/bento/tools/_shape_features.py b/bento/tools/_shape_features.py index 9eac1dc..3f5c78d 100644 --- a/bento/tools/_shape_features.py +++ b/bento/tools/_shape_features.py @@ -20,7 +20,7 @@ from ..geometry import get_points, get_shape, set_shape_metadata -def _area(sdata: SpatialData, shape_key: str, recompute: bool = False): +def area(sdata: SpatialData, shape_key: str, recompute: bool = False): """ Compute the area of each shape. @@ -34,7 +34,7 @@ def _area(sdata: SpatialData, shape_key: str, recompute: bool = False): If True, forces the computation of the area even if it already exists in the shape metadata. If False (default), the computation is skipped if the area already exists. - Fields + Returns ------ .shapes[shape_key]['{shape}_area'] : float Area of each polygon @@ -71,7 +71,7 @@ def _poly_aspect_ratio(poly): return length / width -def _aspect_ratio(sdata: SpatialData, shape_key: str, recompute: bool = False): +def aspect_ratio(sdata: SpatialData, shape_key: str, recompute: bool = False): """Compute the aspect ratio of the minimum rotated rectangle that contains each shape. Parameters @@ -95,7 +95,7 @@ def _aspect_ratio(sdata: SpatialData, shape_key: str, recompute: bool = False): set_shape_metadata(sdata=sdata, shape_key=shape_key, metadata=ar, column_names=feature_key) -def _bounds(sdata: SpatialData, shape_key: str, recompute: bool = False): +def bounds(sdata: SpatialData, shape_key: str, recompute: bool = False): """Compute the minimum and maximum coordinate values that bound each shape. Parameters @@ -105,7 +105,7 @@ def _bounds(sdata: SpatialData, shape_key: str, recompute: bool = False): shape_key : str Key in `sdata.shapes[shape_key]` that contains the shape information. - Fields + Returns ------ .shapes[shape_key]['{shape}_minx'] : float x-axis lower bound of each polygon @@ -132,7 +132,7 @@ def _bounds(sdata: SpatialData, shape_key: str, recompute: bool = False): set_shape_metadata(sdata=sdata, shape_key=shape_key, metadata=bounds[feat_names], column_names=feature_keys) -def _density(sdata: SpatialData, shape_key: str, recompute: bool = False): +def density(sdata: SpatialData, shape_key: str, recompute: bool = False): """Compute the RNA density of each shape. Parameters @@ -142,7 +142,7 @@ def _density(sdata: SpatialData, shape_key: str, recompute: bool = False): shape_key : str Key in `sdata.shapes[shape_key]` that contains the shape information. - Fields + Returns ------ .shapes[shape_key]['{shape}_density'] : float Density (molecules / shape area) of each polygon @@ -159,7 +159,7 @@ def _density(sdata: SpatialData, shape_key: str, recompute: bool = False): .value_counts() .compute() ) - _area(sdata, shape_key) + area(sdata, shape_key) set_shape_metadata( sdata=sdata, @@ -169,7 +169,7 @@ def _density(sdata: SpatialData, shape_key: str, recompute: bool = False): ) -def _opening(sdata: SpatialData, shape_key: str, proportion: float, recompute: bool = False): +def opening(sdata: SpatialData, shape_key: str, proportion: float, recompute: bool = False): """Compute the opening (morphological) of distance d for each cell. Parameters @@ -177,7 +177,7 @@ def _opening(sdata: SpatialData, shape_key: str, proportion: float, recompute: b sdata : SpatialData Spatial formatted SpatialData - Fields + Returns ------- .shapes[shape_key]['cell_open_{d}_shape'] : Polygons Ratio of long / short axis for each polygon in `.shapes[shape_key]['cell_boundaries']` @@ -188,7 +188,7 @@ def _opening(sdata: SpatialData, shape_key: str, proportion: float, recompute: b if feature_key in sdata.shapes[shape_key].keys() and not recompute: return - _radius(sdata, shape_key) + radius(sdata, shape_key) shapes = get_shape(sdata, shape_key, sync=False) d = proportion * sdata.shapes[shape_key][f"{shape_key}_radius"] @@ -213,7 +213,7 @@ def _second_moment_polygon(centroid, pts): return second_moment -def _second_moment(sdata: SpatialData, shape_key: str, recompute: bool = False): +def second_moment(sdata: SpatialData, shape_key: str, recompute: bool = False): """Compute the second moment of each shape. Parameters @@ -221,7 +221,7 @@ def _second_moment(sdata: SpatialData, shape_key: str, recompute: bool = False): sdata : SpatialData Spatial formatted SpatialData - Fields + Returns ------- .shapes[shape_key]['{shape}_moment'] : float The second moment for each polygon @@ -278,7 +278,7 @@ def _raster_polygon(poly, step=1): return xy -def _raster( +def raster( sdata: SpatialData, shape_key: str, points_key: str = "transcripts", @@ -293,7 +293,7 @@ def _raster( sdata : SpatialData Spatial formatted SpatialData - Fields + Returns ------- .shapes[shape_key]['{shape}_raster'] : np.array Long DataFrame of points annotated by shape from `.shapes[shape_key]['{shape_key}']` @@ -331,7 +331,7 @@ def _raster( sdata.points[feature_key].attrs = transform -def _perimeter(sdata: SpatialData, shape_key: str, recompute: bool = False): +def perimeter(sdata: SpatialData, shape_key: str, recompute: bool = False): """Compute the perimeter of each shape. Parameters @@ -339,7 +339,7 @@ def _perimeter(sdata: SpatialData, shape_key: str, recompute: bool = False): sdata : SpatialData Spatial formatted SpatialData - Fields + Returns ------- `.shapes[shape_key]['{shape}_perimeter']` : np.array Perimeter of each polygon @@ -358,7 +358,7 @@ def _perimeter(sdata: SpatialData, shape_key: str, recompute: bool = False): ) -def _radius(sdata: SpatialData, shape_key: str, recompute: bool = False): +def radius(sdata: SpatialData, shape_key: str, recompute: bool = False): """Compute the radius of each cell. Parameters @@ -366,7 +366,7 @@ def _radius(sdata: SpatialData, shape_key: str, recompute: bool = False): sdata : SpatialData Spatial formatted SpatialData - Fields + Returns ------- .shapes[shape_key]['{shape}_radius'] : np.array Radius of each polygon in `obs['cell_shape']` @@ -393,7 +393,7 @@ def _shape_radius(poly): ).mean() -def _span(sdata: SpatialData, shape_key: str, recompute: bool = False): +def span(sdata: SpatialData, shape_key: str, recompute: bool = False): """Compute the length of the longest diagonal of each shape. Parameters @@ -401,7 +401,7 @@ def _span(sdata: SpatialData, shape_key: str, recompute: bool = False): sdata : SpatialData Spatial formatted SpatialData - Fields + Returns ------- .shapes[shape_key]['{shape}_span'] : float Length of longest diagonal for each polygon @@ -443,24 +443,24 @@ def list_shape_features(): shape_features = dict( - area=_area, - aspect_ratio=_aspect_ratio, - bounds=_bounds, - density=_density, - opening=_opening, - perimeter=_perimeter, - radius=_radius, - raster=_raster, - second_moment=_second_moment, - span=_span, + area=area, + aspect_ratio=aspect_ratio, + bounds=bounds, + density=density, + opening=opening, + perimeter=perimeter, + radius=radius, + raster=raster, + second_moment=second_moment, + span=span, ) -def obs_stats( +def shape_stats( sdata: SpatialData, feature_names: List[str] = ["area", "aspect_ratio", "density"], ): - """Compute features for each cell shape. Convenient wrapper for `bento.tl.shape_features`. + """Compute descriptive stats for cells. Convenient wrapper for `bento.tl.shape_features`. See list of available features in `bento.tl.shape_features`. Parameters @@ -470,9 +470,9 @@ def obs_stats( feature_names : list List of features to compute. See list of available features in `bento.tl.shape_features`. - Fields + Returns ------- - .shapes[shape_key]['{shape}_{feature}'] : np.array + .shapes['cell_boundaries']['cell_boundaries_{feature}'] : np.array Feature of each polygon """ diff --git a/docs/Makefile b/docs/Makefile index cefa9c0..fe517d3 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -21,3 +21,7 @@ help: livehtml: sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +clean: + rm -rf "$(BUILDDIR)" + rm -rf "source/api" \ No newline at end of file diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css index a1099f2..6293b30 100644 --- a/docs/source/_static/custom.css +++ b/docs/source/_static/custom.css @@ -15,6 +15,19 @@ var(--pst-font-family-monospace-system) !important; } +.inline-link { + display: inline-block; +} + +/* right margin */ +.sd-octicon { + margin-right: 0.3em !important; +} + +/* .headerlink{ + +} */ + /* Font size */ /* --pst-font-size-base: 14px; base font size - applied at body / html level */ diff --git a/docs/source/_templates/autosummary/base.rst b/docs/source/_templates/autosummary/base.rst index fd455b5..ca8f628 100644 --- a/docs/source/_templates/autosummary/base.rst +++ b/docs/source/_templates/autosummary/base.rst @@ -5,7 +5,3 @@ .. http://www.sphinx-doc.org/en/stable/ext/autosummary.html#customizing-templates .. _sphx_glr_backref_{{fullname}}: - -.. minigallery:: {{fullname}} - :add-heading: Gallery - :heading-level: - diff --git a/docs/source/_templates/autosummary/class.rst b/docs/source/_templates/autosummary/class.rst index 7ba92f8..4988ea4 100644 --- a/docs/source/_templates/autosummary/class.rst +++ b/docs/source/_templates/autosummary/class.rst @@ -34,6 +34,3 @@ .. _sphx_glr_backref_{{fullname}}: -.. minigallery:: {{fullname}} - :add-heading: Gallery - :heading-level: - diff --git a/docs/source/_templates/autosummary/function.rst b/docs/source/_templates/autosummary/function.rst index 42c6a60..9a74a81 100644 --- a/docs/source/_templates/autosummary/function.rst +++ b/docs/source/_templates/autosummary/function.rst @@ -5,7 +5,3 @@ .. autofunction:: {{ fullname }} .. _sphx_glr_backref_{{fullname}}: - -.. minigallery:: {{fullname}} - :add-heading: Gallery - :heading-level: - diff --git a/docs/source/api.md b/docs/source/api.md index 651ac5d..4274976 100644 --- a/docs/source/api.md +++ b/docs/source/api.md @@ -1,253 +1,251 @@ +```{toctree} +:hidden: true +``` + ```{eval-rst} .. module:: bento - -.. automodule:: bento - :noindex: ``` + # {octicon}`code-square` API Import Bento with: -```python -import bento as bt +```{eval-rst} +.. code-block:: python + + import bento as bt ``` + Bento's API structure takes inspiration from other libraries in the Scverse ecosystem. It is organized under a set of modules including: -- `bt.tl`: subcellular spatial analyses -- `bt.pl`: conveniently plot spatial data and embeddings -- `bt.io`: reading and writing spatial data to `AnnData` as `h5ad` files -- `bt.geo`: manipulating spatial data -- `bt.datasets`: included spatial transcriptomics datasets -- `bt.ut`: utility functions +`bt.io`: provides out of the box compatibility with `SpatialData` objects -# Tools +`bt.tl`: subcellular analysis tools -## Point features +`bt.pl`: conveniently plot spatial data and embeddings -Compute spatial summary statistics describing groups of molecules e.g. distance to the cell membrane, relative symmetry, dispersion, etc. +`bt.geo`: manipulating data structures -A list of available cell features and their names is stored in the dict :func:`bt.tl.point_features`. +`bt.datasets`: included spatial transcriptomics datasets `WIP` + +`bt.ut`: utility functions + +## Read/Write + +Bento is designed to work with [`SpatialData`](https://spatialdata.scverse.org/en/latest/) objects out of the box! Check out [SpatialData documentation](https://spatialdata.scverse.org/en/latest/tutorials/notebooks/notebooks.html) to learn how to bring your own data, whether it is from commercial platforms or a custom data format. ```{eval-rst} -.. module:: bento.tl -.. currentmodule:: bento +.. currentmodule:: bento.io .. autosummary:: - :toctree: api/ + :toctree: api + :nosignatures: - tl.analyze_points - tl.register_point_feature + prep ``` -## Shape features +## Tools -Compute spatial properties of shape features e.g. area, aspect ratio, etc. of the cell, nucleus, or other region of interest. +### Point Features -A list of available cell features and their names is stored in the dict :func:`bt.tl.shape_features`. +Compute spatial summary statistics describing groups of molecules e.g. distance to the cell membrane, relative symmetry, dispersion, etc. The set of available point features is described in the Point Feature Catalog. Use the function `bt.tl.analyze_points()` to compute features and add your own custom calculation. See the [tutorial](https://bento-tools.github.io/bento/tutorials/TBD.html) for more information. ```{eval-rst} -.. module:: bento.tl -.. currentmodule:: bento +.. currentmodule:: bento.tl .. autosummary:: - :toctree: api/ + :toctree: api + :nosignatures: - tl.analyze_shapes - tl.register_shape_feature - tl.obs_stats + analyze_points + list_point_features + register_point_feature ``` -## RNAflux: Subcellular RNA embeddings and domains +### Shape Features -Methods for computing RNAflux embeddings and semantic segmentation of subcellular domains. +Compute spatial properties of shape features e.g. area, aspect ratio, etc. of the cell, nucleus, or other region of interest. The set of available shape features is described in the Shape Feature Catalog. Use the function `bt.analyze_points()` to compute features and add your own custom calculation. See the [tutorial](https://bento-tools.github.io/bento/tutorials/TBD.html) for more information. ```{eval-rst} -.. module: bento.tl -.. currentmodule:: bento .. autosummary:: - :toctree: api/ + :toctree: api + :nosignatures: - tl.flux - tl.fluxmap - tl.fe - tl.fe_fazal2019 - tl.load_gene_sets + shape_stats + analyze_shapes + list_shape_features + register_shape_feature ``` -## RNAforest: Predict RNA localization patterns +#### Shape Feature Catalog -Perform multilabel classification of RNA localization patterns using spatial summary statistics as features. +The set of implemented shape features is described below. Each feature is computed using the `bt.analyze_shapes()` function. ```{eval-rst} -.. module:: bento.tl -.. currentmodule:: bento .. autosummary:: - :toctree: api/ + :toctree: api + :nosignatures: + + area + aspect_ratio + bounds + density + opening + perimeter + radius + raster + second_moment + span - tl.lp - tl.lp_stats - tl.lp_diff ``` -## Colocalization analysis +### RNAflux: Subcellular RNA embeddings and domains -Methods for colocalization analyses of gene pairs. +Methods for computing RNAflux embeddings and semantic segmentation of subcellular domains. ```{eval-rst} -.. module:: bento.tl -.. currentmodule:: bento .. autosummary:: - :toctree: api/ + :toctree: api + :nosignatures: - tl.colocation - tl.coloc_quotient + flux + fluxmap + fe + fe_fazal2019 + fe_xia2019 + load_gene_sets ``` -# Plotting +### RNAforest: Predict RNA localization patterns -## Spatial plots - -These are convenient functions for quick 2D visualizations of cells, molecules, and embeddings. We generate `matplotlib` style figures for accessible publication quality plots. +Perform multilabel classification of RNA localization patterns using spatial summary statistics as features. ```{eval-rst} -.. module:: bento.pl -.. currentmodule:: bento .. autosummary:: - :toctree: api/ - - pl.points - pl.density - pl.shapes - pl.flux - pl.fluxmap + :toctree: api + :nosignatures: + lp + lp_stats + lp_diff_discrete + lp_diff_continuous ``` -## Shape features +### RNAcoloc: Colocalization analysis + +Methods for compartments-ecific gene-gene colocalization analyses. ```{eval-rst} -.. module:: bento.pl -.. currentmodule:: bento .. autosummary:: - :toctree: api/ + :toctree: api + :nosignatures: - pl.obs_stats + colocation + coloc_quotient ``` -## RNAflux +## Plotting + +These are convenient functions for static 2D plots of cells, molecules, and embeddings. We generate `matplotlib` style figures for accessible publication quality plots. There are a couple additional functions summarizing results from `bt.tl` analysis. + +### Spatial plots ```{eval-rst} -.. module:: bento.pl -.. currentmodule:: bento +.. currentmodule:: bento.pl .. autosummary:: - :toctree: api/ + :toctree: api + :nosignatures: - pl.flux_summary - pl.fe + points + density + shapes ``` -## RNAforest +### Shape features ```{eval-rst} -.. module:: bento.pl -.. currentmodule:: bento .. autosummary:: - :toctree: api/ - - pl.lp_genes - pl.lp_gene_dist - pl.lp_dist - pl.lp_diff + :toctree: api + :nosignatures: + shape_stats ``` -## Colocalization analysis +### RNAflux ```{eval-rst} -.. module:: bento.pl -.. currentmodule:: bento .. autosummary:: - :toctree: api/ - - pl.signatures - pl.signatures_error - pl.factor - pl.colocation + :toctree: api + :nosignatures: + flux + fluxmap + flux_summary + fe ``` -# Manipulating spatial data - -Convenient methods for setting, getting, and reformatting data. +### RNAforest ```{eval-rst} -.. module:: bento.geo -.. currentmodule:: bento .. autosummary:: - :toctree: api/ + :toctree: api + :nosignatures: - geo.count_points - geo.crop - geo.get_points - geo.get_points_metadata - geo.get_shape - geo.rename_shapes - geo.sindex_points + lp_diff_discrete + lp_dist + lp_gene_dist + lp_genes ``` -# Read/Write +### Colocalization analysis ```{eval-rst} -.. module:: bento.io -.. currentmodule:: bento .. autosummary:: - :toctree: api/ + :toctree: api + :nosignatures: - io.read_h5ad - io.write_h5ad - io.concatenate - io.prepare + factor + colocation ``` -# Datasets +## Manipulating spatial data + +Convenient methods for setting, getting, and reformatting data. These functions are used internally by other functions in Bento. ```{eval-rst} -.. module:: bento.ds -.. currentmodule:: bento +.. currentmodule:: bento.geo .. autosummary:: - :toctree: api/ - - ds.sample_data - ds.load_dataset - ds.get_dataset_info - ds.load_gene_sets + :toctree: api + :nosignatures: + sjoin_points + sjoin_shapes + get_points + get_shape + get_points_metadata + get_shape_metadata + set_points_metadata + set_shape_metadata ``` -# Utility functions +## Utility functions ```{eval-rst} -.. module:: bento.ut -.. currentmodule:: bento +.. currentmodule:: bento.ut .. autosummary:: - :toctree: api/ - - ut.sync - ut.geo_format - ut.sc_format - ut.pheno_to_color -``` + :toctree: api + :nosignatures: diff --git a/docs/source/conf.py b/docs/source/conf.py index 2d8618c..3aa286c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,6 +11,9 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. import os import sys +from dataclasses import asdict + +from sphinxawesome_theme import LinkIcon, ThemeOptions sys.path.insert(0, os.path.abspath("..")) # Source code dir relative to this file @@ -23,7 +26,7 @@ html_favicon = "favicon.ico" # The full version, including alpha/beta/rc tags -release = "2.0.0a0" +release = "2.1" # -- General configuration --------------------------------------------------- @@ -35,11 +38,21 @@ "sphinx.ext.autosummary", "sphinx.ext.napoleon", "sphinx.ext.intersphinx", + "sphinx.ext.autodoc", + "sphinx_autodoc_typehints", "myst_nb", "sphinx_design", + "sphinxawesome_theme.highlighting", ] -myst_enable_extensions = ["colon_fence", "html_image", "dollarmath"] +myst_enable_extensions = [ + "amsmath", + "colon_fence", + "deflist", + "dollarmath", + "html_image", + "html_admonition", +] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] @@ -54,16 +67,31 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = "sphinx_book_theme" - -html_theme_options = { - "repository_url": "https://github.com/ckmah/bento-tools", - "use_repository_button": True, - "use_edit_page_button": True, - "path_to_docs": "docs", - "logo": { - "alt_text": "Bento Logo", +html_theme = "sphinxawesome_theme" + + +theme_options = ThemeOptions( + show_scrolltop=True, + show_breadcrumbs=True, + awesome_external_links=True, + main_nav_links={ + "Installation": "installation", + "Tutorials": "tutorials", + "How it Works": "howitworks", + "API": "api", + }, + extra_header_link_icons={ + "GitHub": LinkIcon( + link="https://github.com/ckmah/bento-tools", + icon='', + ) }, +) + +html_theme_options = asdict(theme_options) + +html_sidebars = { + "**": ["sidebar_main_nav_links.html", "sidebar_toc.html"] } html_context = {"default_mode": "auto"} @@ -75,18 +103,22 @@ html_css_files = ["custom.css"] -# -- Options for Autosummary, Autodoc, Napolean docstring format ------------------------------------------------- +# -- Options for Autosummary, Autodoc, typehints, Napolean docstring format ------------------------------------------------- autosummary_generate = True autodoc_docstring_signature = True +typehint_defaults = "braces" +typehints_use_signature_return = True +typehints_document_rtype = True +always_use_bar_union = True napoleon_google_docstring = False napoleon_numpy_docstring = True napoleon_use_param = False -napoleon_use_rtype = False +napoleon_use_rtype = True numpydoc_show_class_members = False html_title = "bento-tools" -html_logo = "_static/bento-name.png" +html_logo = "_static/no_image.png" # -- Options for extensions ------------------------------------------------------------------------------- diff --git a/docs/source/howitworks.md b/docs/source/howitworks.md index 23c41d7..0cae986 100644 --- a/docs/source/howitworks.md +++ b/docs/source/howitworks.md @@ -1,3 +1,7 @@ +```{toctree} +:hidden: true +``` + # {octicon}`gear` How it Works ## Data Structure diff --git a/docs/source/index.md b/docs/source/index.md index 0c3d9b2..b640379 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -1,16 +1,43 @@ +```{toctree} +:hidden: true + +installation +tutorials +howitworks +api +``` -[![PyPI version](https://badge.fury.io/py/bento-tools.svg)](https://badge.fury.io/py/bento-tools) -[![codecov](https://codecov.io/gh/ckmah/bento-tools/branch/master/graph/badge.svg?token=XVHDKNDCDT)](https://codecov.io/gh/ckmah/bento-tools) -[![Documentation Status](https://readthedocs.org/projects/bento-tools/badge/?version=latest)](https://bento-tools.readthedocs.io/en/latest/?badge=latest) -![PyPI - Downloads](https://img.shields.io/pypi/dm/bento-tools) -[![GitHub stars](https://badgen.net/github/stars/ckmah/bento-tools)](https://GitHub.com/Naereen/ckmah/bento-tools) +```{image} https://badge.fury.io/py/bento-tools.svg +:alt: PyPI version +:target: https://badge.fury.io/py/bento-tools +:class: inline-link +``` +```{image} https://codecov.io/gh/ckmah/bento-tools/branch/master/graph/badge.svg?token=XVHDKNDCDT +:alt: codecov +:target: https://codecov.io/gh/ckmah/bento-tools +:class: inline-link +``` -# Bento +```{image} https://readthedocs.org/projects/bento-tools/badge/?version=latest +:alt: Documentation Status +:target: https://bento-tools.readthedocs.io/en/latest/?badge=latest +:class: inline-link +``` -Bento Workflow +```{image} https://img.shields.io/pypi/dm/bento-tools +:alt: PyPI - Downloads +:class: inline-link +``` +# Bento +:::{image} _static/tutorial_img/bento_tools.png +:alt: Bento Workflow +:align: center +:width: 800px +::: + Bento is a Python toolkit for performing subcellular analysis of spatial transcriptomics data. The package is part of the [Scverse ecosystem](https://scverse.org/packages/#ecosystem). Check out the [documentation](https://bento-tools.readthedocs.io/en/latest/) for installation instructions, tutorials, and API. Cite [our preprint](https://doi.org/10.1101/2022.06.10.495510) if you use Bento in your work. Thanks! @@ -35,15 +62,7 @@ Bento is a Python toolkit for performing subcellular analysis of spatial transcr :::: --- -[![GitHub license](https://img.shields.io/github/license/ckmah/bento-tools.svg)](https://github.com/ckmah/bento-tools/blob/master/LICENSE) - - -```{toctree} -:maxdepth: 2 -:hidden: true - -installation -tutorials -howitworks -api -``` +:::{image} https://img.shields.io/github/license/ckmah/bento-tools.svg +:alt: GitHub license +:class: inline-link +::: diff --git a/docs/source/installation.md b/docs/source/installation.md index a138e6e..3a1d618 100644 --- a/docs/source/installation.md +++ b/docs/source/installation.md @@ -1,76 +1,53 @@ -# {octicon}`terminal` Installation - -Bento requires Python version 3.8 or 3.9. - -## Setup a virtual environment - -We highly recommend using a virtual environment to install Bento to avoid conflicting dependencies with other packages. If you are unfamiliar with virtual environments, we recommend using [Miniconda](https://docs.conda.io/en/latest/miniconda.html). - -To setup a virtual environment with `Miniconda`, run the following. This will create and activate a new environment called `bento` with Python 3.8. - -```bash -VERSION=3.8 # or 3.9 -conda create -n bento python=$VERSION - -# set channel priorities -conda config --env --add channels defaults -conda config --env --add channels bioconda -conda config --env --add channels conda-forge - -conda activate bento -``` - -## 2. Dependencies - -Bento makes use of several packages for spatial analyses that require addtional non-Python dependencies. - -```bash -conda install -c conda-forge gdal cmake +```{toctree} +:hidden: true ``` -For developing docs, you will also need pandoc: +# {octicon}`terminal` Installation -```bash -conda install -c conda-forge pandoc -``` +Bento requires Python version 3.9 or higher. We recommend using a virtual environment to install Bento to avoid conflicting dependencies with other packages. If you are unfamiliar with virtual environments, we recommend using [Miniconda](https://docs.conda.io/en/latest/miniconda.html). -## 3. Install Bento +## PyPI -All that's left is the package itself. Install with pip: +Bento is available on PyPI: -```bash -pip install bento-tools +```console +$ pip install bento-tools ``` ---- +## Troubleshooting +If you encounter installation errors, you may need double check that package dependencies are installed correctly. +- [GeoPandas](https://geopandas.org/en/stable/getting_started/install.html#installing-with-pip) install instructions ## Development -The package and its dependencies are built using [Poetry](https://python-poetry.org/). +We currently use [Rye](https://rye-up.com/) for package management. -1. Install [Poetry](https://python-poetry.org/). -2. Clone the `bento-tools` GitHub repository. -3. Use poetry to manage dependencies and pip to install the package in editable mode. - - ```bash +1. Install [Rye](https://rye-up.com/guide/installation/). +2. Clone the repository and navigate to the root directory. + ```console + gh repo clone ckmah/bento-tools cd bento-tools - poetry install - pip install -e . ``` - For updating documentation locally, install extra dependencies and launch a live server to preview doc builds: +3. Install the package in editable mode: + + ```console + pip install -e . + ``` + +Run tests: + ```console + python -m unittest tests - First install pandoc (see [dependencies](#Dependencies) section for more details). +### Documentation - ```bash - poetry install --extras "docs" - pip install -e .\[docs\] - cd docs - make livehtml # See output for URL + ```console + pip install -e ".[docs]" # install optional deps for docs + cd docs + make livehtml ``` ---- ## GPU Support (Optional) -Bento currently only uses GPUs to accelerate tensor decomposition (via [Tensorly](https://tensorly.org/stable/index.html)) GPU support can be enabled by installing PyTorch. We recommend the [PyTorch installation instructions](https://pytorch.org/get-started/locally/) for more details as installation varies by platform. +Bento currently only uses GPUs to accelerate tensor decomposition (via [Tensorly](https://tensorly.org/stable/index.html)). PyTorch is already installed, but users should consult [PyTorch installation instructions](https://pytorch.org/get-started/locally/) for enabling GPU support, as installation varies by platform. diff --git a/docs/source/tutorials.md b/docs/source/tutorials.md index 533861d..98e507e 100644 --- a/docs/source/tutorials.md +++ b/docs/source/tutorials.md @@ -1,30 +1 @@ # {octicon}`workflow` Tutorials - -:::{toctree} -:maxdepth: 2 -:hidden: true - -tutorial_gallery/Main_Guide -tutorial_gallery/Data_Visualization -tutorial_gallery/Spatial_Features -::: - -::::{grid} 3 -:::{grid-item-card} Main Guide -:link: tutorial_gallery/Main_Guide.html - -This tutorial will walk you through how to load, visualize data, and perform subcellular analysis. -::: - -:::{grid-item-card} Data Visualization -:link: tutorial_gallery/Data_Visualization.html - -This tutorial will cover how to visualize spatial data using Bento. -::: - -:::{grid-item-card} Subcellular Spatial Features -:link: tutorial_gallery/Spatial_Features.html - -Learn how to compute spatial features across cells, domains, and molecular distributions. -::: -:::: \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 2b590ed..5693e35 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,63 +1,62 @@ -[tool.poetry] +[project] name = "bento-tools" -packages = [{ include = "bento" }] +version = "2.1" +description = "A toolkit for subcellular analysis of spatial transcriptomics data" +authors = [ + { name = "ckmah", email = "clarence.k.mah@gmail.com" } +] +dependencies = [ + "adjusttext>=1.1.1", + "astropy>=6.0.1", + "decoupler~=1.4.0", + "emoji>=2.11.0", + "kneed>=0.8.5", + "matplotlib-scalebar>=0.8.1", + "minisom>=2.3.2", + "rasterio>=1.3.9", + "rtree>=1.2.0", + "scipy>=1.13.0", + "seaborn>=0.13.2", + "shapely~=2.0.1", + "sparse>=0.15.1", + "spatialdata>=0.1.2", + "tensorly>=0.8.1", + "tqdm>=4.66.2", + "upsetplot>=0.9.0", + "xgboost>=2.0.3", + "statsmodels>=0.14.1", + "scikit-learn>=1.4.2", + "torch>=2.2.2", +] +license = "BSD-2-Clause" +readme = "README.md" +requires-python = ">= 3.9" include = [ "bento/datasets/datasets.csv", "bento/models/**/*", "bento/tools/gene_sets/*", ] -version = "2.1.0a0" -description = "A toolkit for subcellular analysis of spatial transcriptomics data" -authors = ["Clarence Mah "] -license = "BSD-2-Clause" -readme = "README.md" - -[tool.poetry.dependencies] -python = ">3.8" -anndata = "^0.9.2" -astropy = "^5.0" -matplotlib = "~3.7" -matplotlib-scalebar = "^0.8.1" -scanpy = "^1.9.1" -scipy = "^1.7.0" -seaborn = "^0.12.1" -Shapely = "^2.0.1" -Sphinx = { version = "^4.1.2", extras = ["docs"] } -sphinx-autobuild = { version = "^2021.3.14", extras = ["docs"] } -sphinx-book-theme = {version = "^1.0.0", extras = ["docs"] } -sphinx-gallery = { version = "^0.10.1", extras = ["docs"] } -statsmodels = "^0.13.2" -tqdm = "^4.64.0" -UpSetPlot = "^0.6.1" -emoji = "^1.7.0" -tensorly = "^0.7.0" -rasterio = "^1.3.0" -ipywidgets = "^8.0" -decoupler = "1.4.0" -MiniSom = "^2.3.0" -kneed = "^0.8.1" -adjustText = "^0.7.3" -sparse = "^0.13.0" -pandas = "^1.5.3" -xgboost = "2.0.0" -myst-nb = {version = "^0.17.1", extras = ["docs"]} -sphinx_design = {version = "^0.3.0", extras = ["docs"]} -rtree = "^1.0.1" -spatialdata = "0.0.15" -[tool.poetry.extras] +[project.optional-dependencies] docs = [ - "Sphinx", - "sphinx-autobuild", - "sphinx-book-theme", - "sphinx-gallery", - "myst-nb", - "sphinx_design", + "sphinx>=7.2.6", + "sphinx-design>=0.5.0", + "sphinx-autobuild>=2024.2.4", + "sphinxawesome-theme>=5.1.1", + "myst-nb>=1.0.0", + "sphinx-autodoc-typehints>=2.0.1", ] -[tool.setuptools] -py_modules = [] - [build-system] -requires = ["poetry-core>=1.0.0", 'setuptools'] -build-backend = "poetry.core.masonry.api" +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.rye] +managed = true +dev-dependencies = [] + +[tool.hatch.metadata] +allow-direct-references = true + +[tool.hatch.build.targets.wheel] +packages = ["bento"] diff --git a/tests/test_geometry.py b/tests/test_geometry.py index 48a809e..9278c2c 100644 --- a/tests/test_geometry.py +++ b/tests/test_geometry.py @@ -34,7 +34,7 @@ def test_sjoin_shapes(self): ) def test_get_points(self): - self.data = bt.io.format_sdata( + self.data = bt.io.prep( self.data, points_key="transcripts", feature_key="feature_name", @@ -79,7 +79,7 @@ def test_get_points(self): self.assertTrue(len(dd_no_sync) == len(self.data.points["transcripts"])) def test_get_shape(self): - self.data = bt.io.format_sdata( + self.data = bt.io.prep( self.data, points_key="transcripts", feature_key="feature_name", diff --git a/tests/test_io.py b/tests/test_io.py index 7f06a5c..ce59759 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -7,7 +7,7 @@ class TestIO(unittest.TestCase): def setUp(self): datadir = "/".join(bt.__file__.split("/")[:-1]) + "/datasets" self.data = sd.read_zarr(f"{datadir}/small_data.zarr") - self.data = bt.io.format_sdata( + self.data = bt.io.prep( self.data, points_key="transcripts", feature_key="feature_name", diff --git a/tests/test_shape_features.py b/tests/test_shape_features.py index d80d469..ce21e67 100644 --- a/tests/test_shape_features.py +++ b/tests/test_shape_features.py @@ -178,9 +178,9 @@ def test_multiple_shapes_multiple_features(self): "transform" in self.data.shapes["nucleus_boundaries"].attrs.keys() ) - # Test case to check if obs_stats function calculates area, aspect_ratio and density for both cell_boundaries and nucleus_boundaries - def test_obs_stats(self): - bt.tl.obs_stats(sdata=self.data) + # Test case to check if shape_stats function calculates area, aspect_ratio and density for both cell_boundaries and nucleus_boundaries + def test_shape_stats(self): + bt.tl.shape_stats(sdata=self.data) # Check if cell_boundaries and nucleus_boundaries shape features are calculated self.assertTrue(