Skip to content

Variant Benchmarking

Benchmark variant callers against truth sets: precision, recall and F1 per tool, sample and stratum, for germline small variants, somatic indels and structural variants.

Experimental

The variantbenchmarking template turns a benchmarking run into a precision/recall funnel:

  • Overview: four key figures, live findings and four figures for the route the run took, each linked to its tab
  • Germline: rtg-tools vcfeval and hap.py, on the precision-recall plane, by variant type and over the quality-threshold sweep
  • Somatic: som.py with binomial 95% intervals and allele-fraction strata, cross-checked by rtg-tools vcfeval
  • Structural & CNV: Truvari, SVanalyzer and Wittyer, per event and per base
  • MultiQC: the run's own report, in the per-variant-type templates

Choosing a template

nf-core/variantbenchmarking benchmarks one variant type per run: its own documentation states that "only one type of variant analysis is possible for each run". Depictio therefore ships one template per variant type, plus an umbrella template that reads any of them, one route or several under one root.

There is no variable and no selector for this choice. It is made entirely by the id you pass to --template. Pick the row matching the run you want to explore.

--template id Produced by a run with Benchmark tools Expected in the results directory
nf-core/variantbenchmarking/1.4.0/categories/small --analysis germline --variant_type small hap.py, rtg-tools vcfeval small/ and multiqc/multiqc_data/multiqc.parquet
nf-core/variantbenchmarking/1.4.0/categories/indel --analysis somatic --variant_type indel som.py, rtg-tools vcfeval indel/ and multiqc/multiqc_data/multiqc.parquet
nf-core/variantbenchmarking/1.4.0/categories/structural --variant_type structural truvari, SURVIVOR, through MultiQC only multiqc/multiqc_data/multiqc.parquet
nf-core/variantbenchmarking/1.4.0 any of the above, or several runs collected under one root rtg-tools vcfeval, hap.py, som.py, Truvari, SVanalyzer, Wittyer any of small/, indel/, sv/, cnv/; all optional

Each category is a self-contained project with its own dashboard, so three pipeline runs give you three projects. The umbrella template shows the tab of each route it finds, so it also reads a data root holding several, which is how nf-core's own megatest is laid out.

Category ids must pin the version

latest is resolved only in the last segment of a template id. So nf-core/variantbenchmarking/latest works and resolves to 1.4.0, but nf-core/variantbenchmarking/latest/categories/small does not: the literal latest is never substituted mid-path, the directory it names does not exist, and the run fails with Template ... not found. Always spell category ids with the pinned version, nf-core/variantbenchmarking/1.4.0/categories/small.

See _resolve_template_id_in in depictio/cli/cli/utils/templates.py.

Self-adapting layout

Nearly every collection is optional, so each dashboard adapts to what the run actually produced: components bound to missing collections are hidden and tabs left with no visualizations are dropped. On the umbrella template the Structural & CNV tab binds the optional Truvari, SVanalyzer and Wittyer collections, so it disappears entirely on a run with no sv/ or cnv/ directory, which is the case for every published nf-core megatest.


Quick start

DATA_ROOT is the only template variable, so the results directory is the only thing you ever have to pass. None of the four templates needs a --var flag.

depictio ingest /path/to/germline_results \
  --template nf-core/variantbenchmarking/1.4.0/categories/small

Two tabs: hap.py and rtg-tools benchmark metrics, plus the run's MultiQC report.

depictio ingest /path/to/somatic_results \
  --template nf-core/variantbenchmarking/1.4.0/categories/indel

Two tabs: som.py metrics with allele-fraction strata and confidence intervals, plus the run's MultiQC report.

depictio ingest /path/to/sv_results \
  --template nf-core/variantbenchmarking/1.4.0/categories/structural

One MultiQC tab. The structural benchmark numbers are published only inside the MultiQC report, so this category ships no benchmark tables of its own.

depictio ingest /path/to/megatest_results \
  --template nf-core/variantbenchmarking/1.4.0

An Overview, then a tab for each variant type the data root holds: Germline, Somatic, Structural & CNV. Reads no MultiQC report.


Reference

The four templates are independent projects. Pick one and the reference below switches to it, so the Data collections tables can be read one at a time rather than four deep.

Note the tag naming: the umbrella template prefixes its collections with germline_ and somatic_ to keep both variant types apart inside one project, while each category template uses the short unprefixed tag.

Template

Germline small variants

Template variables

Variables you provide when running the template: DATA_ROOT is the results directory given to depictio ingest, the others are set with --var NAME=value:

Variable Required Description
DATA_ROOT ✓ Root containing small/ (germline benchmark tables) and multiqc/multiqc_data/multiqc.parquet.

Data collections

4 data collections — 2 required 2 optional · 4 direct 0 derived.

Origin tells you whether a collection is real pipeline data or a reshape of it: direct = a pipeline output (scanned, or a recipe that reads raw files); derived = a recipe that reshapes one or more direct collections into the layout a visualization needs (no new measurement). Reads shows what produces it: a recipe .py transform, whose name links to its source on GitHub, or a raw file scanned off disk. (A direct collection can still have a recipe — one that merely parses/cleans the raw file; derived means the recipe reshapes another collection.)

Tag Origin Type Reads Status
vcfeval_summary direct Table recipe rtgtools/vcfeval_summary.py required
happy_summary direct Table recipe happy/summary.py optional
happy_roc direct Table recipe happy/roc.py optional
multiqc_data direct MultiQC MultiQC file multiqc/multiqc_data/multiqc.parquet required

Recipes

Each recipe reshapes raw pipeline output into a tidy table. The name links to its source; Output lists the validated OUTPUT_SCHEMA columns.

Recipe Transforms Output
happy/roc.py Extract a germline precision/recall ROC curve from hap.py per-quality ROC output. quality, recall, precision, f1
happy/summary.py Pool hap.py per-sample summaries into a germline SNP/INDEL performance table. variant_type, filter, truth_tp, truth_fn, query_fp, recall, precision, f1
rtgtools/vcfeval_summary.py Normalize an rtg-tools vcfeval aggregated summary into a tidy benchmark table. label, caller, truth_set, tp_base, tp_comp, fp, fn, precision, recall, f1

Somatic indels

Template variables

Variables you provide when running the template: DATA_ROOT is the results directory given to depictio ingest, the others are set with --var NAME=value:

Variable Required Description
DATA_ROOT ✓ Root containing indel/ (somatic benchmark tables) and multiqc/multiqc_data/multiqc.parquet.

Data collections

4 data collections — 2 required 2 optional · 4 direct 0 derived.

Origin tells you whether a collection is real pipeline data or a reshape of it: direct = a pipeline output (scanned, or a recipe that reads raw files); derived = a recipe that reshapes one or more direct collections into the layout a visualization needs (no new measurement). Reads shows what produces it: a recipe .py transform, whose name links to its source on GitHub, or a raw file scanned off disk. (A direct collection can still have a recipe — one that merely parses/cleans the raw file; derived means the recipe reshapes another collection.)

Tag Origin Type Reads Status
sompy_summary direct Table recipe sompy/summary.py required
sompy_regions direct Table recipe sompy/regions.py optional
vcfeval_summary direct Table recipe rtgtools/vcfeval_summary.py optional
multiqc_data direct MultiQC MultiQC file multiqc/multiqc_data/multiqc.parquet required

1 links — selecting a value in the source collection filters the target. The join column is shown after the source.

Recipes

Each recipe reshapes raw pipeline output into a tidy table. The name links to its source; Output lists the validated OUTPUT_SCHEMA columns.

Recipe Transforms Output
rtgtools/vcfeval_summary.py Normalize an rtg-tools vcfeval aggregated summary into a tidy benchmark table. label, caller, truth_set, tp_base, tp_comp, fp, fn, precision, recall, f1
sompy/regions.py Reshape the som.py region-stratified benchmark into a caller × AF-bin metrics table. caller, label, truth_set, af_bin, recall, precision, f1
sompy/summary.py Normalize the som.py somatic benchmark summary into a tidy per-caller table. caller, label, truth_set, variant_type, tp, fp, fn, recall, precision, f1, recall_lower, recall_upper, precision_lower, precision_upper

Structural variants

Template variables

Variables you provide when running the template: DATA_ROOT is the results directory given to depictio ingest, the others are set with --var NAME=value:

Variable Required Description
DATA_ROOT ✓ Root containing multiqc/multiqc_data/multiqc.parquet for the structural run.

Data collections

1 data collections — 1 required 0 optional · 1 direct 0 derived.

Origin tells you whether a collection is real pipeline data or a reshape of it: direct = a pipeline output (scanned, or a recipe that reads raw files); derived = a recipe that reshapes one or more direct collections into the layout a visualization needs (no new measurement). Reads shows what produces it: a recipe .py transform, whose name links to its source on GitHub, or a raw file scanned off disk. (A direct collection can still have a recipe — one that merely parses/cleans the raw file; derived means the recipe reshapes another collection.)

Tag Origin Type Reads Status
multiqc_data direct MultiQC MultiQC file multiqc/multiqc_data/multiqc.parquet required

All variant types in one project

Template variables

Variables you provide when running the template: DATA_ROOT is the results directory given to depictio ingest, the others are set with --var NAME=value:

Variable Required Description
DATA_ROOT ✓ Root directory containing variantbenchmarking output (small/, indel/, and optionally sv/, cnv/).

Data collections

9 data collections — 0 required 9 optional · 9 direct 0 derived.

Origin tells you whether a collection is real pipeline data or a reshape of it: direct = a pipeline output (scanned, or a recipe that reads raw files); derived = a recipe that reshapes one or more direct collections into the layout a visualization needs (no new measurement). Reads shows what produces it: a recipe .py transform, whose name links to its source on GitHub, or a raw file scanned off disk. (A direct collection can still have a recipe — one that merely parses/cleans the raw file; derived means the recipe reshapes another collection.)

Tag Origin Type Reads Status
germline_vcfeval_summary direct Table recipe rtgtools/vcfeval_summary.py optional
germline_happy_summary direct Table recipe happy/summary.py optional
germline_happy_roc direct Table recipe happy/roc.py optional
somatic_vcfeval_summary direct Table recipe rtgtools/vcfeval_summary.py optional
somatic_sompy_summary direct Table recipe sompy/summary.py optional
somatic_sompy_regions direct Table recipe sompy/regions.py optional
sv_truvari_summary direct Table recipe truvari/summary.py optional
sv_svbenchmark_summary direct Table recipe svanalyzer/svbenchmark.py optional
cnv_wittyer_summary direct Table recipe wittyer/summary.py optional

4 links — selecting a value in the source collection filters the target. The join column is shown after the source.

Recipes

Each recipe reshapes raw pipeline output into a tidy table. The name links to its source; Output lists the validated OUTPUT_SCHEMA columns.

Recipe Transforms Output
happy/roc.py Extract a germline precision/recall ROC curve from hap.py per-quality ROC output. quality, recall, precision, f1
happy/summary.py Pool hap.py per-sample summaries into a germline SNP/INDEL performance table. variant_type, filter, truth_tp, truth_fn, query_fp, recall, precision, f1
rtgtools/vcfeval_summary.py Normalize an rtg-tools vcfeval aggregated summary into a tidy benchmark table. label, caller, truth_set, tp_base, tp_comp, fp, fn, precision, recall, f1
sompy/regions.py Reshape the som.py region-stratified benchmark into a caller × AF-bin metrics table. caller, label, truth_set, af_bin, recall, precision, f1
sompy/summary.py Normalize the som.py somatic benchmark summary into a tidy per-caller table. caller, label, truth_set, variant_type, tp, fp, fn, recall, precision, f1, recall_lower, recall_upper, precision_lower, precision_upper
svanalyzer/svbenchmark.py Normalize an SVanalyzer (svbenchmark) structural-variant summary into a tidy table. label, precision, recall, f1
truvari/summary.py Normalize a Truvari structural-variant benchmark summary into a tidy table. label, precision, recall, f1
wittyer/summary.py Normalize a Wittyer CNV/SV benchmark summary into a tidy, optionally stratified table. label, precision, recall, f1

Dashboard tabs

The umbrella template, nf-core/variantbenchmarking/1.4.0, builds one dashboard: the Overview, then one child tab per variant type, in two groups. A run benchmarks one variant type, so it shows the Overview and the tab of its route; a data root holding several routes shows the tab of each. Each tab below carries the same icon and colour the dashboard gives it.

Group Tabs
Small variants Germline, Somatic
Structural Structural & CNV

The pipeline writes no MultiQC report into the tables this template reads, and it has no sample sheet: there is no MultiQC tab, no Data & QC group, no persistent sample filters and no Sample sheet section. Each child tab opens with a short intro and a strip of four cards, then at most three open sections; tables and the cross-check follow, collapsed. Each caller keeps one colour on every tab, and the precision-recall scatters draw no point labels.

Which callset recovers its truth set best, on precision, recall and F1.

Overview dashboard

Overview dashboard

A short hero links the run parameters. The run lists the analysis and variant type, the truth set, the benchmarking methods, the genome and the callsets, and Pipeline shows the steps of the route the run took: the steps of the other routes are dropped at import. Key figures, the findings and the four figures below them come from that route as well.

Filters and components

Filters · the left panel starts collapsed. Key figures and Findings each have a filter bar (caller and callset) that narrows its own section only.

Section What it holds
Top Hero, About this dashboard, The run, Pipeline
Key figures 4 headline cards for the run's route: true positives, F1, recall, precision
Findings Three live result rows for the route, then 4 figures from its tab
How to read this dashboard The tabs by group, each with its question

Small variants · How well does each germline callset recover the truth set?

Germline dashboard

Germline dashboard

F1 with its spread, recall against a 0.9 floor, the callers with most false positives and the true positives by caller, all from rtg-tools vcfeval. Then the precision-recall scatter beside the errors per callset, and hap.py's F1 by variant type (all calls against PASS calls) beside the quality-threshold sweep.

Filters and components

Filters · Caller and Callset on germline_vcfeval_summary, hap.py variant type and hap.py calls (ALL or PASS) on germline_happy_summary.

Section What it holds
Germline at a glance 4 cards
Precision and recall 2 advanced visualizations
hap.py by variant type 1 bar + 1 advanced visualization
Germline tables (collapsed) rtg-tools vcfeval summary, hap.py pooled summary, hap.py threshold sweep

Small variants · How well does each somatic caller recover the truth set?

Somatic dashboard

Somatic dashboard

F1 with its spread, precision against a 0.5 floor, the callers with most false positives and the true positives by caller, all from som.py. Then the precision-recall scatter beside the errors per caller, precision and recall with their binomial 95% intervals, and F1 and recall per allele-fraction bin. The collapsed rtg-tools cross-check scores the same callers on haplotypes.

Filters and components

Filters · Caller on somatic_sompy_summary and Allele-fraction bin on somatic_sompy_regions. The caller reaches the strata and the cross-check through cross-DC links on the caller column.

Section What it holds
Somatic at a glance 4 cards
Precision and recall 2 advanced visualizations
Confidence intervals 2 advanced visualizations
Allele-fraction strata 2 bars
rtg-tools cross-check (collapsed) 1 advanced visualization + rtg-tools vcfeval summary
Somatic tables (collapsed) som.py summary, som.py allele-fraction strata

Structural · How well do the structural callsets match the truth set?

Structural & CNV dashboard

Structural & CNV dashboard

The true positives by caller, F1 with its spread, recall against a 0.8 floor and the spread of precision, all from Truvari. Then the Truvari precision-recall scatter beside its errors per callset, and the SVanalyzer F1 per callset beside the Wittyer F1 per event and per base. A callset that finds events but misplaces their breakpoints scores well per event and poorly per base. A copy-number run keeps only the Wittyer tiles.

Filters and components

Filters · Callset and Caller on sv_truvari_summary, Wittyer level on cnv_wittyer_summary. The callset reaches SVanalyzer and Wittyer through the links.

Section What it holds
Structural at a glance 4 cards
Precision and recall 2 advanced visualizations
SVanalyzer and Wittyer 2 bars
Structural tables (collapsed) Truvari summary, SVanalyzer svbenchmark summary, Wittyer summary

The callset tables select rows on their identifier: label for the vcfeval, Truvari, SVanalyzer and Wittyer tables, caller for the som.py tables and the somatic vcfeval table. A pick narrows the tiles that read the same table; a som.py pick also reaches its allele-fraction strata and the cross-check, and a Truvari pick reaches the SVanalyzer and Wittyer tiles, through the links. The hap.py pooled summary and threshold sweep have no callset column and do not select.

Per-variant-type templates

The three categories/ templates keep their own layout, one project per variant type: a Benchmark tab over the benchmark tables, and the run's MultiQC report. The structural category reads the MultiQC report only, since the public nf-core megatest publishes no structural summary table.

Germline category MultiQC tab

The MultiQC tab: general statistics, the hap.py SNP and INDEL panels, and the bcftools substitution types and indel lengths, collapsed.

Somatic category MultiQC tab

The MultiQC tab: general statistics, the som.py Combined, Indel and SNV panels, and the bcftools substitution types and variant depths, collapsed.

Structural category MultiQC tab

The only tab: general statistics with the Truvari precision, recall, F1 and genotype concordance, the Truvari precision-recall view and classifications, and the SURVIVOR summary, collapsed.


Benchmarking visualizations

The template introduced four visualization kinds built for benchmarking, used across the Germline, Somatic and Structural & CNV tabs. Each is bound through a catalog module, so any project reading a comparable table can reuse them.

PR benchmark

One point per callset at (recall, precision), coloured by its caller, over dotted equal-F1 contours and the recall = precision diagonal, so a callset's balance is readable at a glance.

ROC and PR curve

Threshold-sweep curves with a per-curve AUC. Its View switch draws the PR curve, the ROC, or precision and recall vs threshold.

Confusion matrix

TP, FP and FN per callset. Shading is the per-callset normalised fraction while the label keeps the raw count, and the label colour follows cell luminance so it stays legible at both ends of the scale.

Metric confidence intervals

A forest plot: point estimate plus 95 % confidence interval per caller, on an x-axis that auto-zooms to the spread so overlapping intervals stay distinguishable.


Running the pipeline

Depictio reads the output of nf-core/variantbenchmarking, it does not run the pipeline. Run the pipeline first, once per variant type:

nextflow run nf-core/variantbenchmarking -r 1.4.0 \
  --input samplesheet.csv \
  --outdir results/ \
  --genome GRCh38 \
  --truth_id HG002 --truth_vcf truth.vcf.gz \
  --analysis germline \
  --variant_type small \
  -profile docker

Then point Depictio at the results, choosing the template id for the variant type that run produced:

depictio ingest results/ \
  --template nf-core/variantbenchmarking/1.4.0/categories/small

To benchmark somatic indels as well, run the pipeline again with --analysis somatic --variant_type indel into a second output directory, and import it with the categories/indel template. Point the umbrella template at a root holding both result sets instead, if you would rather have one project than two.

See nf-co.re/variantbenchmarking/usage for full pipeline documentation.


Required data structure

Point depictio ingest at the directory holding the pipeline output. A category template requires its first table and its MultiQC report; on the umbrella template every table is optional. The dashboard adapts to what is present.

<DATA_ROOT>/
├── small/                                                  # --variant_type small
│   ├── summary/tables/rtgtools/
│   │   └── rtgtools.summary.csv                            # required by small
│   └── <sample>/benchmarks/happy/
│       ├── *.summary.csv                                   # optional
│       └── *.roc.Locations.SNP.PASS.csv.gz                 # optional
├── indel/                                                  # --variant_type indel
│   └── summary/tables/
│       ├── sompy/sompy.summary.csv                         # required by indel
│       ├── sompy/sompy.regions.csv                         # optional, AF strata
│       └── rtgtools/rtgtools.summary.csv                   # optional, cross-check
├── sv/summary/tables/                                      # optional, umbrella only
│   ├── truvari/truvari.summary.csv
│   └── svbenchmark/svbenchmark.summary.csv
├── cnv/summary/tables/wittyer/
│   └── wittyer.summary.csv                                 # optional, umbrella only
└── multiqc/multiqc_data/
    └── multiqc.parquet                                     # required by each category

Each category template requires the MultiQC report of its own run. The umbrella template reads no MultiQC report, and shows the tab of each route it finds under the root.


Validation runs

The repository ships download_test_data.sh, which pulls a real run from nf-core's public megatest bucket:

bash depictio/projects/nf-core/variantbenchmarking/1.4.0/download_test_data.sh \
  /tmp/variantbenchmarking_test

It fetches the small/ and indel/ summary tables plus the hap.py per-sample files from s3://nf-core-awsmegatests/variantbenchmarking/, then prints the follow-up commands.

The fixture suits the umbrella template

No published megatest contains a multiqc/ directory, and the script does not fetch one, so this fixture will not satisfy the three category templates, which each require a MultiQC report. Use it with --template nf-core/variantbenchmarking/1.4.0, which reads no MultiQC report and covers both variant types the fixture provides.


Additional resources


Authorship

Developers Wrote the four templates, their recipes and their dashboards. weber8thomas
Reviewers Nobody has run them on their own data and signed them off yet, which is what keeps the status Experimental. Open
Maintainers Keep them working as nf-core/variantbenchmarking releases. weber8thomas

Reviewing a template on your own data, or taking over a role here, is a contribution in itself: the contributing guide says what each one involves.