name: calculate_qc_metrics
namespace: "qc"
scope: "public"
description: |
  Add basic quality control metrics to an .h5mu file.

  The metrics are comparable to what scanpy.pp.calculate_qc_metrics output,
  although they have slightly different names:

  Var metrics (name in this component -> name in scanpy):
    - pct_dropout -> pct_dropout_by_{expr_type}
    - num_nonzero_obs -> n_cells_by_{expr_type}
    - obs_mean -> mean_{expr_type}
    - total_counts -> total_{expr_type}

    Obs metrics:
      - num_nonzero_vars -> n_genes_by_{expr_type}
      - pct_{var_qc_metrics} -> pct_{expr_type}_{qc_var}
      - total_counts_{var_qc_metrics} -> total_{expr_type}_{qc_var}
      - pct_of_counts_in_top_{top_n_vars}_vars -> pct_{expr_type}_in_top_{n}_{var_type}
      - total_counts -> total_{expr_type}
      
authors:
  - __merge__: /src/authors/dries_schaumont.yaml
    roles: [ author ]
argument_groups:
  - name: Inputs
    arguments:
      - name: "--input"
        type: file
        description: Input data. Can be encoded in H5 or Zarr (v3) format.
        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"
        description: |
          Layer from modality to use as input data. If not provided the .X attribute is used.
        type: string
        example: "raw_counts"
        required: false
      - name: "--log1p_transform"
        description: |
          Compute log1p-transformed versions of the metrics added to `.var` and `.obs`.
          For each emitted metric column `<col>`, an additional column `log1p_<col>` is added
          containing `log1p(<col>)`. Mirrors scanpy's `log1p` flag.
        type: boolean
        default: true
  - name: Metrics added to .obs
    arguments:
      - name: "--var_qc_metrics"
        description: |
          Keys to select a boolean (containing only True or False) column from .var.
          For each cell, calculate the proportion of total values for genes which are labeled 'True', 
          compared to the total sum of the values for all genes.
        type: string
        multiple: True
        example: "ercc,highly_variable,mitochondrial"
      - name: "--var_qc_metrics_fill_na_value"
        type: boolean
        description: |
          Fill any 'NA' values found in the columns specified with --var_qc_metrics to 'True' or 'False'.
          as False.
      - name: "--top_n_vars"
        type: integer
        description: |
          Number of top vars to be used to calculate cumulative proportions.
          If not specified, proportions are not calculated. `--top_n_vars 20;50` finds
          cumulative proportion to the 20th and 50th most expressed vars.
        multiple: true
        required: false
      - name: "--output_obs_top_n_vars"
        description: |
          Format string for the names of the .obs columns that contain the cumulative
          proportion of counts in the top N vars (one column per value in `--top_n_vars`).
          Use `{n}` as a placeholder for the top-N value provided in `--top_n_vars`.
        type: string
        required: false
        default: "pct_of_counts_in_top_{n}_vars"
      - name: "--output_obs_num_nonzero_vars"
        description: |
          Name of column in .obs describing, for each observation, the number of stored values
          (including explicit zeroes). In other words, the name of the column that counts
          for each row the number of columns that contain data.
        type: string
        required: false
        default: "num_nonzero_vars"
      - name: "--output_obs_total_counts_vars"
        description: |
          Name of the column for .obs describing, for each observation (row),
          the sum of the stored values in the columns.
        type: string
        required: false
        default: total_counts
  - name: Metrics added to .var
    arguments:
      - name: "--output_var_num_nonzero_obs"
        description: |
          Name of column describing, for each feature, the number of stored values
          (including explicit zeroes). In other words, the name of the column that counts
          for each column the number of rows that contain data.
        type: string
        required: false
        default: "num_nonzero_obs"
      - name: "--output_var_total_counts_obs"
        description: |
          Name of the column in .var describing, for each feature (column),
          the sum of the stored values in the rows.
        type: string
        required: false
        default: total_counts
      - name: "--output_var_obs_mean"
        type: string
        description: |
          Name of the column in .obs providing the mean of the values in each row.
        default: "obs_mean"
        required: false
      - name: "--output_var_pct_dropout"
        type: string
        default: "pct_dropout"
        description: |
          Name of the column in .obs providing for each feature the percentage of
          observations the feature does not appear on (i.e. is missing). Same as `--num_nonzero_obs`
          but percentage based.
  - name: Outputs
    arguments:
      - name: "--output"
        type: file
        description: Output data. Can be encoded using H5 or Zarr v3, matching the format of the input data.
        direction: output
        example: output.h5mu
    __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
test_resources:
  - type: python_script
    path: test.py
  - path: /resources_test/pbmc_1k_protein_v3/pbmc_1k_protein_v3_filtered_feature_bc_matrix.h5mu
engines:
  - type: docker
    image: python:3.13-slim
    setup:
      - type: apt
        packages: 
          - procps
      - type: python
        __merge__: [/src/base/requirements/anndata_mudata.yaml, .]
        packages:
          - scipy
    __merge__: [ /src/base/requirements/python_test_setup.yaml, .]
    test_setup:
      - type: python
        __merge__: [ /src/base/requirements/scanpy.yaml, .]
runners:
  - type: executable
  - type: nextflow
    directives:
      label: [singlecpu, midmem]
