Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/api/scanpy_gpu.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

These functions offer accelerated near drop-in replacements for common tools provided by [`scanpy`](https://scanpy.readthedocs.io/en/stable/api/index.html) {cite}`Wolf2018`.

## Scanpy backend

With Scanpy versions that support computational backends, RAPIDS-singlecell is available as the `rapids_singlecell` backend with the aliases `cuda`, `rapids`, `rapids-singlecell`, and `rsc`.

```python
import scanpy as sc

sc.settings.backend = "cuda"
```

The backend exposes RAPIDS-singlecell's `pp` and `tl` functions, plus {func}`rapids_singlecell.get.aggregate`, for Scanpy's backend dispatcher.

## Preprocessing `pp`
Filtering of highly-variable genes, batch-effect correction, per-cell normalization.

Expand Down
12 changes: 12 additions & 0 deletions docs/api/squidpy_gpu.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@
{mod}`squidpy.gr` is a tool for the analysis of spatial molecular data {cite}`Palla2022`.
{mod}`rapids_singlecell.gr` accelerates some of these functions.

## Squidpy backend

With Squidpy versions that support computational backends, RAPIDS-singlecell is available as the `rapids_singlecell` backend with the aliases `cuda`, `rapids-singlecell`, and `rsc`.

```python
import squidpy as sq

sq.settings.backend = "cuda"
```

The backend exposes RAPIDS-singlecell's {mod}`rapids_singlecell.gr` functions for Squidpy's backend dispatcher.

```{eval-rst}
.. module:: rapids_singlecell.gr
.. currentmodule:: rapids_singlecell
Expand Down
2 changes: 2 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"pylibraft",
"dask",
"cuvs",
"spatialdata",
]
default_role = "literal"
napoleon_google_docstring = False
Expand Down Expand Up @@ -126,6 +127,7 @@
"statsmodels": ("https://www.statsmodels.org/stable/", None),
"omnipath": ("https://omnipath.readthedocs.io/en/latest/", None),
"dask": ("https://docs.dask.org/en/stable/", None),
"spatialdata": ("https://spatialdata.scverse.org/en/stable/", None),
}

# List of patterns, relative to source directory, that match files and
Expand Down
4 changes: 4 additions & 0 deletions docs/release-notes/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
# Release notes


## Version 0.16.0
```{include} /release-notes/0.16.0.md
```

## Version 0.15.0
```{include} /release-notes/0.15.0.md
```
Expand Down
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ dev = [
"pre-commit",
]

[project.entry-points."scanpy.backends"]
rapids_singlecell = "rapids_singlecell._backends.scanpy"

[project.entry-points."squidpy.backends"]
rapids_singlecell = "rapids_singlecell._backends.squidpy"

[project.urls]
Documentation = "https://rapids-singlecell.readthedocs.io"
Source = "https://github.com/scverse/rapids_singlecell"
Expand Down
1 change: 1 addition & 0 deletions src/rapids_singlecell/_backends/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from __future__ import annotations
160 changes: 160 additions & 0 deletions src/rapids_singlecell/_backends/scanpy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from rapids_singlecell.get import aggregate
from rapids_singlecell.preprocessing import (
bbknn,
calculate_qc_metrics,
filter_cells,
filter_genes,
filter_highly_variable,
flag_gene_family,
harmony_integrate,
highly_variable_genes,
neighbors,
normalize_pearson_residuals,
normalize_total,
regress_out,
scrublet,
scrublet_simulate_doublets,
)
from rapids_singlecell.preprocessing import log1p as _log1p
from rapids_singlecell.preprocessing import pca as _pca
from rapids_singlecell.preprocessing import scale as _scale
from rapids_singlecell.preprocessing._pca import _empty
from rapids_singlecell.tools import (
diffmap,
draw_graph,
embedding_density,
kmeans,
leiden,
louvain,
rank_genes_groups,
rank_genes_groups_logreg,
score_genes,
score_genes_cell_cycle,
tsne,
umap,
)

if TYPE_CHECKING:
from anndata import AnnData
from numpy.typing import DTypeLike, NDArray

name = "rapids_singlecell"
aliases = ["cuda", "rapids", "rapids-singlecell", "rsc"]


def log1p(
data: AnnData,
*,
base: float | None = None,
layer: str | None = None,
obsm: str | None = None,
inplace: bool = True,
copy: bool = False,
):
return _log1p(
data,
base=base,
layer=layer,
obsm=obsm,
inplace=inplace,
copy=copy,
)


def pca(
data: AnnData,
n_comps: int | None = None,
*,
layer: str | None = None,
zero_center: bool = True,
svd_solver: str | None = None,
chunked: bool = False,
chunk_size: int | None = None,
rng=None,
mask_var: NDArray | str | None = _empty,
dtype: DTypeLike = "float32",
key_added: str | None = None,
copy: bool = False,
random_state: int | None = 0,
use_highly_variable: bool | None = None,
**kwargs,
) -> None | AnnData:
if rng is not None:
random_state = rng
return _pca(
data,
n_comps=n_comps,
layer=layer,
zero_center=zero_center,
svd_solver=svd_solver,
random_state=random_state,
mask_var=mask_var,
use_highly_variable=use_highly_variable,
dtype=dtype,
chunked=chunked,
chunk_size=chunk_size,
key_added=key_added,
copy=copy,
**kwargs,
)


def scale(
data: AnnData,
*,
zero_center: bool = True,
max_value: float | None = None,
copy: bool = False,
layer: str | None = None,
obsm: str | None = None,
mask_obs: NDArray | str | None = None,
inplace: bool = True,
):
return _scale(
data,
zero_center=zero_center,
max_value=max_value,
copy=copy,
layer=layer,
obsm=obsm,
mask_obs=mask_obs,
inplace=inplace,
)


__all__ = [
"aggregate",
"bbknn",
"calculate_qc_metrics",
"diffmap",
"draw_graph",
"embedding_density",
"filter_cells",
"filter_genes",
"filter_highly_variable",
"flag_gene_family",
"harmony_integrate",
"highly_variable_genes",
"kmeans",
"leiden",
"log1p",
"louvain",
"neighbors",
"normalize_pearson_residuals",
"normalize_total",
"pca",
"rank_genes_groups",
"rank_genes_groups_logreg",
"regress_out",
"scale",
"score_genes",
"score_genes_cell_cycle",
"scrublet",
"scrublet_simulate_doublets",
"tsne",
"umap",
]
8 changes: 8 additions & 0 deletions src/rapids_singlecell/_backends/squidpy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from __future__ import annotations

from rapids_singlecell.squidpy_gpu import co_occurrence, ligrec, spatial_autocorr

name = "rapids_singlecell"
aliases = ["rapids-singlecell", "rsc", "cuda"]

__all__ = ["co_occurrence", "ligrec", "spatial_autocorr"]
5 changes: 5 additions & 0 deletions src/rapids_singlecell/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
from scipy.sparse import csc_matrix as csc_matrix_cpu
from scipy.sparse import csr_matrix as csr_matrix_cpu

try:
from spatialdata import SpatialData
except ImportError:
SpatialData = None


def _meta_dense(dtype):
return cp.zeros([0], dtype=dtype)
Expand Down
5 changes: 3 additions & 2 deletions src/rapids_singlecell/preprocessing/_normalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ def _calc_log1p(X: ArrayTypesDask, base: float | None = None) -> ArrayTypesDask:


def log1p(
adata: AnnData,
data: AnnData,
*,
base: float | None = None,
layer: str | None = None,
Expand All @@ -373,7 +373,7 @@ def log1p(

Parameters
----------
adata
data
AnnData object
base
Base of the logarithm. Natural logarithm is used by default.
Expand All @@ -393,6 +393,7 @@ def log1p(
in-place and returns None.

"""
adata = data
if copy:
if not inplace:
raise ValueError("`copy=True` cannot be used with `inplace=False`.")
Expand Down
5 changes: 3 additions & 2 deletions src/rapids_singlecell/preprocessing/_pca.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def _resolve_mask_var(


def pca(
adata: AnnData,
data: AnnData,
n_comps: int | None = None,
*,
layer: str = None,
Expand Down Expand Up @@ -112,7 +112,7 @@ def pca(

Parameters
----------
adata
data
AnnData object

n_comps
Expand Down Expand Up @@ -210,6 +210,7 @@ def pca(
Explained variance, equivalent to the eigenvalues of the \
covariance matrix.
"""
adata = data
if use_highly_variable is True and "highly_variable" not in adata.var.keys():
raise ValueError(
"Did not find adata.var['highly_variable']. "
Expand Down
5 changes: 3 additions & 2 deletions src/rapids_singlecell/preprocessing/_scale.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@


def scale(
adata: AnnData,
data: AnnData,
*,
zero_center: bool = True,
max_value: float | None = None,
Expand All @@ -39,7 +39,7 @@ def scale(

Parameters
----------
adata
data
AnnData object

zero_center
Expand Down Expand Up @@ -74,6 +74,7 @@ def scale(
depending on `inplace`.

"""
adata = data
if copy:
if not inplace:
raise ValueError("`copy=True` cannot be used with `inplace=False`.")
Expand Down
5 changes: 4 additions & 1 deletion src/rapids_singlecell/squidpy_gpu/_autocorr.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from scipy import sparse
from statsmodels.stats.multitest import multipletests

from rapids_singlecell._compat import SpatialData
from rapids_singlecell.preprocessing._utils import _sparse_to_dense

from ._gearysc import _gearys_C_cupy
Expand Down Expand Up @@ -49,7 +50,7 @@ def _to_cupy(vals, *, use_sparse: bool, dtype):


def spatial_autocorr(
adata: AnnData,
adata: AnnData | SpatialData,
*,
connectivity_key: str = "spatial_connectivities",
genes: str | Sequence[str] | None = None,
Expand Down Expand Up @@ -118,6 +119,8 @@ def spatial_autocorr(
DataFrame containing the autocorrelation scores, p-values, and corrected p-values for each gene. \
If `copy` is False, the results are stored in `adata.uns` and None is returned.
"""
if SpatialData is not None and isinstance(adata, SpatialData):
adata = adata.table
if genes is None:
if "highly_variable" in adata.var:
genes = adata[:, adata.var["highly_variable"]].var_names.values
Expand Down
5 changes: 4 additions & 1 deletion src/rapids_singlecell/squidpy_gpu/_co_oc.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import numpy as np
from cuml.metrics import pairwise_distances

from rapids_singlecell._compat import SpatialData
from rapids_singlecell._cuda import _cooc_cuda as _co
from rapids_singlecell._utils import (
_calculate_blocks_per_pair,
Expand All @@ -21,7 +22,7 @@


def co_occurrence(
adata: AnnData,
adata: AnnData | SpatialData,
cluster_key: str,
*,
spatial_key: str = "spatial",
Expand Down Expand Up @@ -65,6 +66,8 @@ def co_occurrence(
computed at ``interval``.
"""

if SpatialData is not None and isinstance(adata, SpatialData):
adata = adata.table
_assert_categorical_obs(adata, key=cluster_key)
_assert_spatial_basis(adata, key=spatial_key)
spatial = cp.array(adata.obsm[spatial_key]).astype(np.float32)
Expand Down
Loading
Loading