| 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, where ambiguous mixed-ancestry heterozygotes are split with shrinkage toward 1/2, 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.1 |
| Built: | 2026-11-04 14:47:33 UTC |
| Source: | https://github.com/bioc/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
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)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, verbose = TRUE )ancestry_split( vcf_path, msp_path, mode = c("dosage", "haplotype"), chrom = NULL, 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., |
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. |
A mixed-ancestry
heterozygote carries one haplotype from each of its two ancestries, so
which one holds the alt allele cannot be read off the genotype. Its
allele is split between the two ancestries in proportion to the
variant's unambiguous carriers (the raw ratio), shrunk toward 1/2 by
, the share of the variant's alt-allele evidence that comes from
ambiguous heterozygotes:
A variant carried only by ambiguous heterozygotes () is
split 1/2 : 1/2. With K populations every pair is shrunk toward 1/2
in the same way, with computed from that pair's own evidence
(the unambiguous alleles on its two populations and its ambiguous
heterozygotes); see split_diploid_multi.
mode = "haplotype" is deterministic and applies no shrinkage.
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 (variants x samples) |
european |
European ancestry-specific dosage matrix |
counts |
List ( |
overlap |
Overlap information |
Both input paths split ambiguous mixed-ancestry
heterozygotes with the same shrinkage toward 1/2 as
ancestry_split (see its "Shrinkage toward 1/2" section).
The target is the same for every variant, so the direct
gt_matrix/pt_matrix path needs no position information.
Each variant (row of
gt_matrix) is paired with an ancestry column of pt_matrix
by, in order of preference: identical names; position, when rownames
look like "chr:pos" and colnames like "chr:start-end"
(the first region containing the variant; several variants may share a
region); or, when either matrix has no names, position in the matrix.
# 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 = NULL, chrom = NULL, write_vcf = TRUE, verbose = TRUE )ancestry_split_phased( vcf_path, msp_path, out_path = NULL, 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 the GDS files. Only needed (and
then required) when |
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 = sub("\\.bed$", ".bim", bed), fam = sub("\\.bed$", ".fam", bed) )read_bed_file( bed, bim = sub("\\.bed$", ".bim", bed), fam = sub("\\.bed$", ".fam", bed) )
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") # .bim and .fam are found next to the .bed file pt <- read_bed_file(file.path(ext, "toy_ancestry.bed")) pt[, 1:6] # ancestry tracts x samples, codes 1/2/3ext <- system.file("extdata", package = "lantern") # .bim and .fam are found next to the .bed file pt <- read_bed_file(file.path(ext, "toy_ancestry.bed")) 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, shrink = FALSE)split_diploid(gt_genotype, ancestry, shrink = FALSE)
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 |
shrink |
If |
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 = c(AFR = 3L, EUR = 1L), mixed_codes = data.frame(code = 2L, pop1 = "AFR", pop2 = "EUR"), shrink = FALSE )split_diploid_multi( gt_genotype, ancestry, pure_codes = c(AFR = 3L, EUR = 1L), mixed_codes = data.frame(code = 2L, pop1 = "AFR", pop2 = "EUR"), shrink = FALSE )
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. The default is the
two-population mixed code 2 = AFR/EUR, so with both defaults
|
shrink |
If |
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)