pertpy 0.10.0__py3-none-any.whl → 0.11.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. pertpy/__init__.py +5 -1
  2. pertpy/_doc.py +1 -3
  3. pertpy/_types.py +6 -0
  4. pertpy/data/_dataloader.py +68 -24
  5. pertpy/data/_datasets.py +9 -9
  6. pertpy/metadata/__init__.py +2 -1
  7. pertpy/metadata/_cell_line.py +133 -25
  8. pertpy/metadata/_look_up.py +13 -19
  9. pertpy/metadata/_moa.py +1 -1
  10. pertpy/preprocessing/_guide_rna.py +138 -44
  11. pertpy/preprocessing/_guide_rna_mixture.py +17 -19
  12. pertpy/tools/__init__.py +4 -3
  13. pertpy/tools/_augur.py +106 -98
  14. pertpy/tools/_cinemaot.py +74 -114
  15. pertpy/tools/_coda/_base_coda.py +134 -148
  16. pertpy/tools/_coda/_sccoda.py +69 -70
  17. pertpy/tools/_coda/_tasccoda.py +74 -80
  18. pertpy/tools/_dialogue.py +48 -41
  19. pertpy/tools/_differential_gene_expression/_base.py +21 -31
  20. pertpy/tools/_differential_gene_expression/_checks.py +4 -6
  21. pertpy/tools/_differential_gene_expression/_dge_comparison.py +5 -6
  22. pertpy/tools/_differential_gene_expression/_edger.py +6 -10
  23. pertpy/tools/_differential_gene_expression/_pydeseq2.py +1 -1
  24. pertpy/tools/_differential_gene_expression/_simple_tests.py +3 -3
  25. pertpy/tools/_differential_gene_expression/_statsmodels.py +8 -5
  26. pertpy/tools/_distances/_distance_tests.py +1 -2
  27. pertpy/tools/_distances/_distances.py +31 -46
  28. pertpy/tools/_enrichment.py +7 -22
  29. pertpy/tools/_milo.py +19 -15
  30. pertpy/tools/_mixscape.py +73 -75
  31. pertpy/tools/_perturbation_space/_clustering.py +4 -4
  32. pertpy/tools/_perturbation_space/_comparison.py +4 -4
  33. pertpy/tools/_perturbation_space/_discriminator_classifiers.py +83 -32
  34. pertpy/tools/_perturbation_space/_perturbation_space.py +10 -10
  35. pertpy/tools/_perturbation_space/_simple.py +12 -14
  36. pertpy/tools/_scgen/_scgen.py +16 -17
  37. pertpy/tools/_scgen/_scgenvae.py +2 -2
  38. pertpy/tools/_scgen/_utils.py +3 -1
  39. {pertpy-0.10.0.dist-info → pertpy-0.11.1.dist-info}/METADATA +42 -24
  40. pertpy-0.11.1.dist-info/RECORD +58 -0
  41. {pertpy-0.10.0.dist-info → pertpy-0.11.1.dist-info}/licenses/LICENSE +1 -0
  42. pertpy/tools/_kernel_pca.py +0 -50
  43. pertpy-0.10.0.dist-info/RECORD +0 -58
  44. {pertpy-0.10.0.dist-info → pertpy-0.11.1.dist-info}/WHEEL +0 -0
@@ -1,12 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
- import multiprocessing
4
3
  from abc import ABC, abstractmethod
5
4
  from typing import TYPE_CHECKING, Literal, NamedTuple
6
5
 
7
- import numba
8
6
  import numpy as np
9
7
  import pandas as pd
8
+ from numba import jit
10
9
  from ott.geometry.geometry import Geometry
11
10
  from ott.geometry.pointcloud import PointCloud
12
11
  from ott.problems.linear.linear_problem import LinearProblem
@@ -135,9 +134,7 @@ class Distance:
135
134
  self.aggregation_func = agg_fct
136
135
  if metric == "edistance":
137
136
  metric_fct = Edistance()
138
- elif metric == "euclidean":
139
- metric_fct = EuclideanDistance(self.aggregation_func)
140
- elif metric == "root_mean_squared_error":
137
+ elif metric in ("euclidean", "root_mean_squared_error"):
141
138
  metric_fct = EuclideanDistance(self.aggregation_func)
142
139
  elif metric == "mse":
143
140
  metric_fct = MeanSquaredDistance(self.aggregation_func)
@@ -181,7 +178,7 @@ class Distance:
181
178
 
182
179
  if layer_key and obsm_key:
183
180
  raise ValueError(
184
- "Cannot use 'layer_key' and 'obsm_key' at the same time.\n" "Please provide only one of the two keys."
181
+ "Cannot use 'layer_key' and 'obsm_key' at the same time.\nPlease provide only one of the two keys."
185
182
  )
186
183
  if not layer_key and not obsm_key:
187
184
  obsm_key = "X_pca"
@@ -201,6 +198,7 @@ class Distance:
201
198
  Args:
202
199
  X: First vector of shape (n_samples, n_features).
203
200
  Y: Second vector of shape (n_samples, n_features).
201
+ kwargs: Passed to the metric function.
204
202
 
205
203
  Returns:
206
204
  float: Distance between X and Y.
@@ -239,9 +237,10 @@ class Distance:
239
237
  Y: Second vector of shape (n_samples, n_features).
240
238
  n_bootstrap: Number of bootstrap samples.
241
239
  random_state: Random state for bootstrapping.
240
+ **kwargs: Passed to the metric function.
242
241
 
243
242
  Returns:
244
- MeanVar: Mean and variance of distance between X and Y.
243
+ Mean and variance of distance between X and Y.
245
244
 
246
245
  Examples:
247
246
  >>> import pertpy as pt
@@ -286,8 +285,8 @@ class Distance:
286
285
  kwargs: Additional keyword arguments passed to the metric function.
287
286
 
288
287
  Returns:
289
- pd.DataFrame: Dataframe with pairwise distances.
290
- tuple[pd.DataFrame, pd.DataFrame]: Two Dataframes, one for the mean and one for the variance of pairwise distances.
288
+ :class:`pandas.DataFrame`: Dataframe with pairwise distances.
289
+ tuple[:class:`pandas.DataFrame`, :class:`pandas.DataFrame`]: Two Dataframes, one for the mean and one for the variance of pairwise distances.
291
290
 
292
291
  Examples:
293
292
  >>> import pertpy as pt
@@ -309,7 +308,7 @@ class Distance:
309
308
  # able to handle precomputed distances such as the PseudobulkDistance.
310
309
  if self.metric_fct.accepts_precomputed:
311
310
  # Precompute the pairwise distances if needed
312
- if f"{self.obsm_key}_{self.cell_wise_metric}_predistances" not in adata.obsp.keys():
311
+ if f"{self.obsm_key}_{self.cell_wise_metric}_predistances" not in adata.obsp:
313
312
  self.precompute_distances(adata, n_jobs=n_jobs, **kwargs)
314
313
  pwd = adata.obsp[f"{self.obsm_key}_{self.cell_wise_metric}_predistances"]
315
314
  for index_x, group_x in enumerate(fct(groups)):
@@ -339,10 +338,7 @@ class Distance:
339
338
  df.loc[group_x, group_y] = df.loc[group_y, group_x] = bootstrap_output.mean
340
339
  df_var.loc[group_x, group_y] = df_var.loc[group_y, group_x] = bootstrap_output.variance
341
340
  else:
342
- if self.layer_key:
343
- embedding = adata.layers[self.layer_key]
344
- else:
345
- embedding = adata.obsm[self.obsm_key].copy()
341
+ embedding = adata.layers[self.layer_key] if self.layer_key else adata.obsm[self.obsm_key].copy()
346
342
  for index_x, group_x in enumerate(fct(groups)):
347
343
  cells_x = embedding[np.asarray(grouping == group_x)].copy()
348
344
  for group_y in groups[index_x:]: # type: ignore
@@ -409,8 +405,8 @@ class Distance:
409
405
  kwargs: Additional keyword arguments passed to the metric function.
410
406
 
411
407
  Returns:
412
- pd.DataFrame: Dataframe with distances of groups to selected_group.
413
- tuple[pd.DataFrame, pd.DataFrame]: Two Dataframes, one for the mean and one for the variance of distances of groups to selected_group.
408
+ :class:`pandas.DataFrame`: Dataframe with distances of groups to selected_group.
409
+ tuple[:class:`pandas.DataFrame`, :class:`pandas.DataFrame`]: Two Dataframes, one for the mean and one for the variance of distances of groups to selected_group.
414
410
 
415
411
 
416
412
  Examples:
@@ -446,7 +442,7 @@ class Distance:
446
442
  # able to handle precomputed distances such as the PseudobulkDistance.
447
443
  if self.metric_fct.accepts_precomputed:
448
444
  # Precompute the pairwise distances if needed
449
- if f"{self.obsm_key}_{self.cell_wise_metric}_predistances" not in adata.obsp.keys():
445
+ if f"{self.obsm_key}_{self.cell_wise_metric}_predistances" not in adata.obsp:
450
446
  self.precompute_distances(adata, n_jobs=n_jobs, **kwargs)
451
447
  pwd = adata.obsp[f"{self.obsm_key}_{self.cell_wise_metric}_predistances"]
452
448
  for group_x in fct(groups):
@@ -473,10 +469,7 @@ class Distance:
473
469
  df.loc[group_x] = bootstrap_output.mean
474
470
  df_var.loc[group_x] = bootstrap_output.variance
475
471
  else:
476
- if self.layer_key:
477
- embedding = adata.layers[self.layer_key]
478
- else:
479
- embedding = adata.obsm[self.obsm_key].copy()
472
+ embedding = adata.layers[self.layer_key] if self.layer_key else adata.obsm[self.obsm_key].copy()
480
473
  for group_x in fct(groups):
481
474
  cells_x = embedding[np.asarray(grouping == group_x)].copy()
482
475
  group_y = selected_group
@@ -524,10 +517,7 @@ class Distance:
524
517
  >>> distance = pt.tools.Distance(metric="edistance")
525
518
  >>> distance.precompute_distances(adata)
526
519
  """
527
- if self.layer_key:
528
- cells = adata.layers[self.layer_key]
529
- else:
530
- cells = adata.obsm[self.obsm_key].copy()
520
+ cells = adata.layers[self.layer_key] if self.layer_key else adata.obsm[self.obsm_key].copy()
531
521
  pwd = pairwise_distances(cells, cells, metric=self.cell_wise_metric, n_jobs=n_jobs)
532
522
  adata.obsp[f"{self.obsm_key}_{self.cell_wise_metric}_predistances"] = pwd
533
523
 
@@ -618,6 +608,7 @@ class AbstractDistance(ABC):
618
608
  Args:
619
609
  X: First vector of shape (n_samples, n_features).
620
610
  Y: Second vector of shape (n_samples, n_features).
611
+ kwargs: Passed to the metrics function.
621
612
 
622
613
  Returns:
623
614
  float: Distance between X and Y.
@@ -630,8 +621,8 @@ class AbstractDistance(ABC):
630
621
 
631
622
  Args:
632
623
  P: Pairwise distance matrix of shape (n_samples, n_samples).
633
- idx: Boolean array of shape (n_samples,) indicating which
634
- samples belong to X (or Y, since each metric is symmetric).
624
+ idx: Boolean array of shape (n_samples,) indicating which samples belong to X (or Y, since each metric is symmetric).
625
+ kwargs: Passed to the metrics function.
635
626
 
636
627
  Returns:
637
628
  float: Distance between X and Y.
@@ -645,12 +636,12 @@ class Edistance(AbstractDistance):
645
636
  def __init__(self) -> None:
646
637
  super().__init__()
647
638
  self.accepts_precomputed = True
648
- self.cell_wise_metric = "sqeuclidean"
639
+ self.cell_wise_metric = "euclidean"
649
640
 
650
641
  def __call__(self, X: np.ndarray, Y: np.ndarray, **kwargs) -> float:
651
- sigma_X = pairwise_distances(X, X, metric="sqeuclidean").mean()
652
- sigma_Y = pairwise_distances(Y, Y, metric="sqeuclidean").mean()
653
- delta = pairwise_distances(X, Y, metric="sqeuclidean").mean()
642
+ sigma_X = pairwise_distances(X, X, metric=self.cell_wise_metric, **kwargs).mean()
643
+ sigma_Y = pairwise_distances(Y, Y, metric=self.cell_wise_metric, **kwargs).mean()
644
+ delta = pairwise_distances(X, Y, metric=self.cell_wise_metric, **kwargs).mean()
654
645
  return 2 * delta - sigma_X - sigma_Y
655
646
 
656
647
  def from_precomputed(self, P: np.ndarray, idx: np.ndarray, **kwargs) -> float:
@@ -881,7 +872,7 @@ class R2ScoreDistance(AbstractDistance):
881
872
 
882
873
 
883
874
  class SymmetricKLDivergence(AbstractDistance):
884
- """Average of symmetric KL divergence between gene distributions of two groups
875
+ """Average of symmetric KL divergence between gene distributions of two groups.
885
876
 
886
877
  Assuming a Gaussian distribution for each gene in each group, calculates
887
878
  the KL divergence between them and averages over all genes. Repeats this ABBA to get a symmetrized distance.
@@ -908,7 +899,7 @@ class SymmetricKLDivergence(AbstractDistance):
908
899
 
909
900
 
910
901
  class TTestDistance(AbstractDistance):
911
- """Average of T test statistic between two groups assuming unequal variances"""
902
+ """Average of T test statistic between two groups assuming unequal variances."""
912
903
 
913
904
  def __init__(self) -> None:
914
905
  super().__init__()
@@ -932,16 +923,14 @@ class TTestDistance(AbstractDistance):
932
923
 
933
924
 
934
925
  class KSTestDistance(AbstractDistance):
935
- """Average of two-sided KS test statistic between two groups"""
926
+ """Average of two-sided KS test statistic between two groups."""
936
927
 
937
928
  def __init__(self) -> None:
938
929
  super().__init__()
939
930
  self.accepts_precomputed = False
940
931
 
941
932
  def __call__(self, X: np.ndarray, Y: np.ndarray, **kwargs) -> float:
942
- stats = []
943
- for i in range(X.shape[1]):
944
- stats.append(abs(kstest(X[:, i], Y[:, i])[0]))
933
+ stats = [abs(kstest(X[:, i], Y[:, i])[0]) for i in range(X.shape[1])]
945
934
  return sum(stats) / len(stats)
946
935
 
947
936
  def from_precomputed(self, P: np.ndarray, idx: np.ndarray, **kwargs) -> float:
@@ -949,10 +938,7 @@ class KSTestDistance(AbstractDistance):
949
938
 
950
939
 
951
940
  class NBLL(AbstractDistance):
952
- """
953
- Average of Log likelihood (scalar) of group B cells
954
- according to a NB distribution fitted over group A
955
- """
941
+ """Average of Log likelihood (scalar) of group B cells according to a NB distribution fitted over group A."""
956
942
 
957
943
  def __init__(self) -> None:
958
944
  super().__init__()
@@ -960,15 +946,12 @@ class NBLL(AbstractDistance):
960
946
 
961
947
  def __call__(self, X: np.ndarray, Y: np.ndarray, epsilon=1e-8, **kwargs) -> float:
962
948
  def _is_count_matrix(matrix, tolerance=1e-6):
963
- if matrix.dtype.kind == "i" or np.all(np.abs(matrix - np.round(matrix)) < tolerance):
964
- return True
965
- else:
966
- return False
949
+ return bool(matrix.dtype.kind == "i" or np.all(np.abs(matrix - np.round(matrix)) < tolerance))
967
950
 
968
951
  if not _is_count_matrix(matrix=X) or not _is_count_matrix(matrix=Y):
969
952
  raise ValueError("NBLL distance only works for raw counts.")
970
953
 
971
- @numba.jit(forceobj=True)
954
+ @jit(forceobj=True)
972
955
  def _compute_nll(y: np.ndarray, nb_params: tuple[float, float], epsilon: float) -> float:
973
956
  mu = np.exp(nb_params[0])
974
957
  theta = 1 / nb_params[1]
@@ -1163,9 +1146,11 @@ class MeanVarDistributionDistance(AbstractDistance):
1163
1146
 
1164
1147
  def __call__(self, X: np.ndarray, Y: np.ndarray, **kwargs) -> float:
1165
1148
  """Difference of mean-var distributions in 2 matrices.
1149
+
1166
1150
  Args:
1167
1151
  X: Normalized and log transformed cells x genes count matrix.
1168
1152
  Y: Normalized and log transformed cells x genes count matrix.
1153
+ kwargs: Passed to the metrics function.
1169
1154
  """
1170
1155
  mean_x, var_x = self._mean_var(X, log=True)
1171
1156
  mean_y, var_y = self._mean_var(Y, log=True)
@@ -25,10 +25,7 @@ def _prepare_targets(
25
25
  categories: str | Sequence[str] = None,
26
26
  ) -> ChainMap | dict:
27
27
  if categories is not None:
28
- if isinstance(categories, str):
29
- categories = [categories]
30
- else:
31
- categories = list(categories)
28
+ categories = [categories] if isinstance(categories, str) else list(categories)
32
29
 
33
30
  if targets is None:
34
31
  pt_drug = Drug()
@@ -97,10 +94,7 @@ class Enrichment:
97
94
  Returns:
98
95
  An AnnData object with scores.
99
96
  """
100
- if layer is not None:
101
- mtx = adata.layers[layer]
102
- else:
103
- mtx = adata.X
97
+ mtx = adata.layers[layer] if layer is not None else adata.X
104
98
 
105
99
  targets = _prepare_targets(targets=targets, nested=nested, categories=categories) # type: ignore
106
100
  full_targets = targets.copy()
@@ -114,10 +108,7 @@ class Enrichment:
114
108
  weights = pd.DataFrame(targets, index=adata.var_names)
115
109
  weights = weights.loc[:, weights.sum() > 0]
116
110
  weights = weights / weights.sum()
117
- if issparse(mtx):
118
- scores = mtx.dot(weights)
119
- else:
120
- scores = np.dot(mtx, weights)
111
+ scores = mtx.dot(weights) if issparse(mtx) else np.dot(mtx, weights)
121
112
 
122
113
  if method == "seurat":
123
114
  obs_avg = _mean(mtx, names=adata.var_names, axis=0)
@@ -136,10 +127,7 @@ class Enrichment:
136
127
  control_gene_weights = pd.DataFrame(control_groups, index=adata.var_names)
137
128
  control_gene_weights = control_gene_weights / control_gene_weights.sum()
138
129
 
139
- if issparse(mtx):
140
- control_profiles = mtx.dot(control_gene_weights)
141
- else:
142
- control_profiles = np.dot(mtx, control_gene_weights)
130
+ control_profiles = mtx.dot(control_gene_weights) if issparse(mtx) else np.dot(mtx, control_gene_weights)
143
131
  drug_bins = {}
144
132
  for drug in weights.columns:
145
133
  bins = np.unique(obs_cut[targets[drug]])
@@ -178,7 +166,7 @@ class Enrichment:
178
166
  Accepts two forms:
179
167
  - A dictionary with the names of the groups as keys, and the entries being the corresponding gene lists.
180
168
  - A dictionary of dictionaries defined like above, with names of gene group categories as keys.
181
- If passing one of those, specify `nested=True`.
169
+ If passing one of those, specify `nested=True`.
182
170
  nested: Whether `targets` is a dictionary of dictionaries with group categories as keys.
183
171
  categories: If `targets=None` or `nested=True`, this argument can be used to subset the gene groups to one or more categories (keys of the original dictionary).
184
172
  In case of the ChEMBL drug targets, these are ATC level 1/level 2 category codes.
@@ -293,7 +281,7 @@ class Enrichment:
293
281
  return enrichment
294
282
 
295
283
  @_doc_params(common_plot_args=doc_common_plot_args)
296
- def plot_dotplot(
284
+ def plot_dotplot( # pragma: no cover # noqa: D417
297
285
  self,
298
286
  adata: AnnData,
299
287
  *,
@@ -341,10 +329,7 @@ class Enrichment:
341
329
  .. image:: /_static/docstring_previews/enrichment_dotplot.png
342
330
  """
343
331
  if categories is not None:
344
- if isinstance(categories, str):
345
- categories = [categories]
346
- else:
347
- categories = list(categories)
332
+ categories = [categories] if isinstance(categories, str) else list(categories)
348
333
 
349
334
  if targets is None:
350
335
  pt_drug = Drug()
pertpy/tools/_milo.py CHANGED
@@ -51,14 +51,16 @@ class Milo:
51
51
  Args:
52
52
  input: AnnData
53
53
  feature_key: Key to store the cell-level AnnData object in the MuData object
54
+
54
55
  Returns:
55
- MuData: MuData object with original AnnData.
56
+ :class:`mudata.MuData` object with original AnnData.
56
57
 
57
58
  Examples:
58
59
  >>> import pertpy as pt
59
60
  >>> adata = pt.dt.bhattacherjee()
60
61
  >>> milo = pt.tl.Milo()
61
62
  >>> mdata = milo.load(adata)
63
+
62
64
  """
63
65
  mdata = MuData({feature_key: input, "milo": AnnData()})
64
66
 
@@ -113,6 +115,7 @@ class Milo:
113
115
  >>> mdata = milo.load(adata)
114
116
  >>> sc.pp.neighbors(mdata["rna"])
115
117
  >>> milo.make_nhoods(mdata["rna"])
118
+
116
119
  """
117
120
  if isinstance(data, MuData):
118
121
  adata = data[feature_key]
@@ -177,10 +180,7 @@ class Milo:
177
180
  adata.obs["nhood_ixs_random"] = adata.obs["nhood_ixs_random"].astype("int")
178
181
  adata.uns["nhood_neighbors_key"] = neighbors_key
179
182
  # Store distance to K-th nearest neighbor (used for spatial FDR correction)
180
- if neighbors_key is None:
181
- knn_dists = adata.obsp["distances"]
182
- else:
183
- knn_dists = adata.obsp[neighbors_key + "_distances"]
183
+ knn_dists = adata.obsp["distances"] if neighbors_key is None else adata.obsp[neighbors_key + "_distances"]
184
184
 
185
185
  nhood_ixs = adata.obs["nhood_ixs_refined"] == 1
186
186
  dist_mat = knn_dists[np.asarray(nhood_ixs), :]
@@ -223,6 +223,7 @@ class Milo:
223
223
  >>> sc.pp.neighbors(mdata["rna"])
224
224
  >>> milo.make_nhoods(mdata["rna"])
225
225
  >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident")
226
+
226
227
  """
227
228
  if isinstance(data, MuData):
228
229
  adata = data[feature_key]
@@ -297,6 +298,7 @@ class Milo:
297
298
  >>> milo.make_nhoods(mdata["rna"])
298
299
  >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident")
299
300
  >>> milo.da_nhoods(mdata, design="~label")
301
+
300
302
  """
301
303
  try:
302
304
  sample_adata = mdata["milo"]
@@ -428,7 +430,7 @@ class Milo:
428
430
  feature_key: If input data is MuData, specify key to cell-level AnnData object.
429
431
 
430
432
  Returns:
431
- None. Adds in place:
433
+ Adds in place.
432
434
  - `milo_mdata['milo'].var["nhood_annotation"]`: assigning a label to each nhood
433
435
  - `milo_mdata['milo'].var["nhood_annotation_frac"]` stores the fraciton of cells in the neighbourhood with the assigned label
434
436
  - `milo_mdata['milo'].varm['frac_annotation']`: stores the fraction of cells from each label in each nhood
@@ -444,6 +446,7 @@ class Milo:
444
446
  >>> milo.make_nhoods(mdata["rna"])
445
447
  >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident")
446
448
  >>> milo.annotate_nhoods(mdata, anno_col="cell_type")
449
+
447
450
  """
448
451
  try:
449
452
  sample_adata = mdata["milo"]
@@ -482,7 +485,7 @@ class Milo:
482
485
  feature_key: If input data is MuData, specify key to cell-level AnnData object.
483
486
 
484
487
  Returns:
485
- None. Adds in place:
488
+ Adds in place.
486
489
  - `milo_mdata['milo'].var["nhood_{anno_col}"]`: assigning a continuous value to each nhood
487
490
 
488
491
  Examples:
@@ -567,7 +570,7 @@ class Milo:
567
570
  sample_adata.obs = sample_obs.loc[sample_adata.obs_names]
568
571
 
569
572
  def build_nhood_graph(self, mdata: MuData, basis: str = "X_umap", feature_key: str | None = "rna"):
570
- """Build graph of neighbourhoods used for visualization of DA results
573
+ """Build graph of neighbourhoods used for visualization of DA results.
571
574
 
572
575
  Args:
573
576
  mdata: MuData object
@@ -625,6 +628,7 @@ class Milo:
625
628
  >>> milo.make_nhoods(mdata["rna"])
626
629
  >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident")
627
630
  >>> milo.add_nhood_expression(mdata)
631
+
628
632
  """
629
633
  try:
630
634
  sample_adata = mdata["milo"]
@@ -652,7 +656,7 @@ class Milo:
652
656
  def _setup_rpy2(
653
657
  self,
654
658
  ):
655
- """Set up rpy2 to run edgeR"""
659
+ """Set up rpy2 to run edgeR."""
656
660
  from rpy2.robjects import numpy2ri, pandas2ri
657
661
  from rpy2.robjects.packages import importr
658
662
 
@@ -715,7 +719,7 @@ class Milo:
715
719
  sample_adata.var.loc[keep_nhoods, "SpatialFDR"] = adjp
716
720
 
717
721
  @_doc_params(common_plot_args=doc_common_plot_args)
718
- def plot_nhood_graph(
722
+ def plot_nhood_graph( # pragma: no cover # noqa: D417
719
723
  self,
720
724
  mdata: MuData,
721
725
  *,
@@ -730,7 +734,7 @@ class Milo:
730
734
  return_fig: bool = False,
731
735
  **kwargs,
732
736
  ) -> Figure | None:
733
- """Visualize DA results on abstracted graph (wrapper around sc.pl.embedding)
737
+ """Visualize DA results on abstracted graph (wrapper around sc.pl.embedding).
734
738
 
735
739
  Args:
736
740
  mdata: MuData object
@@ -808,7 +812,7 @@ class Milo:
808
812
  return None
809
813
 
810
814
  @_doc_params(common_plot_args=doc_common_plot_args)
811
- def plot_nhood(
815
+ def plot_nhood( # pragma: no cover # noqa: D417
812
816
  self,
813
817
  mdata: MuData,
814
818
  ix: int,
@@ -869,7 +873,7 @@ class Milo:
869
873
  return None
870
874
 
871
875
  @_doc_params(common_plot_args=doc_common_plot_args)
872
- def plot_da_beeswarm(
876
+ def plot_da_beeswarm( # pragma: no cover # noqa: D417
873
877
  self,
874
878
  mdata: MuData,
875
879
  *,
@@ -880,7 +884,7 @@ class Milo:
880
884
  palette: str | Sequence[str] | dict[str, str] | None = None,
881
885
  return_fig: bool = False,
882
886
  ) -> Figure | None:
883
- """Plot beeswarm plot of logFC against nhood labels
887
+ """Plot beeswarm plot of logFC against nhood labels.
884
888
 
885
889
  Args:
886
890
  mdata: MuData object
@@ -995,7 +999,7 @@ class Milo:
995
999
  return None
996
1000
 
997
1001
  @_doc_params(common_plot_args=doc_common_plot_args)
998
- def plot_nhood_counts_by_cond(
1002
+ def plot_nhood_counts_by_cond( # pragma: no cover # noqa: D417
999
1003
  self,
1000
1004
  mdata: MuData,
1001
1005
  test_var: str,