scverse / scverse/scanpy

sc.tl.embedding_density errors when a category has one observation

Open
#2,043 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Area - Plotting 🌺
Dominant language
Python
Stars
2.6k
Forks
779
Avg merge
1d 4h
Merged PRs (30d)
27

Description

Haven't done much investigation into why, but the Fly Cell Atlas head dataset (10x, Stringent, H5AD) causes sc.tl.embedding_density to error when groupby="annotation_broad_extrapolated".

import scanpy as sc
# Warning: 2.5gb
!wget -O s_fca_biohub_head_10x.h5ad https://cloud.flycellatlas.org/index.php/s/LAEybPc2HZnpzKs/download

adata = sc.read_h5ad("s_fca_biohub_head_10x.h5ad")
sc.tl.embedding_density(adata, groupby="annotation_broad_extrapolated")
traceback
/usr/local/lib/python3.8/site-packages/scipy/stats/kde.py:563: RuntimeWarning: Degrees of freedom <= 0 for slice
  self._data_covariance = atleast_2d(cov(self.dataset, rowvar=1,
/usr/local/lib/python3.8/site-packages/numpy/lib/function_base.py:2493: RuntimeWarning: divide by zero encountered in true_divide
  c *= np.true_divide(1, fact)
/usr/local/lib/python3.8/site-packages/numpy/lib/function_base.py:2493: RuntimeWarning: invalid value encountered in multiply
  c *= np.true_divide(1, fact)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/var/folders/bd/43q20k0n6z15tdfzxvd22r7c0000gn/T/ipykernel_4569/1429565136.py in <module>
----> 1 sc.tl.embedding_density(adata, groupby="annotation_broad_extrapolated")

~/github/scanpy/scanpy/tools/_embedding_density.py in embedding_density(adata, basis, groupby, key_added, components)
    164             embed_y = adata.obsm[f'X_{basis}'][cat_mask, components[1]]
    165 
--> 166             dens_embed = _calc_density(embed_x, embed_y)
    167             density_values[cat_mask] = dens_embed
    168 

~/github/scanpy/scanpy/tools/_embedding_density.py in _calc_density(x, y)
     19     # Calculate the point density
     20     xy = np.vstack([x, y])
---> 21     z = gaussian_kde(xy)(xy)
     22 
     23     min_z = np.min(z)

/usr/local/lib/python3.8/site-packages/scipy/stats/kde.py in __init__(self, dataset, bw_method, weights)
    204             self._neff = 1/sum(self._weights**2)
    205 
--> 206         self.set_bandwidth(bw_method=bw_method)
    207 
    208     def evaluate(self, points):

/usr/local/lib/python3.8/site-packages/scipy/stats/kde.py in set_bandwidth(self, bw_method)
    552             raise ValueError(msg)
    553 
--> 554         self._compute_covariance()
    555 
    556     def _compute_covariance(self):

/usr/local/lib/python3.8/site-packages/scipy/stats/kde.py in _compute_covariance(self)
    564                                                bias=False,
    565                                                aweights=self.weights))
--> 566             self._data_inv_cov = linalg.inv(self._data_covariance)
    567 
    568         self.covariance = self._data_covariance * self.factor**2

/usr/local/lib/python3.8/site-packages/scipy/linalg/basic.py in inv(a, overwrite_a, check_finite)
    937 
    938     """
--> 939     a1 = _asarray_validated(a, check_finite=
)
    940     if len(a1.shape) != 2 or a1.shape[0] != a1.shape[1]:
    941         raise ValueError('expected square matrix')

/usr/local/lib/python3.8/site-packages/scipy/_lib/_util.py in _asarray_validated(a, check_finite, sparse_ok, objects_ok, mask_ok, as_inexact)
    291             raise ValueError('masked arrays are not supported')
    292     toarray = np.asarray_chkfinite if check_finite else np.asarray
--> 293     a = toarray(a)
    294     if not objects_ok:
    295         if a.dtype is np.dtype('O'):

/usr/local/lib/python3.8/site-packages/numpy/lib/function_base.py in asarray_chkfinite(a, dtype, order)
    486     a = asarray(a, dtype=dtype, order=order)
    487     if a.dtype.char in typecodes['AllFloat'] and not np.isfinite(a).all():
--> 488         raise ValueError(
    489             "array must not contain infs or NaNs")
    490     return a

ValueError: array must not contain infs or NaNs

I think it's that one of the categories only has one observation. Probably just needs a better error.


Yup, one obs reproduces:

adata = sc.datasets.pbmc3k_processed().raw.to_adata()
mask = adata.obs["louvain"] != "CD4 T cells"
mask.iloc[0] = True
sc.tl.embedding_density(adata[mask], groupby="louvain")

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in scanpy/tools/_embedding_density.py, especially _calc_density, and reproduce the failure with the provided pbmc3k_processed example where one category has a single observation. Determine the intended handling or error for singleton categories, then verify that embedding_density no longer produces the reported NaN-related failure.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
bioinformatics
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.