Step 1: Preparing the Input¶
SweepLink does not read VCF files directly. It reads allele counts per population and timepoint, plus a small meta file describing the sampling design. The sweeplink-vcf2input script builds both from a VCF and a sample list, dropping sites that carry no information along the way.
What we start from¶
Two files in tutorial/data:
example.vcf.gz— the genotypes, all samples from all timepoints in one VCF.samples.txt— the sampling design.
The sample list is a tab-separated file with three named columns:
# time in generations before present
sample population time_in_gen
HG_TP01_0017 Pop1 130
HG_TP01_0072 Pop1 130
HG_TP02_0097 Pop1 115
HG_TP02_0008 Pop1 115
...
sample must match a sample name in the VCF header. Anything listed here but missing from the VCF is reported and skipped.
population groups individuals. Use a single value if you have one population.
time_in_gen is the sampling time. Which direction it runs is your choice, declared with
--time-directionbelow. This example data has time in generations before present.
Running the conversion¶
sweeplink-vcf2input \
--vcf data/example.vcf.gz \
--samples data/samples.txt \
--time-direction bp \
--ploidy diploid \
--min-segregating-timepoints 2 \
--max-missing-total 0.2 \
--out-prefix doc
Inputs
--vcf data/example.vcf.gzThe genotypes. Only biallelic SNPs are used.
--samples data/samples.txtThe sample list shown above.
--time-direction bpOur times are before present, so 130 is the oldest sample and 0 the most recent. SweepLink works forward in time, so the script flips the axis for you. Use
forwardinstead if your times already increase toward the present.--ploidy diploidCounts both alleles of each individual. Use
pseudo-haploidfor low-coverage ancient DNA, where only one allele per individual is drawn.
Filtering
--min-segregating-timepoints 2Keep a site only if the allele is segregating (\(0 < C < N\)) at two or more timepoints. A site seen segregating once carries almost nothing about a trajectory.
--max-missing-total 0.2Drop sites missing more than 20% of their genotypes.
Tip
Filtering is optional — sweepLink is stable on unfiltered data. But uninformative sites cost the same compute as informative ones, and there are usually a lot of them, so filtering mostly buys you time.
Output
--out-prefix docNames the two output files:
doc_alleleCounts.txtanddoc_meta.txt.
What it prints¶
Loaded data (individuals per population per timepoint):
t0 t15 t29 t34 t52 t60 t78 t100 t106 t117 t130 total
Pop1 2 10 4 4 8 6 14 17 50 26 100 241
total 2 10 4 4 8 6 14 17 50 26 100 241
Filtered out:
monomorphic: 245
too_few_seg_timepoints: 109
Wrote 413 loci to doc_alleleCounts.txt
Wrote meta file to doc_meta.txt
The table is worth a second look before moving on — it is the quickest way to catch a mis-specified sample list. Here all 241 individuals were matched and spread over 11 timepoints, and the sample sizes are very uneven: 2 individuals at the oldest timepoint against 100 at the most recent. That is typical of ancient DNA, and sweepLink handles it, but it does mean the oldest timepoints carry much less information.
Of the 767 usable sites in the VCF, 354 were dropped — 245 monomorphic across the whole dataset, 109 segregating at only one timepoint — leaving 413 loci.
The output files¶
Allele counts — one row per locus: chromosome, position, then derived/total
for each population × timepoint. Columns run oldest to most recent:
- - time_130BP_Pop1 time_115BP_Pop1 time_101BP_Pop1 ... time_0BP_Pop1
1 579 3/4 15/20 5/8 ... 129/200
1 740 0/4 0/20 0/8 ... 1/200
Missing data is written 0/0.
Meta — one row per group: label, forward time, population. Note the time column: the oldest sample (130 before present) has become forward time 0.
time_130BP_Pop1 0 Pop1
time_115BP_Pop1 15 Pop1
time_101BP_Pop1 29 Pop1
time_96BP_Pop1 34 Pop1
...
Next¶
With doc_alleleCounts.txt and doc_meta.txt in hand, continue to
Step 2: Inference.