HipSTR: genotyping forensic STRs from a BAM

Tool: HipSTR v0.7
Time: 15 minutes + installation
12 steps

You will learn to run HipSTR on your own files, step by step: where your samples (BAM or CRAM), your reference and your list of STRs go in the command, and how to read and filter the result. As an example we genotype 22 forensic STRs of a public sample (NA12878) over their ISFG minimum ranges, which give forensic allele numbers: you will see why the basic command leaves 8 loci out without telling you on screen, how to fix it, how to read the VCF, turn its length differences into allele numbers, filter it with HipSTR's own script and look at the reads with VizAln. We give you the practice data (the exact files of the video), so you can run every step before trying your own files.

Practice dataNo data of your own yet? Try every step with the exact files of the video: one command downloads them.How to download them

Subtitles in English, Spanish and Portuguese (CC button of the player).

Before you start

Everything runs in your own terminal: Linux, macOS, or Windows with WSL. First install the tools for your system, then set up a working folder with HipSTR. You do this once. Then each step shows the command with our example files, and the table under it says what you put there with yours. No data yet? Download ours with one command (Practice data, below).

1. Install the tools: Linux (Ubuntu, Debian) and Windows with WSL

On Windows, first install WSL: open PowerShell as administrator, run wsl --install, restart, open "Ubuntu" from the Start menu and continue there. On Ubuntu 24.04 or newer (the one WSL installs today), compile HipSTR with make CXX="g++ -include cstdint" instead of make (see the error below).

sudo apt update
sudo apt install -y build-essential git curl zlib1g-dev libbz2-dev liblzma-dev libcurl4-openssl-dev samtools bcftools tabix bsdextrautils python3-venv

1. Install the tools: macOS

You need Homebrew (brew.sh). xcode-select --install opens a window to install the compilers; if it says they are already installed, go on. coreutils is for VizAln (step 12).

xcode-select --install
brew install samtools bcftools coreutils

2. Set up a working folder

mkdir hipstr-tutorial
cd hipstr-tutorial
git clone https://github.com/tfwillems/HipSTR.git
cd HipSTR
make
cd ..
python3 -m venv hipstr-env
hipstr-env/bin/pip install PyVCF3

This creates a working folder, compiles HipSTR inside it exactly as the official HipSTR tutorial does (git clone + make), and creates a small Python environment (hipstr-env) with PyVCF3, which HipSTR's filter script needs. Then put your files in this folder (or write their full paths in the commands): your BAM or CRAM files with their indexes, your reference genome with its .fai, and your BED. The video uses our example files: a public sample (NA12878), a reduced GRCh38 and a BED with the ISFG minimum ranges of 22 forensic STRs. We tested this tutorial with HipSTR commit b2033bf. git clone gets the latest version: if your results differ from the ones shown here, go back to the tested one with git checkout b2033bf inside the HipSTR folder and run make again.

If you see this error:

src/region.h:62:49: error: 'uint32_t' has not been declared

Linux with a recent compiler (gcc 13, Ubuntu 24.04 and newer). HipSTR's code relies on a header that new compilers no longer include by themselves. Inside the HipSTR folder run make CXX="g++ -include cstdint": it adds that header without changing HipSTR's code. We tested it on a clean Ubuntu 24.04.

If you see this error:

Undefined symbols for architecture arm64 (and before it: ld: warning: ignoring file '/usr/local/lib/liblzma.dylib': found architecture 'x86_64', required architecture 'arm64')

macOS with Apple Silicon that still has libraries from an old Intel Homebrew in /usr/local. Build HipSTR with LIBRARY_PATH=/opt/homebrew/lib make instead of make. We hit this on our own Mac and this fixed it.

Practice data

No data of your own yet? Practice with ours: the exact files of the video (a public sample, the reduced reference and the ISFG BED, about 20 MB). Run this inside your working folder and every step gives the same output as the tutorial. Sources and checksums are in the README of the folder.

for f in NA12878.bam NA12878.bam.bai GRCh38_STR_regions.fa.gz GRCh38_STR_regions.fa.gz.fai \
         GRCh38_STR_regions.fa.gz.gzi regions.bed isfg_ranges_grch38.tsv; do
  curl -fLO https://raw.githubusercontent.com/Tfronta/strhub-demo-data/main/tutorials/hipstr/$f
done
See the files on GitHub

What goes in the folder

NA12878.bamExample: Illumina reads of NA12878 (Genome in a Bottle, NIST), aligned to GRCh38, only around 24 forensic STRs (reads of 148 bp). Yours: your BAM or CRAM files, one per sample, aligned to the reference you give HipSTR.
NA12878.bam.baiIndex of the BAM: HipSTR uses it to jump straight to each region. Yours need one too (samtools index).
regions.bedExample: the ISFG minimum ranges of 22 forensic STRs (the 20 CODIS core loci plus Penta D and Penta E), in HipSTR's BED format; with them, HipSTR's lengths turn into forensic allele numbers (step 8). Yours: the STRs you want, in the same format (step 3), with the same chromosome names as your reference. For forensic STRs you can use ours, from strhub-demo-data.
isfg_ranges_grch38.tsvThe same 22 ISFG ranges as a table, with ce_ref: the forensic (CE) allele number of the GRCh38 reference over each range (step 8). From the STRidER FSSG v6-1 (Gettings et al. 2024, FSI: Genetics 68:102946).
GRCh38_STR_regions.fa.gzExample: a reduced GRCh38, with everything set to N except 5,000 bp around each STR (9 MB instead of 3.3 GB; HipSTR writes the same VCF records as with the full one). Yours: the full reference your reads were aligned to, with its .fai index (samtools faidx).
HipSTR/HipSTR, cloned from GitHub and compiled during the setup.
hipstr-env/Python environment with PyVCF3, created during the setup.

Step by step

1Look at the files

Before running anything, look at what you have. Here, our example: the reads (.bam) with their index (.bai), the list of STRs (.bed) with its table of allele numbers (.tsv), the reference (.fa.gz, with its indexes .fai and .gzi), and the two folders from the setup: HipSTR/ and hipstr-env/. With your data you need the same: your BAM or CRAM files with their indexes, your reference with its index, and your BED.

ls -lh
What you should see
total 20M
-rw-r--r-- 1 student student 9.0M Oct 23 13:21 GRCh38_STR_regions.fa.gz
-rw-r--r-- 1 student student  568 Oct 23 13:21 GRCh38_STR_regions.fa.gz.fai
-rw-r--r-- 1 student student 604K Oct 23 13:21 GRCh38_STR_regions.fa.gz.gzi
drwxr-xr-x 8 student student 4.0K Oct 25 22:03 HipSTR
-rw-r--r-- 1 student student 9.4M Oct 23 13:21 NA12878.bam
-rw-r--r-- 1 student student 825K Oct 23 13:21 NA12878.bam.bai
drwxr-xr-x 5 student student 4.0K Oct 25 22:04 hipstr-env
-rw-r--r-- 1 student student 1.3K Oct 25 15:36 isfg_ranges_grch38.tsv
-rw-r--r-- 1 student student  789 Oct 25 15:36 regions.bed

2Does the BAM have a read group?

HipSTR takes the sample name from the read group of the BAM (the @RG line): SM is the sample and LB the library. If your BAM has no read group, HipSTR does not start.

samtools view -H NA12878.bam | grep '^@RG'
What you should see
@RG	ID:NA12878	SM:NA12878	LB:GIAB300x	PL:ILLUMINA

If you see this error:

ERROR: Provided BAM/CRAM files don't contain read groups in the header and the --bam-samps flag was not specified

Your BAM has no @RG. Two ways out (we tested both): add one with samtools addreplacerg -r 'ID:sample1' -r 'SM:sample1' -r 'LB:lib1' -o with_rg.bam your.bam and then samtools index with_rg.bam; or give HipSTR the names with --bam-samps sample1 --bam-libs lib1 (always together).

3Read the BED of regions

Each line is one STR. The columns, as the HipSTR README defines them: chromosome, start, end, motif length (4 = tetranucleotide), number of copies of the motif in the reference allele, and (optional) the locus name, which HipSTR writes in the ID column of the VCF. The BED has no header line.

Our BED uses the ISFG minimum ranges (STRidER FSSG v6-1, Recommendation 3 of Gettings et al. 2024): the stretch of each STR that forensic nomenclature is reported over. They are a little wider than the bare repeat, because they include the bases that the forensic allele number counts. That is what lets you turn HipSTR's results into forensic allele numbers in step 8. For your forensic STRs you can use the same BED: it is in strhub-demo-data.

head -3 regions.bed
What you should see
chr1	230769600	230769687	4	17	D1S1656
chr10	129294238	129294299	4	13	D10S1248
chr11	2171081	2171120	4	7	TH01

4Genotype with the official command

This is the basic command of the HipSTR README (--bams, --fasta, --regions, --str-vcf) plus --viz-out, which the official HipSTR tutorial also uses and which you need for VizAln (step 12). The log goes to the screen and tee keeps a copy in NA12878.log.

The summary at the end says that only 14 of the 22 loci were genotyped, and nothing else on screen warns you:

  • 2 loci skipped for length: D2S1338 (101 bp in its ISFG range) and D21S11 (138 bp) are longer than --max-str-len (default 100 bp).
  • 6 loci skipped for too few reads to learn the stutter model: D1S1656, D12S391, D13S317, D19S433, Penta D and FGA (in the log: TOTAL=65 to 97, MIN=100). HipSTR learns a stutter model per locus from the reads of all samples; with one sample this may not be enough. The ISFG ranges are wider than the bare repeat, so fewer reads cross them completely.

The log suggests --min-reads, but for very few samples the HipSTR README recommends --def-stutter-model.

The table below says, for each option, what you put there with your own data.

HipSTR/HipSTR --bams NA12878.bam --fasta GRCh38_STR_regions.fa.gz \
       --regions regions.bed --str-vcf NA12878.vcf.gz \
       --viz-out NA12878.viz.gz 2>&1 | tee NA12878.log
--bamsNA12878.bamYour samples: BAM or CRAM files, separated by commas, each with its index (.bai or .crai) next to it. Each one needs a read group (@RG) with the sample name (step 2).
--fastaGRCh38_STR_regions.fa.gzYour reference genome: the same one your reads were aligned to, with its .fai index (and .gzi if it is compressed with bgzip). Its chromosome names must match those of your BAM and your BED.
--regionsregions.bedYour list of STRs, in HipSTR's BED format (step 3), with the same coordinates as your reference.
--str-vcfNA12878.vcf.gzWhere HipSTR writes the genotypes: a VCF compressed with bgzip. You choose the name.
--viz-outNA12878.viz.gzOptional: where HipSTR saves the read alignments of each call, to see them with VizAln (step 12).
2>&1 | teeNA12878.logNot a HipSTR option: it shows the log on screen and keeps a copy in that file (step 8 searches it). HipSTR also has --log FILE, which writes the log only to the file.
What you should see

Last 24 of 762 lines (the whole log scrolls by on your screen).



------HipSTR Execution Summary------
Skipped 2 loci whose lengths were above the maximum threshold.
	 If this is a sizeable portion of your loci, see the --max-str-len command line option
Skipped 6 loci with too few reads for stutter model model training or genotyping.
	 If this is a sizeable portion of your loci, see the --min-reads command line option
Stutter model training succeeded for 14/14 loci
Genotyping succeeded for 14/14 loci

Approximate timing breakdown
 BAM seek time       = 8e-05 seconds
 Read filtering      = 0.162134 seconds
 SNP info extraction = 0.001323 seconds
 Stutter estimation  = 0.003236 seconds
 Genotyping          = 2.33122 seconds
	 Left alignment        = 0.285253 seconds
	 Haplotype generation  = 0.006718 seconds
	 Haplotype alignment   = 1.31133 seconds
	 Flank assembly        = 0.009349 seconds
	 Posterior computation = 0.000337 seconds
	 Alignment traceback   = 0.684836 seconds
HipSTR execution finished: Total runtime = 9.45423 sec
-----------------

5Genotype again, fixed

Three options are added at the end, the rest stays the same. The summary now says 22 of 22 (careful: in step 10 you will see that one of them, D21S11, does not pass the filter).

HipSTR/HipSTR --bams NA12878.bam --fasta GRCh38_STR_regions.fa.gz \
       --regions regions.bed --str-vcf NA12878.vcf.gz --viz-out NA12878.viz.gz \
       --max-str-len 150 --def-stutter-model --output-filters 2>&1 | tee NA12878.log
--max-str-len150Only genotype STRs shorter than this many bp in the reference (default 100). 150 lets D2S1338 and D21S11 in.
--def-stutter-modelUse a fixed stutter model (PGEOM=0.9, UP=DOWN=0.05 in-frame, 0.01 out-of-frame) instead of learning one per locus. The README: only when there are too few samples, because learned models are more accurate.
--output-filtersWrite why each call was filtered, in the FORMAT field FILTER. Without it, a filtered call is just empty.
What you should see

Last 18 of 881 lines (the whole log scrolls by on your screen).


------HipSTR Execution Summary------
Genotyping succeeded for 22/22 loci

Approximate timing breakdown
 BAM seek time       = 8.2e-05 seconds
 Read filtering      = 0.180311 seconds
 SNP info extraction = 0.001512 seconds
 Stutter estimation  = 4.8e-05 seconds
 Genotyping          = 4.30741 seconds
	 Left alignment        = 0.463101 seconds
	 Haplotype generation  = 0.010816 seconds
	 Haplotype alignment   = 2.45377 seconds
	 Flank assembly        = 0.014728 seconds
	 Posterior computation = 0.000606 seconds
	 Alignment traceback   = 1.30609 seconds
HipSTR execution finished: Total runtime = 11.4984 sec
-----------------

6Open the VCF

HipSTR writes its result to NA12878.vcf.gz: a VCF (Variant Call Format) file compressed with bgzip. gunzip -k decompresses it and keeps the .gz, which the next steps read (-f overwrites NA12878.vcf if you run it again). Without -k, the .gz disappears and the next commands (bcftools and the filter) stop working.

The lines that start with ## are the header, and they define every field (try grep '^##FORMAT' NA12878.vcf). Then comes one line per STR, with tab-separated columns: CHROM, POS, ID (the locus name), REF and ALT (the allele sequences), QUAL, FILTER, INFO (data for the locus), FORMAT (the names of the per-sample fields, separated by :) and one column per sample, with the values in the same order.

To open it in a spreadsheet (Excel, LibreOffice Calc, Google Sheets), open it from inside the program and choose tab as the separator. Do not double-click it: .vcf is also the extension of contact cards (vCard), and your computer may open your contacts app instead. To see each field next to its value, split the FORMAT and NA12878 columns at : (menu Data, Text to Columns).

The fields below are the ones in the FORMAT column. The descriptions come from the VCF header and from the HipSTR README.

gunzip -kf NA12878.vcf.gz && ls -lh NA12878.vcf*
GTGenotype: which alleles, as indexes (0 = REF, 1 = first ALT, ...). | means phased.
GBBase pair difference of each allele from the reference. With the size of the reference allele, it gives the repeat number.
QPosterior probability of the genotype, from 0 to 1. The HipSTR README calls it the best quality indicator; the filter keeps Q ≥ 0.9.
PQThe same probability for the phased genotype. Without phasing information (no SNPs nearby), a heterozygote has PQ ≈ Q/2.
DPNumber of valid reads used for this sample's genotype: the total coverage at the locus.
PDPReads supporting each allele (fractional: a read can count partly for each allele). Adds up to DP. It is not a probability.
ABAllele bias, as log10 of a p-value: 0 = reads balanced between the two alleles; very negative = one allele has fewer reads than expected for that genotype. The filter keeps AB ≥ -2.
FSStrand bias, as log10 of a Fisher test p-value: very negative = an allele seen mostly on one DNA strand, a sign of sequencing errors. The filter keeps FS ≥ -2.
DSTUTTERReads with a stutter indel in the STR. The filter removes a call if DSTUTTER / DP > 0.15.
DFLANKINDELReads with an indel in the flanks of the STR. The filter removes a call if DFLANKINDEL / DP > 0.15.
MALLREADSFor reads that span the repeat by at least 5 bp: bp difference | number of reads (step 9).
ALLREADSThe same idea, from each read's own alignment, for all reads.
FILTERPASS, or why the call was filtered (written because of --output-filters).
OthersGLDIFF: likelihood gap to the next best genotype. DSNP and PSNP: reads with SNP phasing information. DAB: reads used for AB and FS.
What you should see
-rw-r--r-- 1 student student  19K Oct 25 22:04 NA12878.vcf
-rw-r--r-- 1 student student 4.0K Oct 25 22:04 NA12878.vcf.gz

7The genotypes, one line per locus

bcftools query (bcftools is not part of HipSTR: it comes from the samtools team) prints only the fields you ask for:

  • GT: which sequences were called (indexes into REF/ALT, not alleles).
  • GB: difference in bp of each allele from the reference. 0|4 at D13S317 = one allele as long as the reference, the other 4 bp longer. When GB is not a multiple of the motif, it is a microvariant: TH01 (motif of 4) shows 0|11 = 2 repeats plus 3 bases.
  • DP: valid reads HipSTR used (the total coverage). Q: posterior probability of the genotype.
  • FILTER: PASS, or why the call was filtered (thanks to --output-filters).

All 22 loci have a genotype. To turn GB into a forensic allele number you need the allele number of the reference at each locus: that is step 8. Careful with D21S11 (0|0): HipSTR gives it a genotype, but in step 10 the filter removes it.

bcftools query -f '%ID\t[%GT\t%GB\t%DP\t%Q\t%FILTER]\n' NA12878.vcf.gz | column -t
What you should see
D1S1656   1|2  -12|-5   392  1  PASS
D10S1248  1|2  8|12     326  1  PASS
TH01      0|1  0|11     288  1  PASS
vWA       1|2  -8|0     494  1  PASS
D12S391   1|2  -12|-8   387  1  PASS
D13S317   0|1  0|4      413  1  PASS
PentaE    1|2  10|35    436  1  PASS
D16S539   0|1  0|-4     392  1  PASS
D18S51    1|2  -8|-4    571  1  PASS
D19S433   0|1  0|-8     332  1  PASS
TPOX      0|0  0|0      273  1  PASS
D2S441    1|2  -4|8     445  1  PASS
D2S1338   1|2  -24|-12  279  1  PASS
D21S11    0|0  0|0      551  1  PASS
PentaD    0|1  0|-10    531  1  PASS
D22S1045  1|2  -12|-6   429  1  PASS
D3S1358   1|2  0|4      434  1  PASS
FGA       0|1  0|8      502  1  PASS
D5S818    1|1  4|4      433  1  PASS
CSF1PO    1|2  -12|-8   289  1  PASS
D7S820    1|2  -20|-12  477  1  PASS
D8S1179   1|1  -4|-4    379  1  PASS

8From GB to the forensic allele number

HipSTR reports each allele as a length difference from the reference (GB). Forensic laboratories report allele numbers (the CE designation). Because our BED uses the ISFG minimum ranges, the conversion is a sum: allele = ce_ref + GB / motif length. ce_ref is the allele number of the GRCh38 reference over that range: column 6 of isfg_ranges_grch38.tsv, from the STRidER FSSG v6-1 (Gettings et al. 2024, FSI: Genetics 68:102946).

D13S317: ce_ref 11, GB 0|4, motif of 4 bp: alleles 11 and 12. When the difference is not a whole number of repeats, the remainder goes after a point: TH01 (ce_ref 7, motif 4) with GB 11 is 7 + 2 repeats + 3 bases = 9.3.

With other coordinates (for example the repeat alone, as in HipSTR's own BED files) the same sum gives numbers that do not match the forensic designation in several loci. That is why the BED matters.

grep -w -e locus -e D13S317 isfg_ranges_grch38.tsv | column -t
What you should see
locus    chrom  start     end       len_bp  ce_ref  strnaming_fmt
D13S317  chr13  82148021  82148104  84      11      TATC[n]AATC[2]ATCT[3]

For every locus of your VCF at once. This is not part of HipSTR: a few lines of awk that apply the formula with the ISFG table (a dot means no call).

bcftools query -f '%ID\t%INFO/PERIOD\t[%GB]\n' NA12878.vcf.gz | awk -F'\t' -v OFS='\t' '
  NR == FNR { ce[$1] = $6; next }
  $3 == "." { print $1, "."; next }
  { split($3, gb, "|"); out = $1
    for (i = 1; i <= 2; i++) { t = ce[$1] * $2 + gb[i]; r = t % $2
      out = out OFS (t - r) / $2 (r ? "." r : "") }
    print out }' isfg_ranges_grch38.tsv - | column -t
What you should see
D1S1656   14  15.3
D10S1248  15  16
TH01      7   9.3
vWA       15  17
D12S391   16  17
D13S317   11  12
PentaE    7   12
D16S539   11  10
D18S51    16  17
D19S433   14  12
TPOX      8   8
D2S441    11  14
D2S1338   17  20
D21S11    29  29
PentaD    13  11
D22S1045  13  15
D3S1358   16  17
FGA       22  24
D5S818    12  12
CSF1PO    10  11
D7S820    8   10
D8S1179   12  12

9How many reads support each allele?

MALLREADS (from the HipSTR VCF) gives, for each length difference in bp, how many reads cross the repeat with at least 5 bp on each side. At D13S317: 47 reads at 0 bp and 26 at +4 bp, about 64/36: a balanced heterozygote. The VCF field AB tests this same balance (here -0.42, close to 0 = balanced). There are fewer reads than DP (413) because the ISFG range is wider than the bare repeat, and fewer reads cross all of it with 5 bp to spare.

bcftools query -i 'ID="D13S317"' -f '%ID\t[%GB\t%MALLREADS]\n' NA12878.vcf.gz
-i'ID="D13S317"'Which locus: its name, as in column 6 of your BED (HipSTR writes it in the ID column).
-f'%ID\t[%GB\t%MALLREADS]\n'Which fields to print: the name, GB and MALLREADS of each sample.
What you should see
D13S317	0|4	0|47;4|26

10Filter with HipSTR's own script

HipSTR comes with scripts/filter_vcf.py, and its README suggests these thresholds. The filtered VCF keeps every locus but removes, sample by sample, the calls that fail, and writes the reason in FILTER. The second command lists every call that is not PASS. The script runs with the Python of hipstr-env, which has PyVCF3.

Here D21S11 is removed: 45 % of its reads have a stutter-like indel (the limit is 15 %). Its ISFG range is 138 bp and the reads are 148 bp, so almost no read crosses it with room to spare: HipSTR still writes a genotype (0|0), but it is not reliable. A genotype in the VCF is not always a reliable genotype. Every other call passes (Q = 1, stutter ≤ 2.5 %, allele bias ≥ -1.44): this sample has ~300x.

hipstr-env/bin/python HipSTR/scripts/filter_vcf.py --vcf NA12878.vcf.gz \
    --min-call-qual 0.9 --max-call-flank-indel 0.15 --max-call-stutter 0.15 \
    --min-call-allele-bias -2 --min-call-strand-bias -2 > NA12878.filtered.vcf
bcftools query -f '%ID\t[%GT\t%FILTER]\n' NA12878.filtered.vcf | grep -v PASS
--vcfNA12878.vcf.gzYour VCF from HipSTR (the compressed one).
--min-call-qual0.9Minimum posterior probability of the genotype (Q). The README: Q is the best quality indicator.
--max-call-flank-indel0.15Maximum fraction of reads with an indel in the flanks (DFLANKINDEL / DP).
--max-call-stutter0.15Maximum fraction of reads with a stutter artifact (DSTUTTER / DP).
--min-call-allele-bias-2Minimum allele bias (AB, log10 p-value). Very negative = reads very unbalanced between the alleles.
--min-call-strand-bias-2Minimum strand bias (FS, log10 p-value).
>NA12878.filtered.vcfWhere the filtered VCF goes. It is not an option of the script: > sends its output to that file.
What you should see
D21S11	./.	STUTTER_FRACTION

If you see this error:

error: externally-managed-environment

You used the system pip. Current Python does not let it install into the system. Install into the environment of the setup instead: hipstr-env/bin/pip install PyVCF3. (If python3 -m venv fails on Debian/Ubuntu, install python3-venv first.)

If you see this error:

error in PyVCF setup command: use_2to3 is invalid.

PyVCF, the package filter_vcf.py asks for, no longer installs on current Python. Install PyVCF3, a maintained fork: the script imports it in the same way (import vcf). We tested it with this tutorial.

11What does a removed call look like?

Only to see what a removed call looks like: with a 2 % stutter threshold, D2S1338 (2.5 % of its reads with stutter) is removed too; D21S11 was already out. The genotype becomes ./. and FILTER says STUTTER_FRACTION. Use the README thresholds for real data.

hipstr-env/bin/python HipSTR/scripts/filter_vcf.py --vcf NA12878.vcf.gz \
    --min-call-qual 0.9 --max-call-flank-indel 0.15 --max-call-stutter 0.02 \
    --min-call-allele-bias -2 --min-call-strand-bias -2 > NA12878.filtered.vcf
bcftools query -f '%ID\t[%GT\t%FILTER]\n' NA12878.filtered.vcf | grep -v PASS
What you should see
D2S1338	./.	STUTTER_FRACTION
D21S11	./.	STUTTER_FRACTION

12Look at the reads with VizAln

--viz-out (step 4) saved the alignments. The first command indexes them with tabix -p bed, as the HipSTR README says. The second activates the environment of the setup, because VizAln calls python. The third runs VizAln with the file, the chromosome and start of the locus (columns 1 and 2 of its line in your BED: for D13S317, chr13 82148020) and the sample.

VizAln writes an HTML file in /tmp and tries to open it in your browser. On macOS it usually opens; on WSL or a server there is no browser, so open the file the message names: the reference on top, the call in red (NA12878: 0|4) and one line per read. On macOS, VizAln also needs GNU cut (see the errors below).

tabix -f -p bed NA12878.viz.gz
source hipstr-env/bin/activate
HipSTR/VizAln NA12878.viz.gz chr13 82148020 NA12878
alns.html.gzNA12878.viz.gzThe file you gave HipSTR in --viz-out, indexed with tabix -p bed (the first command).
chrom startchr13 82148020Chromosome and start of the locus you want to see: columns 1 and 2 of its line in your BED.
[sample]NA12878The sample to draw, as in the SM of its read group. Without it, VizAln draws all samples.
What you should see
VizAln successfully generated the alignment visualization file, but failed to open it. Please open /tmp/vizaln.9266.html using a web browser

If you see this error:

VizAln successfully generated the alignment visualization file, but failed to open it. Please open /tmp/vizaln.NNNNN.html using a web browser

There is no browser where VizAln runs (WSL, a server). Nothing is wrong: the message names the file (/tmp/vizaln.<number>.html). Copy it to your folder with cp /tmp/vizaln.*.html . and open it from your file browser; on WSL, explorer.exe . opens the folder in Windows.

If you see this error:

cut: illegal option -- -

macOS: VizAln uses GNU cut (--complement), which macOS does not have. Install it with brew install coreutils and, in that terminal, put it first before running VizAln: export PATH="$(brew --prefix coreutils)/libexec/gnubin:$PATH" (this is how Homebrew says to use these tools with their normal names).

If you see this error:

ERROR: VizAln requires python. Please check that it's appropriately installed

VizAln calls python, not python3. Activate the environment of the setup first: source hipstr-env/bin/activate (your prompt then starts with (hipstr-env)).

What's next

You genotyped 22 forensic STRs over their ISFG minimum ranges, saw why the basic command leaves loci out, that "Genotyping succeeded" is not the same as a reliable genotype (D21S11), and how to turn HipSTR's length differences into forensic allele numbers. Next: name the sequences in ISFG nomenclature with STRNaming (coming tutorial).