| Title: | Ancestry-Specific Rare Variant Association Analysis |
|---|---|
| Description: | Ancestry-specific rare variant burden testing for admixed populations. Splits genotype dosages by local ancestry (as inferred by 'RFMix') into per-ancestry dosages, using either phased haplotypes or unphased genotypes with shrinkage toward global ancestry, and writes them to 'SeqArray' GDS files. Ancestry-stratified gene-level tests are then run with the 'SMMAT' framework of Chen et al. (2019) <doi:10.1016/j.ajhg.2018.12.012> as implemented in 'GMMAT', and the per-ancestry p-values are combined with the Cauchy combination test of Liu and Xie (2020) <doi:10.1080/01621459.2018.1554485>. |
| Authors: | Yu Wang [aut, cre], Bjoernar Tuftin [aut], Paul Auer [aut] |
| Maintainer: | Yu Wang <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.99.0 |
| Built: | 2026-10-07 08:25:49 UTC |
| Source: | https://github.com/BiocStaging/lantern |
Wraps GMMAT::SMMAT() across all ancestry-split GDS files (as
produced by write_ancestry_gds), computes per-gene
ancestry weights from Step 1's ancestry_counts (this replaces the
retired src/step3_weight_finding.R script), and combines the per-gene p-values
across populations with cauchy_combine. This is the
package's Step 3 entry point; it does not run Step 1/2 for you (SMMAT
runs can take hours, so this is always an explicit, separate call).
ancestry_smmat( gds_paths, pheno, formula, kinship, gene_group_file, ancestry_counts = NULL, variant_info = NULL, id_col = "id", family = stats::gaussian(), gene_col = "group", p_col = "E.pval", MAF.range = c(0, 0.5), miss.cutoff = 1, method = "davies", ncores = 1, verbose = TRUE, ... )ancestry_smmat( gds_paths, pheno, formula, kinship, gene_group_file, ancestry_counts = NULL, variant_info = NULL, id_col = "id", family = stats::gaussian(), gene_col = "group", p_col = "E.pval", MAF.range = c(0, 0.5), miss.cutoff = 1, method = "davies", ncores = 1, verbose = TRUE, ... )
gds_paths |
Named list/vector of GDS file paths, one per ancestry
population, e.g. |
pheno |
data.frame with an |
formula |
Model formula for the null model, e.g. |
kinship |
Numeric matrix (or object coercible via |
gene_group_file |
Either a path to the gene_group file passed to
|
ancestry_counts, variant_info
|
Optional: pass
|
id_col |
Name of the sample ID column in |
family |
A family object for |
gene_col |
Name of the gene/group ID column in |
p_col |
Name of the p-value column in |
MAF.range, miss.cutoff, method, ncores
|
Passed straight through to
|
verbose |
Print this function's own step-by-step progress messages
(Steps 1-6 below). Distinct from |
... |
Any other |
A list with two elements:
results |
data.frame with one row per gene: |
smmat_results |
Named list (one entry per population, same names
as |
ancestry_split, write_ancestry_gds,
cauchy_combine
if (requireNamespace("GMMAT", quietly = TRUE) && requireNamespace("SeqVarTools", quietly = TRUE)) { ext <- system.file("extdata", package = "lantern") split <- ancestry_split(file.path(ext, "toy.vcf.gz"), file.path(ext, "toy.msp.tsv"), mode = "dosage", chrom = "chr19", verbose = FALSE) out_dir <- tempfile() gds <- write_ancestry_gds(split, out_dir, verbose = FALSE) pheno <- read.delim(file.path(ext, "toy_pheno.tsv")) kinship <- diag(nrow(pheno)) # unrelated samples dimnames(kinship) <- list(pheno$id, pheno$id) # gene_group_file: a path, or a data.frame with the same six columns out <- ancestry_smmat(gds, pheno, y ~ age + sex, kinship, file.path(ext, "toy_genes.tsv"), ancestry_counts = split$ancestry_counts, variant_info = split$variant_info, verbose = FALSE) out$results # per-gene p-values + Cauchy combination head(out$smmat_results$AFR) # raw GMMAT::SMMAT() output for AFR unlink(out_dir, recursive = TRUE) }if (requireNamespace("GMMAT", quietly = TRUE) && requireNamespace("SeqVarTools", quietly = TRUE)) { ext <- system.file("extdata", package = "lantern") split <- ancestry_split(file.path(ext, "toy.vcf.gz"), file.path(ext, "toy.msp.tsv"), mode = "dosage", chrom = "chr19", verbose = FALSE) out_dir <- tempfile() gds <- write_ancestry_gds(split, out_dir, verbose = FALSE) pheno <- read.delim(file.path(ext, "toy_pheno.tsv")) kinship <- diag(nrow(pheno)) # unrelated samples dimnames(kinship) <- list(pheno$id, pheno$id) # gene_group_file: a path, or a data.frame with the same six columns out <- ancestry_smmat(gds, pheno, y ~ age + sex, kinship, file.path(ext, "toy_genes.tsv"), ancestry_counts = split$ancestry_counts, variant_info = split$variant_info, verbose = FALSE) out$results # per-gene p-values + Cauchy combination head(out$smmat_results$AFR) # raw GMMAT::SMMAT() output for AFR unlink(out_dir, recursive = TRUE) }
Parse an RFMix MSP file and a phased VCF, intersect samples, map each
variant to its ancestry tract, and split genotypes into per-population
dosage matrices using either the proportional ("dosage") or
deterministic ("haplotype") split algorithm. This is the
package's Step 1 entry point: it only computes in-memory dosage
matrices, with no file I/O. Pass the result to
write_ancestry_gds (Step 2) to materialize GDS files, and
then to ancestry_smmat (Step 3) to run SMMAT + Cauchy
combination.
ancestry_split( vcf_path, msp_path, mode = c("dosage", "haplotype"), chrom = NULL, use_gla = TRUE, verbose = TRUE )ancestry_split( vcf_path, msp_path, mode = c("dosage", "haplotype"), chrom = NULL, use_gla = TRUE, verbose = TRUE )
vcf_path |
Path to phased VCF/BCF file (plain or gzipped). Read
with |
msp_path |
Path to RFMix MSP file (plain text or gzipped TSV). |
mode |
Split algorithm: |
chrom |
Chromosome to process (e.g., |
use_gla |
Logical, |
verbose |
Print step-by-step progress messages. |
Invisibly, a list with one named numeric matrix (variants x
samples) per population (named after the MSP population codes, e.g.
$AFR, $EUR), plus:
variant_info |
data.frame with columns chrom, pos, ref, alt. |
sample_ids |
Character vector of common sample IDs. |
mode |
The split mode used. |
ancestry_counts |
Numeric matrix (variants x populations): for
each variant, the number of samples with pure ancestry in that
population. Feeds |
tract_info |
data.frame of ancestry tracts from the MSP file. |
overlap |
List of intersection/filtering statistics. |
write_ancestry_gds, ancestry_smmat
vcf <- system.file("extdata", "toy.vcf.gz", package = "lantern") msp <- system.file("extdata", "toy.msp.tsv", package = "lantern") split <- ancestry_split(vcf, msp, mode = "dosage", chrom = "chr19", verbose = FALSE) split$AFR[1:3, 1:5] # African dosages (variants x samples) split$EUR[1:3, 1:5] # European dosages head(split$variant_info)vcf <- system.file("extdata", "toy.vcf.gz", package = "lantern") msp <- system.file("extdata", "toy.msp.tsv", package = "lantern") split <- ancestry_split(vcf, msp, mode = "dosage", chrom = "chr19", verbose = FALSE) split$AFR[1:3, 1:5] # African dosages (variants x samples) split$EUR[1:3, 1:5] # European dosages head(split$variant_info)
Complete pipeline: split genotype matrix by ancestry, return dosage matrices. Handles sample and variant mismatches by using only overlapping data. Memory efficient: single-pass subsetting using index vectors.
ancestry_split_dosage( gt_matrix = NULL, pt_matrix = NULL, vcf_path = NULL, msp_path = NULL, chrom = NULL, verbose = TRUE )ancestry_split_dosage( gt_matrix = NULL, pt_matrix = NULL, vcf_path = NULL, msp_path = NULL, chrom = NULL, verbose = TRUE )
gt_matrix |
Integer matrix of genotypes (rows=variants, cols=samples).
Values: 0=homozygous ref, 1=heterozygous, 2=homozygous alt.
rownames: variant IDs (e.g., |
pt_matrix |
Integer matrix of parent-of-origin ancestry codes
(rows=samples, cols=regions/variants).
Values: 1=EUR/EUR, 2=AFR/EUR (mixed), 3=AFR/AFR.
rownames: sample IDs (must match colnames of |
vcf_path |
Path to a phased VCF or BCF file. When supplied together
with |
msp_path |
Path to an RFMix MSP file (plain text or gzipped TSV).
Used together with |
chrom |
Chromosome name to restrict to (e.g. |
verbose |
Print progress messages (default TRUE) |
List with elements:
african |
African ancestry-specific dosage matrix |
european |
European ancestry-specific dosage matrix |
counts |
List of ancestry counts per region/sample |
overlap |
Overlap information |
The vcf_path/msp_path shortcut
delegates to ancestry_split, which computes and applies
per-arm global local ancestry (GLA) shrinkage automatically from tract
positions. The direct gt_matrix/pt_matrix path has no
genomic position information and cannot derive GLA automatically, so it
always uses the original (unshrunk) p1/p2 estimator; this path also
reorders and filters variants internally (sample/region overlap,
monomorphic removal), so a caller-supplied gla/arm_id
could not be reliably kept aligned. Call split_diploid
directly (no internal reordering) if you need GLA shrinkage with a
pre-computed gla/arm_id of your own.
# Example with mismatched dimensions gt <- matrix(c(2, 1, 0, 1, 2, 1), nrow = 2, ncol = 3, dimnames = list(c("chr1:100", "chr1:200"), c("sample_A", "sample_B", "sample_C"))) pt <- matrix(c(3, 2, 1, 3, 2, 1), nrow = 3, ncol = 2, dimnames = list(c("sample_A", "sample_B", "sample_D"), c("chr1:50-150", "chr1:150-250"))) result <- ancestry_split_dosage(gt, pt) # Only sample_A and sample_B are kept (common to both) # Only chr1:100 and chr1:200 that overlap regions are kept # Shortcut: build matrices directly from VCF + MSP vcf <- system.file("extdata", "toy.vcf.gz", package = "lantern") msp <- system.file("extdata", "toy.msp.tsv", package = "lantern") result <- ancestry_split_dosage(vcf_path = vcf, msp_path = msp, chrom = "chr19", verbose = FALSE)# Example with mismatched dimensions gt <- matrix(c(2, 1, 0, 1, 2, 1), nrow = 2, ncol = 3, dimnames = list(c("chr1:100", "chr1:200"), c("sample_A", "sample_B", "sample_C"))) pt <- matrix(c(3, 2, 1, 3, 2, 1), nrow = 3, ncol = 2, dimnames = list(c("sample_A", "sample_B", "sample_D"), c("chr1:50-150", "chr1:150-250"))) result <- ancestry_split_dosage(gt, pt) # Only sample_A and sample_B are kept (common to both) # Only chr1:100 and chr1:200 that overlap regions are kept # Shortcut: build matrices directly from VCF + MSP vcf <- system.file("extdata", "toy.vcf.gz", package = "lantern") msp <- system.file("extdata", "toy.msp.tsv", package = "lantern") result <- ancestry_split_dosage(vcf_path = vcf, msp_path = msp, chrom = "chr19", verbose = FALSE)
Backward-compatible 2-population (AFR/EUR) wrapper around
ancestry_split (Step 1, mode = "haplotype") and,
when write_vcf = TRUE, write_ancestry_gds (Step 2).
For K > 2 populations or to keep the split and GDS-writing steps
separate, call ancestry_split() and write_ancestry_gds()
directly.
ancestry_split_phased( vcf_path, msp_path, out_path, chrom = NULL, write_vcf = TRUE, verbose = TRUE )ancestry_split_phased( vcf_path, msp_path, out_path, chrom = NULL, write_vcf = TRUE, verbose = TRUE )
vcf_path |
Path to phased VCF/BCF file (plain or gzipped). Read
with |
msp_path |
Path to RFMix MSP file (plain text or gzipped TSV). |
out_path |
Output directory for GDS and cache files. |
chrom |
Chromosome to process (e.g., |
write_vcf |
Logical; if |
verbose |
Print step-by-step progress messages. |
Invisibly, a list with elements:
african |
Numeric matrix (variants x samples) of African dosages. |
european |
Numeric matrix (variants x samples) of European dosages. |
variant_info |
data.frame with columns chrom, pos, ref, alt. |
sample_ids |
Character vector of common sample IDs. |
tract_info |
data.frame of ancestry tracts from the MSP file. |
overlap |
List of intersection statistics. |
vcf_paths |
(when |
vcf <- system.file("extdata", "toy.vcf.gz", package = "lantern") msp <- system.file("extdata", "toy.msp.tsv", package = "lantern") out_dir <- tempfile() result <- ancestry_split_phased(vcf, msp, out_path = out_dir, chrom = "chr19", write_vcf = FALSE, verbose = FALSE) head(result$variant_info) unlink(out_dir, recursive = TRUE)vcf <- system.file("extdata", "toy.vcf.gz", package = "lantern") msp <- system.file("extdata", "toy.msp.tsv", package = "lantern") out_dir <- tempfile() result <- ancestry_split_phased(vcf, msp, out_path = out_dir, chrom = "chr19", write_vcf = FALSE, verbose = FALSE) head(result$variant_info) unlink(out_dir, recursive = TRUE)
Combines p-values from correlated or independent tests into a single
meta-analysis p-value using the Cauchy combination test (Liu & Xie 2020).
Unlike Fisher's method, the test remains valid under arbitrary dependency
structures among p-values.
cauchy_combine(p_values, weights = NULL)cauchy_combine(p_values, weights = NULL)
p_values |
Numeric vector of p-values ( |
weights |
Optional non-negative numeric weight vector of the same
length as |
A single numeric p-value in .
Liu, Y. and Xie, J. (2020). Cauchy Combination Test: A Powerful Test With Analytic p-Value Calculation Under Arbitrary Dependency Structures. J. Am. Stat. Assoc. 115(529), 393–402. doi:10.1080/01621459.2018.1554485
write_dosage_gds, ancestry_split,
ancestry_smmat
# Combine African-ancestry and European-ancestry p-values for one gene cauchy_combine(c(0.01, 0.04)) # Three-population meta-analysis cauchy_combine(c(0.01, 0.04, 0.20)) # Weighted combination (double weight on AFR) cauchy_combine(c(0.01, 0.04), weights = c(2, 1)) # Apply across a results table (one gene per row) # mapply(cauchy_combine, split(cbind(p_aa, p_ee), seq_len(nrow(res))))# Combine African-ancestry and European-ancestry p-values for one gene cauchy_combine(c(0.01, 0.04)) # Three-population meta-analysis cauchy_combine(c(0.01, 0.04, 0.20)) # Weighted combination (double weight on AFR) cauchy_combine(c(0.01, 0.04), weights = c(2, 1)) # Apply across a results table (one gene per row) # mapply(cauchy_combine, split(cbind(p_aa, p_ee), seq_len(nrow(res))))
Reads a PLINK binary genotype file (.bed/.bim/.fam
trio) into an integer matrix, for the case where local ancestry has been
encoded as PLINK genotype calls at ancestry-tract "SNPs" (as consumed by
src/step1_vcf_split_by_ancestry.R): homozygous first allele = pure
EUR/EUR (code 1), heterozygous = mixed AFR/EUR (code 2), homozygous
second allele = pure AFR/AFR (code 3), missing = no call (code 0). This
matches snpStats::read.plink()'s raw numeric convention (values
feed directly into split_diploid/ancestry_split_dosage
as pt_matrix/ancestry without snpStats as a
dependency.
read_bed_file(bed, bim, fam)read_bed_file(bed, bim, fam)
bed |
Path to the |
bim |
Path to the |
fam |
Path to the |
Integer matrix (variants x samples), dimnamed from the
.bim/.fam files. Values: 0 = no call, 1 = homozygous
first allele, 2 = heterozygous, 3 = homozygous second allele.
split_diploid, ancestry_split_dosage
ext <- system.file("extdata", package = "lantern") pt <- read_bed_file(file.path(ext, "toy_ancestry.bed"), file.path(ext, "toy_ancestry.bim"), file.path(ext, "toy_ancestry.fam")) pt[, 1:6] # ancestry tracts x samples, codes 1/2/3ext <- system.file("extdata", package = "lantern") pt <- read_bed_file(file.path(ext, "toy_ancestry.bed"), file.path(ext, "toy_ancestry.bim"), file.path(ext, "toy_ancestry.fam")) pt[, 1:6] # ancestry tracts x samples, codes 1/2/3
Split a genotype matrix into African and European ancestry-specific dosage matrices based on a parent-of-origin ancestry matrix.
split_diploid(gt_genotype, ancestry, gla = NULL, arm_id = NULL)split_diploid(gt_genotype, ancestry, gla = NULL, arm_id = NULL)
gt_genotype |
Integer matrix of genotypes (0, 1, 2) - Rows represent variants - Columns represent samples |
ancestry |
Integer matrix of ancestry codes (1, 2, 3) - Same dimensions as gt_genotype - Values: 1=EUR/EUR, 2=AFR/EUR (mixed), 3=AFR/AFR |
gla |
Optional 2 x K numeric matrix (rows "p"/"q", columns population
names) of per-arm global local ancestry proportions, as produced by
|
arm_id |
Optional integer vector (length = |
List with two elements:
african |
Matrix of African ancestry-specific dosages |
european |
Matrix of European ancestry-specific dosages |
# Genotype matrix: 5 variants x 4 samples gt <- matrix(c(2, 1, 0, 1, 2, 1, 0, 2, 1, 0, 1, 1, 1, 0, 2, 1, 0, 1, 0, 1), nrow = 5, ncol = 4) # Ancestry matrix: same dimensions ancestry <- matrix(c(3, 2, 1, 3, 2, 1, 2, 2, 1, 1, 3, 1, 2, 1, 3, 2, 1, 2, 1, 3), nrow = 5, ncol = 4) result <- split_diploid(gt, ancestry) result$african result$european# Genotype matrix: 5 variants x 4 samples gt <- matrix(c(2, 1, 0, 1, 2, 1, 0, 2, 1, 0, 1, 1, 1, 0, 2, 1, 0, 1, 0, 1), nrow = 5, ncol = 4) # Ancestry matrix: same dimensions ancestry <- matrix(c(3, 2, 1, 3, 2, 1, 2, 2, 1, 1, 3, 1, 2, 1, 3, 2, 1, 2, 1, 3), nrow = 5, ncol = 4) result <- split_diploid(gt, ancestry) result$african result$european
Generalises split_diploid to an arbitrary number of
ancestries. For each variant, population allele proportions
(summing to 1) are estimated from samples with
unambiguous ancestry (pure-ancestry homozygotes and heterozygotes, plus
mixed hom-alts which each contribute one allele to each parent pool).
Ambiguous heterozygotes in each mixed pair are then split by the
conditional pairwise ratio .
When no unambiguous alt alleles exist for a pair (singleton edge case),
the split defaults to 0.5 / 0.5.
split_diploid_multi( gt_genotype, ancestry, pure_codes, mixed_codes, gla = NULL, arm_id = NULL )split_diploid_multi( gt_genotype, ancestry, pure_codes, mixed_codes, gla = NULL, arm_id = NULL )
gt_genotype |
Integer matrix (variants x samples) of genotypes (0/1/2). |
ancestry |
Integer matrix (variants x samples) of ancestry codes,
same dimensions as |
pure_codes |
Named integer vector mapping each population label to its
pure-ancestry diploid code.
Example: |
mixed_codes |
Data frame with three columns:
One row per mixed-ancestry diploid type.
Example for 3 populations:
|
gla |
Optional 2 x K numeric matrix (rows "p"/"q", columns matching
|
arm_id |
Optional integer vector (length = |
Named list of K numeric matrices (variants x samples), one per
population in pure_codes, in the same order. Each element is
named after the corresponding entry in pure_codes.
split_diploid for the hardcoded 2-population
(AFR + EUR) wrapper; split_haplotype_multi for the phased
K-population analogue.
# 3-population example: AFR=3, EUR=1, NAT=4; mixed codes 2/5/6 set.seed(1) gt <- matrix(sample(0:2, 20, replace = TRUE, prob = c(.8,.15,.05)), nrow = 4, ncol = 5) # ancestry codes: 3=AFR/AFR, 1=EUR/EUR, 4=NAT/NAT, # 2=AFR/EUR, 5=AFR/NAT, 6=EUR/NAT anc <- matrix(sample(c(1L,2L,3L,4L,5L,6L), 20, replace = TRUE), nrow = 4, ncol = 5) pure <- c(AFR = 3L, EUR = 1L, NAT = 4L) mixed <- data.frame(code = c(2L, 5L, 6L), pop1 = c("AFR", "AFR", "EUR"), pop2 = c("EUR", "NAT", "NAT")) out <- split_diploid_multi(gt, anc, pure, mixed) names(out) # "AFR" "EUR" "NAT"# 3-population example: AFR=3, EUR=1, NAT=4; mixed codes 2/5/6 set.seed(1) gt <- matrix(sample(0:2, 20, replace = TRUE, prob = c(.8,.15,.05)), nrow = 4, ncol = 5) # ancestry codes: 3=AFR/AFR, 1=EUR/EUR, 4=NAT/NAT, # 2=AFR/EUR, 5=AFR/NAT, 6=EUR/NAT anc <- matrix(sample(c(1L,2L,3L,4L,5L,6L), 20, replace = TRUE), nrow = 4, ncol = 5) pure <- c(AFR = 3L, EUR = 1L, NAT = 4L) mixed <- data.frame(code = c(2L, 5L, 6L), pop1 = c("AFR", "AFR", "EUR"), pop2 = c("EUR", "NAT", "NAT")) out <- split_diploid_multi(gt, anc, pure, mixed) names(out) # "AFR" "EUR" "NAT"
Split phased haplotypes deterministically into African and European ancestry-specific dosage matrices. Each haplotype's allele is added to whichever ancestry pool matches its local ancestry call; haplotypes with unrecognised ancestry codes contribute nothing to either pool.
split_haplotype( gt_hap0, gt_hap1, anc_hap0, anc_hap1, pop_codes = c(AFR = 0L, EUR = 1L) )split_haplotype( gt_hap0, gt_hap1, anc_hap0, anc_hap1, pop_codes = c(AFR = 0L, EUR = 1L) )
gt_hap0 |
Integer matrix (variants x samples) of haplotype-0 alleles (0/1). |
gt_hap1 |
Integer matrix (variants x samples) of haplotype-1 alleles (0/1). |
anc_hap0 |
Integer matrix (variants x samples) of haplotype-0 ancestry codes. |
anc_hap1 |
Integer matrix (variants x samples) of haplotype-1 ancestry codes. |
pop_codes |
Named integer vector of length 2 giving the AFR and EUR
ancestry codes as used in the MSP file. Defaults to
|
List with two numeric matrices:
african |
African ancestry-specific dosage (variants x samples) |
european |
European ancestry-specific dosage (variants x samples) |
gt0 <- matrix(c(1L, 0L, 0L, 1L), 2, 2) gt1 <- matrix(c(0L, 1L, 1L, 0L), 2, 2) a0 <- matrix(c(0L, 1L, 0L, 1L), 2, 2) a1 <- matrix(c(1L, 0L, 1L, 0L), 2, 2) split_haplotype(gt0, gt1, a0, a1)gt0 <- matrix(c(1L, 0L, 0L, 1L), 2, 2) gt1 <- matrix(c(0L, 1L, 1L, 0L), 2, 2) a0 <- matrix(c(0L, 1L, 0L, 1L), 2, 2) a1 <- matrix(c(1L, 0L, 1L, 0L), 2, 2) split_haplotype(gt0, gt1, a0, a1)
Generalises split_haplotype to an arbitrary number of ancestries.
Each haplotype's allele is routed to the dosage pool whose code matches its
local ancestry call. Haplotypes with unrecognised codes contribute 0 to
all pools. NA genotypes are treated as 0 (reference allele).
split_haplotype_multi( gt_hap0, gt_hap1, anc_hap0, anc_hap1, pop_codes = c(AFR = 0L, EUR = 1L) )split_haplotype_multi( gt_hap0, gt_hap1, anc_hap0, anc_hap1, pop_codes = c(AFR = 0L, EUR = 1L) )
gt_hap0 |
Integer matrix (variants x samples) of haplotype-0 alleles (0/1). |
gt_hap1 |
Integer matrix (variants x samples) of haplotype-1 alleles (0/1). |
anc_hap0 |
Integer matrix (variants x samples) of haplotype-0 ancestry codes. |
anc_hap1 |
Integer matrix (variants x samples) of haplotype-1 ancestry codes. |
pop_codes |
Named integer vector mapping population label to ancestry code,
e.g. |
For the two-population case split_haplotype_multi and split_haplotype
are equivalent; prefer split_haplotype_multi for new code that may later
be extended to three or more ancestries.
Named list of K numeric matrices (variants x samples), one per
entry in pop_codes, in the same order. List names equal the
names of pop_codes.
split_haplotype for the two-population convenience wrapper,
split_diploid for unphased (diploid-code) splitting.
# Three-population panel: AFR=0, EUR=1, NAT=2 gt0 <- matrix(c(1L, 0L, 0L, 1L, 1L, 0L), nrow = 3, ncol = 2) gt1 <- matrix(c(0L, 1L, 1L, 0L, 0L, 1L), nrow = 3, ncol = 2) a0 <- matrix(c(0L, 1L, 2L, 0L, 1L, 2L), nrow = 3, ncol = 2) a1 <- matrix(c(1L, 2L, 0L, 2L, 0L, 1L), nrow = 3, ncol = 2) out <- split_haplotype_multi(gt0, gt1, a0, a1, c(AFR = 0L, EUR = 1L, NAT = 2L)) names(out) # "AFR" "EUR" "NAT" out$NAT # native-ancestry dosage matrix# Three-population panel: AFR=0, EUR=1, NAT=2 gt0 <- matrix(c(1L, 0L, 0L, 1L, 1L, 0L), nrow = 3, ncol = 2) gt1 <- matrix(c(0L, 1L, 1L, 0L, 0L, 1L), nrow = 3, ncol = 2) a0 <- matrix(c(0L, 1L, 2L, 0L, 1L, 2L), nrow = 3, ncol = 2) a1 <- matrix(c(1L, 2L, 0L, 2L, 0L, 1L), nrow = 3, ncol = 2) out <- split_haplotype_multi(gt0, gt1, a0, a1, c(AFR = 0L, EUR = 1L, NAT = 2L)) names(out) # "AFR" "EUR" "NAT" out$NAT # native-ancestry dosage matrix
Takes the list returned by ancestry_split (or the
backward-compatible ancestry_split_dosage /
ancestry_split_phased output, which has the same
per-population matrix + variant_info + sample_ids shape)
and writes one GDS file per population via write_dosage_gds,
printing progress as it goes. This is Step 2 of the package's
Step1/Step2/Step3 workflow: most users only need to call it so they have
GDS paths to pass to ancestry_smmat (Step 3); it's exported
mainly for standalone use (e.g. caching GDS files between SLURM jobs).
write_ancestry_gds(split_result, out_path, verbose = TRUE)write_ancestry_gds(split_result, out_path, verbose = TRUE)
split_result |
List as returned by |
out_path |
Output directory (created if it doesn't exist). One file
|
verbose |
Print per-population progress messages. |
Named list of GDS file paths, one per population, e.g.
list(AFR = "out/AFR.gds", EUR = "out/EUR.gds"). Pass this
directly as gds_paths to ancestry_smmat.
ancestry_split, ancestry_smmat
vcf <- system.file("extdata", "toy.vcf.gz", package = "lantern") msp <- system.file("extdata", "toy.msp.tsv", package = "lantern") split <- ancestry_split(vcf, msp, mode = "dosage", chrom = "chr19", verbose = FALSE) out_dir <- tempfile() gds <- write_ancestry_gds(split, out_dir, verbose = FALSE) gds # one GDS file per population unlink(out_dir, recursive = TRUE)vcf <- system.file("extdata", "toy.vcf.gz", package = "lantern") msp <- system.file("extdata", "toy.msp.tsv", package = "lantern") split <- ancestry_split(vcf, msp, mode = "dosage", chrom = "chr19", verbose = FALSE) out_dir <- tempfile() gds <- write_ancestry_gds(split, out_dir, verbose = FALSE) gds # one GDS file per population unlink(out_dir, recursive = TRUE)
Converts a dosage matrix (rows = variants, columns = samples) to a
SeqArray GDS file via a temporary VCF with a DS FORMAT field.
The resulting GDS can be passed directly to GMMAT::SMMAT() via the
gds.fn argument with is.dosage = TRUE.
write_dosage_gds(dosage_mat, variant_info, sample_ids, gds_path)write_dosage_gds(dosage_mat, variant_info, sample_ids, gds_path)
dosage_mat |
Numeric matrix; rows = variants, columns = samples.
Values should be in |
variant_info |
Data frame with columns |
sample_ids |
Character vector of sample identifiers, length equal to
|
gds_path |
Output file path for the GDS file (e.g. |
Invisibly returns gds_path.
ancestry_split, write_ancestry_gds,
cauchy_combine
vcf <- system.file("extdata", "toy.vcf.gz", package = "lantern") msp <- system.file("extdata", "toy.msp.tsv", package = "lantern") split <- ancestry_split(vcf, msp, mode = "haplotype", chrom = "chr19", verbose = FALSE) afr_gds <- tempfile(fileext = ".gds") write_dosage_gds(split$AFR, split$variant_info, split$sample_ids, afr_gds) unlink(afr_gds)vcf <- system.file("extdata", "toy.vcf.gz", package = "lantern") msp <- system.file("extdata", "toy.msp.tsv", package = "lantern") split <- ancestry_split(vcf, msp, mode = "haplotype", chrom = "chr19", verbose = FALSE) afr_gds <- tempfile(fileext = ".gds") write_dosage_gds(split$AFR, split$variant_info, split$sample_ids, afr_gds) unlink(afr_gds)