.. _reference.cli.usage:

Command-line interface
======================

Installing ``sfsutils`` provides the ``sfsutils`` command, a thin wrapper around the Python API with three
subcommands: ``parse`` derives a spectrum from a VCF, a VCF-Zarr store, or a tskit tree sequence, while
``filter`` and ``annotate`` write a transformed dataset whose format follows the output file's extension (a
VCF, a VCF-Zarr store, or, from a tree-sequence input, a tree sequence).

.. code-block:: bash

   sfsutils --help
   sfsutils parse --help

Global options ``-v``/``--verbose`` and ``-q``/``--quiet`` adjust logging; ``--version`` prints the version.

parse
-----

Derive a one-dimensional, joint (multi-population), or two-site SFS from a VCF, a VCF-Zarr store, or a tskit
tree sequence. The output format follows the spectrum: a single-population SFS is written as CSV, a joint or
two-site SFS as JSON. Several filters and annotations can be stacked and applied in a single pass.

.. code-block:: bash

   # one-dimensional SFS, projected to 20 haplotypes
   sfsutils parse --vcf variants.vcf.gz --n 20 --output sfs.csv

   # the same, reading a VCF-Zarr store instead
   sfsutils parse --zarr variants.vcz --n 20 --output sfs.csv

   # a tree sequence stores the ancestral state as the reference allele rather than in an AA tag, so the
   # polarization has to be told not to skip the sites that carry no such tag
   sfsutils parse --trees ancestry.trees --n 20 --no-skip-non-polarized --output sfs.csv

   # neutral vs selected SFS, annotating and stratifying by degeneracy
   sfsutils parse --vcf variants.vcf.gz --n 20 \
       --fasta genome.fasta --gff genome.gff.gz \
       --annotate degeneracy --stratify degeneracy \
       --filter snp --output sfs.csv

   # synonymous vs non-synonymous SFS
   sfsutils parse --vcf variants.vcf.gz --n 20 \
       --fasta genome.fasta --gff genome.gff.gz \
       --annotate synonymy --stratify synonymy \
       --filter snp --output sfs.csv

   # joint SFS across two populations
   sfsutils parse --vcf variants.vcf.gz --n 10 \
       --pops "CEU=NA06984,NA06985;YRI=NA18486,NA18487" --output jsfs.json

   # two-site SFS, pairing sites within 1 kb
   sfsutils parse --vcf variants.vcf.gz --n 20 --two-sfs --two-sfs-distance 1000 --output two_sfs.json

.. list-table::
   :header-rows: 1
   :widths: 26 74

   * - Option
     - Description
   * - ``--vcf`` / ``--zarr`` / ``--trees``
     - Input source: a VCF (gzipped or a URL), a VCF-Zarr store (``.vcz`` / ``.zarr``), or a tskit tree sequence (``.trees``). Exactly one is required.
   * - ``--output``
     - Output spectrum (CSV for one population, JSON for a joint or two-site SFS). Required.
   * - ``--n``
     - Sample size to project to (per population for a joint SFS). Required.
   * - ``--pops``
     - Population spec ``name=sample1,sample2;...`` for a joint SFS.
   * - ``--fasta`` / ``--gff``
     - Reference files required by some annotations and filtrations.
   * - ``--stratify``
     - Comma-separated stratifications (``degeneracy``, ``synonymy``, ``base-transition``, ``transition-transversion``, ``ancestral-base``, ``contig``).
   * - ``--annotate``
     - Comma-separated on-the-fly annotations (``degeneracy``, ``synonymy``, ``maximum-likelihood-ancestral``). A stratification by ``degeneracy`` or ``synonymy`` needs the matching annotation here, unless the input already carries the tag.
   * - ``--filter``
     - Comma-separated filtrations (``snp``, ``snv``, ``poly-allelic``, ``coding-sequence``, ``cpg``, ``contig``, ``no``, ``all``). Default ``poly-allelic``.
   * - ``--contigs``
     - Contigs to keep (required by the ``contig`` stratification and filtration).
   * - ``--two-sfs`` / ``--two-sfs-distance`` / ``--two-sfs-offset``
     - Parse the two-site SFS, pairing sites separated by ``(offset, offset + distance]`` base pairs (distance default 1000, offset default 0).
   * - ``--no-skip-non-polarized``
     - Use the reference allele as ancestral where no ancestral tag is available.
   * - ``--subsample-mode``
     - ``random`` or ``probabilistic`` (default) down-sampling.
   * - ``--outgroups`` / ``--n-ingroups``
     - Outgroup samples and minimum ingroup count for the maximum-likelihood ancestral annotation.
   * - ``--info-ancestral``
     - INFO tag holding the ancestral allele (default ``AA``).
   * - ``--max-sites``
     - Stop after this many input sites (default: all).
   * - ``--seed``
     - Random seed for the ``random`` subsample mode (default 0).

filter
------

Write only the sites that pass the given filtrations. The output format follows the ``--output`` extension: a VCF
(``.vcf``/``.vcf.gz``), a VCF-Zarr store (``.vcz``/``.zarr``), or a tree sequence (``.trees``). A VCF-Zarr store
can be written from any input. A tree-sequence output requires a tree-sequence input, since a genealogy cannot be
reconstructed from genotype data (the surviving sites are kept via ``delete_sites``). A VCF output requires a VCF
input because the writer copies the header (contigs, INFO/FORMAT definitions) from the source VCF.

.. code-block:: bash

   # keep only biallelic SNPs in coding sequences
   sfsutils filter --vcf variants.vcf.gz --filter snp,coding-sequence \
       --gff genome.gff.gz --output coding.vcf.gz

   # the same, writing a VCF-Zarr store instead
   sfsutils filter --vcf variants.vcf.gz --filter snp,coding-sequence \
       --gff genome.gff.gz --output coding.vcz

   # subset a tree sequence to its SNP sites, keeping the genealogy
   sfsutils filter --trees ancestry.trees --filter snp --output coding.trees

.. list-table::
   :header-rows: 1
   :widths: 26 74

   * - Option
     - Description
   * - ``--vcf`` / ``--zarr`` / ``--trees``
     - Input source (VCF, VCF-Zarr store, or tree sequence). Exactly one is required.
   * - ``--output``
     - Output path; its extension selects the format (``.vcf``/``.vcf.gz``, ``.vcz``/``.zarr``, ``.trees``). Required.
   * - ``--filter``
     - Comma-separated filtrations (see ``parse``). Required.
   * - ``--fasta`` / ``--gff``
     - References required by the ``cpg`` and ``coding-sequence`` filtrations.
   * - ``--contigs``
     - Contigs to keep (for the ``contig`` filtration).
   * - ``--max-sites``
     - Stop after this many input sites (default: all).

annotate
--------

Write the input back with added site-level information: site degeneracy from a reference (``degeneracy``), the
synonymous/non-synonymous status of a coding variant (``synonymy``), or the
ancestral allele inferred from outgroups under a maximum-likelihood substitution model
(``maximum-likelihood-ancestral``). As for ``filter``, the output format follows the ``--output`` extension: a VCF
(``.vcf``/``.vcf.gz``), a VCF-Zarr store (``.vcz``/``.zarr``), or a tree sequence (``.trees``). A VCF-Zarr store can
be written from any input; a VCF requires a VCF input (its header is copied from the source) and a tree sequence a
tree-sequence input.

.. code-block:: bash

   # annotate site degeneracy
   sfsutils annotate --vcf variants.vcf.gz --annotation degeneracy \
       --fasta genome.fasta --gff genome.gff.gz --output degeneracy.vcf.gz

   # the same, writing a VCF-Zarr store instead
   sfsutils annotate --vcf variants.vcf.gz --annotation degeneracy \
       --fasta genome.fasta --gff genome.gff.gz --output degeneracy.vcz

   # infer the ancestral allele from two outgroups
   sfsutils annotate --vcf variants.with_outgroups.vcf.gz \
       --annotation maximum-likelihood-ancestral \
       --outgroups ERR2103730,ERR2103731 --n-ingroups 15 --output polarized.vcf.gz

.. list-table::
   :header-rows: 1
   :widths: 26 74

   * - Option
     - Description
   * - ``--vcf`` / ``--zarr`` / ``--trees``
     - Input source (VCF, VCF-Zarr store, or tree sequence). Exactly one is required.
   * - ``--output``
     - Output path; its extension selects the format (``.vcf``/``.vcf.gz``, ``.vcz``/``.zarr``, ``.trees``). Required.
   * - ``--annotation``
     - Comma-separated annotations (``degeneracy``, ``synonymy``, ``maximum-likelihood-ancestral``). Required.
   * - ``--fasta`` / ``--gff``
     - References required by the ``degeneracy`` annotation.
   * - ``--outgroups`` / ``--n-ingroups``
     - Outgroup samples and minimum ingroup count for the maximum-likelihood ancestral annotation.
   * - ``--info-ancestral``
     - INFO tag holding the ancestral allele (default ``AA``).
   * - ``--max-sites``
     - Stop after this many input sites (default: all).
   * - ``--seed``
     - Random seed for the maximum-likelihood ancestral annotation (default 0).

See also
--------

The subcommands wrap :class:`~sfsutils.parser.Parser`, :class:`~sfsutils.filtration.Filterer`, and
:class:`~sfsutils.annotation.Annotator`; see the :doc:`API reference <../../modules/parser>` for the full set of options.
