name: highly_variable_features_scanpy
namespace: feature_annotation
scope: "public"
description: |
  Annotate highly variable features [Satija15] [Zheng17] [Stuart19].

  Expects logarithmized data, except when flavor='seurat_v3' in which count data is expected.

  Depending on flavor, this reproduces the R-implementations of Seurat [Satija15], Cell Ranger [Zheng17], and Seurat v3 [Stuart19].

  For the dispersion-based methods ([Satija15] and [Zheng17]), the normalized dispersion is obtained by scaling with the mean and standard deviation of the dispersions for features falling into a given bin for mean expression of features. This means that for each bin of mean expression, highly variable features are selected.

  For [Stuart19], a normalized variance for each feature is computed. First, the data are standardized (i.e., z-score normalization per feature) with a regularized standard deviation. Next, the normalized variance is computed as the variance of each feature after the transformation. Features are ranked by the normalized variance.
authors:
  - __merge__: /src/authors/dries_de_maeyer.yaml
    roles: [ contributor ]
  - __merge__: /src/authors/robrecht_cannoodt.yaml
    roles: [ maintainer, contributor ]
arguments:
  # input
  - name: "--input"
    type: file
    description: Input h5mu file
    direction: input
    required: true
    example: input.h5mu

  - name: "--modality"
    description: |
      Which modality from the input MuData file to process.
    type: string
    default: "rna"
    required: false
  - name: "--layer"
    type: string
    description: use adata.layers[layer] for expression values instead of adata.X.
    required: false
  - name: "--var_input"
    type: string
    description: |
      If specified, use boolean array in adata.var[var_input] to calculate hvg on subset of vars.
    required: false
  # output
  - name: "--output"
    type: file
    description: Output h5mu file.
    direction: output
    example: output.h5mu

  - name: "--var_name_filter"
    type: string
    default: "filter_with_hvg"
    description: In which .var slot to store a boolean array corresponding to which observations should be filtered out.

  - name: "--varm_name"
    type: string
    default: "hvg"
    description: In which .varm slot to store additional metadata.

  # arguments
  - name: "--flavor"
    type: string
    default: "seurat"
    choices: ["seurat", "cell_ranger", "seurat_v3"]
    description: |
      Choose the flavor for identifying highly variable features. For the dispersion based methods
      in their default workflows, Seurat passes the cutoffs whereas Cell Ranger passes n_top_features.

  - name: "--n_top_features"
    type: integer
    description: Number of highly-variable features to keep. Mandatory if flavor='seurat_v3'.
  
  - name: "--min_mean"
    type: double
    description: If n_top_features is defined, this and all other cutoffs for the means and the normalized dispersions are ignored. Ignored if flavor='seurat_v3'.
    default: 0.0125
  
  - name: "--max_mean"
    type: double
    description: If n_top_features is defined, this and all other cutoffs for the means and the normalized dispersions are ignored. Ignored if flavor='seurat_v3'.
    default: 3
  
  - name: "--min_disp"
    type: double
    description: If n_top_features is defined, this and all other cutoffs for the means and the normalized dispersions are ignored. Ignored if flavor='seurat_v3'.
    default: 0.5
  
  - name: "--max_disp"
    type: double
    description: If n_top_features is defined, this and all other cutoffs for the means and the normalized dispersions are ignored. Ignored if flavor='seurat_v3'. Default is +inf.
    # default: "+inf"
  
  - name: "--span"
    type: double
    description: The fraction of the data (cells) used when estimating the variance in the loess model fit if flavor='seurat_v3'. 
    default: 0.3
  
  - name: "--n_bins"
    type: integer
    description: Number of bins for binning the mean feature expression. Normalization is done with respect to each bin. If just a single feature falls into a bin, the normalized dispersion is artificially set to 1.
    default: 20
  
  - name: "--obs_batch_key"
    type: string
    description: |
      If specified, highly-variable features are selected within each batch separately and merged. This simple 
      process avoids the selection of batch-specific features and acts as a lightweight batch correction method. 
      For all flavors, features are first sorted by how many batches they are a HVG. For dispersion-based flavors 
      ties are broken by normalized dispersion. If flavor = 'seurat_v3', ties are broken by the median (across
      batches) rank based on within-batch normalized variance.
  
__merge__: [., /src/base/h5_compression_argument.yaml]

resources:
  - type: python_script
    path: script.py
  - path: /src/utils/setup_logger.py
  - path: /src/utils/compress_h5mu.py
  - path: /src/utils/subset_vars.py
test_resources:
  - type: python_script
    path: test.py
  - path: /resources_test/pbmc_1k_protein_v3

engines:
- type: docker
  image: python:3.12
  setup: 
    - type: python
      __merge__: [/src/base/requirements/anndata_mudata.yaml, /src/base/requirements/scanpy.yaml, .]
      packages:
        - scikit-misc
  __merge__: [ /src/base/requirements/python_test_setup.yaml, .]

runners:
- type: executable
- type: nextflow
  directives:
    label: [singlecpu, lowmem]
