Skip to content

Commit 65c5828

Browse files
committed
drop numba dependency
1 parent 28e1ae4 commit 65c5828

File tree

4 files changed

+22
-44
lines changed

4 files changed

+22
-44
lines changed

docs/source/tutorials/VisiumHD_CRC.ipynb

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@
647647
},
648648
{
649649
"cell_type": "code",
650-
"execution_count": 21,
650+
"execution_count": null,
651651
"id": "672b4258-dc91-4fb0-9158-eeb0870c83c9",
652652
"metadata": {
653653
"editable": true,
@@ -664,14 +664,11 @@
664664
"from matplotlib.colors import to_rgb\n",
665665
"from scipy.sparse import coo_array\n",
666666
"\n",
667-
"from sainsc.lazykde._utils import _apply_color\n",
668-
"\n",
669667
"background = \"black\"\n",
670668
"\n",
671669
"cmap_ls = [cmap[celltype] for celltype in adata_16um.obs[\"leiden\"].cat.categories]\n",
672-
"color_map = tuple(\n",
673-
" (np.array(to_rgb(c)) * 255).round().astype(np.uint8) for c in [background] + cmap_ls\n",
674-
")\n",
670+
"color_map = np.array([to_rgb(c) for c in [background] + cmap_ls])\n",
671+
"\n",
675672
"\n",
676673
"celltype = adata_16um.obs[\"leiden\"].cat.codes\n",
677674
"x = adata_16um.obs[\"array_row\"]\n",
@@ -681,7 +678,7 @@
681678
"ctmap_16um = coo_array(\n",
682679
" (celltype + 1, (x, y)), shape=[ceil(i / 8) for i in visium_hd.shape]\n",
683680
")\n",
684-
"ctmap_16um = _apply_color((ctmap_16um).toarray(), color_map)"
681+
"ctmap_16um = np.take(color_map, ctmap_16um.toarray(), axis=0)"
685682
]
686683
},
687684
{

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ dependencies = [
1919
"h5py>=3",
2020
"matplotlib>=3.7",
2121
"matplotlib-scalebar",
22-
"numba>=0.44",
2322
"numpy>=1.24",
2423
"pandas>=2.0",
2524
"polars[pandas]>=1",

sainsc/lazykde/_LazyKDE.py

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from collections.abc import Iterable
2-
from itertools import chain
32
from pathlib import Path
4-
from typing import TYPE_CHECKING, Any, Self
3+
from typing import TYPE_CHECKING, Any, Self, TypeVar
54

65
import matplotlib.pyplot as plt
76
import numpy as np
@@ -15,7 +14,6 @@
1514
from matplotlib.patches import Patch
1615
from matplotlib_scalebar.scalebar import ScaleBar
1716
from mpl_toolkits import axes_grid1
18-
from numba import njit
1917
from numpy.typing import NDArray
2018
from scipy.sparse import coo_array, csc_array, csr_array
2119
from skimage.feature import peak_local_max
@@ -33,7 +31,6 @@
3331
from ._utils import (
3432
SCALEBAR_PARAMS,
3533
CosineCelltypeCallable,
36-
_apply_color,
3734
_filter_blobs,
3835
_get_cell_dtype,
3936
_localmax_anndata,
@@ -358,7 +355,6 @@ def load_local_maxima(
358355
}
359356

360357
if self.total_mRNA_KDE is not None:
361-
362358
sdata_dict["total_mRNA"] = Image2DModel.parse(
363359
np.atleast_3d(self.total_mRNA_KDE).T, dims=("c", "y", "x")
364360
)
@@ -416,7 +412,6 @@ def load_local_maxima(
416412
return adata
417413

418414
def _load_KDE_maxima(self, genes: list[str]) -> csc_array | csr_array:
419-
420415
assert self.local_maxima is not None
421416
if self.kernel is None:
422417
raise ValueError("`kernel` must be set before running KDE")
@@ -461,17 +456,13 @@ def filter_background(
461456
If cell type-specific thresholds do not include all cell types or if
462457
using cell type-specific thresholds before cell type assignment.
463458
"""
459+
T = TypeVar("T")
464460

465-
@njit
466461
def _map_celltype_to_value(
467-
ct_map: NDArray[np.integer], thresholds: tuple[float, ...]
462+
ct_map: NDArray[np.integer], thresholds: dict[T, float], classes: list[T]
468463
) -> NDArray[np.floating]:
469-
values = np.zeros(shape=ct_map.shape, dtype=float)
470-
for i in range(ct_map.shape[0]):
471-
for j in range(ct_map.shape[1]):
472-
if ct_map[i, j] >= 0:
473-
values[i, j] = thresholds[ct_map[i, j]]
474-
return values
464+
ordered_thresholds = np.array([0] + [thresholds[ct] for ct in classes])
465+
return np.take(ordered_thresholds, ct_map + 1)
475466

476467
if self.total_mRNA_KDE is None:
477468
raise ValueError(
@@ -485,8 +476,9 @@ def _map_celltype_to_value(
485476
)
486477
elif not all([ct in min_norm.keys() for ct in self.celltypes]):
487478
raise ValueError("'min_norm' does not contain all celltypes.")
488-
idx2threshold = tuple(min_norm[ct] for ct in self.celltypes)
489-
threshold = _map_celltype_to_value(self.celltype_map, idx2threshold)
479+
threshold = _map_celltype_to_value(
480+
self.celltype_map, min_norm, self.celltypes
481+
)
490482
background = self.total_mRNA_KDE < threshold
491483
else:
492484
background = self.total_mRNA_KDE < min_norm
@@ -503,8 +495,9 @@ def _map_celltype_to_value(
503495
)
504496
elif not all([ct in min_cosine.keys() for ct in self.celltypes]):
505497
raise ValueError("'min_cosine' does not contain all celltypes.")
506-
idx2threshold = tuple(min_cosine[ct] for ct in self.celltypes)
507-
threshold = _map_celltype_to_value(self.celltype_map, idx2threshold)
498+
threshold = _map_celltype_to_value(
499+
self.celltype_map, min_cosine, self.celltypes
500+
)
508501
background |= self.cosine_similarity <= threshold
509502
else:
510503
background |= self.cosine_similarity <= min_cosine
@@ -521,8 +514,9 @@ def _map_celltype_to_value(
521514
)
522515
elif not all([ct in min_assignment.keys() for ct in self.celltypes]):
523516
raise ValueError("'min_assignment' does not contain all celltypes.")
524-
idx2threshold = tuple(min_assignment[ct] for ct in self.celltypes)
525-
threshold = _map_celltype_to_value(self.celltype_map, idx2threshold)
517+
threshold = _map_celltype_to_value(
518+
self.celltype_map, min_assignment, self.celltypes
519+
)
526520
background |= self.assignment_score <= threshold
527521
else:
528522
background |= self.assignment_score <= min_assignment
@@ -1006,11 +1000,11 @@ def plot_celltype_map(
10061000
color_map = [to_rgb(c) if isinstance(c, str) else c for c in cmap]
10071001

10081002
# convert to uint8 to reduce memory of final image
1009-
color_map_int = tuple(
1010-
(np.array(c) * 255).round().astype(np.uint8)
1011-
for c in chain([to_rgb(background)], color_map)
1003+
color_map_int = (
1004+
(np.array([to_rgb(background)] + color_map) * 255).round().astype(np.uint8)
10121005
)
1013-
img = _apply_color(celltype_map.T, color_map_int)
1006+
1007+
img = np.take(color_map_int, celltype_map.T, axis=0)
10141008

10151009
if return_img:
10161010
return img

sainsc/lazykde/_utils.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import numpy as np
66
import pandas as pd
77
from anndata import AnnData
8-
from numba import njit
98
from numpy.typing import NDArray
109
from scipy.sparse import csr_matrix, sparray, spmatrix
1110
from skimage.measure import label, regionprops
@@ -20,17 +19,6 @@
2019
"""Default scalebar parameters"""
2120

2221

23-
@njit
24-
def _apply_color(
25-
img_in: NDArray[np.integer], cmap: tuple[NDArray[T], ...]
26-
) -> NDArray[T]:
27-
img = np.empty(shape=(*img_in.shape, 3), dtype=cmap[0].dtype)
28-
for i in range(img_in.shape[0]):
29-
for j in range(img_in.shape[1]):
30-
img[i, j, :] = cmap[img_in[i, j]]
31-
return img
32-
33-
3422
def _get_cell_dtype(n: int) -> np.dtype:
3523
return np.result_type("int8", n)
3624

0 commit comments

Comments
 (0)