Repository: scverse/scanpy

Issue:
Documentation for percent_top= in scanpy.pp.calculate_qc_metrics is unclear and contradictory
### Please make sure these conditions are met

- [X] I have checked that this issue has not already been reported.
- [X] I have confirmed this bug exists on the latest version of scanpy.
- [X] (optional) I have confirmed this bug exists on the master branch of scanpy.

### What happened?

First, the argument is named "percent"_top, suggesting a fraction in the range [0,1] or at a stretch [0, 100].

Second, the description starts with "Which proportion", again suggesting a fraction.

But then, the description goes on to say that `percent_top=[50]` would use the 50 most expressed genes, NOT the 50% most expressed genes. So in the end, it's not a percentage but an absolute number.

This is further supported by the fact that the default values are `(50, 100, 200, 500)`, which are clearly not percentages.
See: https://github.com/scverse/scanpy/blob/585f58c9e4dd82dd7809a831538c4e230b008818/scanpy/preprocessing/_qc.py#L237


### Minimal code sample

```python
# No code, issue is in documentation
```


### Error output

_No response_

### Versions

<details>

```
-----
anndata     0.10.4
scanpy      1.9.6
-----
PIL                         10.0.0
anyio                       NA
arrow                       1.3.0
asttokens                   NA
attr                        23.1.0
attrs                       23.1.0
babel                       2.13.1
certifi                     2023.07.22
cffi                        1.16.0
charset_normalizer          3.2.0
comm                        0.2.0
cycler                      0.10.0
cython_runtime              NA
dateutil                    2.8.2
debugpy                     1.8.0
decorator                   5.1.1
defusedxml                  0.7.1
entrypoints                 0.4
executing                   2.0.1
fastjsonschema              NA
fqdn                        NA
h5py                        3.10.0
idna                        3.4
igraph                      0.10.8
ipykernel                   6.27.1
ipython_genutils            0.2.0
ipywidgets                  8.1.1
isoduration                 NA
jedi                        0.19.1
jinja2                      3.1.2
joblib                      1.3.2
json5                       NA
jsonpointer                 2.4
jsonschema                  4.20.0
jsonschema_specifications   NA
jupyter_server              1.24.0
jupyterlab_server           2.25.2
kiwisolver                  1.4.5
leidenalg                   0.10.1
llvmlite                    0.41.1
markupsafe                  2.1.3
matplotlib                  3.7.2
matplotlib_inline           0.1.6
mpl_toolkits                NA
mpmath                      1.3.0
natsort                     8.4.0
nbformat                    5.9.2
numba                       0.58.1
numpy                       1.25.2
packaging                   23.1
pandas                      2.1.4
parso                       0.8.3
patsy                       0.5.6
pexpect                     4.9.0
platformdirs                4.1.0
plotly                      5.18.0
prometheus_client           NA
prompt_toolkit              3.0.41
psutil                      5.9.6
ptyprocess                  0.7.0
pure_eval                   0.2.2
pycparser                   2.21
pydev_ipython               NA
pydevconsole                NA
pydevd                      2.9.5
pydevd_file_utils           NA
pydevd_plugins              NA
pydevd_tracing              NA
pygments                    2.16.1
pyparsing                   3.0.9
pytz                        2023.3.post1
referencing                 NA
requests                    2.31.0
rfc3339_validator           0.1.4
rfc3986_validator           0.1.1
rpds                        NA
scipy                       1.11.4
seaborn                     0.13.1
send2trash                  NA
session_info                1.0.0
simplejson                  3.19.1
six                         1.16.0
sklearn                     1.3.2
sniffio                     1.3.0
sparse                      0.14.0
stack_data                  0.6.3
statsmodels                 0.14.1
sympy                       1.12
terminado                   0.18.0
texttable                   1.7.0
threadpoolctl               3.2.0
torch                       2.1.2+cu121
torchgen                    NA
tornado                     6.4
tqdm                        4.66.1
traitlets                   5.14.0
typing_extensions           NA
uri_template                NA
urllib3                     2.0.4
wcwidth                     0.2.12
webcolors                   1.13
websocket                   1.7.0
yaml                        6.0.1
zmq                         24.0.1
-----
IPython             8.18.1
jupyter_client      7.4.9
jupyter_core        5.5.0
jupyterlab          3.6.5
notebook            6.5.6
-----
Python 3.11.3 (main, Aug 25 2023, 17:24:38) [GCC 11.4.0]
Linux-5.15.0-91-generic-x86_64-with-glibc2.35
-----
Session information updated at 2024-02-07 10:05
```

</details>



Discussion:
Well, the parameter documentation says

> `percent_top=[50]` finds cumulative proportion to the 50th most expressed gene.

so the full description is less misleading than the part you mention. But generally I agree.

@ilan-gold @ivirshup something for the scanpy 2.0 board?
What would be a better name?

Also, believe this has been discussed before, but not sure where. I think we wanted to normalize on `frac` vs `pct` vs `percent` or something?

This was also based on `scater`'s qc metrics function, which now lives in `scuttle`. The argument there is named `percent.top`: https://bioconductor.org/packages/release/bioc/manuals/scuttle/man/scuttle.pdf
Actually, very good point about `scater`.

I think the name can be kept. It's more the description that I found slightly convoluted and confusing.

For reference, here is the description of `percent.top` in `scater`:

> An integer vector specifying the size(s) of the top set of high-abundance genes. Used to compute the percentage of library size occupied by the most highly expressed genes in each cell.

(https://rdrr.io/github/LTLA/scuttle/man/perCellQCMetrics.html)

alongside the description of `percent_top` in `scanpy`

> Which proportions of top genes to cover. If empty or None don’t calculate. Values are considered 1-indexed, percent_top=[50] finds cumulative proportion to the 50th most expressed gene.

(https://scanpy.readthedocs.io/en/stable/generated/scanpy.pp.calculate_qc_metrics.html)

I find it clearer when the description starts with "integer" rather than "proportions".

Here's my Pythonized suggestion for scanpy:

> A list of integers specifying the sizes of the top sets of genes used to compute the percentage of library size occupied by the most highly expressed genes in each cell.

Happy to hear feedback and further edits!
I agree the doc string is oddly worded. I do think "cumulative proportion" is probably the easiest way to understand this.

Is this better?

> List of ranks (where genes are ranked by expression) at which the cumulative proportion of expression will be reported as a percentage. This can be used to assess library complexity. Ranks are considered 1-indexed, and if empty or None don’t calculate. 
> 
> *E.g.* `percent_top=[50]` finds cumulative proportion to the 50th most expressed gene.


Resolving patch:
diff --git a/scanpy/preprocessing/_docs.py b/scanpy/preprocessing/_docs.py
--- a/scanpy/preprocessing/_docs.py
+++ b/scanpy/preprocessing/_docs.py
@@ -34,9 +34,12 @@
     Keys for boolean columns of `.var` which identify variables you could
     want to control for (e.g. "ERCC" or "mito").
 percent_top
-    Which proportions of top genes to cover. If empty or `None` don't
-    calculate. Values are considered 1-indexed, `percent_top=[50]` finds
-    cumulative proportion to the 50th most expressed gene.\
+    List of ranks (where genes are ranked by expression) at which the cumulative
+    proportion of expression will be reported as a percentage. This can be used to
+    assess library complexity. Ranks are considered 1-indexed, and if empty or None
+    don't calculate.
+
+    E.g. `percent_top=[50]` finds cumulative proportion to the 50th most expressed gene.
 """
 
 doc_qc_metric_naming = """\


Test patch: