Repository: scverse/scanpy

Issue:
flavor="seurat_v3" from sc.pp.highly_variable_genes() does not work
Hi, I have a Seruat processed dataset, of which I wanted to use scVI for integration. I stored the raw count and cell information then assembled them in scanpy as anndata via method mentioned: `https://smorabit.github.io/tutorials/8_velocyto/`. 

So I could get batch HVG function to work without specifying flavor, however, I couldn't get it to work with specifying `flavor="seurat_v3"`, I wonder how important it is to set this parameter and why does it not work for me?

Thanks a lot!


```
adata
AnnData object with n_obs × n_vars = 73998 × 13639
    obs: 'orig.ident', 'nCount_RNA', 'nFeature_RNA', 'barcode', 'Celltype2', 'Clusters', 'Sample'
    uns: 'log1p'
    layers: 'counts'

for i in adatas:
    i.layers['counts'] = i.X
adata = ad.concat(adatas)
adata.obs_names_make_unique
sc.pp.log1p(adata)
sc.pp.highly_variable_genes(
    adata,
    flavor="seurat_v3",
    layer="counts",
    batch_key="Sample",
    subset=True
)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [197], line 1
----> 1 sc.pp.highly_variable_genes(
      2     adata_new,
      3     flavor="seurat_v3",
      4     layer="counts",
      5     batch_key="Sample",
      6     subset=True
      7 )
      8 adata_new

File ~/.local/lib/python3.8/site-packages/scanpy/preprocessing/_highly_variable_genes.py:422, in highly_variable_genes(adata, layer, n_top_genes, min_disp, max_disp, min_mean, max_mean, span, n_bins, flavor, subset, inplace, batch_key, check_values)
    416     raise ValueError(
    417         '`pp.highly_variable_genes` expects an `AnnData` argument, '
    418         'pass `inplace=False` if you want to return a `pd.DataFrame`.'
    419     )
    421 if flavor == 'seurat_v3':
--> 422     return _highly_variable_genes_seurat_v3(
    423         adata,
    424         layer=layer,
    425         n_top_genes=n_top_genes,
    426         batch_key=batch_key,
    427         check_values=check_values,
    428         span=span,
    429         subset=subset,
    430         inplace=inplace,
    431     )
    433 if batch_key is None:
    434     df = _highly_variable_genes_single_batch(
    435         adata,
    436         layer=layer,
   (...)
    443         flavor=flavor,
    444     )

File ~/.local/lib/python3.8/site-packages/scanpy/preprocessing/_highly_variable_genes.py:126, in _highly_variable_genes_seurat_v3(adata, layer, n_top_genes, batch_key, check_values, span, subset, inplace)
    123 # this is done in SelectIntegrationFeatures() in Seurat v3
    124 ranked_norm_gene_vars = ranked_norm_gene_vars.astype(np.float32)
    125 num_batches_high_var = np.sum(
--> 126     (ranked_norm_gene_vars < n_top_genes).astype(int), axis=0
    127 )
    128 ranked_norm_gene_vars[ranked_norm_gene_vars >= n_top_genes] = np.nan
    129 ma_ranked = np.ma.masked_invalid(ranked_norm_gene_vars)

TypeError: '<' not supported between instances of 'float' and 'NoneType'   ```


Discussion:

Resolving patch:
diff --git a/scanpy/preprocessing/_highly_variable_genes.py b/scanpy/preprocessing/_highly_variable_genes.py
--- a/scanpy/preprocessing/_highly_variable_genes.py
+++ b/scanpy/preprocessing/_highly_variable_genes.py
@@ -1,7 +1,8 @@
 from __future__ import annotations
 
 import warnings
-from typing import Literal
+from inspect import signature
+from typing import Literal, cast
 
 import numpy as np
 import pandas as pd
@@ -328,7 +329,7 @@ def highly_variable_genes(
     max_disp: float | None = np.inf,
     min_mean: float | None = 0.0125,
     max_mean: float | None = 3,
-    span: float | None = 0.3,
+    span: float = 0.3,
     n_bins: int = 20,
     flavor: Literal["seurat", "cell_ranger", "seurat_v3"] = "seurat",
     subset: bool = False,
@@ -455,6 +456,9 @@ def highly_variable_genes(
         )
 
     if flavor == "seurat_v3":
+        if n_top_genes is None:
+            sig = signature(_highly_variable_genes_seurat_v3)
+            n_top_genes = cast(int, sig.parameters["n_top_genes"].default)
         return _highly_variable_genes_seurat_v3(
             adata,
             layer=layer,


Test patch:
diff --git a/scanpy/tests/test_highly_variable_genes.py b/scanpy/tests/test_highly_variable_genes.py
--- a/scanpy/tests/test_highly_variable_genes.py
+++ b/scanpy/tests/test_highly_variable_genes.py
@@ -387,12 +387,16 @@ def test_higly_variable_genes_compare_to_seurat_v3():
     seu = pd.Index(seurat_hvg_info_batch["x"].values)
     assert len(seu.intersection(df.index)) / 4000 > 0.95
 
+
+@needs.skmisc
+def test_higly_variable_genes_seurat_v3_warning():
+    pbmc = pbmc3k()[:200].copy()
     sc.pp.log1p(pbmc)
     with pytest.warns(
         UserWarning,
         match="`flavor='seurat_v3'` expects raw count data, but non-integers were found.",
     ):
-        sc.pp.highly_variable_genes(pbmc, n_top_genes=1000, flavor="seurat_v3")
+        sc.pp.highly_variable_genes(pbmc, flavor="seurat_v3")
 
 
 def test_filter_genes_dispersion_compare_to_seurat():