diff --git a/docs/BIGpopA_user_guide.html b/docs/BIGpopA_user_guide.html new file mode 100644 index 0000000..d45ce52 --- /dev/null +++ b/docs/BIGpopA_user_guide.html @@ -0,0 +1,4503 @@ + + + + +
+ + + + + + + + + + +BIGpopA is an R package for pedigree quality control, parentage +assignment and breed/line composition from SNP genotypes. It works for +diploid and polyploid species and is the analytical engine behind the Familia Shiny +app. This guide runs the functions in the order a breeding program +usually needs them:
+vcf_to_dosage(), ped_to_dosage()check_ped()validate_pedigree()find_parentage()allele_freq_poly(), solve_composition_poly(),
+assign_composition_line()| Function | +Use it to | +Main output | +
|---|---|---|
vcf_to_dosage() |
+Convert a VCF to allele-B dosages | +Dosage table or matrix | +
ped_to_dosage() |
+Convert a PLINK .ped (diploid) to allele-B dosages |
+Dosage table or matrix | +
check_ped() |
+Fix structural pedigree errors before any genotype work | +Corrected pedigree, issue tables | +
validate_pedigree() |
+Test recorded trios against genotypes | +Status per trio, corrected pedigree, marker summary | +
find_parentage() |
+Assign or fill in parents from a candidate pool | +Best parent(s), error %, ties | +
allele_freq_poly() |
+Allele frequencies of reference lines | +Frequency table (markers x lines) | +
solve_composition_poly() |
+Composition of samples from reference frequencies | +Proportions and R2 per sample | +
assign_composition_line() |
+Percentages and assigned line per sample | +Composition table | +
Remarks on the data (violations give misleading results):
+BIGpopA does not call dosages; use your pipeline first (we recommend +BIGapp).
+BIGpopA requires R >= 4.4.0. Install it from CRAN by copying and +pasting this code into your R console:
+ +Every function accepts either a file path or an in-memory object
+(data.frame / data.table). founders_file accepts a file
+path, a character vector of ids, or a data.frame whose first column
+holds the ids. This guide builds a small toy dataset that exercises
+every result category.
| Object | +Format | +Used by | +
|---|---|---|
| Pedigree | +id, male_parent,
+female_parent. Unknown parent = 0. |
+check_ped(), validate_pedigree() |
+
| Genotypes | +id + one column per marker (allele-B dosage,
+NA = missing) |
+validate_pedigree(), find_parentage() |
+
| Parents | +id and sex (M,
+F, A = either). Without a sex
+column all candidates are treated as A. |
+find_parentage() |
+
| Progeny | +id column. For fill_pedigree: the 3-column
+pedigree (unknown parent = 0, NA or
+empty). |
+find_parentage() |
+
| Founders | +File path, character vector or data.frame (first column) | +validate_pedigree(), find_parentage() |
+
library(BIGpopA)
+
+# SNP genotypes coded 0/1/2 (NA = missing); C_low is mostly missing
+genotypes = data.frame(
+ id = c("M1","F1","M2","F2","C1","C2","C3","C_bad","C_low"),
+ snp01 = c( 0, 0, 2, 2, 0, 2, 1, 0, NA),
+ snp02 = c( 0, 0, 2, 0, 0, 1, 0, 0, NA),
+ snp03 = c( 0, 2, 0, 2, 1, 1, 1, 1, NA),
+ snp04 = c( 0, 2, 0, 0, 1, 0, 0, 1, NA),
+ snp05 = c( 2, 0, 1, 1, 1, 1, 1, 1, NA),
+ snp06 = c( 2, 0, 1, 0, 1, 1, 1, 1, NA),
+ snp07 = c( 2, 2, 0, 1, 2, 0, 2, 2, NA),
+ snp08 = c( 2, 2, 2, 2, 2, 2, 2, 2, NA),
+ snp09 = c( 0, 1, 0, 2, 1, 1, 1, 1, 0),
+ snp10 = c( 0, 1, 2, 0, 0, 1, 0, 0, 0),
+ snp11 = c( 2, 1, 1, 2, 1, 2, 2, 1, 2),
+ snp12 = c( 2, 1, 0, 1, 2, 1, 1, 2, 2),
+ stringsAsFactors = FALSE
+)
+
+# pedigree with founders coded 0, a mis-assigned trio (C_bad),
+# and a duplicated row (C_missing)
+pedigree = data.frame(
+ id = c("M1","F1","M2","F2","C1","C2","C3","C_bad","C_low","C_missing","C_missing"),
+ male_parent = c("0", "0", "0", "0", "M1","M2","M1","M2", "M1", "M1", "M1"),
+ female_parent = c("0", "0", "0", "0", "F1","F2","F2","F1", "F1", "F1", "F1"),
+ stringsAsFactors = FALSE
+)
+
+# candidate parents (with sex) and progeny to assign
+parents = data.frame(
+ id = c("M1","M2","F1","F2"),
+ sex = c("M", "M", "F", "F"),
+ stringsAsFactors = FALSE
+)
+
+progeny = data.frame(id = c("C1","C2","C3","C_bad","C_low","C_missing"),
+ stringsAsFactors = FALSE)
+
+pedigreeThe pedigree has four founders (M1, F1,
+M2, F2, both parents 0) and
+several crosses, including a duplicated row (C_missing), a
+mis-assigned trio (C_bad) and a sample with mostly missing
+genotypes (C_low).
Use these converters when your genotypes come as a VCF or a PLINK
+file. Both return an id column followed by one column per
+marker, ready for validate_pedigree() and
+find_parentage().
# VCF (.vcf or .vcf.gz); ploidy is inferred from the GT field when NULL
+geno_vcf = vcf_to_dosage("my_markers.vcf.gz", ploidy = 4)
+
+# PLINK .ped (diploid only); a .map file next to it is used for marker names
+geno_ped = ped_to_dosage("my_markers.ped")
+
+# format = "matrix" returns individuals x markers, the input of
+# allele_freq_poly() and solve_composition_poly()
+geno_mat = vcf_to_dosage("my_markers.vcf.gz", ploidy = 4, format = "matrix")Useful vcf_to_dosage() arguments:
| Argument | +Effect | +
|---|---|
ploidy |
+Checked against the ploidy observed in the file; a warning is issued +if they disagree | +
dosage_field |
+Read a FORMAT field with dosages (e.g. "DS",
+"UD") instead of counting alleles in GT;
+ploidy must be given |
+
ref_dosage |
+Count reference instead of alternate alleles (default
+FALSE) |
+
biallelic_only |
+Drop markers with more than one ALT allele (default
+TRUE) |
+
min_marker_call_rate,
+min_sample_call_rate |
+Drop markers / individuals with a lower call rate (default 0 = no +filtering) | +
check_ped() works on the columns id,
+male_parent and female_parent. It applies the
+checks in this order:
| Issue | +Meaning | +Action | +
|---|---|---|
| Exact duplicates | +The identical row appears more than once | +Always removed | +
| Conflicting trios | +Same id, different parents in different rows |
+Disagreeing parents set to 0 and rows collapsed, or
+flagged (correct_conflicting_trios = FALSE) |
+
| Missing parents | +A parent is listed but has no row of its own | +Always added as a row with unknown parents (0) |
+
| Inconsistent sex roles | +Same individual used as sire and as dam | +Set to 0 as a parent everywhere, or flagged
+(correct_inconsistent_sex_roles = FALSE) |
+
| Cycles / dependencies | +An individual is its own ancestor, or is recorded as its own +parent | +Flagged only; must be fixed manually, since there is no safe +automatic choice | +
Unknown parents must be coded 0.
clean_ped_results = check_ped(pedigree, verbose = FALSE)
+
+# the corrected, analysis-ready pedigree
+clean_ped = clean_ped_results$corrected_pedigree
+clean_pedThe result also holds one table per issue, for example
+clean_ped_results$exact_duplicates (here the repeated
+C_missing row) and
+clean_ped_results$missing_parents. An empty table means the
+issue was not found. Set verbose = TRUE to print a full
+report to the console.
validate_pedigree() compares every trio (offspring, male
+parent, female parent) with the genotypes and computes a Mendelian error
+rate. A marker is testable when the offspring and both parents
+have a call.
ped_validate_results = validate_pedigree(clean_ped, genotypes,
+ verbose = FALSE, plot_results = TRUE)| Argument | +Default | +Effect | +
|---|---|---|
ploidy |
+2 | +Ploidy of the dosages | +
trio_error_threshold |
+5 | +Maximum % of testable markers with a Mendelian error for a trio to +pass | +
min_markers |
+10 | +Minimum testable markers needed to judge a trio; fewer gives
+low_markers |
+
single_parent_error_threshold |
+2 | +Maximum homozygous mismatch % for a single parent to pass the +single-parent check | +
founders_file |
+NULL |
+File path, vector of ids or data.frame; ids listed here with both
+parents 0 are reported as founders |
+
marker_trio_table |
+FALSE |
+Also return the marker x trio table (see below) | +
plot_results |
+TRUE |
+Draw a histogram of trio error percentages | +
| Status | +Meaning | +
|---|---|
pass |
+Mendelian error at or below trio_error_threshold |
+
fail |
+Error above the threshold | +
low_markers |
+Fewer than min_markers testable markers |
+
no_genotype_data |
+At least one of the three individuals is not in the genotype +file | +
founders |
+Both parents 0 and the id is in
+founders_file |
+
missing_both_parents, missing_male_parent,
+missing_female_parent |
+One or both parents are 0 |
+
no_data |
+No testable marker at all | +
In the toy data C1, C2 and C3
+pass, C_bad fails, C_low is
+low_markers and C_missing has
+no_genotype_data.
For a failed trio the function checks each parent alone, using only
+markers where the parent and the offspring are both homozygous (an
+offspring homozygous for one allele cannot have a parent homozygous for
+the other). The recommended_correction column gives the
+result:
recommended_correction |
+Interpretation | +
|---|---|
none |
+Trio passes, or it is a founder, has a missing parent, has no +genotype data or has no testable marker | +
remove_male_parent |
+The trio fails and only the male parent fails the single-parent +check | +
remove_female_parent |
+The trio fails and only the female parent fails the single-parent +check | +
remove_both |
+The trio fails and both parents fail the single-parent check | +
unresolved |
+The trio fails but neither parent fails the single-parent check, for +example an offspring recorded as its own parent; the pedigree is +probably wrong but the faulty parent cannot be identified | +
low_markers_* |
+The trio has fewer than min_markers testable markers;
+the suffix is the decision the same rules would give
+(low_markers_keep_both means the error is within the
+threshold and both parents pass) |
+
corrected_pedigree sets the parent(s) named by the
+recommendation to 0. Run find_parentage() with
+method = "fill_pedigree" afterwards to look for the right
+parent.
marker_summary lists every marker with
+trios_tested, trios_mismatch and
+mismatch_pct, sorted worst first. It answers a different
+question than the trio table: is the problem the individual or the
+marker? A few markers with a mismatch % far above the rest
+(paralogous loci, poor clustering, null alleles) inflate the error of
+many trios. Remove them from the genotype file and rerun.
Set marker_trio_table = TRUE to see, for each marker and
+each trio, where an error comes from. Columns are named
+id_male_female.
mt_results = validate_pedigree(clean_ped, genotypes, verbose = FALSE,
+ plot_results = FALSE, marker_trio_table = TRUE)
+mt_results$marker_trio_table| Label | +Meaning | +
|---|---|
match |
+The trio is consistent at this marker | +
mismatch_male, mismatch_female |
+Only that parent is inconsistent with the offspring | +
mismatch_both |
+Each parent alone is inconsistent with the offspring | +
mismatch_combination |
+Each parent alone is compatible, but the pair cannot produce the +offspring | +
missing_male, missing_female,
+missing_progeny |
+That individual has no call; every missing individual is named (for
+example missing_progeny_male_female) |
+
untestable |
+No call is missing, but the marker cannot be tested (odd ploidy, +offspring not homozygous) | +
Missing marker calls (NA) are handled marker by marker
+and never count as errors:
min_markers are labeled
+low_markers; trios with none are no_data (only
+in full_results).mismatch_pct is
+NA for markers not tested in any trio.markers_tested = 0 and low_markers.solve_composition_poly() stops with an error listing these
+markers. Remove them and rerun.When parentage is unknown, find_parentage() searches a
+pool of candidate parents for the best assignment to each progeny.
find_parentage_results = find_parentage(genotypes, parents, progeny,
+ method = "best_pair",
+ verbose = FALSE, plot_results = TRUE)| Argument | +Default | +Effect | +
|---|---|---|
method |
+"best_pair" |
+The search (see below) | +
ploidy |
+2 | +Ploidy of the dosages | +
error_threshold |
+5 | +Error % above which the best candidate gets
+high_error |
+
min_markers |
+10 | +If the best candidate has fewer testable markers, the status is
+low_markers |
+
top_n |
+1 | +Report the best top_n candidates per progeny |
+
show_ties |
+TRUE |
+Report tied_candidates |
+
allow_parent_selfing |
+FALSE |
+Allow the same individual as male and female parent | +
exclude_self_match |
+TRUE |
+Do not let a progeny match itself as parent | +
founders_file |
+NULL |
+File path, vector of ids or data.frame; founders are skipped by
+fill_pedigree |
+
| Method | +Searches | +
|---|---|
best_pair |
+Male x female pair with the lowest Mendelian error (needs both sexes +in the parents table) | +
best_male_parent, best_female_parent |
+The single candidate of that sex with the lowest homozygous mismatch +(compares only markers homozygous in both candidate and offspring); use +when the other parent is known or unavailable | +
best_match |
+Same homozygous mismatch test over candidates of either sex | +
fill_pedigree |
+Missing parents of a 3-column pedigree (see below) | +
The best candidate is always reported. The status is
+pass (error at or below error_threshold),
+high_error (above it, so treat the assignment with
+caution), low_markers, or
+known_parent_no_genotype. In the toy data
+C_bad, which failed validation, is recovered to its true
+pair (M1/F1) at 0% error, while
+C_low remains low_markers.
tied_candidates is the number of candidates (pairs for
+best_pair) that share the lowest error of a progeny; values
+above 1 mean the best assignment is ambiguous. This is common with few
+markers or with clones. With top_n > 1, rank 1 stays in
+the base columns and ranks 2 to top_n are added as suffix
+columns (male_parent_2, female_parent_2,
+mendelian_error_pct_2).
find_parentage(genotypes, parents, progeny, method = "best_pair", top_n = 3,
+ verbose = FALSE, plot_results = FALSE)$full_resultsWith method = "fill_pedigree", progeny is a
+pedigree with id, male_parent and
+female_parent (for example
+validate_pedigree()$corrected_pedigree). Parents coded
+0, NA or empty are unknown. A known male
+parent searches only females, a known female parent only males, and rows
+with both unknown get the full pair search; rows with both parents known
+are skipped. The parents table (with sex M, F
+or A) is still required. The output adds
+search_mode and known_parent_error_pct.
ped_to_fill = data.frame(id = c("C1", "C2"),
+ male_parent = c("M1", "0"),
+ female_parent = c("0", "0"))
+
+find_parentage(genotypes, parents, ped_to_fill, method = "fill_pedigree",
+ verbose = FALSE, plot_results = FALSE)$full_resultsBIGpopA estimates genome-wide breed or line composition for diploid
+and polyploid populations with a breedTools-style quadratic programming
+approach (Funkhouser et al. 2017). The workflow has three steps: compute
+reference-line allele frequencies, estimate the composition of each
+sample, and assign each sample to a line. This example mirrors an
+autotetraploid analysis (ploidy = 4) that assigns samples
+to two cultivar reference panels, Jewel and Draper.
# reference genotypes: individuals x SNPs, tetraploid dosage of allele B (0..4)
+reference = data.frame(
+ S1 = c(0, 1, 0, 4, 3, 4),
+ S2 = c(1, 0, 0, 3, 4, 4),
+ S3 = c(0, 1, 1, 4, 3, 3),
+ S4 = c(1, 0, 1, 3, 4, 3),
+ S5 = c(0, 1, 0, 4, 3, 4),
+ S6 = c(1, 0, 1, 3, 4, 3),
+ row.names = c("Jewel1","Jewel2","Jewel3","Draper1","Draper2","Draper3")
+)
+
+# reference panel membership (which individuals define each cultivar)
+ref_ids = list(
+ Jewel = c("Jewel1","Jewel2","Jewel3"),
+ Draper = c("Draper1","Draper2","Draper3")
+)
+
+# allele frequencies of the reference panels (SNPs x panels)
+freq = allele_freq_poly(reference, ref_ids, ploidy = 4)
+freq## Jewel Draper
+## S1 0.08333333 0.9166667
+## S2 0.08333333 0.9166667
+## S3 0.16666667 0.8333333
+## S4 0.16666667 0.8333333
+## S5 0.08333333 0.9166667
+## S6 0.16666667 0.8333333
+The references should be representative, unadmixed individuals; the +more distinct the references, the better the estimate. Marker names must +match between the reference and the samples.
+# samples to assign: samples x SNPs (same SNPs as the reference)
+validation = data.frame(
+ S1 = c(0, 4, 2),
+ S2 = c(1, 3, 2),
+ S3 = c(0, 4, 2),
+ S4 = c(1, 3, 2),
+ S5 = c(0, 4, 2),
+ S6 = c(1, 3, 2),
+ row.names = c("Sample1","Sample2","Sample3")
+)
+
+# composition (one column per panel plus an R2 model-fit column)
+prediction = as.data.frame(solve_composition_poly(validation, freq, ploidy = 4))
+predictionThe model returns an R2 value, but it is expected to be low because a +discrete allele dosage is regressed on a continuous allele +frequency.
+assign_composition_line() turns the result into the
+table used by Familia: the estimated percentage of each panel and a
+Predicted line. A sample is assigned to its
+highest-proportion line only if that proportion is at least
+assign_threshold (default 50); otherwise it is labelled
+Undetermined. With assign_threshold = 0 every
+sample is assigned.
pred_results = assign_composition_line(solve_composition_poly(validation, freq, ploidy = 4))
+pred_resultsSample1 is assigned Jewel and Sample2
+Draper (each essentially 100%), while the admixed Sample3
+splits roughly evenly between them. For diploid data set
+ploidy = 2. Save the table with
+write.table(pred_results, "composition.txt", sep = "\t", row.names = FALSE).
# genotypes
+genotypes = vcf_to_dosage("my_markers.vcf.gz", ploidy = 4)
+
+# pedigree quality control
+clean_ped = check_ped(pedigree)$corrected_pedigree
+validated = validate_pedigree(clean_ped, genotypes, ploidy = 4)
+assigned = find_parentage(genotypes, parents, progeny, method = "fill_pedigree",
+ ploidy = 4)
+
+# breed/line composition
+freq = allele_freq_poly(reference, ref_ids, ploidy = 4)
+prediction = solve_composition_poly(validation, freq, ploidy = 4)
+composition_table = assign_composition_line(prediction, assign_threshold = 50)check_ped() ->
+validate_pedigree() -> find_parentage()
+(fill_pedigree) on the corrected pedigree.unresolved flag.tied_candidates.marker_summary before blaming individuals; remove
+bad markers and rerun.Chinchilla-Vargas J, Sandercock AM (2026). BIGpopA: Pedigree +Validation Genetic Composition of Diploids & Polyploids. R +package version 2.2.0. CRAN: https://CRAN.R-project.org/package=BIGpopA
+Run citation("BIGpopA") in R for the BibTeX entry.
## R version 4.5.2 (2025-10-31)
+## Platform: aarch64-apple-darwin20
+## Running under: macOS 27.0.1
+##
+## Matrix products: default
+## BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
+## LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
+##
+## locale:
+## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
+##
+## time zone: America/Indiana/Indianapolis
+## tzcode source: internal
+##
+## attached base packages:
+## [1] stats graphics grDevices utils datasets methods base
+##
+## other attached packages:
+## [1] BIGpopA_2.2.0
+##
+## loaded via a namespace (and not attached):
+## [1] gtable_0.3.6 jsonlite_2.0.0 dplyr_1.2.1
+## [4] compiler_4.5.2 tidyselect_1.2.1 stringr_1.6.0
+## [7] snakecase_0.11.1 jquerylib_0.1.4 scales_1.4.0
+## [10] yaml_2.3.12 fastmap_1.2.0 ggplot2_4.0.3
+## [13] R6_2.6.1 labeling_0.4.3 generics_0.1.4
+## [16] knitr_1.52 tibble_3.3.1 janitor_2.2.1
+## [19] lubridate_1.9.5 bslib_0.12.0 pillar_1.11.1
+## [22] RColorBrewer_1.1-3 rlang_1.3.0 stringi_1.8.9
+## [25] cachem_1.1.0 xfun_0.61 quadprog_1.5-8
+## [28] sass_0.4.10 S7_0.2.2 otel_0.2.0
+## [31] timechange_0.4.0 cli_3.6.6 withr_3.0.3
+## [34] magrittr_2.0.5 digest_0.6.39 grid_4.5.2
+## [37] rstudioapi_0.19.0 lifecycle_1.0.5 vctrs_0.7.3
+## [40] evaluate_1.0.5 glue_1.8.1 data.table_1.18.6.1
+## [43] farver_2.1.2 rmarkdown_2.32 tools_4.5.2
+## [46] pkgconfig_2.0.3 htmltools_0.5.9
+