All protocols

Filter a VCF by depth and quality with bcftools

Drop low-confidence variants from a VCF by hard-filtering on QUAL and INFO/DP with bcftools, then compare record counts before and after.

SSSudipta SardarUpdated July 21, 2026

Prerequisites

  • bcftools installed (`bcftools view`, `bcftools index`)
  • A bgzipped VCF (`calls.vcf.gz`, ideally already indexed)

1Drop low-QUAL and low-depth sites

The `-e` flag EXCLUDES any site matching the expression, so this removes variants with QUAL below 20 or total depth (INFO/DP) below 10. `-Oz` writes a bgzipped VCF; index it afterwards so downstream tools can random-access the result.

bash
bcftools view -e 'QUAL<20 || INFO/DP<10' calls.vcf.gz -Oz -o filtered.vcf.gz
bcftools index filtered.vcf.gz

Expected output

# both commands run silently on success
# writes filtered.vcf.gz, then filtered.vcf.gz.csi

2Compare variant counts before and after

`-H` prints only data lines (no header), so piping to `wc -l` counts variant records. The difference between the two numbers is how many low-confidence sites the filter dropped.

bash
bcftools view -H calls.vcf.gz | wc -l
bcftools view -H filtered.vcf.gz | wc -l

Expected output

48213
41190

Troubleshooting

Error: the tag "DP" is not defined in the VCF header

Qualify the tag as `INFO/DP` or `FORMAT/DP` depending on where the field lives. List what is actually available with `bcftools view -h calls.vcf.gz | grep -E 'INFO|FORMAT'`.

You want to keep failing sites and just mark them, not delete them

Use a soft filter instead: `bcftools filter -s LowQual -e 'QUAL<20' calls.vcf.gz -Oz -o tagged.vcf.gz` writes `LowQual` into the FILTER column and keeps every record.