From 9d7f3e4c7e8957559d435444ae17e46e7f3e8c17 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Mon, 10 Mar 2025 13:44:31 -0400 Subject: [PATCH 01/33] Create makeLinks.R --- R/makeLinks.R | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 R/makeLinks.R diff --git a/R/makeLinks.R b/R/makeLinks.R new file mode 100644 index 00000000..9e501de9 --- /dev/null +++ b/R/makeLinks.R @@ -0,0 +1,89 @@ +com2links <- function( + rel_pairs_file = "dataRelatedPairs.csv", + ad_ped_matrix, + mt_ped_matrix, + cn_ped_matrix#, + # pat_ped_matrix, +# mat_ped_matrix, +# mapa_id_file <- "data_mapaID.csv" +) { + require(Matrix) + require(igraph) + + # Convert CN matrix to symmetric if needed + cn_ped_matrix <- as(cn_ped_matrix, "symmetricMatrix") + + # Ensure mitochondrial matrix values are binary (0/1) + mt_ped_matrix@x[mt_ped_matrix@x > 0] <- 1 + + # File names + rel_pairs_file <- paste0(outcome_name, "_dataRelatedPairs.csv") + # mapa_id_file <- paste0(outcome_name, "_data_mapaID.csv") + + # Initialize related pairs file + write.table( + data.frame(ID1 = numeric(0), ID2 = numeric(0), addRel = numeric(0), mitRel = numeric(0), cnuRel = numeric(0)), + file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE + ) + + # Extract IDs + ids <- as.numeric(dimnames(cn_ped_matrix)[[1]]) + + # Matrix index adjustments + newColPos1 <- ad_ped_matrix@p + 1L + iss1 <- ad_ped_matrix@i + 1L + newColPos2 <- mt_ped_matrix@p + 1L + iss2 <- mt_ped_matrix@i + 1L + newColPos3 <- cn_ped_matrix@p + 1L + iss3 <- cn_ped_matrix@i + 1L + nc <- ncol(ad_ped_matrix) + + for (j in 1L:nc) { + ID2 <- ids[j] + + # Extract column indices + ncp1 <- newColPos1[j] + ncp1p <- newColPos1[j + 1L] + cond1 <- ncp1 < ncp1p + if (cond1) { + vv1 <- ncp1:(ncp1p - 1L) + iss1vv <- iss1[vv1] + } + + ncp2 <- newColPos2[j] + ncp2p <- newColPos2[j + 1L] + cond2 <- ncp2 < ncp2p + if (cond2) { + vv2 <- ncp2:(ncp2p - 1L) + iss2vv <- iss2[vv2] + } + + ncp3 <- newColPos3[j] + ncp3p <- newColPos3[j + 1L] + cond3 <- ncp3 < ncp3p + if (cond3) { + vv3 <- ncp3:(ncp3p - 1L) + iss3vv <- iss3[vv3] + } + + u <- sort(igraph::union(igraph::union(if (cond1) { iss1vv }, if (cond2) { iss2vv }), if (cond3) { iss3vv })) + + if (cond1 || cond2 || cond3) { + ID1 <- ids[u] + tds <- data.frame(ID1 = ID1, ID2 = ID2, addRel = 0, mitRel = 0, cnuRel = 0) + + if (cond1) { tds$addRel[u %in% iss1vv] <- ad_ped_matrix@x[vv1] } + if (cond2) { tds$mitRel[u %in% iss2vv] <- mt_ped_matrix@x[vv2] } + if (cond3) { tds$cnuRel[u %in% iss3vv] <- cn_ped_matrix@x[vv3] } + + write.table(tds, file = rel_pairs_file, row.names = FALSE, col.names = FALSE, append = TRUE, sep = ",") + } + + if (!(j %% 500)) { cat(paste0("Done with ", j, " of ", nc, "\n")) } + } + + # Merge and write the parentage matrices + df <- full_join(mat_ped_matrix %>% arrange(ID), pat_ped_matrix %>% arrange(ID)) + + write.table(df, file = mapa_id_file, sep = ",", append = FALSE, row.names = FALSE) +} From 93c365647d0aaf0685d7545f28d5df1ecb1f88b6 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Mon, 10 Mar 2025 15:46:03 -0400 Subject: [PATCH 02/33] Update makeLinks.R --- R/makeLinks.R | 126 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 26 deletions(-) diff --git a/R/makeLinks.R b/R/makeLinks.R index 9e501de9..985293a0 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -1,42 +1,91 @@ com2links <- function( rel_pairs_file = "dataRelatedPairs.csv", - ad_ped_matrix, - mt_ped_matrix, - cn_ped_matrix#, - # pat_ped_matrix, -# mat_ped_matrix, -# mapa_id_file <- "data_mapaID.csv" + ad_ped_matrix = NULL, + mt_ped_matrix = NULL, + cn_ped_matrix = NULL, + pat_ped_matrix = NULL, + mat_ped_matrix = NULL, + mapa_id_file <- "data_mapaID.csv" ) { require(Matrix) require(igraph) - # Convert CN matrix to symmetric if needed - cn_ped_matrix <- as(cn_ped_matrix, "symmetricMatrix") + # Ensure at least one relationship matrix is provided + if (is.null(ad_ped_matrix) && is.null(mt_ped_matrix) && is.null(cn_ped_matrix)) { + stop("At least one of 'ped_matrix', 'mt_ped_matrix', or 'cn_ped_matrix' must be provided.") + } + + + # Extract IDs from the first available matrix + ids <- NULL + if (!is.null(cn_ped_matrix)) { + # Convert CN matrix to symmetric if needed + cn_ped_matrix <- as(cn_ped_matrix, "symmetricMatrix") + ids <- as.numeric(dimnames(cn_ped_matrix)[[1]]) + nc <- ncol(cn_ped_matrix) + } else if (!is.null(ad_ped_matrix)) { + ids <- as.numeric(dimnames(ad_ped_matrix)[[1]]) + nc <- ncol(ad_ped_matrix) + } else if (!is.null(mt_ped_matrix)) { + ids <- as.numeric(dimnames(mt_ped_matrix)[[1]]) + nc <- ncol(mt_ped_matrix) + } + + if (is.null(ids)) { + stop("Could not extract IDs from the provided matrices.") + } + if (!is.null(mt_ped_matrix)) { + # Ensure mitochondrial matrix values are binary (0/1) + mt_ped_matrix@x[mt_ped_matrix@x > 0] <- 1 + } + +sum_nulls <- sum(is.null(ad_ped_matrix), is.null(mt_ped_matrix), is.null(cn_ped_matrix)) - # Ensure mitochondrial matrix values are binary (0/1) - mt_ped_matrix@x[mt_ped_matrix@x > 0] <- 1 # File names - rel_pairs_file <- paste0(outcome_name, "_dataRelatedPairs.csv") +# rel_pairs_file <- paste0(outcome_name, "_dataRelatedPairs.csv") # mapa_id_file <- paste0(outcome_name, "_data_mapaID.csv") # Initialize related pairs file write.table( - data.frame(ID1 = numeric(0), ID2 = numeric(0), addRel = numeric(0), mitRel = numeric(0), cnuRel = numeric(0)), + data.frame(ID1 = numeric(0), ID2 = numeric(0), + addRel = numeric(0), + mitRel = numeric(0), + cnuRel = numeric(0)), file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE ) - # Extract IDs - ids <- as.numeric(dimnames(cn_ped_matrix)[[1]]) + + # Extract matrix pointers (directly) + if (!is.null( ad_ped_matrix)){ + ad_ped_p <- ad_ped_matrix@p + 1L + ad_ped_i <- ad_ped_matrix@i + 1L + ad_ped_x <- ad_ped_matrix@x + } + if (!is.null(mt_ped_matrix)){ + mt_p <- mt_ped_matrix@p + 1L + mt_i <- mt_ped_matrix@i + 1L + mt_x <- mt_ped_matrix@x + } + if (!is.null(cn_ped_matrix)){ + cn_p <- cn_ped_matrix@p + 1L + cn_i <- cn_ped_matrix@i + 1L + cn_x <- cn_ped_matrix@x + } + + # if all matrices are provided + if (sum_nulls==3){ # Matrix index adjustments - newColPos1 <- ad_ped_matrix@p + 1L - iss1 <- ad_ped_matrix@i + 1L - newColPos2 <- mt_ped_matrix@p + 1L - iss2 <- mt_ped_matrix@i + 1L - newColPos3 <- cn_ped_matrix@p + 1L - iss3 <- cn_ped_matrix@i + 1L - nc <- ncol(ad_ped_matrix) + newColPos1 <- ad_ped_p + iss1 <- ad_ped_i + x1 <- ad_ped_x + newColPos2 <- mt_p + iss2 <- mt_i + x2 <- mt_x + newColPos3 <- cn_p + iss3 <- cn_i + x3 <- cn_x for (j in 1L:nc) { ID2 <- ids[j] @@ -72,18 +121,43 @@ com2links <- function( ID1 <- ids[u] tds <- data.frame(ID1 = ID1, ID2 = ID2, addRel = 0, mitRel = 0, cnuRel = 0) - if (cond1) { tds$addRel[u %in% iss1vv] <- ad_ped_matrix@x[vv1] } - if (cond2) { tds$mitRel[u %in% iss2vv] <- mt_ped_matrix@x[vv2] } - if (cond3) { tds$cnuRel[u %in% iss3vv] <- cn_ped_matrix@x[vv3] } + if (cond1) { tds$addRel[u %in% iss1vv] <- x1[vv1] } + if (cond2) { tds$mitRel[u %in% iss2vv] <- x2[vv2] } + if (cond3) { tds$cnuRel[u %in% iss3vv] <- x3[vv3] } write.table(tds, file = rel_pairs_file, row.names = FALSE, col.names = FALSE, append = TRUE, sep = ",") } if (!(j %% 500)) { cat(paste0("Done with ", j, " of ", nc, "\n")) } } + } else if (sum_nulls==2){ + # one matrix is missing + if (is.null(ad_ped_matrix)){ + newColPos1 <- mt_p + iss1 <- mt_i + newColPos2 <- cn_p + iss2 <- cn_i + } + if (is.null(mt_ped_matrix)){ + newColPos1 <- ad_ped_p + iss1 <- ad_ped_i + newColPos2 <- cn_p + iss2 <- cn_i + } + if (is.null(cn_ped_matrix)){ + newColPos1 <- ad_ped_p + iss1 <- ad_ped_i + newColPos2 <- mt_p + iss2 <- mt_i + } + # Matrix index adjustments + + + + # Merge and write the parentage matrices - df <- full_join(mat_ped_matrix %>% arrange(ID), pat_ped_matrix %>% arrange(ID)) +# df <- full_join(mat_ped_matrix %>% arrange(ID), pat_ped_matrix %>% arrange(ID)) - write.table(df, file = mapa_id_file, sep = ",", append = FALSE, row.names = FALSE) +# write.table(df, file = mapa_id_file, sep = ",", append = FALSE, row.names = FALSE) } From e669c5c071de97e0f86412fd72de6b4d89e947fb Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Tue, 11 Mar 2025 11:34:33 -0400 Subject: [PATCH 03/33] Update makeLinks.R --- R/makeLinks.R | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/R/makeLinks.R b/R/makeLinks.R index 985293a0..a24973a7 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -1,3 +1,12 @@ +#' Take a component and turn it into kinship links +#' @param rel_pairs_file File to write related pairs to +#' @param ad_ped_matrix Matrix of additive genetic relatedness coefficients +#' @param mt_ped_matrix Matrix of mitochondrial relatedness coefficients +#' @param cn_ped_matrix Matrix of common nuclear relatedness coefficients +#' @param pat_ped_matrix Matrix of paternal relatedness coefficients +#' @param mat_ped_matrix Matrix of maternal relatedness coefficients +#' @param mapa_id_file File to write the map of parental IDs to individual IDs + com2links <- function( rel_pairs_file = "dataRelatedPairs.csv", ad_ped_matrix = NULL, @@ -39,7 +48,7 @@ com2links <- function( mt_ped_matrix@x[mt_ped_matrix@x > 0] <- 1 } -sum_nulls <- sum(is.null(ad_ped_matrix), is.null(mt_ped_matrix), is.null(cn_ped_matrix)) +sum_nulls <- sum(is.null(ad_ped_matrix), is.null(mt_ped_matrix), is.null(cn_ped_matrix), na.rm = TRUE) # File names @@ -57,7 +66,7 @@ sum_nulls <- sum(is.null(ad_ped_matrix), is.null(mt_ped_matrix), is.null(cn_ped_ # Extract matrix pointers (directly) - if (!is.null( ad_ped_matrix)){ + if (!is.null(ad_ped_matrix)){ ad_ped_p <- ad_ped_matrix@p + 1L ad_ped_i <- ad_ped_matrix@i + 1L ad_ped_x <- ad_ped_matrix@x @@ -86,6 +95,10 @@ sum_nulls <- sum(is.null(ad_ped_matrix), is.null(mt_ped_matrix), is.null(cn_ped_ newColPos3 <- cn_p iss3 <- cn_i x3 <- cn_x + # cleanup + if(gc==TRUE){ +remove(ad_ped_p, ad_ped_i, ad_ped_x, mt_p, mt_i, mt_x, cn_p, cn_i, cn_x) + } for (j in 1L:nc) { ID2 <- ids[j] From 85f2d7601c3a7525162cd3e4dc5fae1e76a6d995 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Tue, 11 Mar 2025 13:10:41 -0400 Subject: [PATCH 04/33] style --- R/makeLinks.R | 345 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 244 insertions(+), 101 deletions(-) diff --git a/R/makeLinks.R b/R/makeLinks.R index a24973a7..c64ce61f 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -1,29 +1,58 @@ #' Take a component and turn it into kinship links #' @param rel_pairs_file File to write related pairs to #' @param ad_ped_matrix Matrix of additive genetic relatedness coefficients -#' @param mt_ped_matrix Matrix of mitochondrial relatedness coefficients +#' @param mit_ped_matrix Matrix of mitochondrial relatedness coefficients #' @param cn_ped_matrix Matrix of common nuclear relatedness coefficients #' @param pat_ped_matrix Matrix of paternal relatedness coefficients #' @param mat_ped_matrix Matrix of maternal relatedness coefficients #' @param mapa_id_file File to write the map of parental IDs to individual IDs +#' @param gc logical. If TRUE, do frequent garbage collection via \code{\link{gc}} to save memory +#' @param writetodisk logical. If TRUE, write the related pairs to disk +#' @return A data frame of related pairs com2links <- function( rel_pairs_file = "dataRelatedPairs.csv", ad_ped_matrix = NULL, - mt_ped_matrix = NULL, + mit_ped_matrix = NULL, cn_ped_matrix = NULL, - pat_ped_matrix = NULL, - mat_ped_matrix = NULL, - mapa_id_file <- "data_mapaID.csv" -) { + pat_ped_matrix = NULL, + mat_ped_matrix = NULL, + mapa_id_file = "data_mapaID.csv", + gc = TRUE, + writetodisk = TRUE, + ...) { require(Matrix) require(igraph) - # Ensure at least one relationship matrix is provided - if (is.null(ad_ped_matrix) && is.null(mt_ped_matrix) && is.null(cn_ped_matrix)) { - stop("At least one of 'ped_matrix', 'mt_ped_matrix', or 'cn_ped_matrix' must be provided.") + # Fast fails + + ## Check for deprecated arguments + if (exists("mt_ped_matrix", inherits = F)) { + mit_ped_matrix <- mt_ped_matrix + remove(mt_ped_matrix) } + # Ensure at least one relationship matrix is provided + if (is.null(ad_ped_matrix) && is.null(mit_ped_matrix) && is.null(cn_ped_matrix)) { + stop("At least one of 'ped_matrix', 'mit_ped_matrix', or 'cn_ped_matrix' must be provided.") + } + # Check for matrix type + if (!is.null(ad_ped_matrix)) { + if (!class(ad_ped_matrix) %in% c("matrix", "dgCMatrix", "dsCMatrix")) { + stop("The 'ad_ped_matrix' must be a matrix or dgCMatrix.") + } + } + if (!is.null(cn_ped_matrix)) { + if (!class(cn_ped_matrix) %in% c("matrix", "dgCMatrix", "dsCMatrix")) { + stop("The 'cn_ped_matrix' must be a matrix or dgCMatrix.") + } + } + if (!is.null(mit_ped_matrix)) { + mit_ped_matrix <- as(mit_ped_matrix, "dgCMatrix") + if (!class(mit_ped_matrix) %in% c("matrix", "dgCMatrix", "dsCMatrix")) { + stop("The 'mit_ped_matrix' must be a matrix or dgCMatrix.") + } + } # Extract IDs from the first available matrix ids <- NULL @@ -35,142 +64,256 @@ com2links <- function( } else if (!is.null(ad_ped_matrix)) { ids <- as.numeric(dimnames(ad_ped_matrix)[[1]]) nc <- ncol(ad_ped_matrix) - } else if (!is.null(mt_ped_matrix)) { - ids <- as.numeric(dimnames(mt_ped_matrix)[[1]]) - nc <- ncol(mt_ped_matrix) + } else if (!is.null(mit_ped_matrix)) { + ids <- as.numeric(dimnames(mit_ped_matrix)[[1]]) + nc <- ncol(mit_ped_matrix) } if (is.null(ids)) { stop("Could not extract IDs from the provided matrices.") } - if (!is.null(mt_ped_matrix)) { + if (!is.null(mit_ped_matrix)) { # Ensure mitochondrial matrix values are binary (0/1) - mt_ped_matrix@x[mt_ped_matrix@x > 0] <- 1 + mit_ped_matrix@x[mit_ped_matrix@x > 0] <- 1 } -sum_nulls <- sum(is.null(ad_ped_matrix), is.null(mt_ped_matrix), is.null(cn_ped_matrix), na.rm = TRUE) - - - # File names -# rel_pairs_file <- paste0(outcome_name, "_dataRelatedPairs.csv") - # mapa_id_file <- paste0(outcome_name, "_data_mapaID.csv") - - # Initialize related pairs file - write.table( - data.frame(ID1 = numeric(0), ID2 = numeric(0), - addRel = numeric(0), - mitRel = numeric(0), - cnuRel = numeric(0)), - file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE + # check which matrices are provided + sum_nulls <- sum(!is.null(ad_ped_matrix), + !is.null(mit_ped_matrix), + !is.null(cn_ped_matrix), + na.rm = TRUE ) + print(sum_nulls) + # File names + # rel_pairs_file <- paste0(outcome_name, "_dataRelatedPairs.csv") + # mapa_id_file <- paste0(outcome_name, "_data_mapaID.csv") + if (writetodisk == TRUE) { + # Initialize related pairs file + write.table( + data.frame( + ID1 = numeric(0), ID2 = numeric(0), + addRel = numeric(0), + mitRel = numeric(0), + cnuRel = numeric(0) + ), + file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE + ) + } else { + df_relpairs <- data.frame( + ID1 = numeric(0), ID2 = numeric(0), + addRel = numeric(0), + mitRel = numeric(0), + cnuRel = numeric(0) + ) + } # Extract matrix pointers (directly) - if (!is.null(ad_ped_matrix)){ - ad_ped_p <- ad_ped_matrix@p + 1L - ad_ped_i <- ad_ped_matrix@i + 1L - ad_ped_x <- ad_ped_matrix@x + if (!is.null(ad_ped_matrix)) { + ad_ped_p <- ad_ped_matrix@p + 1L + ad_ped_i <- ad_ped_matrix@i + 1L + ad_ped_x <- ad_ped_matrix@x } - if (!is.null(mt_ped_matrix)){ - mt_p <- mt_ped_matrix@p + 1L - mt_i <- mt_ped_matrix@i + 1L - mt_x <- mt_ped_matrix@x + if (!is.null(mit_ped_matrix)) { + mt_p <- mit_ped_matrix@p + 1L + mt_i <- mit_ped_matrix@i + 1L + mt_x <- mit_ped_matrix@x } - if (!is.null(cn_ped_matrix)){ - cn_p <- cn_ped_matrix@p + 1L - cn_i <- cn_ped_matrix@i + 1L - cn_x <- cn_ped_matrix@x + if (!is.null(cn_ped_matrix)) { + cn_p <- cn_ped_matrix@p + 1L + cn_i <- cn_ped_matrix@i + 1L + cn_x <- cn_ped_matrix@x } # if all matrices are provided - if (sum_nulls==3){ - - # Matrix index adjustments - newColPos1 <- ad_ped_p - iss1 <- ad_ped_i - x1 <- ad_ped_x - newColPos2 <- mt_p - iss2 <- mt_i - x2 <- mt_x - newColPos3 <- cn_p - iss3 <- cn_i - x3 <- cn_x - # cleanup - if(gc==TRUE){ -remove(ad_ped_p, ad_ped_i, ad_ped_x, mt_p, mt_i, mt_x, cn_p, cn_i, cn_x) - } + if (sum_nulls == 3) { + # Matrix index adjustments + newColPos1 <- ad_ped_p + iss1 <- ad_ped_i + x1 <- ad_ped_x + newColPos2 <- mt_p + iss2 <- mt_i + x2 <- mt_x + newColPos3 <- cn_p + iss3 <- cn_i + x3 <- cn_x + # cleanup + relNames <- c("addRel", "mitRel", "cnuRel") + if (gc == TRUE) { + remove(ad_ped_p, ad_ped_i, ad_ped_x, mt_p, mt_i, mt_x, cn_p, cn_i, cn_x) + } + print("Only 3 matrix is present") - for (j in 1L:nc) { - ID2 <- ids[j] + for (j in 1L:nc) { + ID2 <- ids[j] - # Extract column indices - ncp1 <- newColPos1[j] - ncp1p <- newColPos1[j + 1L] - cond1 <- ncp1 < ncp1p - if (cond1) { - vv1 <- ncp1:(ncp1p - 1L) - iss1vv <- iss1[vv1] - } + # Extract column indices + ncp1 <- newColPos1[j] + ncp1p <- newColPos1[j + 1L] + cond1 <- ncp1 < ncp1p + if (cond1) { + vv1 <- ncp1:(ncp1p - 1L) + iss1vv <- iss1[vv1] + } - ncp2 <- newColPos2[j] - ncp2p <- newColPos2[j + 1L] - cond2 <- ncp2 < ncp2p - if (cond2) { - vv2 <- ncp2:(ncp2p - 1L) - iss2vv <- iss2[vv2] - } + ncp2 <- newColPos2[j] + ncp2p <- newColPos2[j + 1L] + cond2 <- ncp2 < ncp2p + if (cond2) { + vv2 <- ncp2:(ncp2p - 1L) + iss2vv <- iss2[vv2] + } - ncp3 <- newColPos3[j] - ncp3p <- newColPos3[j + 1L] - cond3 <- ncp3 < ncp3p - if (cond3) { - vv3 <- ncp3:(ncp3p - 1L) - iss3vv <- iss3[vv3] - } + ncp3 <- newColPos3[j] + ncp3p <- newColPos3[j + 1L] + cond3 <- ncp3 < ncp3p + if (cond3) { + vv3 <- ncp3:(ncp3p - 1L) + iss3vv <- iss3[vv3] + } - u <- sort(igraph::union(igraph::union(if (cond1) { iss1vv }, if (cond2) { iss2vv }), if (cond3) { iss3vv })) + u <- sort(igraph::union(igraph::union(if (cond1) { + iss1vv + }, if (cond2) { + iss2vv + }), if (cond3) { + iss3vv + })) - if (cond1 || cond2 || cond3) { - ID1 <- ids[u] - tds <- data.frame(ID1 = ID1, ID2 = ID2, addRel = 0, mitRel = 0, cnuRel = 0) + if (cond1 || cond2 || cond3) { + ID1 <- ids[u] + tds <- data.frame(ID1 = ID1, ID2 = ID2) + tds[[relNames[1]]] <- 0 + tds[[relNames[2]]] <- 0 + tds[[relNames[3]]] <- 0 - if (cond1) { tds$addRel[u %in% iss1vv] <- x1[vv1] } - if (cond2) { tds$mitRel[u %in% iss2vv] <- x2[vv2] } - if (cond3) { tds$cnuRel[u %in% iss3vv] <- x3[vv3] } + if (cond1) { + tds[u %in% iss1vv, relNames[1]] <- x1[vv1] + } + if (cond2) { + tds[u %in% iss2vv, relNames[2]] <- x2[vv2] + } + if (cond3) { + tds[u %in% iss3vv, relNames[3]] <- x3[vv3] + } + if (writetodisk == TRUE) { + write.table(tds, + file = rel_pairs_file, row.names = FALSE, + col.names = FALSE, append = TRUE, sep = "," + ) + } else { + df_relpairs <- rbind(df_relpairs, tds) + } + } - write.table(tds, file = rel_pairs_file, row.names = FALSE, col.names = FALSE, append = TRUE, sep = ",") + if (!(j %% 500)) { + cat(paste0("Done with ", j, " of ", nc, "\n")) + } } - - if (!(j %% 500)) { cat(paste0("Done with ", j, " of ", nc, "\n")) } - } - } else if (sum_nulls==2){ + } else if (sum_nulls == 2) { # one matrix is missing - if (is.null(ad_ped_matrix)){ - newColPos1 <- mt_p - iss1 <- mt_i + if (is.null(ad_ped_matrix)) { + newColPos1 <- mt_p + iss1 <- mt_i + x1 <- mt_x newColPos2 <- cn_p iss2 <- cn_i + x2 <- cn_x + relNames <- c("mitRel", "cnuRel") + if (gc == TRUE) { + remove(mt_p, mt_i, mt_x, cn_p, cn_i, cn_x) + } } - if (is.null(mt_ped_matrix)){ + if (is.null(mit_ped_matrix)) { newColPos1 <- ad_ped_p iss1 <- ad_ped_i + x1 <- ad_ped_x newColPos2 <- cn_p iss2 <- cn_i + x2 <- cn_x + relNames <- c("addRel", "cnuRel") + if (gc == TRUE) { + remove(ad_ped_p, ad_ped_i, ad_ped_x, cn_p, cn_i, cn_x) + } } - if (is.null(cn_ped_matrix)){ + if (is.null(cn_ped_matrix)) { newColPos1 <- ad_ped_p iss1 <- ad_ped_i - newColPos2 <- mt_p - iss2 <- mt_i + x1 <- ad_ped_x + newColPos2 <- mt_p + iss2 <- mt_i + x2 <- mt_x + relNames <- c("addRel", "mitRel") + if (gc == TRUE) { + remove(ad_ped_p, ad_ped_i, ad_ped_x, mt_p, mt_i, mt_x) + } } # Matrix index adjustments + for (j in 1L:nc) { + ID2 <- ids[j] + + # Extract column indices + ncp1 <- newColPos1[j] + ncp1p <- newColPos1[j + 1L] + cond1 <- ncp1 < ncp1p + if (cond1) { + vv1 <- ncp1:(ncp1p - 1L) + iss1vv <- iss1[vv1] + } + ncp2 <- newColPos2[j] + ncp2p <- newColPos2[j + 1L] + cond2 <- ncp2 < ncp2p + if (cond2) { + vv2 <- ncp2:(ncp2p - 1L) + iss2vv <- iss2[vv2] + } + + + u <- sort(igraph::union(if (cond1) { + iss1vv + }, if (cond2) { + iss2vv + })) + + if (cond1 || cond2) { + ID1 <- ids[u] + tds <- data.frame(ID1 = ID1, ID2 = ID2) + tds[[relNames[1]]] <- 0 + tds[[relNames[2]]] <- 0 + + if (cond1) { + tds[u %in% iss1vv, relNames[1]] <- x1[vv1] + } + if (cond2) { + tds[u %in% iss2vv, relNames[2]] <- x2[vv2] + } + if (writetodisk == TRUE) { + write.table(tds, + file = rel_pairs_file, row.names = FALSE, + col.names = FALSE, append = TRUE, sep = "," + ) + } else { + df_relpairs <- rbind(df_relpairs, tds) + } + } + + if (!(j %% 500)) { + cat(paste0("Done with ", j, " of ", nc, "\n")) + } + } + } else if (sum_nulls == 1) { + print("Only one matrix is present") + } + if (writetodisk == FALSE) { + return(df_relpairs) + } # Merge and write the parentage matrices -# df <- full_join(mat_ped_matrix %>% arrange(ID), pat_ped_matrix %>% arrange(ID)) + # df <- full_join(mat_ped_matrix %>% arrange(ID), pat_ped_matrix %>% arrange(ID)) -# write.table(df, file = mapa_id_file, sep = ",", append = FALSE, row.names = FALSE) + # write.table(df, file = mapa_id_file, sep = ",", append = FALSE, row.names = FALSE) } From 1313e4745a3ced841c8d43748fdfe0049b5df421 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Tue, 11 Mar 2025 13:54:17 -0400 Subject: [PATCH 05/33] Update makeLinks.R --- R/makeLinks.R | 163 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 128 insertions(+), 35 deletions(-) diff --git a/R/makeLinks.R b/R/makeLinks.R index c64ce61f..918c737a 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -8,6 +8,8 @@ #' @param mapa_id_file File to write the map of parental IDs to individual IDs #' @param gc logical. If TRUE, do frequent garbage collection via \code{\link{gc}} to save memory #' @param writetodisk logical. If TRUE, write the related pairs to disk +#' @param verbose logical. If TRUE, print progress messages +#' @param ... Additional arguments to be passed to \code{\link{com2links}} #' @return A data frame of related pairs com2links <- function( @@ -20,6 +22,7 @@ com2links <- function( mapa_id_file = "data_mapaID.csv", gc = TRUE, writetodisk = TRUE, + verbose = TRUE, ...) { require(Matrix) require(igraph) @@ -38,22 +41,28 @@ com2links <- function( } # Check for matrix type if (!is.null(ad_ped_matrix)) { - if (!class(ad_ped_matrix) %in% c("matrix", "dgCMatrix", "dsCMatrix")) { + if (!inherits(ad_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix"))) { stop("The 'ad_ped_matrix' must be a matrix or dgCMatrix.") } } if (!is.null(cn_ped_matrix)) { - if (!class(cn_ped_matrix) %in% c("matrix", "dgCMatrix", "dsCMatrix")) { + if (!inherits(ad_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix")) { stop("The 'cn_ped_matrix' must be a matrix or dgCMatrix.") } } if (!is.null(mit_ped_matrix)) { mit_ped_matrix <- as(mit_ped_matrix, "dgCMatrix") - if (!class(mit_ped_matrix) %in% c("matrix", "dgCMatrix", "dsCMatrix")) { + if (!inherits(ad_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix")) { stop("The 'mit_ped_matrix' must be a matrix or dgCMatrix.") } + if (!inherits(mit_ped_matrix, "dgCMatrix")) { + mit_ped_matrix <- as(mit_ped_matrix, "dgCMatrix") + } + # Ensure mitochondrial matrix values are binary (0/1) + mit_ped_matrix@x[mit_ped_matrix@x > 0] <- 1 } + # build IDs # Extract IDs from the first available matrix ids <- NULL if (!is.null(cn_ped_matrix)) { @@ -72,10 +81,6 @@ com2links <- function( if (is.null(ids)) { stop("Could not extract IDs from the provided matrices.") } - if (!is.null(mit_ped_matrix)) { - # Ensure mitochondrial matrix values are binary (0/1) - mit_ped_matrix@x[mit_ped_matrix@x > 0] <- 1 - } # check which matrices are provided sum_nulls <- sum(!is.null(ad_ped_matrix), @@ -83,31 +88,9 @@ com2links <- function( !is.null(cn_ped_matrix), na.rm = TRUE ) - +if(verbose){ print(sum_nulls) - # File names - # rel_pairs_file <- paste0(outcome_name, "_dataRelatedPairs.csv") - # mapa_id_file <- paste0(outcome_name, "_data_mapaID.csv") - if (writetodisk == TRUE) { - # Initialize related pairs file - write.table( - data.frame( - ID1 = numeric(0), ID2 = numeric(0), - addRel = numeric(0), - mitRel = numeric(0), - cnuRel = numeric(0) - ), - file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE - ) - } else { - df_relpairs <- data.frame( - ID1 = numeric(0), ID2 = numeric(0), - addRel = numeric(0), - mitRel = numeric(0), - cnuRel = numeric(0) - ) - } - +} # Extract matrix pointers (directly) if (!is.null(ad_ped_matrix)) { ad_ped_p <- ad_ped_matrix@p + 1L @@ -142,8 +125,28 @@ com2links <- function( if (gc == TRUE) { remove(ad_ped_p, ad_ped_i, ad_ped_x, mt_p, mt_i, mt_x, cn_p, cn_i, cn_x) } - print("Only 3 matrix is present") + if(verbose){ + print("All 3 matrix is present") + } + + # File names + # rel_pairs_file <- paste0(outcome_name, "_dataRelatedPairs.csv") + # mapa_id_file <- paste0(outcome_name, "_data_mapaID.csv") + # Initialize related pairs file + df_relpairs <- data.frame( + ID1 = numeric(0), ID2 = numeric(0) + ) + df_relpairs[[relNames[1]]] <- numeric(0) + df_relpairs[[relNames[2]]] <- numeric(0) + df_relpairs[[relNames[3]]] <- numeric(0) + if (writetodisk == TRUE) { + write.table( + df_relpairs, + file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE + ) + remove(df_relpairs) + } for (j in 1L:nc) { ID2 <- ids[j] @@ -249,9 +252,19 @@ com2links <- function( } } # Matrix index adjustments - - - + # Initialize related pairs file + df_relpairs <- data.frame( + ID1 = numeric(0), ID2 = numeric(0) + ) + df_relpairs[[relNames[1]]] <- numeric(0) + df_relpairs[[relNames[2]]] <- numeric(0) + if (writetodisk == TRUE) { + write.table( + df_relpairs, + file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE + ) + remove(df_relpairs) + } for (j in 1L:nc) { ID2 <- ids[j] @@ -308,6 +321,86 @@ com2links <- function( } } else if (sum_nulls == 1) { print("Only one matrix is present") + + if (!is.null(ad_ped_matrix)) { + newColPos1 <- ad_ped_p + iss1 <- ad_ped_i + x1 <- ad_ped_x + relNames <- c("addRel") + if (gc == TRUE) { + remove(ad_ped_p, ad_ped_i, ad_ped_x) + } + } + if (!is.null(mit_ped_matrix)) { + newColPos1 <- mt_p + iss1 <- mt_i + x1 <- mt_x + relNames <- c("mitRel") + if (gc == TRUE) { + remove(mt_p, mt_i, mt_x) + } + } + if (!is.null(cn_ped_matrix)) { + newColPos1 <- cn_p + iss1 <- cn_i + x1 <- cn_x + relNames <- c("cnuRel") + if (gc == TRUE) { + remove(cn_p, cn_i, cn_x) + } + } + + # Initialize related pairs file + df_relpairs <- data.frame( + ID1 = numeric(0), ID2 = numeric(0) + ) + df_relpairs[[relNames[1]]] <- numeric(0) + if (writetodisk == TRUE) { + write.table( + df_relpairs, + file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE + ) + remove(df_relpairs) + } + + for (j in 1L:nc) { + ID2 <- ids[j] + + # Extract column indices + ncp1 <- newColPos1[j] + ncp1p <- newColPos1[j + 1L] + cond1 <- ncp1 < ncp1p + if (cond1) { + vv1 <- ncp1:(ncp1p - 1L) + iss1vv <- iss1[vv1] + } + + u <- sort(iss1vv) + + if (cond1) { + ID1 <- ids[u] + tds <- data.frame(ID1 = ID1, ID2 = ID2) + tds[[relNames[1]]] <- 0 + + if (cond1) { + tds[u %in% iss1vv, relNames[1]] <- x1[vv1] + } + if (writetodisk == TRUE) { + write.table(tds, + file = rel_pairs_file, row.names = FALSE, + col.names = FALSE, append = TRUE, sep = "," + ) + } else { + df_relpairs <- rbind(df_relpairs, tds) + } + } + + if (!(j %% 500)) { + cat(paste0("Done with ", j, " of ", nc, "\n")) + } + } + + } if (writetodisk == FALSE) { return(df_relpairs) From 1d7fb5f203399749509db96359a2327c35ee7116 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Tue, 11 Mar 2025 14:47:35 -0400 Subject: [PATCH 06/33] Update makeLinks.R --- R/makeLinks.R | 1 - 1 file changed, 1 deletion(-) diff --git a/R/makeLinks.R b/R/makeLinks.R index 918c737a..80f875b4 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -51,7 +51,6 @@ com2links <- function( } } if (!is.null(mit_ped_matrix)) { - mit_ped_matrix <- as(mit_ped_matrix, "dgCMatrix") if (!inherits(ad_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix")) { stop("The 'mit_ped_matrix' must be a matrix or dgCMatrix.") } From 29874f9b2015dca2d7eaa3f164754b3062904240 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Tue, 11 Mar 2025 16:36:04 -0400 Subject: [PATCH 07/33] add buffer --- NEWS.md | 3 +++ R/makeLinks.R | 70 +++++++++++++++++++++++++++++++++--------------- man/com2links.Rd | 49 +++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 21 deletions(-) create mode 100644 man/com2links.Rd diff --git a/NEWS.md b/NEWS.md index da7ea6d3..bd7c3267 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,6 @@ +# BGmisc 1.3.5 +* Add com2links function that converts components to kinship links + # BGmisc 1.3.4.1 * Hot fix to resolve issue with list of adjacency matrix not loading saved version * Reoptimized generation calculation diff --git a/R/makeLinks.R b/R/makeLinks.R index 80f875b4..f1f644a7 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -22,7 +22,7 @@ com2links <- function( mapa_id_file = "data_mapaID.csv", gc = TRUE, writetodisk = TRUE, - verbose = TRUE, + verbose = FALSE, ...) { require(Matrix) require(igraph) @@ -46,12 +46,12 @@ com2links <- function( } } if (!is.null(cn_ped_matrix)) { - if (!inherits(ad_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix")) { + if (!inherits(ad_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix"))) { stop("The 'cn_ped_matrix' must be a matrix or dgCMatrix.") } } if (!is.null(mit_ped_matrix)) { - if (!inherits(ad_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix")) { + if (!inherits(ad_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix"))) { stop("The 'mit_ped_matrix' must be a matrix or dgCMatrix.") } if (!inherits(mit_ped_matrix, "dgCMatrix")) { @@ -144,6 +144,8 @@ if(verbose){ df_relpairs, file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE ) + # initial buffer + write_buffer <- list() remove(df_relpairs) } for (j in 1L:nc) { @@ -199,10 +201,15 @@ if(verbose){ tds[u %in% iss3vv, relNames[3]] <- x3[vv3] } if (writetodisk == TRUE) { - write.table(tds, - file = rel_pairs_file, row.names = FALSE, - col.names = FALSE, append = TRUE, sep = "," - ) + write_buffer[[length(write_buffer) + 1]] <- tds + + if (length(write_buffer) >= 1000) { # Write in batches + write.table(do.call(rbind, write_buffer), + file = rel_pairs_file, + row.names = FALSE, col.names = FALSE, append = TRUE, sep = "," + ) + write_buffer <- list() + } } else { df_relpairs <- rbind(df_relpairs, tds) } @@ -262,6 +269,8 @@ if(verbose){ df_relpairs, file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE ) + # initial buffer + write_buffer <- list() remove(df_relpairs) } for (j in 1L:nc) { @@ -284,8 +293,6 @@ if(verbose){ iss2vv <- iss2[vv2] } - - u <- sort(igraph::union(if (cond1) { iss1vv }, if (cond2) { @@ -305,10 +312,15 @@ if(verbose){ tds[u %in% iss2vv, relNames[2]] <- x2[vv2] } if (writetodisk == TRUE) { - write.table(tds, - file = rel_pairs_file, row.names = FALSE, - col.names = FALSE, append = TRUE, sep = "," - ) + write_buffer[[length(write_buffer) + 1]] <- tds + + if (length(write_buffer) >= 1000) { # Write in batches + write.table(do.call(rbind, write_buffer), + file = rel_pairs_file, + row.names = FALSE, col.names = FALSE, append = TRUE, sep = "," + ) + write_buffer <- list() + } } else { df_relpairs <- rbind(df_relpairs, tds) } @@ -319,8 +331,10 @@ if(verbose){ } } } else if (sum_nulls == 1) { - print("Only one matrix is present") + if (verbose) { + print("Only one matrix is present") + } if (!is.null(ad_ped_matrix)) { newColPos1 <- ad_ped_p iss1 <- ad_ped_i @@ -359,12 +373,15 @@ if(verbose){ df_relpairs, file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE ) + + # initial buffer + write_buffer <- list() + remove(df_relpairs) } for (j in 1L:nc) { ID2 <- ids[j] - # Extract column indices ncp1 <- newColPos1[j] ncp1p <- newColPos1[j + 1L] @@ -385,10 +402,16 @@ if(verbose){ tds[u %in% iss1vv, relNames[1]] <- x1[vv1] } if (writetodisk == TRUE) { - write.table(tds, - file = rel_pairs_file, row.names = FALSE, - col.names = FALSE, append = TRUE, sep = "," - ) + + write_buffer[[length(write_buffer) + 1]] <- tds + + if (length(write_buffer) >= 1000) { # Write in batches + write.table(do.call(rbind, write_buffer), + file = rel_pairs_file, + row.names = FALSE, col.names = FALSE, append = TRUE, sep = "," + ) + write_buffer <- list() + } } else { df_relpairs <- rbind(df_relpairs, tds) } @@ -398,11 +421,16 @@ if(verbose){ cat(paste0("Done with ", j, " of ", nc, "\n")) } } - - } if (writetodisk == FALSE) { return(df_relpairs) + } else { + if (length(write_buffer) > 0) { + write.table(do.call(rbind, write_buffer), + file = rel_pairs_file, + row.names = FALSE, col.names = FALSE, append = TRUE, sep = "," + ) + } } # Merge and write the parentage matrices # df <- full_join(mat_ped_matrix %>% arrange(ID), pat_ped_matrix %>% arrange(ID)) diff --git a/man/com2links.Rd b/man/com2links.Rd new file mode 100644 index 00000000..d451897d --- /dev/null +++ b/man/com2links.Rd @@ -0,0 +1,49 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/makeLinks.R +\name{com2links} +\alias{com2links} +\title{Take a component and turn it into kinship links} +\usage{ +com2links( + rel_pairs_file = "dataRelatedPairs.csv", + ad_ped_matrix = NULL, + mit_ped_matrix = NULL, + cn_ped_matrix = NULL, + pat_ped_matrix = NULL, + mat_ped_matrix = NULL, + mapa_id_file = "data_mapaID.csv", + gc = TRUE, + writetodisk = TRUE, + verbose = FALSE, + ... +) +} +\arguments{ +\item{rel_pairs_file}{File to write related pairs to} + +\item{ad_ped_matrix}{Matrix of additive genetic relatedness coefficients} + +\item{mit_ped_matrix}{Matrix of mitochondrial relatedness coefficients} + +\item{cn_ped_matrix}{Matrix of common nuclear relatedness coefficients} + +\item{pat_ped_matrix}{Matrix of paternal relatedness coefficients} + +\item{mat_ped_matrix}{Matrix of maternal relatedness coefficients} + +\item{mapa_id_file}{File to write the map of parental IDs to individual IDs} + +\item{gc}{logical. If TRUE, do frequent garbage collection via \code{\link{gc}} to save memory} + +\item{writetodisk}{logical. If TRUE, write the related pairs to disk} + +\item{verbose}{logical. If TRUE, print progress messages} + +\item{...}{Additional arguments to be passed to \code{\link{com2links}}} +} +\value{ +A data frame of related pairs +} +\description{ +Take a component and turn it into kinship links +} From 3dd1796d35a5a08a6a0b0c2eba9cb767f022966f Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Tue, 11 Mar 2025 18:00:32 -0400 Subject: [PATCH 08/33] tests --- NEWS.md | 1 + R/makeLinks.R | 22 +++-- man/com2links.Rd | 3 +- tests/testthat/test-makeLinks.R | 144 ++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 tests/testthat/test-makeLinks.R diff --git a/NEWS.md b/NEWS.md index bd7c3267..c5a534bb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # BGmisc 1.3.5 * Add com2links function that converts components to kinship links +* Add tests for com2links # BGmisc 1.3.4.1 * Hot fix to resolve issue with list of adjacency matrix not loading saved version diff --git a/R/makeLinks.R b/R/makeLinks.R index f1f644a7..6ac6b2c7 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -15,7 +15,8 @@ com2links <- function( rel_pairs_file = "dataRelatedPairs.csv", ad_ped_matrix = NULL, - mit_ped_matrix = NULL, + mit_ped_matrix = mt_ped_matrix, + mt_ped_matrix = NULL, cn_ped_matrix = NULL, pat_ped_matrix = NULL, mat_ped_matrix = NULL, @@ -29,12 +30,6 @@ com2links <- function( # Fast fails - ## Check for deprecated arguments - if (exists("mt_ped_matrix", inherits = F)) { - mit_ped_matrix <- mt_ped_matrix - remove(mt_ped_matrix) - } - # Ensure at least one relationship matrix is provided if (is.null(ad_ped_matrix) && is.null(mit_ped_matrix) && is.null(cn_ped_matrix)) { stop("At least one of 'ped_matrix', 'mit_ped_matrix', or 'cn_ped_matrix' must be provided.") @@ -46,12 +41,12 @@ com2links <- function( } } if (!is.null(cn_ped_matrix)) { - if (!inherits(ad_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix"))) { + if (!inherits(cn_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix"))) { stop("The 'cn_ped_matrix' must be a matrix or dgCMatrix.") } } if (!is.null(mit_ped_matrix)) { - if (!inherits(ad_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix"))) { + if (!inherits(mit_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix"))) { stop("The 'mit_ped_matrix' must be a matrix or dgCMatrix.") } if (!inherits(mit_ped_matrix, "dgCMatrix")) { @@ -214,10 +209,11 @@ if(verbose){ df_relpairs <- rbind(df_relpairs, tds) } } - + if(verbose){ if (!(j %% 500)) { cat(paste0("Done with ", j, " of ", nc, "\n")) } + } } } else if (sum_nulls == 2) { # one matrix is missing @@ -325,10 +321,11 @@ if(verbose){ df_relpairs <- rbind(df_relpairs, tds) } } - + if(verbose){ if (!(j %% 500)) { cat(paste0("Done with ", j, " of ", nc, "\n")) } + } } } else if (sum_nulls == 1) { @@ -416,10 +413,11 @@ if(verbose){ df_relpairs <- rbind(df_relpairs, tds) } } - + if(verbose){ if (!(j %% 500)) { cat(paste0("Done with ", j, " of ", nc, "\n")) } + } } } if (writetodisk == FALSE) { diff --git a/man/com2links.Rd b/man/com2links.Rd index d451897d..f958327f 100644 --- a/man/com2links.Rd +++ b/man/com2links.Rd @@ -7,7 +7,8 @@ com2links( rel_pairs_file = "dataRelatedPairs.csv", ad_ped_matrix = NULL, - mit_ped_matrix = NULL, + mit_ped_matrix = mt_ped_matrix, + mt_ped_matrix = NULL, cn_ped_matrix = NULL, pat_ped_matrix = NULL, mat_ped_matrix = NULL, diff --git a/tests/testthat/test-makeLinks.R b/tests/testthat/test-makeLinks.R new file mode 100644 index 00000000..9c14bd15 --- /dev/null +++ b/tests/testthat/test-makeLinks.R @@ -0,0 +1,144 @@ +test_that("com2links handles missing matrices properly", { + expect_error(com2links(ad_ped_matrix = NULL, mit_ped_matrix = NULL, cn_ped_matrix = NULL), + "At least one of 'ped_matrix', 'mit_ped_matrix', or 'cn_ped_matrix' must be provided.") +}) + +test_that("com2links rejects invalid matrix types", { + fake_matrix <- data.frame(A = c(1, 2), B = c(3, 4)) + expect_error(com2links(ad_ped_matrix = fake_matrix), "The 'ad_ped_matrix' must be a matrix or dgCMatrix.") +}) + +test_that("com2links produces correct output with a single relationship matrix (hazard dataset)", { + data(hazard) + ad_ped_matrix <- ped2add(hazard,sparse=TRUE) + + result <- com2links(ad_ped_matrix = ad_ped_matrix, writetodisk = FALSE) + + expect_true(is.data.frame(result)) + expect_true(all(c("ID1", "ID2", "addRel") %in% colnames(result))) + expect_equal(ncol(result), 3) # Expect ID1, ID2, and addRel + expect_true(all(result$addRel >= 0)) # Relatedness values should be non-negative +}) + +test_that("com2links produces correct output with mt_ped_matrix", { + data(hazard) + mit_ped_matrix <- ped2mit(hazard,sparse=TRUE) + + result <- com2links(mt_ped_matrix = mit_ped_matrix, writetodisk = FALSE) + + expect_true(is.data.frame(result)) + expect_true(all(c("ID1", "ID2", "mitRel") %in% colnames(result))) + expect_equal(ncol(result), 3) # Expect ID1, ID2, and addRel + expect_true(all(result$addRel >= 0)) # Relatedness values should be non-negative +}) + +test_that("com2links processes multiple matrices correctly (hazard dataset)", { + data(hazard) + ad_ped_matrix <- ped2add(hazard,sparse=TRUE) + mit_ped_matrix <- ped2mit(hazard,sparse=TRUE) + cn_ped_matrix <- ped2cn(hazard,sparse=TRUE) + + result <- com2links(ad_ped_matrix = ad_ped_matrix, mit_ped_matrix = mit_ped_matrix, cn_ped_matrix = cn_ped_matrix, writetodisk = FALSE) + + expect_true(is.data.frame(result)) + expect_true(all(c("ID1", "ID2", "addRel", "mitRel", "cnuRel") %in% colnames(result))) + expect_equal(ncol(result), 5) # Expect ID1, ID2, addRel, mitRel, and cnuRel + expect_true(all(result$addRel >= 0)) + expect_true(all(result$mitRel %in% c(0, 1))) # Mitochondrial should be binary + expect_true(all(result$cnuRel >= 0)) +}) + +test_that("com2links correctly handles missing matrices", { + data(hazard) + ad_ped_matrix <- ped2add(hazard) + + expect_error(com2links(ad_ped_matrix = NULL, mit_ped_matrix = NULL, cn_ped_matrix = NULL), + "At least one of 'ped_matrix', 'mit_ped_matrix', or 'cn_ped_matrix' must be provided.") + + expect_error(com2links(ad_ped_matrix = hazard), "The 'ad_ped_matrix' must be a matrix or dgCMatrix.") +}) + +test_that("com2links correctly processes inbreeding dataset", { + data(inbreeding) + ad_ped_matrix <- ped2add(inbreeding,sparse=TRUE) + mit_ped_matrix <- ped2mit(inbreeding,sparse=TRUE) + cn_ped_matrix <- ped2cn(inbreeding,sparse=TRUE) + + result <- com2links(ad_ped_matrix = ad_ped_matrix, + mit_ped_matrix = mit_ped_matrix, + cn_ped_matrix = cn_ped_matrix, + writetodisk = FALSE) + + expect_true(is.data.frame(result)) + expect_true(all(c("ID1", "ID2", "addRel", "mitRel", "cnuRel") %in% colnames(result))) + expect_equal(ncol(result), 5) + expect_true(all(result$addRel >= 0)) + expect_true(all(result$mitRel %in% c(0, 1))) # Mitochondrial should be binary + expect_true(all(result$cnuRel >= 0)) +}) + + +test_that("com2links writes correct data to disk", { + data(hazard) + ad_ped_matrix <- ped2add(hazard,sparse=TRUE) + + temp_file <- tempfile(fileext = ".csv") + com2links(ad_ped_matrix = ad_ped_matrix, rel_pairs_file = temp_file, writetodisk = TRUE) + + expect_true(file.exists(temp_file)) + written_data <- read.csv(temp_file) + expect_true(all(c("ID1", "ID2", "addRel") %in% colnames(written_data))) +}) + +test_that("com2links handles large batch writing correctly", { + set.seed(123) + kpc <- 4 + Ngen <- 4 + marR <- 0.8 + sexR <- 0.5 + df_fam <- simulatePedigree(kpc = kpc, Ngen = Ngen, sexR = sexR, marR = marR) + + ad_ped_matrix <- ped2add(df_fam,sparse=TRUE) + + temp_file <- tempfile(fileext = ".csv") + com2links(ad_ped_matrix = ad_ped_matrix, rel_pairs_file = temp_file, writetodisk = TRUE, verbose = TRUE) + + expect_true(file.exists(temp_file)) + written_data <- read.csv(temp_file) + expect_true(nrow(written_data) > 1000) # Ensuring batch writing logic works +}) + +test_that("com2links garbage collection does not affect output, using two components", { + data(hazard) + ad_ped_matrix <- ped2add(hazard,sparse=TRUE) + mit_ped_matrix <- ped2mit(hazard,sparse=TRUE) + cn_ped_matrix <- ped2cn(hazard,sparse=TRUE) + + result_gc <- com2links(ad_ped_matrix = ad_ped_matrix, + mit_ped_matrix = mit_ped_matrix, + gc = TRUE, writetodisk = FALSE) + result_no_gc <- com2links(ad_ped_matrix = ad_ped_matrix, + mit_ped_matrix = mit_ped_matrix, + gc = FALSE, writetodisk = FALSE) + + expect_equal(result_gc, result_no_gc) + + result_gc <- com2links(ad_ped_matrix = ad_ped_matrix, + cn_ped_matrix = cn_ped_matrix, + gc = TRUE, writetodisk = FALSE) + result_no_gc <- com2links(ad_ped_matrix = ad_ped_matrix, + cn_ped_matrix = cn_ped_matrix, + gc = FALSE, writetodisk = FALSE) + + expect_equal(result_gc, result_no_gc) + + result_gc <- com2links(mit_ped_matrix =mit_ped_matrix, + cn_ped_matrix = cn_ped_matrix, + gc = TRUE, writetodisk = FALSE) + result_no_gc <- com2links(mit_ped_matrix = mit_ped_matrix, + cn_ped_matrix = cn_ped_matrix, + gc = FALSE, writetodisk = FALSE) + + expect_equal(result_gc, result_no_gc) +}) + From 21da97af6207afa936aee9458aa42183233949b2 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Wed, 12 Mar 2025 15:52:43 -0400 Subject: [PATCH 09/33] links --- R/checkSex.R | 6 ++-- R/convertPedigree.R | 6 ++-- R/makeLinks.R | 63 +++++++++++++++++++++++---------- R/summarizePedigree.R | 6 ++-- man/com2links.Rd | 12 +++---- tests/testthat/test-makeLinks.R | 2 +- 6 files changed, 59 insertions(+), 36 deletions(-) diff --git a/R/checkSex.R b/R/checkSex.R index a3c51dc5..35b14a49 100644 --- a/R/checkSex.R +++ b/R/checkSex.R @@ -166,7 +166,7 @@ recodeSex <- function( } # Recode as "F" or "M" based on code_male, preserving NAs - if (!is.null(code_male) & !is.null(code_female)) { + if (!is.null(code_male) && !is.null(code_female)) { # Initialize sex_recode as NA, preserving the length of the 'sex' column ped$sex_recode <- recode_na ped$sex_recode[ped$sex == code_female] <- recode_female @@ -174,7 +174,7 @@ recodeSex <- function( # Overwriting temp recode variable ped$sex <- ped$sex_recode ped$sex_recode <- NULL - } else if (!is.null(code_male) & is.null(code_female)) { + } else if (!is.null(code_male) && is.null(code_female)) { # Initialize sex_recode as NA, preserving the length of the 'sex' column ped$sex_recode <- recode_na ped$sex_recode[ped$sex != code_male & !is.na(ped$sex)] <- recode_female @@ -182,7 +182,7 @@ recodeSex <- function( # Overwriting temp recode variable ped$sex <- ped$sex_recode ped$sex_recode <- NULL - } else if (is.null(code_male) & !is.null(code_female)) { + } else if (is.null(code_male) && !is.null(code_female)) { # Initialize sex_recode as NA, preserving the length of the 'sex' column ped$sex_recode <- recode_na ped$sex_recode[ped$sex != code_female & !is.na(ped$sex)] <- recode_male diff --git a/R/convertPedigree.R b/R/convertPedigree.R index 2f1c31f0..03f163c8 100644 --- a/R/convertPedigree.R +++ b/R/convertPedigree.R @@ -142,7 +142,7 @@ ped2com <- function(ped, component, if (verbose) cat("Resuming: Constructed matrix...\n") jss <- readRDS(checkpoint_files$jss) iss <- readRDS(checkpoint_files$iss) - list_of_adjacencies <- list(iss=iss, jss=jss) + list_of_adjacencies <- list(iss = iss, jss = jss) } else { list_of_adjacencies <- compute_parent_adjacency( @@ -175,7 +175,7 @@ ped2com <- function(ped, component, } # Garbage collection if gc is TRUE if (gc) { - rm(parList, lens,list_of_adjacencies) + rm(parList, lens, list_of_adjacencies) gc() } } @@ -254,7 +254,7 @@ ped2com <- function(ped, component, # r is I + A + A^2 + ... = (I-A)^-1 from RAM # could trim, here - while (mtSum != 0 & count < maxCount) { + while (mtSum != 0 && count < maxCount) { r <- r + newIsPar gen <- gen + (Matrix::rowSums(newIsPar) > 0) newIsPar <- newIsPar %*% isPar diff --git a/R/makeLinks.R b/R/makeLinks.R index 6ac6b2c7..df653d00 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -2,10 +2,9 @@ #' @param rel_pairs_file File to write related pairs to #' @param ad_ped_matrix Matrix of additive genetic relatedness coefficients #' @param mit_ped_matrix Matrix of mitochondrial relatedness coefficients +#' @param mt_ped_matrix (alternative) Matrix of mitochondrial relatedness coefficients #' @param cn_ped_matrix Matrix of common nuclear relatedness coefficients -#' @param pat_ped_matrix Matrix of paternal relatedness coefficients -#' @param mat_ped_matrix Matrix of maternal relatedness coefficients -#' @param mapa_id_file File to write the map of parental IDs to individual IDs +#' @param write_buffer_size Number of related pairs to write to disk at a time #' @param gc logical. If TRUE, do frequent garbage collection via \code{\link{gc}} to save memory #' @param writetodisk logical. If TRUE, write the related pairs to disk #' @param verbose logical. If TRUE, print progress messages @@ -18,9 +17,10 @@ com2links <- function( mit_ped_matrix = mt_ped_matrix, mt_ped_matrix = NULL, cn_ped_matrix = NULL, - pat_ped_matrix = NULL, - mat_ped_matrix = NULL, - mapa_id_file = "data_mapaID.csv", + # pat_ped_matrix = NULL, + # mat_ped_matrix = NULL, + # mapa_id_file = "data_mapaID.csv", + write_buffer_size = 1000, gc = TRUE, writetodisk = TRUE, verbose = FALSE, @@ -28,6 +28,24 @@ com2links <- function( require(Matrix) require(igraph) + # match arguments +# a <- match.call() +# alternative names +# mit_ped_names <- c("mit_ped_matrix","mt_ped_matrix","mtdna_ped_matrix") + # cn_ped_names <- c("cn_ped_matrix","comn_ped_matrix","nuc_ped_matrix") +# ad_ped_names <- c("ad_ped_matrix","add_ped_matrix","additive_ped_matrix") + +# if (sum(names(a) %in% mit_ped_names)>0) { +# mit_ped_matrix <- unlist(as.list(match.call())[mit_ped_names])[1] + # print(inherits(mit_ped_matrix)) + # } +# if (sum(names(a) %in% cn_ped_names) > 0) { +# cn_ped_matrix <- unlist(as.list(match.call())[cn_ped_names])[1] +# } +# +# if (sum(names(a) %in% ad_ped_names) > 0) { +# ad_ped_matrix <- unlist(as.list(match.call())[ad_ped_names])[1] +#} # Fast fails # Ensure at least one relationship matrix is provided @@ -39,18 +57,26 @@ com2links <- function( if (!inherits(ad_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix"))) { stop("The 'ad_ped_matrix' must be a matrix or dgCMatrix.") } + # convert to sparse + if (!inherits(ad_ped_matrix, "dgCMatrix")) { + ad_ped_matrix <- as(ad_ped_matrix, "dgCMatrix") + } } if (!is.null(cn_ped_matrix)) { if (!inherits(cn_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix"))) { stop("The 'cn_ped_matrix' must be a matrix or dgCMatrix.") } + # convert to sparse + if (!inherits(cn_ped_matrix, "dgCMatrix")) { + cn_ped_matrix <- as(cn_ped_matrix, "dgCMatrix") + } } if (!is.null(mit_ped_matrix)) { if (!inherits(mit_ped_matrix, c("matrix", "dgCMatrix", "dsCMatrix"))) { stop("The 'mit_ped_matrix' must be a matrix or dgCMatrix.") } if (!inherits(mit_ped_matrix, "dgCMatrix")) { - mit_ped_matrix <- as(mit_ped_matrix, "dgCMatrix") + mit_ped_matrix <- as(mit_ped_matrix, "symmetricMatrix") } # Ensure mitochondrial matrix values are binary (0/1) mit_ped_matrix@x[mit_ped_matrix@x > 0] <- 1 @@ -135,7 +161,7 @@ if(verbose){ df_relpairs[[relNames[2]]] <- numeric(0) df_relpairs[[relNames[3]]] <- numeric(0) if (writetodisk == TRUE) { - write.table( + utils::write.table( df_relpairs, file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE ) @@ -198,8 +224,8 @@ if(verbose){ if (writetodisk == TRUE) { write_buffer[[length(write_buffer) + 1]] <- tds - if (length(write_buffer) >= 1000) { # Write in batches - write.table(do.call(rbind, write_buffer), + if (length(write_buffer) >= write_buffer_size) { # Write in batches + utils::write.table(do.call(rbind, write_buffer), file = rel_pairs_file, row.names = FALSE, col.names = FALSE, append = TRUE, sep = "," ) @@ -261,7 +287,7 @@ if(verbose){ df_relpairs[[relNames[1]]] <- numeric(0) df_relpairs[[relNames[2]]] <- numeric(0) if (writetodisk == TRUE) { - write.table( + utils::write.table( df_relpairs, file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE ) @@ -310,8 +336,8 @@ if(verbose){ if (writetodisk == TRUE) { write_buffer[[length(write_buffer) + 1]] <- tds - if (length(write_buffer) >= 1000) { # Write in batches - write.table(do.call(rbind, write_buffer), + if (length(write_buffer) >= write_buffer_size) { # Write in batches + utils::write.table(do.call(rbind, write_buffer), file = rel_pairs_file, row.names = FALSE, col.names = FALSE, append = TRUE, sep = "," ) @@ -330,7 +356,7 @@ if(verbose){ } else if (sum_nulls == 1) { if (verbose) { - print("Only one matrix is present") + message("Only one matrix is present") } if (!is.null(ad_ped_matrix)) { newColPos1 <- ad_ped_p @@ -366,7 +392,7 @@ if(verbose){ ) df_relpairs[[relNames[1]]] <- numeric(0) if (writetodisk == TRUE) { - write.table( + utils::write.table( df_relpairs, file = rel_pairs_file, sep = ",", append = FALSE, row.names = FALSE ) @@ -402,8 +428,8 @@ if(verbose){ write_buffer[[length(write_buffer) + 1]] <- tds - if (length(write_buffer) >= 1000) { # Write in batches - write.table(do.call(rbind, write_buffer), + if (length(write_buffer) >= write_buffer_size) { # Write in batches + utils::write.table(do.call(rbind, write_buffer), file = rel_pairs_file, row.names = FALSE, col.names = FALSE, append = TRUE, sep = "," ) @@ -424,11 +450,12 @@ if(verbose){ return(df_relpairs) } else { if (length(write_buffer) > 0) { - write.table(do.call(rbind, write_buffer), + utils::write.table(do.call(rbind, write_buffer), file = rel_pairs_file, row.names = FALSE, col.names = FALSE, append = TRUE, sep = "," ) } + return(NULL) } # Merge and write the parentage matrices # df <- full_join(mat_ped_matrix %>% arrange(ID), pat_ped_matrix %>% arrange(ID)) diff --git a/R/summarizePedigree.R b/R/summarizePedigree.R index 93feda0f..66c6e91d 100644 --- a/R/summarizePedigree.R +++ b/R/summarizePedigree.R @@ -75,7 +75,6 @@ summarizePedigrees <- function(ped, famID = "famID", personID = "ID", founder_sort_var <- byr } - # Build the pedigree using the provided functions if ("families" %in% type && !famID %in% names(ped)) { if (verbose) message("Counting families...") @@ -183,7 +182,7 @@ summarizePedigrees <- function(ped, famID = "famID", personID = "ID", ## oldest - if (!is.null(byr) & noldest > 0) { + if (!is.null(byr) && noldest > 0) { if (!is.null(n_families) && "families" %in% type) { if (verbose) message("Finding oldest families...") output$oldest_families <- try_na(family_summary_dt[order(get(byr))][1:min(c(noldest, n_families), @@ -206,7 +205,7 @@ summarizePedigrees <- function(ped, famID = "famID", personID = "ID", # biggest lines if (!is.null(nbiggest) && nbiggest > 0) { - if (!is.null(n_families) & "families" %in% type) { + if (!is.null(n_families) && "families" %in% type) { output$biggest_families <- try_na(family_summary_dt[order(-get("count"))][1:min(c(nbiggest, n_families), na.rm = TRUE )]) @@ -248,6 +247,7 @@ calculateSummaryDT <- function(data, group_var, skip_var, # count = .N, mean = as.double(base::mean(x, na.rm = TRUE)), median = as.double(stats::median(x, na.rm = TRUE)), + # mode = as.double(stats::mode(x, na.rm = TRUE)), min = ifelse(all(is.na(x)), as.double(NA), as.double(base::min(x, na.rm = TRUE))), max = ifelse(all(is.na(x)), as.double(NA), as.double(base::max(x, na.rm = TRUE))), sd = as.double(stats::sd(x, na.rm = TRUE)) diff --git a/man/com2links.Rd b/man/com2links.Rd index f958327f..caea428e 100644 --- a/man/com2links.Rd +++ b/man/com2links.Rd @@ -10,9 +10,7 @@ com2links( mit_ped_matrix = mt_ped_matrix, mt_ped_matrix = NULL, cn_ped_matrix = NULL, - pat_ped_matrix = NULL, - mat_ped_matrix = NULL, - mapa_id_file = "data_mapaID.csv", + write_buffer_size = 1000, gc = TRUE, writetodisk = TRUE, verbose = FALSE, @@ -26,13 +24,11 @@ com2links( \item{mit_ped_matrix}{Matrix of mitochondrial relatedness coefficients} -\item{cn_ped_matrix}{Matrix of common nuclear relatedness coefficients} - -\item{pat_ped_matrix}{Matrix of paternal relatedness coefficients} +\item{mt_ped_matrix}{(alternative) Matrix of mitochondrial relatedness coefficients} -\item{mat_ped_matrix}{Matrix of maternal relatedness coefficients} +\item{cn_ped_matrix}{Matrix of common nuclear relatedness coefficients} -\item{mapa_id_file}{File to write the map of parental IDs to individual IDs} +\item{write_buffer_size}{Number of related pairs to write to disk at a time} \item{gc}{logical. If TRUE, do frequent garbage collection via \code{\link{gc}} to save memory} diff --git a/tests/testthat/test-makeLinks.R b/tests/testthat/test-makeLinks.R index 9c14bd15..dded44d8 100644 --- a/tests/testthat/test-makeLinks.R +++ b/tests/testthat/test-makeLinks.R @@ -50,7 +50,7 @@ test_that("com2links processes multiple matrices correctly (hazard dataset)", { test_that("com2links correctly handles missing matrices", { data(hazard) - ad_ped_matrix <- ped2add(hazard) +# ad_ped_matrix <- ped2add(hazard) expect_error(com2links(ad_ped_matrix = NULL, mit_ped_matrix = NULL, cn_ped_matrix = NULL), "At least one of 'ped_matrix', 'mit_ped_matrix', or 'cn_ped_matrix' must be provided.") From 0f7d43d5c1ab790b036f401860c69287535824a8 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Wed, 12 Mar 2025 16:15:42 -0400 Subject: [PATCH 10/33] fixed methods call error --- DESCRIPTION | 3 ++- R/makeLinks.R | 10 ++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 115dc66c..9725e329 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -33,7 +33,8 @@ Imports: kinship2, Matrix, stats, - stringr + stringr, + methods Suggests: dplyr, EasyMx, diff --git a/R/makeLinks.R b/R/makeLinks.R index df653d00..fe29e7db 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -25,8 +25,6 @@ com2links <- function( writetodisk = TRUE, verbose = FALSE, ...) { - require(Matrix) - require(igraph) # match arguments # a <- match.call() @@ -59,7 +57,7 @@ com2links <- function( } # convert to sparse if (!inherits(ad_ped_matrix, "dgCMatrix")) { - ad_ped_matrix <- as(ad_ped_matrix, "dgCMatrix") + ad_ped_matrix <- methods::as(ad_ped_matrix, "dgCMatrix") } } if (!is.null(cn_ped_matrix)) { @@ -68,7 +66,7 @@ com2links <- function( } # convert to sparse if (!inherits(cn_ped_matrix, "dgCMatrix")) { - cn_ped_matrix <- as(cn_ped_matrix, "dgCMatrix") + cn_ped_matrix <- methods::as(cn_ped_matrix, "dgCMatrix") } } if (!is.null(mit_ped_matrix)) { @@ -76,7 +74,7 @@ com2links <- function( stop("The 'mit_ped_matrix' must be a matrix or dgCMatrix.") } if (!inherits(mit_ped_matrix, "dgCMatrix")) { - mit_ped_matrix <- as(mit_ped_matrix, "symmetricMatrix") + mit_ped_matrix <- methods::as(mit_ped_matrix, "symmetricMatrix") } # Ensure mitochondrial matrix values are binary (0/1) mit_ped_matrix@x[mit_ped_matrix@x > 0] <- 1 @@ -87,7 +85,7 @@ com2links <- function( ids <- NULL if (!is.null(cn_ped_matrix)) { # Convert CN matrix to symmetric if needed - cn_ped_matrix <- as(cn_ped_matrix, "symmetricMatrix") + cn_ped_matrix <- methods::as(cn_ped_matrix, "symmetricMatrix") ids <- as.numeric(dimnames(cn_ped_matrix)[[1]]) nc <- ncol(cn_ped_matrix) } else if (!is.null(ad_ped_matrix)) { From 6dc9fe744ee7a8fd96dcdd45012a65d7578273c9 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Wed, 12 Mar 2025 17:12:46 -0400 Subject: [PATCH 11/33] read wikitree --- NEWS.md | 1 + R/readPedigree.R | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/NEWS.md b/NEWS.md index c5a534bb..d9fcb7d7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,7 @@ # BGmisc 1.3.5 * Add com2links function that converts components to kinship links * Add tests for com2links +* Add function to extract family tree from wiki family tree template # BGmisc 1.3.4.1 * Hot fix to resolve issue with list of adjacency matrix not loading saved version diff --git a/R/readPedigree.R b/R/readPedigree.R index 31ca0511..5304dea1 100644 --- a/R/readPedigree.R +++ b/R/readPedigree.R @@ -558,3 +558,77 @@ countPatternRows <- function(file) { ) return(num_rows) } + +#' Read Wiki Family Tree +#' +#' @param text A character string containing the text of a family tree in wiki format. +#' @export +readWikifamilytree <- function(text) { + + # Extract summary text + summary_match <- stringr::str_match(text, "\\{\\{familytree/start \\|summary=(.*?)\\}\\}") + summary_text <- ifelse(!is.na(summary_match[,2]), summary_match[,2], NA) + + # Extract all lines defining the family tree + tree_lines <- unlist(stringr::str_extract_all(text, "\\{\\{familytree.*?\\}\\}")) + tree_lines <- tree_lines[!stringr::str_detect(tree_lines, "start|end")] # Remove start/end markers + tree_lines <- gsub("\\{\\{familytree(.*?)\\}\\}", "\\1", tree_lines) # Remove wrapping markup + + # Convert tree structure into a coordinate grid (preserves symbols!) + tree_matrix <- base::strsplit(tree_lines, "\\|") # Split each row into columns + max_cols <- max(sapply(tree_matrix, length)) # Find the max column count + + # Convert to a data frame (ensures correct structure) + tree_df <- do.call(rbind, lapply(tree_matrix, function(row) { + length(row) <- max_cols # Ensure uniform column length + return(row) + })) + + tree_df <- as.data.frame(tree_df, stringsAsFactors = FALSE) + colnames(tree_df) <- paste0("Y", seq_len(ncol(tree_df))) # Assign column names + tree_df$Row <- seq_len(nrow(tree_df)) # Assign row numbers + + # Identify columns that start with "Y" + cols_to_pivot <- grep("^Y", names(tree_df), value = TRUE) + + # Reshape from wide to long format + tree_long <- stats::reshape(tree_df, + varying = cols_to_pivot, + v.names = "Value", + timevar = "Column", + times = cols_to_pivot, + idvar = setdiff(names(tree_df), cols_to_pivot), + direction = "long") + + tree_long <- tree_long[!is.na(tree_long$Value), ] + tree_long$Value <- stringr::str_trim(tree_long$Value) + tree_long$Column <- as.numeric(gsub("^Y", "", tree_long$Column)) + + # Extract member definitions + member_matches <- stringr::str_extract_all(text, "\\|\\s*([A-Za-z0-9]+)\\s*=\\s*([^|}]*)")[[1]] + member_matches <- gsub("\\[|\\]|'''", "", member_matches) # Remove formatting + + members_df <- data.frame( + identifier = stringr::str_trim(stringr::str_extract(member_matches, "^[^=]+")), + name = stringr::str_trim(stringr::str_extract(member_matches, "(?<=\\=).*")), + stringsAsFactors = FALSE + ) + + # Remove leading pipes (`|`) from identifiers for consistency + members_df$identifier <- gsub("^\\|\\s*", "", members_df$identifier) + + # remove summary row + members_df <- members_df[members_df$identifier!="summary", ] + + # Merge names into the tree structure (keeping all symbols!) + tree_long <- merge(tree_long, members_df, by.x = "Value", by.y = "identifier", all.x = TRUE) + + tree_long$DisplayName <- ifelse(!is.na(tree_long$name), tree_long$name, tree_long$Value) # Use name if available + + # Return structured table of the family tree (symbols included) + list( + summary = summary_text, + members = members_df, + structure = tree_long + ) +} From 8f8b8f690f7eebb38a8d2bf53a9fd1fccb74ad28 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 13 Mar 2025 12:13:53 -0400 Subject: [PATCH 12/33] REFACTOR --- R/readPedigree.R | 123 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 38 deletions(-) diff --git a/R/readPedigree.R b/R/readPedigree.R index 5304dea1..98bdc691 100644 --- a/R/readPedigree.R +++ b/R/readPedigree.R @@ -566,59 +566,25 @@ countPatternRows <- function(file) { readWikifamilytree <- function(text) { # Extract summary text - summary_match <- stringr::str_match(text, "\\{\\{familytree/start \\|summary=(.*?)\\}\\}") - summary_text <- ifelse(!is.na(summary_match[,2]), summary_match[,2], NA) + summary_text <- extractSummaryText(text) # Extract all lines defining the family tree tree_lines <- unlist(stringr::str_extract_all(text, "\\{\\{familytree.*?\\}\\}")) tree_lines <- tree_lines[!stringr::str_detect(tree_lines, "start|end")] # Remove start/end markers tree_lines <- gsub("\\{\\{familytree(.*?)\\}\\}", "\\1", tree_lines) # Remove wrapping markup # Convert tree structure into a coordinate grid (preserves symbols!) - tree_matrix <- base::strsplit(tree_lines, "\\|") # Split each row into columns - max_cols <- max(sapply(tree_matrix, length)) # Find the max column count - - # Convert to a data frame (ensures correct structure) - tree_df <- do.call(rbind, lapply(tree_matrix, function(row) { - length(row) <- max_cols # Ensure uniform column length - return(row) - })) - tree_df <- as.data.frame(tree_df, stringsAsFactors = FALSE) - colnames(tree_df) <- paste0("Y", seq_len(ncol(tree_df))) # Assign column names - tree_df$Row <- seq_len(nrow(tree_df)) # Assign row numbers + tree_df <- parseTree(tree_lines) # Identify columns that start with "Y" cols_to_pivot <- grep("^Y", names(tree_df), value = TRUE) # Reshape from wide to long format - tree_long <- stats::reshape(tree_df, - varying = cols_to_pivot, - v.names = "Value", - timevar = "Column", - times = cols_to_pivot, - idvar = setdiff(names(tree_df), cols_to_pivot), - direction = "long") - - tree_long <- tree_long[!is.na(tree_long$Value), ] - tree_long$Value <- stringr::str_trim(tree_long$Value) - tree_long$Column <- as.numeric(gsub("^Y", "", tree_long$Column)) + tree_long <- makeLongTree(tree_df, cols_to_pivot) # Extract member definitions - member_matches <- stringr::str_extract_all(text, "\\|\\s*([A-Za-z0-9]+)\\s*=\\s*([^|}]*)")[[1]] - member_matches <- gsub("\\[|\\]|'''", "", member_matches) # Remove formatting - - members_df <- data.frame( - identifier = stringr::str_trim(stringr::str_extract(member_matches, "^[^=]+")), - name = stringr::str_trim(stringr::str_extract(member_matches, "(?<=\\=).*")), - stringsAsFactors = FALSE - ) - - # Remove leading pipes (`|`) from identifiers for consistency - members_df$identifier <- gsub("^\\|\\s*", "", members_df$identifier) - - # remove summary row - members_df <- members_df[members_df$identifier!="summary", ] + members_df <- matchMembers(text) # Merge names into the tree structure (keeping all symbols!) tree_long <- merge(tree_long, members_df, by.x = "Value", by.y = "identifier", all.x = TRUE) @@ -632,3 +598,84 @@ readWikifamilytree <- function(text) { structure = tree_long ) } + +#' Make Long Tree +#' @inheritParams readWikifamilytree +#' @param tree_df A data frame containing the tree structure. +#' @param cols_to_pivot A character vector of column names to pivot. +#' @return A long data frame containing the tree structure. +#' @keywords internal +makeLongTree <- function(tree_df, cols_to_pivot) { + tree_long <- stats::reshape(tree_df, + varying = cols_to_pivot, + v.names = "Value", + timevar = "Column", + times = cols_to_pivot, + idvar = setdiff(names(tree_df), cols_to_pivot), + direction = "long") + + tree_long <- tree_long[!is.na(tree_long$Value), ] + tree_long$Value <- stringr::str_trim(tree_long$Value) + tree_long$Column <- as.numeric(gsub("^Y", "", tree_long$Column)) + return(tree_long) + } + +#' Match Members +#' @inheritParams readWikifamilytree +#' @return A data frame containing information about the members of the family tree. +#' @keywords internal + +matchMembers <- function(text) { + member_matches <- stringr::str_extract_all(text, "\\|\\s*([A-Za-z0-9]+)\\s*=\\s*([^|}]*)")[[1]] + member_matches <- gsub("\\[|\\]|'''", "", member_matches) # Remove formatting + + members_df <- data.frame( + identifier = stringr::str_trim(stringr::str_extract(member_matches, "^[^=]+")), + name = stringr::str_trim(stringr::str_extract(member_matches, "(?<=\\=).*")), + stringsAsFactors = FALSE + ) + + # Remove leading pipes (`|`) from identifiers for consistency + members_df$identifier <- gsub("^\\|\\s*", "", members_df$identifier) + + # remove summary row + members_df <- members_df[members_df$identifier!="summary", ] + + return(members_df) + } + +#' Extract Summary Text +#' @inheritParams readWikifamilytree +#' @return A character string containing the summary text. +#' @keywords internal +#' @export + +extractSummaryText <- function(text) { + summary_match <- stringr::str_match(text, "\\{\\{familytree/start \\|summary=(.*?)\\}\\}") + summary_text <- ifelse(!is.na(summary_match[, 2]), summary_match[, 2], NA) +return(summary_text) +} + +#' Parse Tree +#' @inheritParams readWikifamilytree +#' @param tree_lines A character vector containing the lines of the tree structure. +#' @return A data frame containing the tree structure. +#' @keywords internal +#' @export + + parseTree <- function(tree_lines) { + tree_matrix <- base::strsplit(tree_lines, "\\|") # Split each row into columns + max_cols <- max(sapply(tree_matrix, length)) # Find the max column count + + # Convert to a data frame (ensures correct structure) + tree_df <- do.call(rbind, lapply(tree_matrix, function(row) { + length(row) <- max_cols # Ensure uniform column length + return(row) + })) + + tree_df <- as.data.frame(tree_df, stringsAsFactors = FALSE) + colnames(tree_df) <- paste0("Y", seq_len(ncol(tree_df))) # Assign column names + tree_df$Row <- seq_len(nrow(tree_df)) # Assign row numbers + + return(tree_df) + } \ No newline at end of file From 8ebf25882c29cb30ad56d7e354acc7ab5c92f68b Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 13 Mar 2025 12:50:27 -0400 Subject: [PATCH 13/33] add different data types --- NAMESPACE | 3 + R/readPedigree.R | 168 ++++++++++++++++++++++++++------------ man/extractSummaryText.Rd | 18 ++++ man/makeLongTree.Rd | 20 +++++ man/matchMembers.Rd | 18 ++++ man/parseTree.Rd | 18 ++++ man/readWikifamilytree.Rd | 14 ++++ 7 files changed, 206 insertions(+), 53 deletions(-) create mode 100644 man/extractSummaryText.Rd create mode 100644 man/makeLongTree.Rd create mode 100644 man/matchMembers.Rd create mode 100644 man/parseTree.Rd create mode 100644 man/readWikifamilytree.Rd diff --git a/NAMESPACE b/NAMESPACE index a907a21a..8d9ffd82 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -9,12 +9,14 @@ export(comp2vech) export(createGenDataFrame) export(dropLink) export(evenInsert) +export(extractSummaryText) export(famSizeCal) export(fitComponentModel) export(identifyComponentModel) export(inferRelatedness) export(makeInbreeding) export(makeTwins) +export(parseTree) export(ped2add) export(ped2ce) export(ped2cn) @@ -26,6 +28,7 @@ export(ped2mit) export(ped2paternal) export(plotPedigree) export(readGedcom) +export(readWikifamilytree) export(recodeSex) export(related_coef) export(relatedness) diff --git a/R/readPedigree.R b/R/readPedigree.R index 98bdc691..b23c6899 100644 --- a/R/readPedigree.R +++ b/R/readPedigree.R @@ -326,7 +326,7 @@ readGedcom <- function(file_path, if (verbose) { print("Processing parents") } - df_temp <- processParents(df_temp) + df_temp <- processParents(df_temp, datasource="gedcom") } @@ -383,7 +383,7 @@ readGedcom <- function(file_path, #' @param df_temp A data frame containing information about individuals. #' @return A list mapping family IDs to parent IDs. #' @keywords internal -createFamilyToParentsMapping <- function(df_temp) { +createFamilyToParentsMapping <- function(df_temp,datasource) { if (!all(c("FAMS", "sex") %in% colnames(df_temp))) { warning("The data frame does not contain the necessary columns (FAMS, sex)") return(NULL) @@ -420,12 +420,13 @@ createFamilyToParentsMapping <- function(df_temp) { #' #' @param df_temp A data frame containing individual information. #' @param family_to_parents A list mapping family IDs to parent IDs. +#' @param datasource A string indicating the data source. Options are "gedcom" and "wikitree". #' @return A data frame with added momID and dad_ID columns. #' @keywords internal -assignParentIDs <- function(df_temp, family_to_parents) { +assignParentIDs <- function(df_temp, family_to_parents,datasource) { df_temp$momID <- NA_character_ df_temp$dadID <- NA_character_ - +if(datasource == "gedcom"){ for (i in 1:nrow(df_temp)) { if (!is.na(df_temp$FAMC[i])) { famc_ids <- unlist(strsplit(df_temp$FAMC[i], ", ")) @@ -442,6 +443,9 @@ assignParentIDs <- function(df_temp, family_to_parents) { } } return(df_temp) +} else if(datasource=="wikitree"){ + + } } #' Process parents information @@ -451,8 +455,9 @@ assignParentIDs <- function(df_temp, family_to_parents) { #' @param df_temp A data frame containing information about individuals. #' @return A data frame with added momID and dadID columns. #' @keywords internal -processParents <- function(df_temp) { +processParents <- function(df_temp,datasource) { # Ensure required columns are present + if(datasource=="gedcom"){ required_cols <- c("FAMC", "sex", "FAMS") if (!all(required_cols %in% colnames(df_temp))) { @@ -460,12 +465,21 @@ processParents <- function(df_temp) { warning("Missing necessary columns: ", paste(missing_cols, collapse = ", ")) return(df_temp) } - family_to_parents <- createFamilyToParentsMapping(df_temp) + family_to_parents <- createFamilyToParentsMapping(df_temp,datasource=datasource) if (is.null(family_to_parents) || length(family_to_parents) == 0) { return(df_temp) } - df_temp <- assignParentIDs(df_temp, family_to_parents) + df_temp <- assignParentIDs(df_temp, family_to_parents,datasource=datasource) return(df_temp) + } else if(datasource=="wikitree"){ + df_temp$momID <- NA_character_ + df_temp$dadID <- NA_character_ + return(df_temp) + } else { + + stop("Invalid datasource") + } + } @@ -564,7 +578,6 @@ countPatternRows <- function(file) { #' @param text A character string containing the text of a family tree in wiki format. #' @export readWikifamilytree <- function(text) { - # Extract summary text summary_text <- extractSummaryText(text) @@ -574,7 +587,6 @@ readWikifamilytree <- function(text) { tree_lines <- gsub("\\{\\{familytree(.*?)\\}\\}", "\\1", tree_lines) # Remove wrapping markup # Convert tree structure into a coordinate grid (preserves symbols!) - tree_df <- parseTree(tree_lines) # Identify columns that start with "Y" @@ -589,36 +601,42 @@ readWikifamilytree <- function(text) { # Merge names into the tree structure (keeping all symbols!) tree_long <- merge(tree_long, members_df, by.x = "Value", by.y = "identifier", all.x = TRUE) - tree_long$DisplayName <- ifelse(!is.na(tree_long$name), tree_long$name, tree_long$Value) # Use name if available + tree_long$DisplayName <- ifelse(!is.na(tree_long$name), tree_long$name, tree_long$Value) # Use name if available + + # parse relationships and infer them + + relationships_df <- parseRelationships(tree_long) + # Return structured table of the family tree (symbols included) list( summary = summary_text, members = members_df, - structure = tree_long + structure = tree_long, + relationships = relationships_df ) } #' Make Long Tree -#' @inheritParams readWikifamilytree #' @param tree_df A data frame containing the tree structure. #' @param cols_to_pivot A character vector of column names to pivot. #' @return A long data frame containing the tree structure. #' @keywords internal makeLongTree <- function(tree_df, cols_to_pivot) { - tree_long <- stats::reshape(tree_df, - varying = cols_to_pivot, - v.names = "Value", - timevar = "Column", - times = cols_to_pivot, - idvar = setdiff(names(tree_df), cols_to_pivot), - direction = "long") - - tree_long <- tree_long[!is.na(tree_long$Value), ] - tree_long$Value <- stringr::str_trim(tree_long$Value) - tree_long$Column <- as.numeric(gsub("^Y", "", tree_long$Column)) - return(tree_long) - } + tree_long <- stats::reshape(tree_df, + varying = cols_to_pivot, + v.names = "Value", + timevar = "Column", + times = cols_to_pivot, + idvar = setdiff(names(tree_df), cols_to_pivot), + direction = "long" + ) + + tree_long <- tree_long[!is.na(tree_long$Value), ] + tree_long$Value <- stringr::str_trim(tree_long$Value) + tree_long$Column <- as.numeric(gsub("^Y", "", tree_long$Column)) + return(tree_long) +} #' Match Members #' @inheritParams readWikifamilytree @@ -626,23 +644,23 @@ makeLongTree <- function(tree_df, cols_to_pivot) { #' @keywords internal matchMembers <- function(text) { - member_matches <- stringr::str_extract_all(text, "\\|\\s*([A-Za-z0-9]+)\\s*=\\s*([^|}]*)")[[1]] - member_matches <- gsub("\\[|\\]|'''", "", member_matches) # Remove formatting + member_matches <- stringr::str_extract_all(text, "\\|\\s*([A-Za-z0-9]+)\\s*=\\s*([^|}]*)")[[1]] + member_matches <- gsub("\\[|\\]|'''", "", member_matches) # Remove formatting - members_df <- data.frame( - identifier = stringr::str_trim(stringr::str_extract(member_matches, "^[^=]+")), - name = stringr::str_trim(stringr::str_extract(member_matches, "(?<=\\=).*")), - stringsAsFactors = FALSE - ) + members_df <- data.frame( + identifier = stringr::str_trim(stringr::str_extract(member_matches, "^[^=]+")), + name = stringr::str_trim(stringr::str_extract(member_matches, "(?<=\\=).*")), + stringsAsFactors = FALSE + ) - # Remove leading pipes (`|`) from identifiers for consistency - members_df$identifier <- gsub("^\\|\\s*", "", members_df$identifier) + # Remove leading pipes (`|`) from identifiers for consistency + members_df$identifier <- gsub("^\\|\\s*", "", members_df$identifier) - # remove summary row - members_df <- members_df[members_df$identifier!="summary", ] + # remove summary row + members_df <- members_df[members_df$identifier != "summary", ] - return(members_df) - } + return(members_df) +} #' Extract Summary Text #' @inheritParams readWikifamilytree @@ -653,29 +671,73 @@ matchMembers <- function(text) { extractSummaryText <- function(text) { summary_match <- stringr::str_match(text, "\\{\\{familytree/start \\|summary=(.*?)\\}\\}") summary_text <- ifelse(!is.na(summary_match[, 2]), summary_match[, 2], NA) -return(summary_text) + return(summary_text) } #' Parse Tree -#' @inheritParams readWikifamilytree #' @param tree_lines A character vector containing the lines of the tree structure. #' @return A data frame containing the tree structure. #' @keywords internal #' @export - parseTree <- function(tree_lines) { - tree_matrix <- base::strsplit(tree_lines, "\\|") # Split each row into columns - max_cols <- max(sapply(tree_matrix, length)) # Find the max column count +parseTree <- function(tree_lines) { + tree_matrix <- base::strsplit(tree_lines, "\\|") # Split each row into columns + max_cols <- max(sapply(tree_matrix, length)) # Find the max column count + + # Convert to a data frame (ensures correct structure) + tree_df <- do.call(rbind, lapply(tree_matrix, function(row) { + length(row) <- max_cols # Ensure uniform column length + return(row) + })) + + tree_df <- as.data.frame(tree_df, stringsAsFactors = FALSE) + colnames(tree_df) <- paste0("Y", seq_len(ncol(tree_df))) # Assign column names + tree_df$Row <- seq_len(nrow(tree_df)) # Assign row numbers + return(tree_df) +} + +#' infer relationship from tree template +#' +#' @param tree_long A data frame containing the tree structure in long format. +#' @return A data frame containing the relationships between family members. +#' @keywords internal +#' +parseRelationships <- function(tree_long) { + relationships <- data.frame( + id = unique(tree_long$Value), + momID = NA_character_, + dadID = NA_character_, + spouseID = NA_character_, + stringsAsFactors = FALSE + ) - # Convert to a data frame (ensures correct structure) - tree_df <- do.call(rbind, lapply(tree_matrix, function(row) { - length(row) <- max_cols # Ensure uniform column length - return(row) - })) + # Loop through rows to find connections + for (i in seq_len(nrow(tree_long))) { + row <- tree_long[i, ] - tree_df <- as.data.frame(tree_df, stringsAsFactors = FALSE) - colnames(tree_df) <- paste0("Y", seq_len(ncol(tree_df))) # Assign column names - tree_df$Row <- seq_len(nrow(tree_df)) # Assign row numbers + # **Parent-Child Detection** + if (row$Value == "y") { + parent <- tree_long$Value[tree_long$Row == row$Row - 1 & tree_long$Column == row$Column] + child <- tree_long$Value[tree_long$Row == row$Row + 1 & tree_long$Column == row$Column] - return(tree_df) - } \ No newline at end of file + # Assign mom/dad IDs based on tree structure + if (!is.na(parent) && !is.na(child)) { + relationships$momID[relationships$id == child] <- parent + relationships$dadID[relationships$id == child] <- parent # Assuming one parent detected for now + } + } + + # **Spouse Detection** + if (row$Value == "+") { + spouse1 <- tree_long$Value[tree_long$Row == row$Row & tree_long$Column == row$Column - 1] + spouse2 <- tree_long$Value[tree_long$Row == row$Row & tree_long$Column == row$Column + 1] + + if (!is.na(spouse1) && !is.na(spouse2)) { + relationships$spouseID[relationships$id == spouse1] <- spouse2 + relationships$spouseID[relationships$id == spouse2] <- spouse1 + } + } + } + + return(relationships) +} diff --git a/man/extractSummaryText.Rd b/man/extractSummaryText.Rd new file mode 100644 index 00000000..ad1e90a9 --- /dev/null +++ b/man/extractSummaryText.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/readPedigree.R +\name{extractSummaryText} +\alias{extractSummaryText} +\title{Extract Summary Text} +\usage{ +extractSummaryText(text) +} +\arguments{ +\item{text}{A character string containing the text of a family tree in wiki format.} +} +\value{ +A character string containing the summary text. +} +\description{ +Extract Summary Text +} +\keyword{internal} diff --git a/man/makeLongTree.Rd b/man/makeLongTree.Rd new file mode 100644 index 00000000..e03db2f9 --- /dev/null +++ b/man/makeLongTree.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/readPedigree.R +\name{makeLongTree} +\alias{makeLongTree} +\title{Make Long Tree} +\usage{ +makeLongTree(tree_df, cols_to_pivot) +} +\arguments{ +\item{tree_df}{A data frame containing the tree structure.} + +\item{cols_to_pivot}{A character vector of column names to pivot.} +} +\value{ +A long data frame containing the tree structure. +} +\description{ +Make Long Tree +} +\keyword{internal} diff --git a/man/matchMembers.Rd b/man/matchMembers.Rd new file mode 100644 index 00000000..e02311af --- /dev/null +++ b/man/matchMembers.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/readPedigree.R +\name{matchMembers} +\alias{matchMembers} +\title{Match Members} +\usage{ +matchMembers(text) +} +\arguments{ +\item{text}{A character string containing the text of a family tree in wiki format.} +} +\value{ +A data frame containing information about the members of the family tree. +} +\description{ +Match Members +} +\keyword{internal} diff --git a/man/parseTree.Rd b/man/parseTree.Rd new file mode 100644 index 00000000..e429662c --- /dev/null +++ b/man/parseTree.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/readPedigree.R +\name{parseTree} +\alias{parseTree} +\title{Parse Tree} +\usage{ +parseTree(tree_lines) +} +\arguments{ +\item{tree_lines}{A character vector containing the lines of the tree structure.} +} +\value{ +A data frame containing the tree structure. +} +\description{ +Parse Tree +} +\keyword{internal} diff --git a/man/readWikifamilytree.Rd b/man/readWikifamilytree.Rd new file mode 100644 index 00000000..b06acf7b --- /dev/null +++ b/man/readWikifamilytree.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/readPedigree.R +\name{readWikifamilytree} +\alias{readWikifamilytree} +\title{Read Wiki Family Tree} +\usage{ +readWikifamilytree(text) +} +\arguments{ +\item{text}{A character string containing the text of a family tree in wiki format.} +} +\description{ +Read Wiki Family Tree +} From 1120a3d6edbb44819fadfa92a70d3a57574a5e82 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 13 Mar 2025 14:12:44 -0400 Subject: [PATCH 14/33] adding documenation --- R/readPedigree.R | 27 +++++++++++++-------------- man/assignParentIDs.Rd | 4 +++- man/createFamilyToParentsMapping.Rd | 2 +- man/parseRelationships.Rd | 18 ++++++++++++++++++ man/processParents.Rd | 2 +- 5 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 man/parseRelationships.Rd diff --git a/R/readPedigree.R b/R/readPedigree.R index b23c6899..dcc92547 100644 --- a/R/readPedigree.R +++ b/R/readPedigree.R @@ -420,7 +420,7 @@ createFamilyToParentsMapping <- function(df_temp,datasource) { #' #' @param df_temp A data frame containing individual information. #' @param family_to_parents A list mapping family IDs to parent IDs. -#' @param datasource A string indicating the data source. Options are "gedcom" and "wikitree". +#' @param datasource A string indicating the data source. Options are "gedcom" and "wiki". #' @return A data frame with added momID and dad_ID columns. #' @keywords internal assignParentIDs <- function(df_temp, family_to_parents,datasource) { @@ -443,8 +443,9 @@ if(datasource == "gedcom"){ } } return(df_temp) -} else if(datasource=="wikitree"){ - +} else if(datasource=="wiki"){ +message("No parents information available for wiki data") +return(df_temp) } } @@ -459,27 +460,24 @@ processParents <- function(df_temp,datasource) { # Ensure required columns are present if(datasource=="gedcom"){ required_cols <- c("FAMC", "sex", "FAMS") +} else if(datasource=="wiki"){ + required_cols <- c("id") +} else { + stop("Invalid datasource") +} - if (!all(required_cols %in% colnames(df_temp))) { +if (!all(required_cols %in% colnames(df_temp))) { missing_cols <- setdiff(required_cols, colnames(df_temp)) warning("Missing necessary columns: ", paste(missing_cols, collapse = ", ")) return(df_temp) } + family_to_parents <- createFamilyToParentsMapping(df_temp,datasource=datasource) if (is.null(family_to_parents) || length(family_to_parents) == 0) { return(df_temp) } df_temp <- assignParentIDs(df_temp, family_to_parents,datasource=datasource) return(df_temp) - } else if(datasource=="wikitree"){ - df_temp$momID <- NA_character_ - df_temp$dadID <- NA_character_ - return(df_temp) - } else { - - stop("Invalid datasource") - } - } @@ -605,7 +603,8 @@ readWikifamilytree <- function(text) { # parse relationships and infer them - relationships_df <- parseRelationships(tree_long) + relationships_df <- processParents(tree_long, datasource = "wiki") + (tree_long) # Return structured table of the family tree (symbols included) diff --git a/man/assignParentIDs.Rd b/man/assignParentIDs.Rd index e57dd6cc..8bd15170 100644 --- a/man/assignParentIDs.Rd +++ b/man/assignParentIDs.Rd @@ -4,12 +4,14 @@ \alias{assignParentIDs} \title{Assign momID and dadID based on family mapping} \usage{ -assignParentIDs(df_temp, family_to_parents) +assignParentIDs(df_temp, family_to_parents, datasource) } \arguments{ \item{df_temp}{A data frame containing individual information.} \item{family_to_parents}{A list mapping family IDs to parent IDs.} + +\item{datasource}{A string indicating the data source. Options are "gedcom" and "wiki".} } \value{ A data frame with added momID and dad_ID columns. diff --git a/man/createFamilyToParentsMapping.Rd b/man/createFamilyToParentsMapping.Rd index 87f14848..20d8216d 100644 --- a/man/createFamilyToParentsMapping.Rd +++ b/man/createFamilyToParentsMapping.Rd @@ -4,7 +4,7 @@ \alias{createFamilyToParentsMapping} \title{Create a mapping of family IDs to parent IDs} \usage{ -createFamilyToParentsMapping(df_temp) +createFamilyToParentsMapping(df_temp, datasource) } \arguments{ \item{df_temp}{A data frame containing information about individuals.} diff --git a/man/parseRelationships.Rd b/man/parseRelationships.Rd new file mode 100644 index 00000000..a02a5983 --- /dev/null +++ b/man/parseRelationships.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/readPedigree.R +\name{parseRelationships} +\alias{parseRelationships} +\title{infer relationship from tree template} +\usage{ +parseRelationships(tree_long) +} +\arguments{ +\item{tree_long}{A data frame containing the tree structure in long format.} +} +\value{ +A data frame containing the relationships between family members. +} +\description{ +infer relationship from tree template +} +\keyword{internal} diff --git a/man/processParents.Rd b/man/processParents.Rd index 9f8064d1..e8077472 100644 --- a/man/processParents.Rd +++ b/man/processParents.Rd @@ -4,7 +4,7 @@ \alias{processParents} \title{Process parents information} \usage{ -processParents(df_temp) +processParents(df_temp, datasource) } \arguments{ \item{df_temp}{A data frame containing information about individuals.} From b71256c8922721fb80995e79a954f5cf14a2881c Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 13 Mar 2025 14:25:24 -0400 Subject: [PATCH 15/33] forgfot to export --- NAMESPACE | 1 + R/makeLinks.R | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NAMESPACE b/NAMESPACE index 8d9ffd82..f6f979b8 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -5,6 +5,7 @@ export(allGens) export(calculateRelatedness) export(checkIDs) export(checkSex) +export(com2links) export(comp2vech) export(createGenDataFrame) export(dropLink) diff --git a/R/makeLinks.R b/R/makeLinks.R index fe29e7db..6444171a 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -10,7 +10,7 @@ #' @param verbose logical. If TRUE, print progress messages #' @param ... Additional arguments to be passed to \code{\link{com2links}} #' @return A data frame of related pairs - +#' @export com2links <- function( rel_pairs_file = "dataRelatedPairs.csv", ad_ped_matrix = NULL, From 72859a55429d5be61495ab951b360705eee140bd Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 13 Mar 2025 15:01:43 -0400 Subject: [PATCH 16/33] Update makeLinks.R --- R/makeLinks.R | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/R/makeLinks.R b/R/makeLinks.R index 6444171a..ef597b3c 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -21,6 +21,7 @@ com2links <- function( # mat_ped_matrix = NULL, # mapa_id_file = "data_mapaID.csv", write_buffer_size = 1000, + update_rate = 1000, gc = TRUE, writetodisk = TRUE, verbose = FALSE, @@ -234,7 +235,7 @@ if(verbose){ } } if(verbose){ - if (!(j %% 500)) { + if (!(j %% update_rate)) { cat(paste0("Done with ", j, " of ", nc, "\n")) } } @@ -346,7 +347,7 @@ if(verbose){ } } if(verbose){ - if (!(j %% 500)) { + if (!(j %% update_rate)) { cat(paste0("Done with ", j, " of ", nc, "\n")) } } @@ -438,7 +439,7 @@ if(verbose){ } } if(verbose){ - if (!(j %% 500)) { + if (!(j %% update_rate)) { cat(paste0("Done with ", j, " of ", nc, "\n")) } } From 92b0ca803143b12b2cb99d6342b09ce5c96e98bb Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 13 Mar 2025 16:04:19 -0400 Subject: [PATCH 17/33] adds IDs --- R/makeLinks.R | 5 +++-- R/readPedigree.R | 11 ++++++++-- tests/testthat/test-readPedigrees.R | 31 +++++++++++++++++++++++++++-- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/R/makeLinks.R b/R/makeLinks.R index ef597b3c..8f997999 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -1,4 +1,4 @@ -#' Take a component and turn it into kinship links +#' Take a sparse component and turn it into kinship links #' @param rel_pairs_file File to write related pairs to #' @param ad_ped_matrix Matrix of additive genetic relatedness coefficients #' @param mit_ped_matrix Matrix of mitochondrial relatedness coefficients @@ -8,6 +8,7 @@ #' @param gc logical. If TRUE, do frequent garbage collection via \code{\link{gc}} to save memory #' @param writetodisk logical. If TRUE, write the related pairs to disk #' @param verbose logical. If TRUE, print progress messages +#' @param update_rate numeric. How often to print progress messages #' @param ... Additional arguments to be passed to \code{\link{com2links}} #' @return A data frame of related pairs #' @export @@ -454,7 +455,7 @@ if(verbose){ row.names = FALSE, col.names = FALSE, append = TRUE, sep = "," ) } - return(NULL) + # return(NULL) } # Merge and write the parentage matrices # df <- full_join(mat_ped_matrix %>% arrange(ID), pat_ped_matrix %>% arrange(ID)) diff --git a/R/readPedigree.R b/R/readPedigree.R index dcc92547..32de209c 100644 --- a/R/readPedigree.R +++ b/R/readPedigree.R @@ -384,6 +384,7 @@ readGedcom <- function(file_path, #' @return A list mapping family IDs to parent IDs. #' @keywords internal createFamilyToParentsMapping <- function(df_temp,datasource) { + if (datasource == "gedcom") { if (!all(c("FAMS", "sex") %in% colnames(df_temp))) { warning("The data frame does not contain the necessary columns (FAMS, sex)") return(NULL) @@ -410,6 +411,11 @@ createFamilyToParentsMapping <- function(df_temp,datasource) { } } } + } else if (datasource == "wiki") { + + warning("The data source is not supported") + return(df_temp) + } return(family_to_parents) } @@ -458,7 +464,7 @@ return(df_temp) #' @keywords internal processParents <- function(df_temp,datasource) { # Ensure required columns are present - if(datasource=="gedcom"){ +if(datasource=="gedcom"){ required_cols <- c("FAMC", "sex", "FAMS") } else if(datasource=="wiki"){ required_cols <- c("id") @@ -595,6 +601,7 @@ readWikifamilytree <- function(text) { # Extract member definitions members_df <- matchMembers(text) + members_df$id <- paste0("P", seq_len(nrow(members_df))) # Assign unique person IDs # Merge names into the tree structure (keeping all symbols!) tree_long <- merge(tree_long, members_df, by.x = "Value", by.y = "identifier", all.x = TRUE) @@ -604,7 +611,7 @@ readWikifamilytree <- function(text) { # parse relationships and infer them relationships_df <- processParents(tree_long, datasource = "wiki") - (tree_long) + # Return structured table of the family tree (symbols included) diff --git a/tests/testthat/test-readPedigrees.R b/tests/testthat/test-readPedigrees.R index 810040e4..9f3c1439 100644 --- a/tests/testthat/test-readPedigrees.R +++ b/tests/testthat/test-readPedigrees.R @@ -137,7 +137,7 @@ test_that("processParents adds momID and dadID correctly", { ) # Call processParents - df_temp <- processParents(df_temp) + df_temp <- processParents(df_temp,datasource="gedcom") # Check the structure of the data frame expect_true("momID" %in% colnames(df_temp)) @@ -161,7 +161,7 @@ test_that("processParents adds momID and dadID correctly", { ) # Call processParents - df_temp <- processParents(df_temp) + df_temp <- processParents(df_temp,datasource="gedcom") # Check the contents of the data frame expect_equal(df_temp$momID[3], "I2") @@ -176,3 +176,30 @@ test_that("if file does not exist, readGedcom throws an error", { # Call readGedcom with a non-existent file expect_error(readGedcom("nonexistent.ged")) }) + + + +# readWikifamilytree + +test_that("readWikifamilytree reads a simple file correctly", { + # Create a temporary WikiFamilyTree file for testing + # Example usage + family_tree_text <- "{{familytree/start |summary=I have a brother Joe and a little sister: my mom married my dad, and my dad's parents were Grandma and Grandpa; they had another child, Aunt Daisy.}} +{{familytree | | | | GMa |~|y|~| GPa | | GMa=Gladys|GPa=Sydney}} +{{familytree | | | | | | | |)|-|-|-|.| }} +{{familytree | | | MOM |y| DAD | |DAISY| MOM=Mom|DAD=Dad|DAISY=[[Daisy Duke]]}} +{{familytree | |,|-|-|-|+|-|-|-|.| | | }} +{{familytree | JOE | | ME | | SIS | | | JOE=My brother Joe|ME='''Me!'''|SIS=My little sister}} +{{familytree/end}}" + +result <- readWikifamilytree(family_tree_text) + +#list( +# summary = summary_text, +# members = members_df, +# structure = tree_long, +# relationships = relationships_df +#) +expect_equal(result$summary, + "I have a brother Joe and a little sister: my mom married my dad, and my dad's parents were Grandma and Grandpa; they had another child, Aunt Daisy.") +}) From 3c7df6c6ad79826951d5c64131871a64576bf03f Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 13 Mar 2025 16:39:28 -0400 Subject: [PATCH 18/33] convert warnings to messages --- R/readPedigree.R | 4 ++-- man/com2links.Rd | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/R/readPedigree.R b/R/readPedigree.R index 32de209c..55e5e80d 100644 --- a/R/readPedigree.R +++ b/R/readPedigree.R @@ -413,7 +413,7 @@ createFamilyToParentsMapping <- function(df_temp,datasource) { } } else if (datasource == "wiki") { - warning("The data source is not supported") + message("The data source is not supported") return(df_temp) } return(family_to_parents) @@ -450,7 +450,7 @@ if(datasource == "gedcom"){ } return(df_temp) } else if(datasource=="wiki"){ -message("No parents information available for wiki data") + message("No parents information available for wiki data") return(df_temp) } } diff --git a/man/com2links.Rd b/man/com2links.Rd index caea428e..bcb6d2ff 100644 --- a/man/com2links.Rd +++ b/man/com2links.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/makeLinks.R \name{com2links} \alias{com2links} -\title{Take a component and turn it into kinship links} +\title{Take a sparse component and turn it into kinship links} \usage{ com2links( rel_pairs_file = "dataRelatedPairs.csv", @@ -11,6 +11,7 @@ com2links( mt_ped_matrix = NULL, cn_ped_matrix = NULL, write_buffer_size = 1000, + update_rate = 1000, gc = TRUE, writetodisk = TRUE, verbose = FALSE, @@ -30,6 +31,8 @@ com2links( \item{write_buffer_size}{Number of related pairs to write to disk at a time} +\item{update_rate}{numeric. How often to print progress messages} + \item{gc}{logical. If TRUE, do frequent garbage collection via \code{\link{gc}} to save memory} \item{writetodisk}{logical. If TRUE, write the related pairs to disk} @@ -42,5 +45,5 @@ com2links( A data frame of related pairs } \description{ -Take a component and turn it into kinship links +Take a sparse component and turn it into kinship links } From b717ce70202e36b7ff3b3487b236c08a81467e74 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 13 Mar 2025 18:34:49 -0400 Subject: [PATCH 19/33] smarter --- NEWS.md | 1 + R/readPedigree.R | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index d9fcb7d7..be6f48cd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,7 @@ * Add com2links function that converts components to kinship links * Add tests for com2links * Add function to extract family tree from wiki family tree template +* Add tests for readWikifamilytree # BGmisc 1.3.4.1 * Hot fix to resolve issue with list of adjacency matrix not loading saved version diff --git a/R/readPedigree.R b/R/readPedigree.R index 55e5e80d..d9f69428 100644 --- a/R/readPedigree.R +++ b/R/readPedigree.R @@ -610,7 +610,9 @@ readWikifamilytree <- function(text) { # parse relationships and infer them - relationships_df <- processParents(tree_long, datasource = "wiki") + relationships_df <- parseRelationships(tree_long) + + # relationships_df <- processParents(tree_long, datasource = "wiki") @@ -710,7 +712,7 @@ parseTree <- function(tree_lines) { #' parseRelationships <- function(tree_long) { relationships <- data.frame( - id = unique(tree_long$Value), + id = tree_long$id, momID = NA_character_, dadID = NA_character_, spouseID = NA_character_, @@ -726,6 +728,8 @@ parseRelationships <- function(tree_long) { parent <- tree_long$Value[tree_long$Row == row$Row - 1 & tree_long$Column == row$Column] child <- tree_long$Value[tree_long$Row == row$Row + 1 & tree_long$Column == row$Column] + if(length(parent) == 0) parent <- NA + if(length(child) == 0) child <- NA # Assign mom/dad IDs based on tree structure if (!is.na(parent) && !is.na(child)) { relationships$momID[relationships$id == child] <- parent From 6e7261bfba27b0d99ed69a50df549e48efa7971e Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Fri, 14 Mar 2025 13:31:03 -0400 Subject: [PATCH 20/33] Update makeLinks.R --- R/makeLinks.R | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/R/makeLinks.R b/R/makeLinks.R index 8f997999..198c7efc 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -26,8 +26,9 @@ com2links <- function( gc = TRUE, writetodisk = TRUE, verbose = FALSE, + legacy = FALSE, ...) { - +if(!legacy){ # match arguments # a <- match.call() # alternative names @@ -457,8 +458,11 @@ if(verbose){ } # return(NULL) } +} else if (legacy) { + # Merge and write the parentage matrices # df <- full_join(mat_ped_matrix %>% arrange(ID), pat_ped_matrix %>% arrange(ID)) # write.table(df, file = mapa_id_file, sep = ",", append = FALSE, row.names = FALSE) } +} From 0d4e51892d3aec7111792dd84b68d16dc76850fb Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Sat, 15 Mar 2025 14:50:44 -0400 Subject: [PATCH 21/33] merge legacy --- R/convertPedigree.R | 1 + R/makeLinks.R | 74 ++++++++++++++++++++++++++++++++++++++++++++- man/com2links.Rd | 1 + man/ped2com.Rd | 2 ++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/R/convertPedigree.R b/R/convertPedigree.R index ecfca0ae..5c9ce2a5 100644 --- a/R/convertPedigree.R +++ b/R/convertPedigree.R @@ -18,6 +18,7 @@ #' @param standardize.colnames logical. If TRUE, standardize the column names of the pedigree dataset #' @param transpose_method character. The method to use for computing the transpose. Options are "tcrossprod", "crossprod", or "star" #' @param adjacency_method character. The method to use for computing the adjacency matrix. Options are "loop" or "indexed" +#' @param isChild_method character. The method to use for computing the isChild matrix. Options are "classic" or "partialparent" #' @param ... additional arguments to be passed to \code{\link{ped2com}} #' @details The algorithms and methodologies used in this function are further discussed and exemplified in the vignette titled "examplePedigreeFunctions". For more advanced scenarios and detailed explanations, consult this vignette. #' @export diff --git a/R/makeLinks.R b/R/makeLinks.R index 198c7efc..332f03bc 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -459,10 +459,82 @@ if(verbose){ # return(NULL) } } else if (legacy) { + if (verbose) { + message("Using legacy mode") + } + + +# load(paste0(outcome_name,'_dataBiggestCnPedigree.Rdata')) +# biggestCnPed <- as(biggestCnPed, "symmetricMatrix") + #load(paste0(outcome_name,'_dataBiggestPedigree.Rdata')) +# load(paste0(outcome_name,'_dataBiggestMtPedigree.Rdata')) + + # rel_pairs_file <- paste0(outcome_name,'_datacnmitBiggestRelatedPairsTake3.csv') + + biggestMtPed <- mit_ped_matrix + remove(mit_ped_matrix) + biggestCnPed <- as(cn_ped_matrix , "symmetricMatrix") + remove(cn_ped_matrix) + biggestPed <- ad_ped_matrix + remove(ad_ped_matrix) + biggestMtPed@x[biggestMtPed@x > 0] <- 1 + +if(exists("rel_pairs_file")){ + fname <- rel_pairs_file}else{ + fname <- paste0(outcome_name,'_dataBiggestRelatedPairsTake2.csv') + } + ds <- data.frame(ID1=numeric(0), ID2=numeric(0), addRel=numeric(0), mitRel=numeric(0), cnuRel=numeric(0)) + write.table(ds, file=fname, sep=',', append=FALSE, row.names=FALSE) + ids <- as.numeric(dimnames(biggestCnPed)[[1]]) + newColPos1 <- biggestPed@p + 1L + iss1 <- biggestPed@i + 1L + newColPos2 <- biggestMtPed@p + 1L + iss2 <- biggestMtPed@i + 1L + newColPos3 <- biggestCnPed@p + 1L + iss3 <- biggestCnPed@i + 1L + nc <- ncol(biggestPed) + for(j in 1L:nc){ + ID2 <- ids[j] + ncp1 <- newColPos1[j] + ncp1p <- newColPos1[j+1L] + cond1 <- ncp1 < ncp1p + if(cond1){ + vv1 <- ncp1:(ncp1p-1L) + iss1vv <- iss1[vv1] + } + ncp2 <- newColPos2[j] + ncp2p <- newColPos2[j+1L] + cond2 <- ncp2 < ncp2p + if(cond2){ + vv2 <- ncp2:(ncp2p-1L) + iss2vv <- iss2[vv2] + } + ncp3 <- newColPos3[j] + ncp3p <- newColPos3[j+1L] + cond3 <- ncp3 < ncp3p + if(cond3){ + vv3 <- ncp3:(ncp3p-1L) + iss3vv <- iss3[vv3] + } + u <- sort(igraph::union(igraph::union(if(cond1){iss1vv}, if(cond2){iss2vv}), if(cond3){iss3vv})) + #browser() + if(cond1 || cond2 || cond3){ + ID1 <- ids[u] + tds <- data.frame(ID1=ID1, ID2=ID2, addRel=0, mitRel=0, cnuRel=0) + if(cond1){ tds$addRel[u %in% iss1vv] <- biggestPed@x[vv1] } + if(cond2){ tds$mitRel[u %in% iss2vv] <- biggestMtPed@x[vv2] } + if(cond3){ tds$cnuRel[u %in% iss3vv] <- biggestCnPed@x[vv3] } + write.table(tds, file=fname, row.names=FALSE, col.names=FALSE, append=TRUE, sep=',') + } + if( !(j %% 500) ) { cat(paste0('Done with ', j, ' of ', nc, '\n')) } + } +} + + # Merge and write the parentage matrices # df <- full_join(mat_ped_matrix %>% arrange(ID), pat_ped_matrix %>% arrange(ID)) # write.table(df, file = mapa_id_file, sep = ",", append = FALSE, row.names = FALSE) } -} + diff --git a/man/com2links.Rd b/man/com2links.Rd index bcb6d2ff..73f53b6d 100644 --- a/man/com2links.Rd +++ b/man/com2links.Rd @@ -15,6 +15,7 @@ com2links( gc = TRUE, writetodisk = TRUE, verbose = FALSE, + legacy = FALSE, ... ) } diff --git a/man/ped2com.Rd b/man/ped2com.Rd index 524d892d..60c8fc05 100644 --- a/man/ped2com.Rd +++ b/man/ped2com.Rd @@ -49,6 +49,8 @@ ped2com( \item{adjacency_method}{character. The method to use for computing the adjacency matrix. Options are "loop" or "indexed"} +\item{isChild_method}{character. The method to use for computing the isChild matrix. Options are "classic" or "partialparent"} + \item{saveable}{logical. If TRUE, save the intermediate results to disk} \item{resume}{logical. If TRUE, resume from a checkpoint} From 2e067315c1db724edd4723d91f35f89035c3aff8 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Mon, 17 Mar 2025 14:47:56 -0400 Subject: [PATCH 22/33] Update test-convertPedigree.R --- tests/testthat/test-convertPedigree.R | 119 ++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 19 deletions(-) diff --git a/tests/testthat/test-convertPedigree.R b/tests/testthat/test-convertPedigree.R index 346e5bfb..46a89e39 100644 --- a/tests/testthat/test-convertPedigree.R +++ b/tests/testthat/test-convertPedigree.R @@ -321,10 +321,75 @@ test_that("adjacency_method 'indexed', 'loop', and direct produce the same resu expect_equal(ped_gen_indexed, ped_gen_direct, tolerance = tolerance) }) -test_that("isChild_method product the same results for add matrix", { - data(inbreeding) - df <- inbreeding - df$momID[df$ID == 6] <- NA +test_that("isChild_method product the same results for mtdna matrix, remove mom", { + data(hazard) + df <- hazard + + ped_mit_partial_nona <- ped2com(df, isChild_method= "partialparent", + component = "mitochondrial", + adjacency_method = "direct") + ped_mit_classic_nona <- ped2com(df, isChild_method= "classic", + component = "mitochondrial", adjacency_method = "direct") + + expect_equal(ped_mit_partial_nona, ped_mit_classic_nona, tolerance = tolerance) + df$momID[df$ID == 4] <- NA + tolerance <- 1e-10 + # maternal + ped_mit_partial <- ped2com(df, isChild_method= "partialparent", + component = "mitochondrial", + adjacency_method = "direct") + ped_mit_classic <- ped2com(df, isChild_method= "classic", + component = "mitochondrial", adjacency_method = "direct") + # should be the same within method + expect_equal(ped_mit_partial, ped_mit_classic, tolerance = tolerance) + expect_equal(ped_mit_partial, ped_mit_classic_nona, tolerance = tolerance) + + # should be the same across methods + expect_equal(ped_mit_partial_nona, ped_mit_partial, tolerance = tolerance) + expect_equal(ped_mit_classic_nona, ped_mit_classic, tolerance = tolerance) +}) + +test_that("isChild_method product the same results for mtdna matrix, remove dad", { + data(hazard) + df <- hazard + + ped_mit_partial_nona <- ped2com(df, isChild_method= "partialparent", + component = "mitochondrial", + adjacency_method = "direct") + ped_mit_classic_nona <- ped2com(df, isChild_method= "classic", + component = "mitochondrial", adjacency_method = "direct") + + expect_equal(ped_mit_partial_nona, ped_mit_classic_nona, tolerance = tolerance) + df$dadID[df$ID == 4] <- NA + tolerance <- 1e-10 + # maternal + ped_mit_partial <- ped2com(df, isChild_method= "partialparent", + component = "mitochondrial", + adjacency_method = "direct") + ped_mit_classic <- ped2com(df, isChild_method= "classic", + component = "mitochondrial", adjacency_method = "direct") + # should be the same within method + expect_equal(ped_mit_partial, ped_mit_classic, tolerance = tolerance) + expect_equal(ped_mit_partial, ped_mit_classic_nona, tolerance = tolerance) + + # should be the same across methods + expect_equal(ped_mit_partial_nona, ped_mit_partial, tolerance = tolerance) + expect_equal(ped_mit_classic_nona, ped_mit_classic, tolerance = tolerance) +}) + +test_that("isChild_method product the same results for add matrix for hazard", { + data(hazard) + + df <- hazard + + ped_add_partial_nona <- ped2com(df, isChild_method= "partialparent", + component = "additive", + adjacency_method = "direct") + ped_add_classic_nona <- ped2com(df, isChild_method= "classic", + component = "additive", adjacency_method = "direct") + + + df$momID[df$ID == 4] <- NA tolerance <- 1e-10 # add ped_add_partial <- ped2com(df, isChild_method= "partialparent", @@ -333,10 +398,10 @@ test_that("isChild_method product the same results for add matrix", { ped_add_classic <- ped2com(df, isChild_method= "classic", component = "additive", adjacency_method = "direct") - expect_equal(ped_add_partial[6,6], 1, tolerance = tolerance) - expect_equal(ped_add_classic[6,6], .75, tolerance = tolerance) + expect_equal(ped_add_partial[4,4], 1, tolerance = tolerance) + expect_equal(ped_add_classic[4,4], .75, tolerance = tolerance) difference <- ped_add_partial - ped_add_classic -# expect_equal(ped_add_partial, ped_add_classic, tolerance = tolerance) + expect_equal(ped_add_partial, ped_add_classic_nona, tolerance = tolerance) difference <- ped_add_partial - ped_add_classic @@ -345,21 +410,37 @@ test_that("isChild_method product the same results for add matrix", { -test_that("isChild_method product the same results for mtdna matrix", { - data(hazard) - df <- hazard - df$momID[df$ID == 4] <- NA +test_that("isChild_method product the same results for add matrix with inbreeding", { + data(inbreeding) + df <- inbreeding + + ped_add_classic_nona <- ped2com(df, isChild_method= "classic", + component = "additive", adjacency_method = "direct") + ped_add_partial_nona <- ped2com(df, isChild_method= "partialparent", + component = "additive", + adjacency_method = "direct") +# df$momID[df$ID == 6] <- NA tolerance <- 1e-10 - # maternal - ped_mit_partial <- ped2com(df, isChild_method= "partialparent", - component = "mitochondrial", - adjacency_method = "indexed") - ped_mit_classic <- ped2com(df, isChild_method= "classic", - component = "mitochondrial", adjacency_method = "indexed") - # should be the same - expect_equal(ped_mit_partial, ped_mit_classic, tolerance = tolerance) + # add + ped_add_partial <- ped2com(df, isChild_method= "partialparent", + component = "additive", + adjacency_method = "direct") + ped_add_classic <- ped2com(df, isChild_method= "classic", + component = "additive", adjacency_method = "direct") + expect_equal(ped_add_partial[4,4], 1, tolerance = tolerance) + expect_equal(ped_add_classic[4,4], .75, tolerance = tolerance) + difference <- ped_add_partial - ped_add_classic + # expect_equal(ped_add_partial, ped_add_classic, tolerance = tolerance) + + difference <- ped_add_partial - ped_add_classic + + expect_gt(sum(abs(difference)),0) }) + + + + From cb29d276aad36cf4a3d33757eb1387bd0f25a096 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Mon, 17 Mar 2025 15:51:10 -0400 Subject: [PATCH 23/33] testing out --- tests/testthat/test-convertPedigree.R | 2 +- vignettes/partial.Rmd | 77 +++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 vignettes/partial.Rmd diff --git a/tests/testthat/test-convertPedigree.R b/tests/testthat/test-convertPedigree.R index 46a89e39..cfe67ff1 100644 --- a/tests/testthat/test-convertPedigree.R +++ b/tests/testthat/test-convertPedigree.R @@ -419,7 +419,7 @@ test_that("isChild_method product the same results for add matrix with inbreedin ped_add_partial_nona <- ped2com(df, isChild_method= "partialparent", component = "additive", adjacency_method = "direct") -# df$momID[df$ID == 6] <- NA + df$momID[df$ID == 6] <- NA tolerance <- 1e-10 # add ped_add_partial <- ped2com(df, isChild_method= "partialparent", diff --git a/vignettes/partial.Rmd b/vignettes/partial.Rmd new file mode 100644 index 00000000..5a9e6dbb --- /dev/null +++ b/vignettes/partial.Rmd @@ -0,0 +1,77 @@ +--- +title: "Partial" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Validation} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +options(rmarkdown.html_vignette.check_title = FALSE) +library(tidyverse) +``` + +# Introduction + + +```{r} +library(BGmisc) + +data(hazard) + +df <- hazard + + +ped_add_partial_nona <- ped2com(df, isChild_method= "partialparent", + component = "additive", + adjacency_method = "direct") +ped_add_classic_nona <- ped2com(df, isChild_method= "classic", + component = "additive", adjacency_method = "direct") +``` + + +First, we will compare the results of the two methods for the additive component. We will use the direct adjacency method. The first method is the classic method, which is the default method in the function. The second method is the partial parent method. These should behave the same when there are no missing values. However, when there are missing values, the partial parent method should be more accurate. For this example, we will remove the mother of individual 4. + +```{r} + + df$momID[df$ID == 4] <- NA + tolerance <- 1e-10 + # add + ped_add_partial <- ped2com(df, isChild_method= "partialparent", + component = "additive", + adjacency_method = "direct") + ped_add_classic <- ped2com(df, isChild_method= "classic", + component = "additive", adjacency_method = "direct") + + + difference <- ped_add_partial - ped_add_classic + difference_nona <- ped_add_partial_nona - ped_add_classic_nona + +``` + + +As we can see, the difference between the two methods is very small, when we remove the mother of individual 4. This is because the mother of individual 4 is not used in the calculation of the additive component. The difference between the two methods is `r mean(difference)` and `r mean(difference_nona)` when we remove the mother of individual 4. + + +```{r} +image(ped_add_partial) + +``` + +```{r} +image(ped_add_partial_nona) +``` + +```{r} + image(ped_add_classic) +``` + +```{r} +image(ped_add_classic_nona) + +``` From d1d473df922045b3132c9e611570f047920f3c4a Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Wed, 19 Mar 2025 15:24:17 -0400 Subject: [PATCH 24/33] temp --- vignettes/partial.Rmd | 55 ++++++++++++++++++++++++++---- vignettes/ped_add_classic.csv | 44 ++++++++++++++++++++++++ vignettes/ped_add_classic_nona.csv | 44 ++++++++++++++++++++++++ vignettes/ped_add_partial.csv | 44 ++++++++++++++++++++++++ vignettes/ped_add_partial_nona.csv | 44 ++++++++++++++++++++++++ 5 files changed, 225 insertions(+), 6 deletions(-) create mode 100644 vignettes/ped_add_classic.csv create mode 100644 vignettes/ped_add_classic_nona.csv create mode 100644 vignettes/ped_add_partial.csv create mode 100644 vignettes/ped_add_partial_nona.csv diff --git a/vignettes/partial.Rmd b/vignettes/partial.Rmd index 5a9e6dbb..0d1dd35f 100644 --- a/vignettes/partial.Rmd +++ b/vignettes/partial.Rmd @@ -18,6 +18,7 @@ library(tidyverse) # Introduction +The `ped2com` function can be used to calculate the components of the genetic relationship matrix. The function has two methods to handle the parent adjacency matrix. The first method is the classic method, which is the default method in the function. The second method is the partial parent method. The partial parent method is more accurate when there are missing values in the parent adjacency matrix. This vignette will show the difference between the two methods when there are missing values in the parent adjacency matrix. ```{r} library(BGmisc) @@ -32,37 +33,79 @@ ped_add_partial_nona <- ped2com(df, isChild_method= "partialparent", adjacency_method = "direct") ped_add_classic_nona <- ped2com(df, isChild_method= "classic", component = "additive", adjacency_method = "direct") + +write.csv(ped_add_partial_nona, "ped_add_partial_nona.csv") +write.csv(ped_add_classic_nona, "ped_add_classic_nona.csv") ``` -First, we will compare the results of the two methods for the additive component. We will use the direct adjacency method. The first method is the classic method, which is the default method in the function. The second method is the partial parent method. These should behave the same when there are no missing values. However, when there are missing values, the partial parent method should be more accurate. For this example, we will remove the mother of individual 4. +```{r} + +library(ggcorrplot) +library(corrplot) + +if(FALSE){ +ggcorrplot(ped_add_partial_nona, hc.order = TRUE, + lab = TRUE, lab_size = 3, method = "square", outline.col = "white", digits = 3, + title = "Additive component - Partial parent method") + +} + +corrplot(as.matrix(ped_add_classic_nona), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) + +corrplot(as.matrix(ped_add_partial_nona), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) + +``` +First, we will compare the results of the two methods for the additive component. We will use the direct adjacency method. The first method is the classic method, which is the default method in the function. The second method is the partial parent method. These should behave the same when there are no missing values. However, when there are missing values, the partial parent method should be more accurate. For this example, we will remove the mother of individual 4. We will then compare the results of the two methods. ```{r} df$momID[df$ID == 4] <- NA - tolerance <- 1e-10 # add ped_add_partial <- ped2com(df, isChild_method= "partialparent", component = "additive", adjacency_method = "direct") + ped_add_classic <- ped2com(df, isChild_method= "classic", component = "additive", adjacency_method = "direct") - difference <- ped_add_partial - ped_add_classic difference_nona <- ped_add_partial_nona - ped_add_classic_nona - + + difference_best <- ped_add_partial- ped_add_classic_nona + write.csv(ped_add_partial, "ped_add_partial.csv") + write.csv(ped_add_classic, "ped_add_classic.csv") ``` -As we can see, the difference between the two methods is very small, when we remove the mother of individual 4. This is because the mother of individual 4 is not used in the calculation of the additive component. The difference between the two methods is `r mean(difference)` and `r mean(difference_nona)` when we remove the mother of individual 4. +As we can see, the difference between the two methods is very small, when we remove the mother of individual 4. This is because the mother of individual 4 is not used in the calculation of the additive component. + + +The difference between the two methods is `r mean(difference)` and `r mean(difference_nona)` when we remove the mother of individual 4. If the correction is applied to the additive component, the difference between the matrix using the partial parent correction compared to the method without any missing data is `r mean(difference_best)`. ```{r} -image(ped_add_partial) +corrplot(as.matrix(ped_add_classic), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) +``` +When we plot the difference between the two methods, we can see that there are differences between the matrices. +```{r} +corrplot(as.matrix(ped_add_partial), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) ``` +```{r} +corrplot(as.matrix(ped_add_classic_nona-ped_add_partial), + method = 'color', type = 'lower', + is.corr = FALSE) +``` ```{r} image(ped_add_partial_nona) ``` diff --git a/vignettes/ped_add_classic.csv b/vignettes/ped_add_classic.csv new file mode 100644 index 00000000..45421932 --- /dev/null +++ b/vignettes/ped_add_classic.csv @@ -0,0 +1,44 @@ +"","1","2","3","4","7","5","6","8","10","9","11","13","12","15","14","16","17","18","19","20","21","23","22","24","27","25","26","32","28","37","29","30","41","31","33","34","35","36","38","39","40","42","43" +"1",1,0,0.5,0,0,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"2",0,1,0.5,0.5,0,0.5,0.5,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"3",0.5,0.5,1,0.25,0,0.5,0.5,0.125,0,0.125,0.0625,0,0.0625,0,0.03125,0.03125,0.03125,0.03125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"4",0,0.5,0.25,0.75,0,0.25,0.25,0.375,0,0.375,0.1875,0,0.1875,0,0.09375,0.09375,0.09375,0.09375,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"7",0,0,0,0,1,0,0,0.5,0,0.5,0.25,0,0.25,0,0.125,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"5",0.5,0.5,0.5,0.25,0,1,0.5,0.125,0,0.125,0.0625,0,0.0625,0,0.03125,0.03125,0.03125,0.03125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"6",0.5,0.5,0.5,0.25,0,0.5,1,0.125,0,0.125,0.0625,0,0.0625,0,0.03125,0.03125,0.03125,0.03125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"8",0,0.25,0.125,0.375,0.5,0.125,0.125,0.9375,0,0.4375,0.46875,0,0.46875,0,0.234375,0.234375,0.234375,0.234375,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"10",0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0,0.25,0.25,0.25,0.25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"9",0,0.25,0.125,0.375,0.5,0.125,0.125,0.4375,0,0.9375,0.21875,0,0.21875,0,0.109375,0.109375,0.109375,0.109375,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"11",0,0.125,0.0625,0.1875,0.25,0.0625,0.0625,0.46875,0.5,0.21875,0.984375,0,0.484375,0,0.4921875,0.2421875,0.2421875,0.2421875,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"13",0,0,0,0,0,0,0,0,0,0,0,1,0,0,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"12",0,0.125,0.0625,0.1875,0.25,0.0625,0.0625,0.46875,0.5,0.21875,0.484375,0,0.984375,0,0.2421875,0.4921875,0.4921875,0.4921875,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"15",0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"14",0,0.0625,0.03125,0.09375,0.125,0.03125,0.03125,0.234375,0.25,0.109375,0.4921875,0.5,0.2421875,0,0.99609375,0.12109375,0.12109375,0.12109375,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"16",0,0.0625,0.03125,0.09375,0.125,0.03125,0.03125,0.234375,0.25,0.109375,0.2421875,0,0.4921875,0.5,0.12109375,0.99609375,0.49609375,0.49609375,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"17",0,0.0625,0.03125,0.09375,0.125,0.03125,0.03125,0.234375,0.25,0.109375,0.2421875,0,0.4921875,0.5,0.12109375,0.49609375,0.99609375,0.49609375,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"18",0,0.0625,0.03125,0.09375,0.125,0.03125,0.03125,0.234375,0.25,0.109375,0.2421875,0,0.4921875,0.5,0.12109375,0.49609375,0.49609375,0.99609375,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"19",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"20",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0.5,0,0.5,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"21",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.5,0.5,1,0,0.5,0.5,0,0.5,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"23",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"22",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.5,0.5,0.5,0,1,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"24",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,1,0,0.5,0.5,0,0.5,0,0.5,0.5,0,0.5,0.25,0.25,0.25,0.25,0.25,0.25,0.25,0.25,0.25 +"27",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0.5,0,0.5,0.5,0,0.5,0,0,0,0,0.25,0.25,0.25,0.25,0.25 +"25",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,0.5,0,1,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"26",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,0.5,0,0.5,1,0,0.25,0,0.25,0.25,0,0.25,0.5,0.5,0.5,0.5,0.125,0.125,0.125,0.125,0.125 +"32",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0.5,0.5,0.5,0.5,0,0,0,0,0 +"28",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,1,0,0.5,0.5,0,0.5,0.125,0.125,0.125,0.125,0.5,0.5,0.5,0.25,0.25 +"37",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0.5,0.5,0.5,0,0 +"29",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,1,0.5,0,0.5,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.25,0.25 +"30",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,0.5,1,0,0.5,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.5,0.5 +"41",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0.5,0.5 +"31",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,0.5,0.5,0,1,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.25,0.25 +"33",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,1,0.5,0.5,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"34",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,1,0.5,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"35",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,0.5,1,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"36",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,0.5,0.5,1,0.0625,0.0625,0.0625,0.0625,0.0625 +"38",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,1,0.5,0.5,0.125,0.125 +"39",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,0.5,1,0.5,0.125,0.125 +"40",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,0.5,0.5,1,0.125,0.125 +"42",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.25,0,0.25,0.5,0.5,0.25,0.0625,0.0625,0.0625,0.0625,0.125,0.125,0.125,1,0.5 +"43",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.25,0,0.25,0.5,0.5,0.25,0.0625,0.0625,0.0625,0.0625,0.125,0.125,0.125,0.5,1 diff --git a/vignettes/ped_add_classic_nona.csv b/vignettes/ped_add_classic_nona.csv new file mode 100644 index 00000000..7e01d9aa --- /dev/null +++ b/vignettes/ped_add_classic_nona.csv @@ -0,0 +1,44 @@ +"","1","2","3","4","7","5","6","8","10","9","11","13","12","15","14","16","17","18","19","20","21","23","22","24","27","25","26","32","28","37","29","30","41","31","33","34","35","36","38","39","40","42","43" +"1",1,0,0.5,0.5,0,0.5,0.5,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"2",0,1,0.5,0.5,0,0.5,0.5,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"3",0.5,0.5,1,0.5,0,0.5,0.5,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"4",0.5,0.5,0.5,1,0,0.5,0.5,0.5,0,0.5,0.25,0,0.25,0,0.125,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"7",0,0,0,0,1,0,0,0.5,0,0.5,0.25,0,0.25,0,0.125,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"5",0.5,0.5,0.5,0.5,0,1,0.5,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"6",0.5,0.5,0.5,0.5,0,0.5,1,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"8",0.25,0.25,0.25,0.5,0.5,0.25,0.25,1,0,0.5,0.5,0,0.5,0,0.25,0.25,0.25,0.25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"10",0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0,0.25,0.25,0.25,0.25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"9",0.25,0.25,0.25,0.5,0.5,0.25,0.25,0.5,0,1,0.25,0,0.25,0,0.125,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"11",0.125,0.125,0.125,0.25,0.25,0.125,0.125,0.5,0.5,0.25,1,0,0.5,0,0.5,0.25,0.25,0.25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"13",0,0,0,0,0,0,0,0,0,0,0,1,0,0,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"12",0.125,0.125,0.125,0.25,0.25,0.125,0.125,0.5,0.5,0.25,0.5,0,1,0,0.25,0.5,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"15",0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"14",0.0625,0.0625,0.0625,0.125,0.125,0.0625,0.0625,0.25,0.25,0.125,0.5,0.5,0.25,0,1,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"16",0.0625,0.0625,0.0625,0.125,0.125,0.0625,0.0625,0.25,0.25,0.125,0.25,0,0.5,0.5,0.125,1,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"17",0.0625,0.0625,0.0625,0.125,0.125,0.0625,0.0625,0.25,0.25,0.125,0.25,0,0.5,0.5,0.125,0.5,1,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"18",0.0625,0.0625,0.0625,0.125,0.125,0.0625,0.0625,0.25,0.25,0.125,0.25,0,0.5,0.5,0.125,0.5,0.5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"19",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"20",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0.5,0,0.5,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"21",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.5,0.5,1,0,0.5,0.5,0,0.5,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"23",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"22",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.5,0.5,0.5,0,1,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"24",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,1,0,0.5,0.5,0,0.5,0,0.5,0.5,0,0.5,0.25,0.25,0.25,0.25,0.25,0.25,0.25,0.25,0.25 +"27",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0.5,0,0.5,0.5,0,0.5,0,0,0,0,0.25,0.25,0.25,0.25,0.25 +"25",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,0.5,0,1,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"26",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,0.5,0,0.5,1,0,0.25,0,0.25,0.25,0,0.25,0.5,0.5,0.5,0.5,0.125,0.125,0.125,0.125,0.125 +"32",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0.5,0.5,0.5,0.5,0,0,0,0,0 +"28",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,1,0,0.5,0.5,0,0.5,0.125,0.125,0.125,0.125,0.5,0.5,0.5,0.25,0.25 +"37",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0.5,0.5,0.5,0,0 +"29",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,1,0.5,0,0.5,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.25,0.25 +"30",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,0.5,1,0,0.5,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.5,0.5 +"41",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0.5,0.5 +"31",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,0.5,0.5,0,1,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.25,0.25 +"33",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,1,0.5,0.5,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"34",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,1,0.5,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"35",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,0.5,1,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"36",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,0.5,0.5,1,0.0625,0.0625,0.0625,0.0625,0.0625 +"38",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,1,0.5,0.5,0.125,0.125 +"39",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,0.5,1,0.5,0.125,0.125 +"40",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,0.5,0.5,1,0.125,0.125 +"42",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.25,0,0.25,0.5,0.5,0.25,0.0625,0.0625,0.0625,0.0625,0.125,0.125,0.125,1,0.5 +"43",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.25,0,0.25,0.5,0.5,0.25,0.0625,0.0625,0.0625,0.0625,0.125,0.125,0.125,0.5,1 diff --git a/vignettes/ped_add_partial.csv b/vignettes/ped_add_partial.csv new file mode 100644 index 00000000..a9fcce6c --- /dev/null +++ b/vignettes/ped_add_partial.csv @@ -0,0 +1,44 @@ +"","1","2","3","4","7","5","6","8","10","9","11","13","12","15","14","16","17","18","19","20","21","23","22","24","27","25","26","32","28","37","29","30","41","31","33","34","35","36","38","39","40","42","43" +"1",1,0,0.5,0,0,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"2",0,1,0.5,0.5,0,0.5,0.5,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"3",0.5,0.5,1,0.25,0,0.5,0.5,0.125,0,0.125,0.0625,0,0.0625,0,0.03125,0.03125,0.03125,0.03125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"4",0,0.5,0.25,1,0,0.25,0.25,0.5,0,0.5,0.25,0,0.25,0,0.125,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"7",0,0,0,0,1,0,0,0.5,0,0.5,0.25,0,0.25,0,0.125,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"5",0.5,0.5,0.5,0.25,0,1,0.5,0.125,0,0.125,0.0625,0,0.0625,0,0.03125,0.03125,0.03125,0.03125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"6",0.5,0.5,0.5,0.25,0,0.5,1,0.125,0,0.125,0.0625,0,0.0625,0,0.03125,0.03125,0.03125,0.03125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"8",0,0.25,0.125,0.5,0.5,0.125,0.125,1,0,0.5,0.5,0,0.5,0,0.25,0.25,0.25,0.25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"10",0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0,0.25,0.25,0.25,0.25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"9",0,0.25,0.125,0.5,0.5,0.125,0.125,0.5,0,1,0.25,0,0.25,0,0.125,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"11",0,0.125,0.0625,0.25,0.25,0.0625,0.0625,0.5,0.5,0.25,1,0,0.5,0,0.5,0.25,0.25,0.25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"13",0,0,0,0,0,0,0,0,0,0,0,1,0,0,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"12",0,0.125,0.0625,0.25,0.25,0.0625,0.0625,0.5,0.5,0.25,0.5,0,1,0,0.25,0.5,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"15",0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"14",0,0.0625,0.03125,0.125,0.125,0.03125,0.03125,0.25,0.25,0.125,0.5,0.5,0.25,0,1,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"16",0,0.0625,0.03125,0.125,0.125,0.03125,0.03125,0.25,0.25,0.125,0.25,0,0.5,0.5,0.125,1,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"17",0,0.0625,0.03125,0.125,0.125,0.03125,0.03125,0.25,0.25,0.125,0.25,0,0.5,0.5,0.125,0.5,1,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"18",0,0.0625,0.03125,0.125,0.125,0.03125,0.03125,0.25,0.25,0.125,0.25,0,0.5,0.5,0.125,0.5,0.5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"19",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"20",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0.5,0,0.5,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"21",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.5,0.5,1,0,0.5,0.5,0,0.5,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"23",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"22",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.5,0.5,0.5,0,1,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"24",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,1,0,0.5,0.5,0,0.5,0,0.5,0.5,0,0.5,0.25,0.25,0.25,0.25,0.25,0.25,0.25,0.25,0.25 +"27",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0.5,0,0.5,0.5,0,0.5,0,0,0,0,0.25,0.25,0.25,0.25,0.25 +"25",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,0.5,0,1,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"26",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,0.5,0,0.5,1,0,0.25,0,0.25,0.25,0,0.25,0.5,0.5,0.5,0.5,0.125,0.125,0.125,0.125,0.125 +"32",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0.5,0.5,0.5,0.5,0,0,0,0,0 +"28",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,1,0,0.5,0.5,0,0.5,0.125,0.125,0.125,0.125,0.5,0.5,0.5,0.25,0.25 +"37",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0.5,0.5,0.5,0,0 +"29",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,1,0.5,0,0.5,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.25,0.25 +"30",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,0.5,1,0,0.5,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.5,0.5 +"41",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0.5,0.5 +"31",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,0.5,0.5,0,1,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.25,0.25 +"33",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,1,0.5,0.5,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"34",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,1,0.5,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"35",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,0.5,1,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"36",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,0.5,0.5,1,0.0625,0.0625,0.0625,0.0625,0.0625 +"38",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,1,0.5,0.5,0.125,0.125 +"39",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,0.5,1,0.5,0.125,0.125 +"40",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,0.5,0.5,1,0.125,0.125 +"42",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.25,0,0.25,0.5,0.5,0.25,0.0625,0.0625,0.0625,0.0625,0.125,0.125,0.125,1,0.5 +"43",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.25,0,0.25,0.5,0.5,0.25,0.0625,0.0625,0.0625,0.0625,0.125,0.125,0.125,0.5,1 diff --git a/vignettes/ped_add_partial_nona.csv b/vignettes/ped_add_partial_nona.csv new file mode 100644 index 00000000..7e01d9aa --- /dev/null +++ b/vignettes/ped_add_partial_nona.csv @@ -0,0 +1,44 @@ +"","1","2","3","4","7","5","6","8","10","9","11","13","12","15","14","16","17","18","19","20","21","23","22","24","27","25","26","32","28","37","29","30","41","31","33","34","35","36","38","39","40","42","43" +"1",1,0,0.5,0.5,0,0.5,0.5,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"2",0,1,0.5,0.5,0,0.5,0.5,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"3",0.5,0.5,1,0.5,0,0.5,0.5,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"4",0.5,0.5,0.5,1,0,0.5,0.5,0.5,0,0.5,0.25,0,0.25,0,0.125,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"7",0,0,0,0,1,0,0,0.5,0,0.5,0.25,0,0.25,0,0.125,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"5",0.5,0.5,0.5,0.5,0,1,0.5,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"6",0.5,0.5,0.5,0.5,0,0.5,1,0.25,0,0.25,0.125,0,0.125,0,0.0625,0.0625,0.0625,0.0625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"8",0.25,0.25,0.25,0.5,0.5,0.25,0.25,1,0,0.5,0.5,0,0.5,0,0.25,0.25,0.25,0.25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"10",0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0,0.25,0.25,0.25,0.25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"9",0.25,0.25,0.25,0.5,0.5,0.25,0.25,0.5,0,1,0.25,0,0.25,0,0.125,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"11",0.125,0.125,0.125,0.25,0.25,0.125,0.125,0.5,0.5,0.25,1,0,0.5,0,0.5,0.25,0.25,0.25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"13",0,0,0,0,0,0,0,0,0,0,0,1,0,0,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"12",0.125,0.125,0.125,0.25,0.25,0.125,0.125,0.5,0.5,0.25,0.5,0,1,0,0.25,0.5,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"15",0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"14",0.0625,0.0625,0.0625,0.125,0.125,0.0625,0.0625,0.25,0.25,0.125,0.5,0.5,0.25,0,1,0.125,0.125,0.125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"16",0.0625,0.0625,0.0625,0.125,0.125,0.0625,0.0625,0.25,0.25,0.125,0.25,0,0.5,0.5,0.125,1,0.5,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"17",0.0625,0.0625,0.0625,0.125,0.125,0.0625,0.0625,0.25,0.25,0.125,0.25,0,0.5,0.5,0.125,0.5,1,0.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"18",0.0625,0.0625,0.0625,0.125,0.125,0.0625,0.0625,0.25,0.25,0.125,0.25,0,0.5,0.5,0.125,0.5,0.5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +"19",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"20",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0.5,0,0.5,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"21",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.5,0.5,1,0,0.5,0.5,0,0.5,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"23",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0.5,0,0.5,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"22",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.5,0.5,0.5,0,1,0.25,0,0.25,0.25,0,0.125,0,0.125,0.125,0,0.125,0.125,0.125,0.125,0.125,0.0625,0.0625,0.0625,0.0625,0.0625 +"24",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,1,0,0.5,0.5,0,0.5,0,0.5,0.5,0,0.5,0.25,0.25,0.25,0.25,0.25,0.25,0.25,0.25,0.25 +"27",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0.5,0,0.5,0.5,0,0.5,0,0,0,0,0.25,0.25,0.25,0.25,0.25 +"25",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,0.5,0,1,0.5,0,0.25,0,0.25,0.25,0,0.25,0.25,0.25,0.25,0.25,0.125,0.125,0.125,0.125,0.125 +"26",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.25,0.25,0.5,0.5,0.25,0.5,0,0.5,1,0,0.25,0,0.25,0.25,0,0.25,0.5,0.5,0.5,0.5,0.125,0.125,0.125,0.125,0.125 +"32",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0.5,0.5,0.5,0.5,0,0,0,0,0 +"28",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,1,0,0.5,0.5,0,0.5,0.125,0.125,0.125,0.125,0.5,0.5,0.5,0.25,0.25 +"37",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0.5,0.5,0.5,0,0 +"29",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,1,0.5,0,0.5,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.25,0.25 +"30",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,0.5,1,0,0.5,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.5,0.5 +"41",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0.5,0.5 +"31",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.5,0.5,0.25,0.25,0,0.5,0,0.5,0.5,0,1,0.125,0.125,0.125,0.125,0.25,0.25,0.25,0.25,0.25 +"33",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,1,0.5,0.5,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"34",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,1,0.5,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"35",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,0.5,1,0.5,0.0625,0.0625,0.0625,0.0625,0.0625 +"36",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.125,0.125,0.25,0.25,0.125,0.25,0,0.25,0.5,0.5,0.125,0,0.125,0.125,0,0.125,0.5,0.5,0.5,1,0.0625,0.0625,0.0625,0.0625,0.0625 +"38",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,1,0.5,0.5,0.125,0.125 +"39",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,0.5,1,0.5,0.125,0.125 +"40",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.5,0.5,0.25,0.25,0,0.25,0.0625,0.0625,0.0625,0.0625,0.5,0.5,1,0.125,0.125 +"42",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.25,0,0.25,0.5,0.5,0.25,0.0625,0.0625,0.0625,0.0625,0.125,0.125,0.125,1,0.5 +"43",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0625,0.0625,0.125,0.125,0.0625,0.25,0.25,0.125,0.125,0,0.25,0,0.25,0.5,0.5,0.25,0.0625,0.0625,0.0625,0.0625,0.125,0.125,0.125,0.5,1 From 5ce5a2a33a6d2c01aa32397169810df6a508bcd4 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 20 Mar 2025 12:52:04 -0400 Subject: [PATCH 25/33] Update partial.Rmd --- vignettes/partial.Rmd | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/vignettes/partial.Rmd b/vignettes/partial.Rmd index 0d1dd35f..148cdc27 100644 --- a/vignettes/partial.Rmd +++ b/vignettes/partial.Rmd @@ -102,8 +102,35 @@ corrplot(as.matrix(ped_add_partial), ``` ```{r} + +true_diff <- as.matrix(ped_add_classic_nona-ped_add_partial) + +# filter rows that aren't impacted a.k.a. rows that are all 0 or columns that are all 0 + +true_diff_thin <- as.data.frame(ped_add_classic_nona-ped_add_partial) %>% mutate(row = row_number()) %>% + filter(row %in% which(rowSums(ped_add_classic_nona-ped_add_partial)!=0)) + +#true_diff_thin %>% as.data.frame()%>% + # columns that sum to 0 so that we can remove them +# mutate(col = colSums(true_diff_thin)==1) +# +#%>% +# filter(col != 0) %>% select(-col, -row) %>% as.matrix() + +# key comparison isn't versus truth. it's versus the alterative solution + +# think about this more mason. these comparisons are important + +corrplot(as.matrix(ped_add_classic_nona-ped_add_classic), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) + +corrplot(as.matrix(ped_add_partial-ped_add_classic), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) + corrplot(as.matrix(ped_add_classic_nona-ped_add_partial), - method = 'color', type = 'lower', + method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE) ``` ```{r} From 04a084db3874668aa312167c14147740ccfbd8f2 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 20 Mar 2025 13:56:01 -0400 Subject: [PATCH 26/33] Update partial.Rmd --- vignettes/partial.Rmd | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vignettes/partial.Rmd b/vignettes/partial.Rmd index 148cdc27..2bb515ac 100644 --- a/vignettes/partial.Rmd +++ b/vignettes/partial.Rmd @@ -124,14 +124,20 @@ true_diff_thin <- as.data.frame(ped_add_classic_nona-ped_add_partial) %>% mutate corrplot(as.matrix(ped_add_classic_nona-ped_add_classic), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE) + +sqrt(mean((ped_add_classic_nona-ped_add_classic)^2)) corrplot(as.matrix(ped_add_partial-ped_add_classic), method = 'color', type = 'lower', col.lim = c(0,1), - is.corr = FALSE) + is.corr = FALSE) sqrt(mean((ped_add_partial-ped_add_classic)^2)) + corrplot(as.matrix(ped_add_classic_nona-ped_add_partial), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE) + +sqrt(mean((ped_add_classic_nona-ped_add_partial)^2)) + ``` ```{r} image(ped_add_partial_nona) From c8e81296ecbb4355e3ec1ce5b2ae9e73cb966a9c Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 20 Mar 2025 17:02:31 -0400 Subject: [PATCH 27/33] Update partial.Rmd --- vignettes/partial.Rmd | 86 ++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/vignettes/partial.Rmd b/vignettes/partial.Rmd index 2bb515ac..22fb7c65 100644 --- a/vignettes/partial.Rmd +++ b/vignettes/partial.Rmd @@ -25,7 +25,11 @@ library(BGmisc) data(hazard) -df <- hazard +df <- hazard # this is the data that we will use for the example + +# LOOK AT THAT UNUNUAL DYADS + +## SISTER WIVES ped_add_partial_nona <- ped2com(df, isChild_method= "partialparent", @@ -39,6 +43,8 @@ write.csv(ped_add_classic_nona, "ped_add_classic_nona.csv") ``` +These first two additive matrices show what happens in both methods when you have intact family trees. The two matrices should be the same. + ```{r} library(ggcorrplot) @@ -53,14 +59,31 @@ ggcorrplot(ped_add_partial_nona, hc.order = TRUE, corrplot(as.matrix(ped_add_classic_nona), method = 'color', type = 'lower', col.lim = c(0,1), - is.corr = FALSE) + is.corr = FALSE, title = "Additive component - Classic method") corrplot(as.matrix(ped_add_partial_nona), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE, title = "Additive component - Partial parent method") + +``` +First, we will compare the results of the two methods for the additive component. We will use the direct adjacency method. The first method is the classic method, which is the default method in the function. The second method is the partial parent method. These should behave the same when there are no missing values. + + +Indeed when we subtract one matrix from the other , we can see that they are the same. And we note that the RMSE is `r sqrt(mean((ped_add_classic_nona-ped_add_partial_nona)^2))`. + +```{r} + +corrplot(as.matrix(ped_add_classic_nona-ped_add_partial_nona), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE) + ``` -First, we will compare the results of the two methods for the additive component. We will use the direct adjacency method. The first method is the classic method, which is the default method in the function. The second method is the partial parent method. These should behave the same when there are no missing values. However, when there are missing values, the partial parent method should be more accurate. For this example, we will remove the mother of individual 4. We will then compare the results of the two methods. + + +However, when there are missing values, the partial parent method should be more accurate. For this example, we will remove the mother of individual 4. We will then compare the results of the two methods. The key comparisons are how each method performs relative to the "true" additive component. The true additive component is the additive component calculated without any missing data. And how they compare to each other. + + ```{r} @@ -73,27 +96,22 @@ First, we will compare the results of the two methods for the additive component ped_add_classic <- ped2com(df, isChild_method= "classic", component = "additive", adjacency_method = "direct") - difference <- ped_add_partial - ped_add_classic - difference_nona <- ped_add_partial_nona - ped_add_classic_nona - - difference_best <- ped_add_partial- ped_add_classic_nona - write.csv(ped_add_partial, "ped_add_partial.csv") - write.csv(ped_add_classic, "ped_add_classic.csv") ``` -As we can see, the difference between the two methods is very small, when we remove the mother of individual 4. This is because the mother of individual 4 is not used in the calculation of the additive component. - - -The difference between the two methods is `r mean(difference)` and `r mean(difference_nona)` when we remove the mother of individual 4. If the correction is applied to the additive component, the difference between the matrix using the partial parent correction compared to the method without any missing data is `r mean(difference_best)`. +As we can see, the two matrices are different. The RMSE between the two matrices is `r sqrt(mean((ped_add_classic-ped_add_partial)^2))`. +This plot shows the relatedness matrix when we use the classic method. ```{r} corrplot(as.matrix(ped_add_classic), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE) ``` -When we plot the difference between the two methods, we can see that there are differences between the matrices. + + +This plot shows the relatedness matrix when we use the partial parent method. + ```{r} corrplot(as.matrix(ped_add_partial), @@ -101,6 +119,11 @@ corrplot(as.matrix(ped_add_partial), is.corr = FALSE) ``` + + + +When we compare these methods to the true additive component, we can see that the partial parent method is more accurate. The RMSE between the true additive component and the classic method is `r sqrt(mean((ped_add_classic_nona-ped_add_classic)^2))`. The RMSE between the true additive component and the partial parent method is `r sqrt(mean((ped_add_classic_nona-ped_add_partial)^2))`. And the RMSE between the classic method and the partial parent method is `r sqrt(mean((ped_add_classic-ped_add_partial)^2))`. + ```{r} true_diff <- as.matrix(ped_add_classic_nona-ped_add_partial) @@ -120,18 +143,26 @@ true_diff_thin <- as.data.frame(ped_add_classic_nona-ped_add_partial) %>% mutate # key comparison isn't versus truth. it's versus the alterative solution # think about this more mason. these comparisons are important +``` + + +The classic adjustment compared to the true additive component is shown below. + +```{r} corrplot(as.matrix(ped_add_classic_nona-ped_add_classic), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE) sqrt(mean((ped_add_classic_nona-ped_add_classic)^2)) - -corrplot(as.matrix(ped_add_partial-ped_add_classic), - method = 'color', type = 'lower', col.lim = c(0,1), - is.corr = FALSE) sqrt(mean((ped_add_partial-ped_add_classic)^2)) - +``` + + +The partial parent adjustment compared to the true additive component is shown below. + + +```{r} corrplot(as.matrix(ped_add_classic_nona-ped_add_partial), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE) @@ -139,15 +170,18 @@ corrplot(as.matrix(ped_add_classic_nona-ped_add_partial), sqrt(mean((ped_add_classic_nona-ped_add_partial)^2)) ``` -```{r} -image(ped_add_partial_nona) -``` + + + +The classic adjustment compared to the partial parent adjustment is shown below. ```{r} - image(ped_add_classic) +corrplot(as.matrix(ped_add_partial-ped_add_classic), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) sqrt(mean((ped_add_partial-ped_add_classic)^2)) + ``` -```{r} -image(ped_add_classic_nona) -``` + + From 7d4f150c58cd439433421d83abeabf762d87b141 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Thu, 20 Mar 2025 21:52:17 -0400 Subject: [PATCH 28/33] bias --- vignettes/partial.Rmd | 162 +++++++++++++++--- .../figure-html/unnamed-chunk-10-1.png | Bin 0 -> 10910 bytes .../figure-html/unnamed-chunk-3-1.png | Bin 0 -> 12225 bytes .../figure-html/unnamed-chunk-3-2.png | Bin 0 -> 12026 bytes .../figure-html/unnamed-chunk-4-1.png | Bin 0 -> 10647 bytes .../figure-html/unnamed-chunk-6-1.png | Bin 0 -> 11445 bytes .../figure-html/unnamed-chunk-7-1.png | Bin 0 -> 11370 bytes .../figure-html/unnamed-chunk-9-1.png | Bin 0 -> 10996 bytes 8 files changed, 142 insertions(+), 20 deletions(-) create mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-10-1.png create mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-3-1.png create mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-3-2.png create mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-4-1.png create mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-6-1.png create mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-7-1.png create mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-9-1.png diff --git a/vignettes/partial.Rmd b/vignettes/partial.Rmd index 22fb7c65..a18f3622 100644 --- a/vignettes/partial.Rmd +++ b/vignettes/partial.Rmd @@ -20,6 +20,10 @@ library(tidyverse) The `ped2com` function can be used to calculate the components of the genetic relationship matrix. The function has two methods to handle the parent adjacency matrix. The first method is the classic method, which is the default method in the function. The second method is the partial parent method. The partial parent method is more accurate when there are missing values in the parent adjacency matrix. This vignette will show the difference between the two methods when there are missing values in the parent adjacency matrix. + +### Hazzard data +#### Drop mom of individual 4 + ```{r} library(BGmisc) @@ -32,14 +36,14 @@ df <- hazard # this is the data that we will use for the example ## SISTER WIVES -ped_add_partial_nona <- ped2com(df, isChild_method= "partialparent", +ped_add_partial_complete <- ped2com(df, isChild_method= "partialparent", component = "additive", adjacency_method = "direct") -ped_add_classic_nona <- ped2com(df, isChild_method= "classic", +ped_add_classic_complete <- ped2com(df, isChild_method= "classic", component = "additive", adjacency_method = "direct") -write.csv(ped_add_partial_nona, "ped_add_partial_nona.csv") -write.csv(ped_add_classic_nona, "ped_add_classic_nona.csv") +write.csv(ped_add_partial_complete, "ped_add_partial_complete.csv") +write.csv(ped_add_classic_complete, "ped_add_classic_complete.csv") ``` @@ -51,29 +55,30 @@ library(ggcorrplot) library(corrplot) if(FALSE){ -ggcorrplot(ped_add_partial_nona, hc.order = TRUE, +ggcorrplot(ped_add_partial_complete, hc.order = TRUE, lab = TRUE, lab_size = 3, method = "square", outline.col = "white", digits = 3, title = "Additive component - Partial parent method") } -corrplot(as.matrix(ped_add_classic_nona), +corrplot(as.matrix(ped_add_classic_complete), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE, title = "Additive component - Classic method") -corrplot(as.matrix(ped_add_partial_nona), +corrplot(as.matrix(ped_add_partial_complete), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE, title = "Additive component - Partial parent method") ``` + First, we will compare the results of the two methods for the additive component. We will use the direct adjacency method. The first method is the classic method, which is the default method in the function. The second method is the partial parent method. These should behave the same when there are no missing values. -Indeed when we subtract one matrix from the other , we can see that they are the same. And we note that the RMSE is `r sqrt(mean((ped_add_classic_nona-ped_add_partial_nona)^2))`. +Indeed when we subtract one matrix from the other , we can see that they are the same. And we note that the RMSE is `r sqrt(mean((ped_add_classic_complete-ped_add_partial_complete)^2))`. ```{r} -corrplot(as.matrix(ped_add_classic_nona-ped_add_partial_nona), +corrplot(as.matrix(ped_add_classic_complete-ped_add_partial_complete), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE) @@ -84,16 +89,17 @@ corrplot(as.matrix(ped_add_classic_nona-ped_add_partial_nona), However, when there are missing values, the partial parent method should be more accurate. For this example, we will remove the mother of individual 4. We will then compare the results of the two methods. The key comparisons are how each method performs relative to the "true" additive component. The true additive component is the additive component calculated without any missing data. And how they compare to each other. +#### Drop Mom ```{r} df$momID[df$ID == 4] <- NA # add - ped_add_partial <- ped2com(df, isChild_method= "partialparent", +ped_add_partial_mom <- ped_add_partial<- ped2com(df, isChild_method= "partialparent", component = "additive", adjacency_method = "direct") - ped_add_classic <- ped2com(df, isChild_method= "classic", +ped_add_classic_mom <- ped_add_classic <- ped2com(df, isChild_method= "classic", component = "additive", adjacency_method = "direct") ``` @@ -122,16 +128,16 @@ corrplot(as.matrix(ped_add_partial), -When we compare these methods to the true additive component, we can see that the partial parent method is more accurate. The RMSE between the true additive component and the classic method is `r sqrt(mean((ped_add_classic_nona-ped_add_classic)^2))`. The RMSE between the true additive component and the partial parent method is `r sqrt(mean((ped_add_classic_nona-ped_add_partial)^2))`. And the RMSE between the classic method and the partial parent method is `r sqrt(mean((ped_add_classic-ped_add_partial)^2))`. +When we compare these methods to the true additive component, we can see that the partial parent method is more accurate. The RMSE between the true additive component and the classic method is `r sqrt(mean((ped_add_classic_complete-ped_add_classic)^2))`. The RMSE between the true additive component and the partial parent method is `r sqrt(mean((ped_add_classic_complete-ped_add_partial)^2))`. And the RMSE between the classic method and the partial parent method is `r sqrt(mean((ped_add_classic-ped_add_partial)^2))`. ```{r} -true_diff <- as.matrix(ped_add_classic_nona-ped_add_partial) +#true_diff <- as.matrix(ped_add_classic_complete-ped_add_partial) # filter rows that aren't impacted a.k.a. rows that are all 0 or columns that are all 0 -true_diff_thin <- as.data.frame(ped_add_classic_nona-ped_add_partial) %>% mutate(row = row_number()) %>% - filter(row %in% which(rowSums(ped_add_classic_nona-ped_add_partial)!=0)) +#true_diff_thin <- as.data.frame(ped_add_classic_complete-ped_add_partial) %>% mutate(row = #row_number()) %>% +# filter(row %in% which(rowSums(ped_add_classic_complete-ped_add_partial)!=0)) #true_diff_thin %>% as.data.frame()%>% # columns that sum to 0 so that we can remove them @@ -150,11 +156,103 @@ true_diff_thin <- as.data.frame(ped_add_classic_nona-ped_add_partial) %>% mutate The classic adjustment compared to the true additive component is shown below. ```{r} -corrplot(as.matrix(ped_add_classic_nona-ped_add_classic), +corrplot(as.matrix(ped_add_classic_complete-ped_add_classic), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) + +sqrt(mean((ped_add_classic_complete-ped_add_classic)^2)) + +``` + + +The partial parent adjustment compared to the true additive component is shown below. + + +```{r} +corrplot(as.matrix(ped_add_classic_complete-ped_add_partial), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) + +sqrt(mean((ped_add_classic_complete-ped_add_partial)^2)) + +``` + + + +The classic adjustment compared to the partial parent adjustment is shown below. + +```{r} +corrplot(as.matrix(ped_add_partial-ped_add_classic), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) + +sqrt(mean((ped_add_partial-ped_add_classic)^2)) + +``` + +#### Drop dad of individual 4 + +```{r} + + +data(hazard) + +df <- hazard # this is the data that we will use for the example + +``` + + + +What happens if we drop the dad of individual 4? + +```{r} + + df$dadID[df$ID == 4] <- NA + # add +ped_add_partial_dad <- ped_add_partial<- ped2com(df, isChild_method= "partialparent", + component = "additive", + adjacency_method = "direct") + +ped_add_classic_dad <- ped_add_classic <- ped2com(df, isChild_method= "classic", + component = "additive", adjacency_method = "direct") + +``` + + +As we can see, the two matrices are different. The RMSE between the two matrices is `r sqrt(mean((ped_add_classic-ped_add_partial)^2))`. + +This plot shows the relatedness matrix when we use the classic method. + +```{r} +corrplot(as.matrix(ped_add_classic), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) +``` + + +This plot shows the relatedness matrix when we use the partial parent method. + + +```{r} +corrplot(as.matrix(ped_add_partial), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE) +``` + + + + +When we compare these methods to the true additive component, we can see that the partial parent method is more accurate. The RMSE between the true additive component and the classic method is `r sqrt(mean((ped_add_classic_complete-ped_add_classic)^2))`. The RMSE between the true additive component and the partial parent method is `r sqrt(mean((ped_add_classic_complete-ped_add_partial)^2))`. And the RMSE between the classic method and the partial parent method is `r sqrt(mean((ped_add_classic-ped_add_partial)^2))`. + + +The classic adjustment compared to the true additive component is shown below. + +```{r} +corrplot(as.matrix(ped_add_classic_complete-ped_add_classic), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE) -sqrt(mean((ped_add_classic_nona-ped_add_classic)^2)) +sqrt(mean((ped_add_classic_complete-ped_add_classic)^2)) ``` @@ -163,11 +261,11 @@ The partial parent adjustment compared to the true additive component is shown b ```{r} -corrplot(as.matrix(ped_add_classic_nona-ped_add_partial), +corrplot(as.matrix(ped_add_classic_complete-ped_add_partial), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE) -sqrt(mean((ped_add_classic_nona-ped_add_partial)^2)) +sqrt(mean((ped_add_classic_complete-ped_add_partial)^2)) ``` @@ -178,10 +276,34 @@ The classic adjustment compared to the partial parent adjustment is shown below. ```{r} corrplot(as.matrix(ped_add_partial-ped_add_classic), method = 'color', type = 'lower', col.lim = c(0,1), - is.corr = FALSE) sqrt(mean((ped_add_partial-ped_add_classic)^2)) + is.corr = FALSE) + +sqrt(mean((ped_add_partial-ped_add_classic)^2)) ``` +## Inbreeding + +```{r} +data("inbreeding") +df <- inbreeding +FamIDs <- unique(df$FamID) + +for (i in 1:length(FamIDs)) { + +df_fam <- df[df$FamID == FamIDs[i],] + + +ped_add_partial_complete <- ped2com(df_fam, isChild_method= "partialparent", + component = "additive", + adjacency_method = "direct") + +ped_add_classic_complete <- ped2com(df_fam, isChild_method= "classic", + component = "additive", + adjacency_method = "direct") +} + +``` diff --git a/vignettes/partial_files/figure-html/unnamed-chunk-10-1.png b/vignettes/partial_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 0000000000000000000000000000000000000000..b6108a589d493072948cf2175a623fa19e9cd650 GIT binary patch literal 10910 zcma)?Ra9JE(59QO;O-Ed;2tbU(BRfUaCZ+LJPkp@^!LwP z&YCqBXZ1~;)#vQ9Yu8&(y|M4r6tFQUFaQ7mwvwW(CIEmy``?B31^@tj*#$4df6!eO z^*sOpoWcJt1gJ}uB>+GRP?D9>_Rag9?~=f16L=(nOw}*Wg_>zLNpZ#P>1549h|Yr= zU5!uG80fQEGxTG2(>C=zNn_6`Vd}AeYM@)2MIDv}Q)hR4^)9z^){-kFo#Q03_p|wr zbW3oAT-GSqpv;1g+)2PU7Tr1w*MjFr6|bO^RA*7=CAhPuAm<`yTY*c}XHhG-voiPv zGJXH|Wj2gf5)VnB%el=(5)Z~_ZW>mE#|x5rA48T+%PNbdf=5J;!ig zCOy=LBt`ds32Qn-IV`a&1!ipaC`o0f7z;HJgeD_oBlU+U1h%<1;6+j$z{ku`Z&&QGU;19!i6QLzynX zesMgAY{s5Lff#SwxMyZkf!D){|4^I3w&Z=^ie$!DG1>PCB5a`O#5RMa*Dy2^p>Mf{ zr2-A1th<=}6N3D1ByM1WmxtdZn53WeCk5 zi1}KsLb0-I$9@r|1KI80jRsm)$(+zgOz2_)fh_uZUuX83rs7u$?o8+&x(&4Un|WYM=;S#;wRBuq7A16u&NslNd>B$n4YaMN|5AWM7ZALL5@}lc1!G(PiXUnZ(eR`aP-AZpA;K*3jnM!JKzqVJMm0Nz?->MI(I} zi?TMj;7)+Uov$sHRmh=KEUjt3G)I!3wA6~7_qdMzVrV3!oBI?&@R%ZZWKZZ;^c(F# ztg`M`1AGo`@I{2K!UG*PVtq^)d z4tyk6X7|IYtt==Q)edN^Td%MdxIV`?9MTZbCAAnkh_1&l^=60MXlpe>u)MQ27X3$3 ziB|(fX7q0vWYxhN;pawb^bPk}etWj-tvbaZIWtm?`EX-ngoZoIpOetpp0L-Ku1QX+ zc$}gSmR7ureRA_9YC3q{NCIMdWHZDSkr+8|cc_)?1@K6JzLPeV+=E8sE38s+mbE6B zHJe_aOSOkh7Xck>{z*RmI%79c@5L&3Ej-Cu`|-~>d1|&uh>t*m`J8k7&@^|1 z)Ira+1H(0daDtlp3vm)`mG#{yJ=luO>X1M|w5~7o(Y`Epx z2!U`cL54Ck-X~EYax6At<9IvsQ=SGiXx?v3v+ZXi{SglCe{q}I@t(>fkz+fduaeGJ z!QGDQ9Y--ecQlLEG`EI;4Bx4$*37x(T?VeU-s(ZgR_s;wgE2&hgsp1)SSxq{qd_2I6MK`7F-(zx3Q z%4-QCuvp)Mf~iR!-l1BgvVSY`|Mxhi`Ngy-Fc6>$_tF6C~+40U^E*uV@{_2)sz0JbL{We^LNs9 zh0uO0O$tl9A1Y8@J0e)j|~g;lmhsjhr`8uB=b3@e@q<=ypjg=+oRcP$BhfKP#ch1GGjeen#3hpH3c>35r`FRpnCy_o; z5m>LCd}&u(v8nRNcq6#aB81Q`^Q%RBA9h{Q*5$m)fWgj%|1goZ#^Jsv4&R-TK*}R6 za*xSykn0;k%!CC91@)wZjcYl|O0`BQRxhmiec-+EEwScH6X;6#^LcmdP zLl09&hHq^7wG7Qosz1ljJYmB3Pq7aoBrDfltQY;uLpV-0ag;5Pt&BehFD)&!y8&gI zk>?LC0%u_{v4|hlpjgUuq<4O3t^x*|D)Z36!I)dC7B7c3Z|G%-!!gM-^~U(Vw3b}f zdFqs*K@@0Efys{Q5FO_o;kc#ac1kG=R6(S58By7(v@@%SHxLZw<5Pqw)=;ap{f!j2 zvPvbn$AmxofHC)2{Zb-67<}=sg>HHF-`F~|^PAgxviWNn2aNN*4JZ<--QKg~WFEd|5ij|AmxJ4- z7+zn+g}b$5X^TpVTNq3tULq+{!wJ0CJ7Hpf0F<7IB~d`ARJ48c!NlrW6}oQ!@LCK8 zvVh71SAr+WgP4+pNi|MobpwA6>XkHhV0k6gQ~g#?QBXUz>(WxH9}j-#8tJiA)SnQ)jCyNRVv$_AoadbazezJ&@P}HXSm}LA6 zfpHpu4)yA3xDCj+q^~r)%H=emZ?C>Q5RaRLlY(t;_UXnp0-(lkhl*!aOVrt@B*jBv zXwlQR8+;KAzXejs?-_HjYx7&Oz+t_yf-vsN4;TFiuh8&bnE<%73R;^6OpI{r#E_<^ zImN7yfPr7mRz6mF2Mh&WbvNX|P%r4)y9V(@#ja%^Ot|SF1LI$ICC6=o8*M$Pb^-NN+ zMy||gn_+uYfZBMc3PVm;U0j&NJ61xlwEa&qLF)(eWTx)10dM|f?T-ikg!8c@D}MkU z3wtea)qQvHV2&MMrTOrC5?{$BD&VbC_u4g?lJ1im?sU#a1@@>%zXWz@(ArN8?#3+9u%r8bY>%2B$JL)2=|A%3Ps@@>wR-g@dfp*t;0&Q@pinncBb4qU>m zmTnSv4HTymQcZniznqljQuy3Py-3{h^1O@T+&}B%fr7B;4L)+PH=RLXZZBg%e zs=TJZ3WvS6EL_B}wvP==VX_ZU-IMJvhdVRW1Lxx?biXcE_MgP$1Uu^waLd0f0e;_l zMfBv*I3Y269A)zIW_2%m7Wq3KLuNGKYP%M$jEk{N2@ z`+19~OS&1iAfJmu#MEsE@9u)w^v%`ynlTAye#{sZkvEu@kK2ssSJ`tJw2Z>a1m~Pf z`GM#9RF;9(Dv$O+M3USy1WXd*EMnZfGVL>wM`a==Bqb+CGokm|Jym@rp|?ySrN|o? zIC<$h4YBB?xjf#Em;$({d3-=TjI$*T8_S%;9`H7%;rC8wP z;7AWmfzl*&3rXDvskaREwB+QH7QUh%BC$cQ%$hkg4-}O+J9%UNTy!N0w^bjZf>)ed zCWsG*J_ygWK&6HGt`cE8;QN5Sh6J1iRKE^gJ25}L?+VN;EzysDsi@ z=nF57YMpDjJq_WOyba!Thau3z9W_p|$5-O&bVW}tXX~za#kjGDvrO!QzQn#A({z7O z)WFJ}8-|P;?MU&yJn@R9@xF@H+AHB*9nSrf#URH`p5^233KzU>y+od_HP3p@N_np8RN zHaC&ge&>2ELn)_(JwfpHkbB7C7Dy!}yag zA`b~uM+}!NtyI`n4^7ROe#)Ou%#wgHSV}N-omi5+aBnS_z7V$#yH4)w18`;%ehsD7 zq)LS7<-Tdc!gtUEMz1@t8PK~&pc~fiH~zb}f(u@PZ%uEpmLc4pLcNV7$YS5QR2fsA zM@>z2Uy=Ot_-ms}>Gl#^W-Js|kmXU6TVA3Dt&VkRVVq9cN-%`R?-Q1w2Ety%nHURt z>C|vs1-oQU+$Y0piSsrPgnJy#5|zBl@7W=QVfxO5u!dM`4Du!{ZBH!&UyfeEPLdtL z?C4|;qKt&FeR*bdY3|2a?m(*~o?Ht*emei66ioDcM}5?A6U{{h)KLabvHXQJ6)PST z&5v26X%%M3H5i+(=PK;7_Ssh!MjzacM$xA-{5qHg?K;;(M#cCnwwUA{fa**=Fb4@l zmR4SPOHQ1XLRDc=Du1A;(3F0PB+(BUJ)FO}Tos67oIpQQBx_txY{T(@x5(?`FG}T_ zV`d`a@Z8)|%*5>>74&1ieZkNtKRDVoU2!ujyGKYr%{CP;pjeMTH2OpAM%(4<-R` ze&YjF!bH9cmw4Rr!?u}U&)y-}XjRq{HG zp$NIq=?KY+WwJ@05ItcuUTiE%k7K`xd<&z=!N}l{ z)LE+m$s0oOu{J(ea`~-r8HNtJ*68Rb;8{vjpZ6}Bl0~OjldpR%K+j)uco5-V9Es6$ zV8}0Mzs$00Ocz4I=&yoEBl7&|{krgZ&#WhOV`*t1y+UVPbcYJUsl4oH%@5w&T1)>4J{hiIXzY87sd)+g!H8qww+k;OO_^~#cd#h-Le`iSEP{FYuNE}vl|svPqsZt z`+3;CQ{P7DvLPr}?|44IF#;p$JJfN$r!Bp~E>hILVqd5qm%>proBpGUIn%?0=Z~m> zBu;#!6_laCT)a}wlgUnKvq_jQlR??KetE^++?|@+k`smy=1|l_gFVhx9+P zF%n!GpE${$dY-C0ioY1XG{X(}bk|eXcz}K(n>wmd0%sd{`l#4~eUB3d%LLw8_Gz>@ zw`W)7{#d5v9K=H$L@nC1kXBCv`u!I z-KO%g|EAwAC^a)M`p~549|(H|bGmP&#ZXD078$8gNc@F^k++*)LBv@1;bvP|&7FakT1>hBDTkKxZVJ9E%| z$vD0)V7H`YZ19a;CRi_)Hsoz1i-JAxkT2RqlHXOTjBALHb$f2ZPk8yO zQTWC{{OLQ;Fm-yv!8O;O?yoWtWoIs^+!L(H z^x)X{9E}2O$2B*+xjks;(oQTPXzjlQp2RR_P4on$1SM(ft_K0FLQISmy_aCdPGv@7 z;Ce_5ENQ6tuw$M2_iOi^NkA&MLUn7Qf~e}x4AiIT?oEuPtz@UMhMA4(Vnb?&q>KR9 zzE|GJ|DpUWx~1f6o#OV98YH^~THeal+CC4P75qT&+q|N$tiNtS^(`4?c!@&p7I#GFlg;zO=}$4|a4z$^ z0zQb(XvElDepan06f!@1^DzSa?-mj7hq9NJdO#YK@G-TiUO z{L}qN$do{ur?Zy~9J!&0|q_)WL0CPe@0wZFi#_Uu8HLFS25 zy?-yZYUTXna(u)r{GG8myMzC(;*4o1m?&i^G>jvd2Zz%f>j5`iMzgStcOKC5aG_}X6{1T&MI z5o%BKBoc1hzA9xEJj!{etz>>=Sz%+o70I?C_#Pg7D69cs)n*HQVqbm}7V@rvv%D!1 z$ZbG&gud8#?IW;OPuP`pRz2+lp^L;Nf z?`w%bm`!RTOD89MVo*VjhxBO+<-w9&;eHl(kP1tOx-y8#AhAZ96~tY>w7>05)@toW zEi)SH_5vADS`H?w5Se;oZ&Y5SwG~ph5%q)5_}z*_!rkqa-h(&4@SVR7bd^?D_v>I| z#PR>AQ~Am778>P;MON@tU!1t-|x6|!&>c@al?^b7@Fw2FU2i3 z!Qi0zEERJyc{E#3tC3hBnt!3uVlt>)7cTIosw|E%XC6%RbB}#d<)sqat>f)pb3T`hjaQWm?%+!vmuhL}$y&Mxxg&6q5p<58BD3$ucW-JnRZ zpNf+f)TS@9mio00A9yo*v~!HhgO=m03vnQq!%`;5nG;oWxu{>$ zfrm^Xy{wGQpA|%)5n3njGPr6MTzYdj+BCo6?n`9lX0+<0h+e;LSD|OeP(9@Y<)U^s zDI9&YD7dU^CLgCX?zf&NkjS)((c2y8nu6AxGgGyb2e<=VzvrhvZ_ZzRh}19Dg`tJx zT4+of+IS=tB^gR_48FJ-H?hUh{QUeS2z$p(%%I(MheY_-v9a7gE%D^ZU+$#?1=jB! z-JrvE%1) z(#5H({P4||X@;Iz@-cd}G(LH;W3}yN<2guEfcsEnHdnHbvv=iXB7uT4b1G*Th;C4B zm=v&eLwZehesW=e_M^=2K(7Za2rYPS6*KE}R%GQh@RN7AW~7~&-t&sS8qMJkmxN8A zVE_JGld>u%YRMlnLpaq4e(5}MhpBd{42y>YD1F^g2XaL2v|Q{J0=R?)B15qpspzw& zC;9C*X$QY6QnhpRHai@_tDo>iZQYEHMDwjU9pGe3zrhzqwB12Z%pI90Oa!KB?bWD* z3y$&EhGE|P#CarjW>g*i!+o^mI27#DaW4e8yhu?bks3|q<;TrdM~`Ju&0C~ymx4pJ z_A^KJ&sKwj52hc5xX||PfV!{x@0S~cU;dAHPzshb8k76=NhNV~wz~1zp0ARh$?8i{)NU@cJUDVo4eQyz zeTrPdeNc!pw$T3=vt(piCUMlQ)MbE8_5jblL`c%((>o~?RQi=^93B;qrVS2<1`B8NZy6PIq^Az3@b(<0%I6eD)2Eio4j!n| zsG%aC01I6#e)kc_#n^YcxL{eX^v?sY=d2fb02x(j!_u%eWnMy~RtsUqt2 zxmrT_AYZ5bXEi>29PkF%^To5Dw3q8^GqRQCG6aJkk)(FRi8GmE(%H!Pmm;V8GgZh9 z>1UdR%0dEl95d9_sKe_T%*}jRG1LB%&qpfoGha{R9aZKw;{6JL%|e`>>&Cu+*BK$R ziM8zuramg+4gE(Z%--mrG-+LfxgJj@kboVYu1gLi(N0YucaU##TOvD7=`U~@zIf$k zH&&=r_}~a?rdf!x2L5MH0Rz#Gl}@^)bwiI(d{Zu+ZmS#qioZR-z*)1}2Oca~>OM_pw|GrQi-Q!(X{XX0LnQ=Af)|5z$ykDP;2U4@#Rsb$ z@&EqF?0vxwfmEOLw*7a8nl#np)70oud`&}3#7uGAzDi*)!2SH}x~oJI=HU@bZzk=5 zoLFB)u)x}3Y3ku@FZ~l^J+LE=sxq)Z#Y^*7aNLvq-SfQoYoPBd6C69lAQbd7C@z0TiQ%Bu?69t!P;hV^sDaQyTgKQh|e*%wi5h3^vKsvLN z%#jE`@#Z^IV{2-8q>24k0qq%Tl|uhd>b)=4_0J+w9#^YnsDwnkMGtxp$b#pL%H=vT zZBZyXiIbFkRE8x#h1csfr^OLb^;GnqpDuol`}`Gwr0j-;fzXY6H=P3DbA4_8@5Ek< zj|=U}n*pR7d#J{!8+)W_CaQSpAlciZqj%!stFlS1C#H5{23J9Z&!OrqcwQ|N!>bRt zgQ_Vp)@BsPLgtQe!-4p^C@8v<{twHSQT#{ejD67nY7K*0=?sFe2Bbo7jpgvPwW{WY zsl{9zfKqsMvO*$O$!?=YA>RtBbDl1|AGb(&WIpru4aq{l5nn6rEbmmOTCNX9rZe=t{o-m=`)@>&kbAg{3@5aY_ix5Y^VJ~keQHaa7? zvh?}Iq7uTW$p>|&LR4Eq3{Nsa&b4yh$XDzW*Geb75rGQUsr&B48>5D&Q?2NcCn7z> zHWVFEa22iO$8avX5JOc?ASGF+xH<^?I-m?QB#xjif>*V)^Hi{vAsmx#2IX7wH9X5EB~7+eaU&7)qaM%8Oni%U@|A_4T_t``wGw9d~qH267LjTfj12RHCiDTsY-qA~ezk}njdf4(xTw%n~wm+9$<`!jv1jN-L zzAnTxzK+%pXZ9!URyJhYoTKNpKu`(~$xv#A77eX1nlijDgchx}gh$n%)X=jPoe~d8 z<4au~EyVE2&o`>BC?Mc_V<4i~die1LnoINLeoI-XU=?=5q8ot|M@$>w%0SZp-2ztK zrfE%Zcoq51gTBWv_)&}`1^CbE#rA)(dhu~#PB!5%tFQ#vQgg10&VH|zAaRfC_KfOs zX4n@S#nZqe;^UH$m0C$t#Qp#EjxALa3#iWX*ERhSfoyUTD}TIyq;XuKdfkxpFEET&Qxu3f{-|*z>_h!uEJj5V^q``=Q=jdc7?N zY9EHZlJ+=R{*7k7vMX-|R(P zhAkzwY+)vQM0tjzU()%pB$*YSO+rL(up$ZLqnas_<~A0^3lD_bcu@v>rS}`oJQ|+a z(v|%(=qVp2SGM})ROh+Qe|G=LZ}qs#$rwieh7}=!&0)iw?N_E|I`Q@&QAhOBBJs3Q z?tx5*bj!&!k3(*S-Ot+~kCHT^ByK!?yPDSXow{Up>CgMRwzw2}AHUnnZ5r6Bz|@g3 z7OnA+5|Q5(?)*IYXr!Mv3bHT|S~9(M7gp0ZC_Di6HD`8E;ne2c$bL|^G+|+R{_4t+ z+tYN6Dz(E?e@vL`_w{1k!Af=h`&-V{5lbIFxWDklZZWPi^7nGH^#V^mKa}Qsdj=oj zzXK>y^(5`fI%u|UEGA%k4!lnGGPs?k0$c2ClwbHuT>Xyl(`WqMWMe%3n%aPoF7ee( zm4SK+J^vwy`;f#n-F_k6>5njk{H&V*S6%A7rV6{<3PYe;hfhQ+Vqv(r#6U%>5AMGd z7f+ZE?}ZX`&-jq#ykb*{N(D`YLn2+1x;O4gU60e9XwHpKDpZUyZv7x0dp&~`HIMGE zjb++NbZ;_30>de;c@{S3M<>&~`^}>i@x8MKb(K19}Q~+#tR=_>wgB#^+to zfuTDY5xX`kNlOy&-OPmro~}y!exICqtaV^!`k7A>?!Kgt{(tx|Uum?S#LQ`B2MFMX PQ-G43nrywaY1sb)_;$MT literal 0 HcmV?d00001 diff --git a/vignettes/partial_files/figure-html/unnamed-chunk-3-1.png b/vignettes/partial_files/figure-html/unnamed-chunk-3-1.png new file mode 100644 index 0000000000000000000000000000000000000000..de3ac0336a55118c75e38c21347a48eb661ceadd GIT binary patch literal 12225 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 U<~ZMhYVrYcQp%FG;-;bhA2b+LG5`Po literal 0 HcmV?d00001 diff --git a/vignettes/partial_files/figure-html/unnamed-chunk-3-2.png b/vignettes/partial_files/figure-html/unnamed-chunk-3-2.png new file mode 100644 index 0000000000000000000000000000000000000000..da0edb7c588db2bc8a591f978b6d6bb6ba118b5e GIT binary patch literal 12026 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 literal 0 HcmV?d00001 diff --git a/vignettes/partial_files/figure-html/unnamed-chunk-4-1.png b/vignettes/partial_files/figure-html/unnamed-chunk-4-1.png new file mode 100644 index 0000000000000000000000000000000000000000..24cf5c3cc007f03862d381e9e226c71bf78df492 GIT binary patch literal 10647 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ਞSuCg#Z>oWSGcVJnVot(t~*OJ7Mxs!xjN-WRj!`n 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 C3-tm3 literal 0 HcmV?d00001 diff --git a/vignettes/partial_files/figure-html/unnamed-chunk-9-1.png b/vignettes/partial_files/figure-html/unnamed-chunk-9-1.png new file mode 100644 index 0000000000000000000000000000000000000000..f650359ff2a8fef6aa5bbd5b2ed2b11b85e1bb9f GIT binary patch literal 10996 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 Date: Mon, 24 Mar 2025 14:30:13 -0400 Subject: [PATCH 29/33] Update partial.Rmd --- vignettes/partial.Rmd | 75 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/vignettes/partial.Rmd b/vignettes/partial.Rmd index a18f3622..f0d07129 100644 --- a/vignettes/partial.Rmd +++ b/vignettes/partial.Rmd @@ -292,11 +292,25 @@ df <- inbreeding FamIDs <- unique(df$FamID) +inbreeding_list <- list() +results <- data.frame(FamIDs = FamIDs, + RMSE_partial_dad = rep(NA, length(FamIDs)), + RMSE_partial_mom = rep(NA, length(FamIDs)), + RMSE_classic_dad = rep(NA, length(FamIDs)), + RMSE_classic_mom = rep(NA, length(FamIDs)), + max_R_classic_dad = rep(NA, length(FamIDs)), + max_R_partial_dad = rep(NA, length(FamIDs)), + max_R_classic_mom = rep(NA, length(FamIDs)), + max_R_partial_mom = rep(NA, length(FamIDs)), + max_R_classic = rep(NA, length(FamIDs))) for (i in 1:length(FamIDs)) { -df_fam <- df[df$FamID == FamIDs[i],] +# make three versions to filter down +df_fam_dad<-df_fam_mom <- df_fam <- df[df$FamID == FamIDs[i],] +results$RMSE_partial_mom[i] <- sqrt(mean((ped_add_classic_complete-ped_add_partial_mom)^2)) + ped_add_partial_complete <- ped2com(df_fam, isChild_method= "partialparent", component = "additive", adjacency_method = "direct") @@ -304,6 +318,65 @@ ped_add_partial_complete <- ped2com(df_fam, isChild_method= "partialparent", ped_add_classic_complete <- ped2com(df_fam, isChild_method= "classic", component = "additive", adjacency_method = "direct") + + +# select first ID with a mom and dad +momid_to_cut <- df_fam$ID[!is.na(df_fam$momID)] %>% head(1) +dadid_to_cut <- df_fam$ID[!is.na(df_fam$dadID)] %>% head(1) + +df_fam_dad$dadID[df_fam$ID == dadid_to_cut] <- NA + +df_fam_mom$momID[df_fam$ID == momid_to_cut] <- NA + +ped_add_partial_dad <- ped2com(df_fam_dad, isChild_method= "partialparent", + component = "additive", + adjacency_method = "direct") +ped_add_classic_dad <- ped2com(df_fam_dad, isChild_method= "classic", + component = "additive", adjacency_method = "direct") + +results$RMSE_partial_dad[i] <- sqrt(mean((ped_add_classic_complete-ped_add_partial_dad)^2)) +results$RMSE_classic_dad[i] <- sqrt(mean((ped_add_classic_complete-ped_add_classic_dad)^2)) +results$max_R_classic_dad[i] <- max(as.matrix(ped_add_classic_dad)) +results$max_R_partial_dad[i] <- max(as.matrix(ped_add_partial_dad)) + + +ped_add_partial_mom <- ped2com(df_fam_mom, isChild_method= "partialparent", + component = "additive", + adjacency_method = "direct") + +ped_add_classic_mom <- ped2com(df_fam_mom, isChild_method= "classic", + component = "additive", adjacency_method = "direct") + +results$RMSE_partial_mom[i] <- sqrt(mean((ped_add_classic_complete-ped_add_partial_mom)^2)) +results$RMSE_classic_mom[i] <- sqrt(mean((ped_add_classic_complete-ped_add_classic_mom)^2)) +results$max_R_classic_mom[i] <- max(as.matrix(ped_add_classic_mom)) +results$max_R_partial_mom[i] <- max(as.matrix(ped_add_partial_mom)) +results$max_R_classic[i] <- max(as.matrix(ped_add_classic_complete)) + +inbreeding_list[[i]] <- list(df_fam=df_fam, + ped_add_partial_complete = ped_add_partial_complete, + ped_add_classic_complete = ped_add_classic_complete, + ped_add_partial_dad = ped_add_partial_dad, + ped_add_classic_dad = ped_add_classic_dad, + ped_add_partial_mom = ped_add_partial_mom, + ped_add_classic_mom = ped_add_classic_mom) + } +write.csv(results, "results.csv") +``` + +## Summary + +```{r} + +results <- results %>% as.data.frame() %>% mutate(RMSE_diff_dad = RMSE_classic_dad - RMSE_partial_dad, + RMSE_diff_mom = RMSE_classic_mom - RMSE_partial_mom) + +results + +results %>% as.data.frame() %>% select(-FamIDs) %>% summary() ``` + + +The partial parent method is more accurate when there are missing values in the parent adjacency matrix. From 578d3cd208f15e0324c31efc388a51c8e8019751 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Mon, 24 Mar 2025 15:36:40 -0400 Subject: [PATCH 30/33] documentation --- vignettes/partial.Rmd | 306 +++++--- vignettes/partial.html | 741 ++++++++++++++++++ .../figure-html/unnamed-chunk-10-1.png | Bin 10910 -> 0 bytes .../figure-html/unnamed-chunk-3-1.png | Bin 12225 -> 0 bytes .../figure-html/unnamed-chunk-3-2.png | Bin 12026 -> 0 bytes .../figure-html/unnamed-chunk-4-1.png | Bin 10647 -> 0 bytes .../figure-html/unnamed-chunk-6-1.png | Bin 11445 -> 0 bytes .../figure-html/unnamed-chunk-7-1.png | Bin 11370 -> 0 bytes .../figure-html/unnamed-chunk-9-1.png | Bin 10996 -> 0 bytes 9 files changed, 921 insertions(+), 126 deletions(-) create mode 100644 vignettes/partial.html delete mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-10-1.png delete mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-3-1.png delete mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-3-2.png delete mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-4-1.png delete mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-6-1.png delete mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-7-1.png delete mode 100644 vignettes/partial_files/figure-html/unnamed-chunk-9-1.png diff --git a/vignettes/partial.Rmd b/vignettes/partial.Rmd index f0d07129..f4087f73 100644 --- a/vignettes/partial.Rmd +++ b/vignettes/partial.Rmd @@ -18,11 +18,19 @@ library(tidyverse) # Introduction -The `ped2com` function can be used to calculate the components of the genetic relationship matrix. The function has two methods to handle the parent adjacency matrix. The first method is the classic method, which is the default method in the function. The second method is the partial parent method. The partial parent method is more accurate when there are missing values in the parent adjacency matrix. This vignette will show the difference between the two methods when there are missing values in the parent adjacency matrix. +The `ped2com` function computes relationship matrices from pedigree data using a recursive algorithm based on parent-offspring connections. Central to this computation is the parent `adjacency matrix`, which defines how individuals in the pedigree are connected across generations. The adjacency matrix acts as the structural input from which genetic relatedness is propagated. +The function offers two methods for constructing this matrix: + +1. The classic method, which assumes that all parents are known and that the adjacency matrix is complete. +2. The partial parent method, which allows for missing values in the parent adjacency matrix. + +When parent data are complete, both methods return equivalent results. But when parental information is missing, their behavior diverges. This vignette illustrates how and why these differences emerge, and under what conditions the partial method provides more accurate results. + +## Hazard Data Example + +We begin with the `hazard` dataset. First, we examine behavior under complete pedigree data. -### Hazzard data -#### Drop mom of individual 4 ```{r} library(BGmisc) @@ -30,11 +38,15 @@ library(BGmisc) data(hazard) df <- hazard # this is the data that we will use for the example +``` +```{r, echo=FALSE} -# LOOK AT THAT UNUNUAL DYADS +temp<-plotPedigree(df, title = "Complete Pedigree") +``` -## SISTER WIVES +We compute the additive genetic relationship matrix using both the classic and partial parent methods. Because the pedigree is complete, we expect no differences in the resulting matrices. +```{r} ped_add_partial_complete <- ped2com(df, isChild_method= "partialparent", component = "additive", @@ -42,24 +54,16 @@ ped_add_partial_complete <- ped2com(df, isChild_method= "partialparent", ped_add_classic_complete <- ped2com(df, isChild_method= "classic", component = "additive", adjacency_method = "direct") -write.csv(ped_add_partial_complete, "ped_add_partial_complete.csv") -write.csv(ped_add_classic_complete, "ped_add_classic_complete.csv") ``` +The following plots display the full additive matrices. These matrices should be identical. -These first two additive matrices show what happens in both methods when you have intact family trees. The two matrices should be the same. +This can be confirmed visually and numerically. ```{r} -library(ggcorrplot) library(corrplot) -if(FALSE){ -ggcorrplot(ped_add_partial_complete, hc.order = TRUE, - lab = TRUE, lab_size = 3, method = "square", outline.col = "white", digits = 3, - title = "Additive component - Partial parent method") - -} corrplot(as.matrix(ped_add_classic_complete), method = 'color', type = 'lower', col.lim = c(0,1), @@ -71,30 +75,29 @@ corrplot(as.matrix(ped_add_partial_complete), ``` -First, we will compare the results of the two methods for the additive component. We will use the direct adjacency method. The first method is the classic method, which is the default method in the function. The second method is the partial parent method. These should behave the same when there are no missing values. - -Indeed when we subtract one matrix from the other , we can see that they are the same. And we note that the RMSE is `r sqrt(mean((ped_add_classic_complete-ped_add_partial_complete)^2))`. +To verify this, we subtract one matrix from the other and calculate RMSE. The difference should be numerically zero. Indeed, it is `r sqrt(mean((ped_add_classic_complete-ped_add_partial_complete)^2))`. ```{r} corrplot(as.matrix(ped_add_classic_complete-ped_add_partial_complete), method = 'color', type = 'lower', col.lim = c(0,1), is.corr = FALSE) +``` -``` +## Introducing Missingness: Remove a Parent -However, when there are missing values, the partial parent method should be more accurate. For this example, we will remove the mother of individual 4. We will then compare the results of the two methods. The key comparisons are how each method performs relative to the "true" additive component. The true additive component is the additive component calculated without any missing data. And how they compare to each other. +To observe how the two methods diverge when data are incomplete, we remove one parent—starting with the mother of individual 4. -#### Drop Mom +```{r} +df$momID[df$ID == 4] <- NA +``` ```{r} - df$momID[df$ID == 4] <- NA - # add ped_add_partial_mom <- ped_add_partial<- ped2com(df, isChild_method= "partialparent", component = "additive", adjacency_method = "direct") @@ -105,107 +108,70 @@ ped_add_classic_mom <- ped_add_classic <- ped2com(df, isChild_method= "classic" ``` -As we can see, the two matrices are different. The RMSE between the two matrices is `r sqrt(mean((ped_add_classic-ped_add_partial)^2))`. +The two methods now treat individual 4 differently in the parent adjacency matrix. The classic method applies a fixed contribution because one parent remains. The partial parent method inflates the individual’s diagonal contribution to account for the missing parent. + +The resulting additive matrices reflect this difference. The RMSE between the two matrices is `r sqrt(mean((ped_add_classic-ped_add_partial)^2))`. -This plot shows the relatedness matrix when we use the classic method. ```{r} corrplot(as.matrix(ped_add_classic), - method = 'color', type = 'lower', col.lim = c(0,1), - is.corr = FALSE) -``` - - -This plot shows the relatedness matrix when we use the partial parent method. + method = 'color', type = 'lower', col.lim = c(0, 1), + is.corr = FALSE, title = "Classic (mother removed)") - -```{r} corrplot(as.matrix(ped_add_partial), - method = 'color', type = 'lower', col.lim = c(0,1), - is.corr = FALSE) + method = 'color', type = 'lower', col.lim = c(0, 1), + is.corr = FALSE, title = "Partial (mother removed)") ``` - - -When we compare these methods to the true additive component, we can see that the partial parent method is more accurate. The RMSE between the true additive component and the classic method is `r sqrt(mean((ped_add_classic_complete-ped_add_classic)^2))`. The RMSE between the true additive component and the partial parent method is `r sqrt(mean((ped_add_classic_complete-ped_add_partial)^2))`. And the RMSE between the classic method and the partial parent method is `r sqrt(mean((ped_add_classic-ped_add_partial)^2))`. +We quantify the overall matrix difference: ```{r} - -#true_diff <- as.matrix(ped_add_classic_complete-ped_add_partial) - -# filter rows that aren't impacted a.k.a. rows that are all 0 or columns that are all 0 - -#true_diff_thin <- as.data.frame(ped_add_classic_complete-ped_add_partial) %>% mutate(row = #row_number()) %>% -# filter(row %in% which(rowSums(ped_add_classic_complete-ped_add_partial)!=0)) - -#true_diff_thin %>% as.data.frame()%>% - # columns that sum to 0 so that we can remove them -# mutate(col = colSums(true_diff_thin)==1) -# -#%>% -# filter(col != 0) %>% select(-col, -row) %>% as.matrix() - -# key comparison isn't versus truth. it's versus the alterative solution - -# think about this more mason. these comparisons are important +sqrt(mean((ped_add_classic - ped_add_partial)^2)) ``` - -The classic adjustment compared to the true additive component is shown below. +Next, we compare each method to the matrix from the complete pedigree. This evaluates how much each method deviates from the correct additive structure. ```{r} -corrplot(as.matrix(ped_add_classic_complete-ped_add_classic), - method = 'color', type = 'lower', col.lim = c(0,1), +corrplot(as.matrix(ped_add_classic_complete - ped_add_classic), + method = 'color', type = 'lower', col.lim = c(0, 1), is.corr = FALSE) -sqrt(mean((ped_add_classic_complete-ped_add_classic)^2)) +sqrt(mean((ped_add_classic_complete - ped_add_classic)^2)) -``` +``` -The partial parent adjustment compared to the true additive component is shown below. - +The RMSE between the true additive component and the classic method is `r sqrt(mean((ped_add_classic_complete-ped_add_classic)^2))`. ```{r} -corrplot(as.matrix(ped_add_classic_complete-ped_add_partial), - method = 'color', type = 'lower', col.lim = c(0,1), + +corrplot(as.matrix(ped_add_classic_complete - ped_add_partial), + method = 'color', type = 'lower', col.lim = c(0, 1), is.corr = FALSE) -sqrt(mean((ped_add_classic_complete-ped_add_partial)^2)) +sqrt(mean((ped_add_classic_complete - ped_add_partial)^2)) ``` +The RMSE between the true additive component and the partial parent method is `r sqrt(mean((ped_add_classic_complete-ped_add_partial)^2))`. -The classic adjustment compared to the partial parent adjustment is shown below. +The partial method shows smaller deviations from the complete matrix, confirming that it better preserves relatedness structure when one parent is missing. -```{r} -corrplot(as.matrix(ped_add_partial-ped_add_classic), - method = 'color', type = 'lower', col.lim = c(0,1), - is.corr = FALSE) -sqrt(mean((ped_add_partial-ped_add_classic)^2)) - -``` +### Removing the Father Instead -#### Drop dad of individual 4 +We now repeat the same process, this time removing the father of individual 4. -```{r} +```{r} data(hazard) df <- hazard # this is the data that we will use for the example -``` - - - -What happens if we drop the dad of individual 4? - -```{r} df$dadID[df$ID == 4] <- NA # add @@ -221,68 +187,47 @@ ped_add_classic_dad <- ped_add_classic <- ped2com(df, isChild_method= "classic" As we can see, the two matrices are different. The RMSE between the two matrices is `r sqrt(mean((ped_add_classic-ped_add_partial)^2))`. -This plot shows the relatedness matrix when we use the classic method. - ```{r} -corrplot(as.matrix(ped_add_classic), - method = 'color', type = 'lower', col.lim = c(0,1), - is.corr = FALSE) -``` - - -This plot shows the relatedness matrix when we use the partial parent method. +corrplot(as.matrix(ped_add_classic_dad), + method = 'color', type = 'lower', col.lim = c(0, 1), + is.corr = FALSE, title = "Classic (father removed)") +corrplot(as.matrix(ped_add_partial_dad), + method = 'color', type = 'lower', col.lim = c(0, 1), + is.corr = FALSE, title = "Partial (father removed)") -```{r} -corrplot(as.matrix(ped_add_partial), - method = 'color', type = 'lower', col.lim = c(0,1), - is.corr = FALSE) ``` +Again, we compare to the true matrix from the complete pedigree: - -When we compare these methods to the true additive component, we can see that the partial parent method is more accurate. The RMSE between the true additive component and the classic method is `r sqrt(mean((ped_add_classic_complete-ped_add_classic)^2))`. The RMSE between the true additive component and the partial parent method is `r sqrt(mean((ped_add_classic_complete-ped_add_partial)^2))`. And the RMSE between the classic method and the partial parent method is `r sqrt(mean((ped_add_classic-ped_add_partial)^2))`. - - -The classic adjustment compared to the true additive component is shown below. - ```{r} -corrplot(as.matrix(ped_add_classic_complete-ped_add_classic), - method = 'color', type = 'lower', col.lim = c(0,1), +corrplot(as.matrix(ped_add_classic_complete - ped_add_classic), + method = 'color', type = 'lower', col.lim = c(0, 1), is.corr = FALSE) -sqrt(mean((ped_add_classic_complete-ped_add_classic)^2)) +sqrt(mean((ped_add_classic_complete - ped_add_classic)^2)) ``` -The partial parent adjustment compared to the true additive component is shown below. - - ```{r} -corrplot(as.matrix(ped_add_classic_complete-ped_add_partial), - method = 'color', type = 'lower', col.lim = c(0,1), + +corrplot(as.matrix(ped_add_classic_complete - ped_add_partial), + method = 'color', type = 'lower', col.lim = c(0, 1), is.corr = FALSE) -sqrt(mean((ped_add_classic_complete-ped_add_partial)^2)) +sqrt(mean((ped_add_classic_complete - ped_add_partial)^2)) ``` +The partial parent method again yields a matrix closer to the full-data version. -The classic adjustment compared to the partial parent adjustment is shown below. -```{r} -corrplot(as.matrix(ped_add_partial-ped_add_classic), - method = 'color', type = 'lower', col.lim = c(0,1), - is.corr = FALSE) - -sqrt(mean((ped_add_partial-ped_add_classic)^2)) - -``` +## Inbreeding Dataset: Family-Level Evaluation -## Inbreeding +To generalize the comparison across a larger and more varied set of pedigrees, we use the `inbreeding` dataset. Each family in this dataset is analyzed independently. ```{r} @@ -292,6 +237,19 @@ df <- inbreeding FamIDs <- unique(df$FamID) +``` + +For each one, we construct the additive relationship matrix under complete information and then simulate two missingness scenarios: + +- Missing mother: One individual with a known mother is randomly selected, and the mother's ID is set to NA. + +- Missing father: Similarly, one individual with a known father is selected, and the father's ID is set to NA. + + +In each condition, we recompute the additive matrix using both the classic and partial parent methods. We then calculate the RMSE between each estimate and the matrix from the complete pedigree. This allows us to quantify which method more accurately reconstructs the original relatedness structure when parental data are partially missing. + + +```{r} inbreeding_list <- list() results <- data.frame(FamIDs = FamIDs, RMSE_partial_dad = rep(NA, length(FamIDs)), @@ -303,6 +261,14 @@ results <- data.frame(FamIDs = FamIDs, max_R_classic_mom = rep(NA, length(FamIDs)), max_R_partial_mom = rep(NA, length(FamIDs)), max_R_classic = rep(NA, length(FamIDs))) +``` + +The loop below performs this procedure for all families in the dataset and stores both the RMSEs and the maximum relatedness values. + + +```{r} + + for (i in 1:length(FamIDs)) { # make three versions to filter down @@ -363,20 +329,108 @@ inbreeding_list[[i]] <- list(df_fam=df_fam, } -write.csv(results, "results.csv") ``` +### Example: Family ``r FamIDs[1]`` + + +To understand what these matrices look like, we visualize them for one representative family. For this example, we select the first family in the dataset. + +```{r echo=FALSE, message=FALSE, warning=FALSE} +temp<- plotPedigree(inbreeding_list[[1]]$df_fam, title = "Family 1",verbose = FALSE) +``` + +```{r} +# pull the first family from the list +fam1 <- inbreeding_list[[1]] + +corrplot(as.matrix(fam1$ped_add_classic_complete), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE, title = "Classic - Complete") + +corrplot(as.matrix(fam1$ped_add_classic_mom), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE, title = "Classic - Mom Missing") + +corrplot(as.matrix(fam1$ped_add_partial_mom), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE, title = "Partial - Mom Missing") + +corrplot(as.matrix(fam1$ped_add_classic_dad), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE, title = "Classic - Dad Missing") + +corrplot(as.matrix(fam1$ped_add_partial_dad), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE, title = "Partial - Dad Missing") +``` + + +To visualize the differences from the true matrix: + +```{r} +corrplot(as.matrix(fam1$ped_add_classic_complete - fam1$ped_add_classic_mom), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE, title = "Classic Mom Diff from Complete") + +corrplot(as.matrix(fam1$ped_add_classic_complete - fam1$ped_add_partial_mom), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE, title = "Partial Mom Diff from Complete") + +corrplot(as.matrix(fam1$ped_add_classic_complete - fam1$ped_add_classic_dad), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE, title = "Classic Dad Diff from Complete") + +corrplot(as.matrix(fam1$ped_add_classic_complete - fam1$ped_add_partial_dad), + method = 'color', type = 'lower', col.lim = c(0,1), + is.corr = FALSE, title = "Partial Dad Diff from Complete") + +``` + +These plots show how each method responds to missing data, and whether it maintains consistency with the complete pedigree. We observe that the partial parent method typically introduces smaller deviations. If desired, this same diagnostic can be repeated for additional families, such as inbreeding_list[[2]]. + + + + ## Summary +Across all families in the inbreeding dataset, the results show a consistent pattern: +the partial parent method outperforms the classic method in reconstructing the additive genetic relationship matrix when either a mother or a father is missing. + +To make this explicit, we calculate the RMSE difference between methods. A positive value means that the partial method had lower RMSE (i.e., better accuracy) than the classic method: + ```{r} results <- results %>% as.data.frame() %>% mutate(RMSE_diff_dad = RMSE_classic_dad - RMSE_partial_dad, RMSE_diff_mom = RMSE_classic_mom - RMSE_partial_mom) +``` + +We can then summarize the pattern across families: + + +```{r} + +results %>% + select(RMSE_diff_mom, RMSE_diff_dad) %>% + summary() +``` + +In all families, both `RMSE_diff_mom` and `RMSE_diff_dad` are positive—indicating that the classic method produces larger the errors relative to the partial method. This holds regardless of whether the missing parent is a mother or a father. -results +To verify this directly: -results %>% as.data.frame() %>% select(-FamIDs) %>% summary() +```{r} +mean(results$RMSE_diff_mom > 0, na.rm = TRUE) +mean(results$RMSE_diff_dad > 0, na.rm = TRUE) ``` +These proportions show how often the partial method produces a lower RMSE across the dataset. This confirms the earlier findings: when pedigree data are incomplete, the partial parent method more faithfully reconstructs the full-data relatedness matrix. + +```{r} +results %>% as.data.frame() %>% select(-FamIDs,-RMSE_diff_mom,-RMSE_diff_dad,-max_R_classic_dad, + -max_R_partial_dad,-max_R_classic_mom,-max_R_partial_mom,-max_R_classic) %>% summary() +``` + + + -The partial parent method is more accurate when there are missing values in the parent adjacency matrix. diff --git a/vignettes/partial.html b/vignettes/partial.html new file mode 100644 index 00000000..e0211151 --- /dev/null +++ b/vignettes/partial.html @@ -0,0 +1,741 @@ + + + + + + + + + + + + + + +Partial + + + + + + + + + + + + + + + + + + + + + + + + + + +

Partial

+ + + +
+

Introduction

+

The ped2com function computes relationship matrices from +pedigree data using a recursive algorithm based on parent-offspring +connections. Central to this computation is the parent +adjacency matrix, which defines how individuals in the +pedigree are connected across generations. The adjacency matrix acts as +the structural input from which genetic relatedness is propagated.

+

The function offers two methods for constructing this matrix:

+
    +
  1. The classic method, which assumes that all parents are known and +that the adjacency matrix is complete.
  2. +
  3. The partial parent method, which allows for missing values in the +parent adjacency matrix.
  4. +
+

When parent data are complete, both methods return equivalent +results. But when parental information is missing, their behavior +diverges. This vignette illustrates how and why these differences +emerge, and under what conditions the partial method provides more +accurate results.

+
+

Hazard Data Example

+

We begin with the hazard dataset. First, we examine +behavior under complete pedigree data.

+
library(BGmisc)
+
+data(hazard)
+
+df <- hazard # this is the data that we will use for the example
+

+

We compute the additive genetic relationship matrix using both the +classic and partial parent methods. Because the pedigree is complete, we +expect no differences in the resulting matrices.

+

+ped_add_partial_complete <- ped2com(df, isChild_method= "partialparent",
+                                  component = "additive",
+                                  adjacency_method = "direct")
+ped_add_classic_complete <- ped2com(df, isChild_method= "classic",
+                                  component = "additive", adjacency_method = "direct")
+

The following plots display the full additive matrices. These +matrices should be identical.

+

This can be confirmed visually and numerically.

+

+library(corrplot)
+#> Warning: package 'corrplot' was built under R version 4.4.3
+#> corrplot 0.95 loaded
+
+
+corrplot(as.matrix(ped_add_classic_complete),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE, title = "Additive component - Classic method")
+

+

+corrplot(as.matrix(ped_add_partial_complete),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE, title = "Additive component - Partial parent method")
+

+

To verify this, we subtract one matrix from the other and calculate +RMSE. The difference should be numerically zero. Indeed, it is 0.

+

+corrplot(as.matrix(ped_add_classic_complete-ped_add_partial_complete),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE)
+#> Warning in corrplot(as.matrix(ped_add_classic_complete -
+#> ped_add_partial_complete), : col.lim interval too wide, please set a suitable
+#> value
+

+
+
+

Introducing Missingness: Remove a Parent

+

To observe how the two methods diverge when data are incomplete, we +remove one parent—starting with the mother of individual 4.

+
df$momID[df$ID == 4] <- NA
+

+ped_add_partial_mom <- ped_add_partial<- ped2com(df, isChild_method= "partialparent",
+                             component = "additive",
+                             adjacency_method = "direct")
+  
+ped_add_classic_mom <-  ped_add_classic <- ped2com(df, isChild_method= "classic",
+                             component = "additive", adjacency_method = "direct")
+

The two methods now treat individual 4 differently in the parent +adjacency matrix. The classic method applies a fixed contribution +because one parent remains. The partial parent method inflates the +individual’s diagonal contribution to account for the missing +parent.

+

The resulting additive matrices reflect this difference. The RMSE +between the two matrices is 0.009811.

+
corrplot(as.matrix(ped_add_classic),
+         method = 'color', type = 'lower', col.lim = c(0, 1),
+         is.corr = FALSE, title = "Classic (mother removed)")
+

+

+corrplot(as.matrix(ped_add_partial),
+         method = 'color', type = 'lower', col.lim = c(0, 1),
+         is.corr = FALSE, title = "Partial (mother removed)")
+

+

We quantify the overall matrix difference:

+
sqrt(mean((ped_add_classic - ped_add_partial)^2))
+#> [1] 0.009811047
+

Next, we compare each method to the matrix from the complete +pedigree. This evaluates how much each method deviates from the correct +additive structure.

+
corrplot(as.matrix(ped_add_classic_complete - ped_add_classic),
+         method = 'color', type = 'lower', col.lim = c(0, 1),
+         is.corr = FALSE)
+

+

+sqrt(mean((ped_add_classic_complete - ped_add_classic)^2))
+#> [1] 0.02991371
+

The RMSE between the true additive component and the classic method +is 0.0299137.

+

+corrplot(as.matrix(ped_add_classic_complete - ped_add_partial),
+         method = 'color', type = 'lower', col.lim = c(0, 1),
+         is.corr = FALSE)
+

+

+sqrt(mean((ped_add_classic_complete - ped_add_partial)^2))
+#> [1] 0.02825904
+

The RMSE between the true additive component and the partial parent +method is 0.028259.

+

The partial method shows smaller deviations from the complete matrix, +confirming that it better preserves relatedness structure when one +parent is missing.

+
+

Removing the Father Instead

+

We now repeat the same process, this time removing the father of +individual 4.

+

+data(hazard)
+
+df <- hazard # this is the data that we will use for the example
+
+
+  df$dadID[df$ID == 4] <- NA
+  # add
+ped_add_partial_dad <- ped_add_partial<- ped2com(df, isChild_method= "partialparent",
+                             component = "additive",
+                             adjacency_method = "direct")
+  
+ped_add_classic_dad <-  ped_add_classic <- ped2com(df, isChild_method= "classic",
+                             component = "additive", adjacency_method = "direct")
+

As we can see, the two matrices are different. The RMSE between the +two matrices is 0.009811.

+
corrplot(as.matrix(ped_add_classic_dad),
+         method = 'color', type = 'lower', col.lim = c(0, 1),
+         is.corr = FALSE, title = "Classic (father removed)")
+

+

+corrplot(as.matrix(ped_add_partial_dad),
+         method = 'color', type = 'lower', col.lim = c(0, 1),
+         is.corr = FALSE, title = "Partial (father removed)")
+

+

Again, we compare to the true matrix from the complete pedigree:

+
corrplot(as.matrix(ped_add_classic_complete - ped_add_classic),
+         method = 'color', type = 'lower', col.lim = c(0, 1),
+         is.corr = FALSE)
+

+

+sqrt(mean((ped_add_classic_complete - ped_add_classic)^2))
+#> [1] 0.02991371
+

+corrplot(as.matrix(ped_add_classic_complete - ped_add_partial),
+         method = 'color', type = 'lower', col.lim = c(0, 1),
+         is.corr = FALSE)
+

+

+sqrt(mean((ped_add_classic_complete - ped_add_partial)^2))
+#> [1] 0.02825904
+

The partial parent method again yields a matrix closer to the +full-data version.

+
+
+
+

Inbreeding Dataset: Family-Level Evaluation

+

To generalize the comparison across a larger and more varied set of +pedigrees, we use the inbreeding dataset. Each family in +this dataset is analyzed independently.

+

+data("inbreeding")
+
+df <- inbreeding
+
+FamIDs <- unique(df$FamID)
+

For each one, we construct the additive relationship matrix under +complete information and then simulate two missingness scenarios:

+
    +
  • Missing mother: One individual with a known mother is randomly +selected, and the mother’s ID is set to NA.

  • +
  • Missing father: Similarly, one individual with a known father is +selected, and the father’s ID is set to NA.

  • +
+

In each condition, we recompute the additive matrix using both the +classic and partial parent methods. We then calculate the RMSE between +each estimate and the matrix from the complete pedigree. This allows us +to quantify which method more accurately reconstructs the original +relatedness structure when parental data are partially missing.

+
inbreeding_list <- list()
+results <- data.frame(FamIDs = FamIDs,
+                      RMSE_partial_dad = rep(NA, length(FamIDs)),
+                      RMSE_partial_mom = rep(NA, length(FamIDs)),
+                      RMSE_classic_dad = rep(NA, length(FamIDs)),
+                      RMSE_classic_mom = rep(NA, length(FamIDs)),
+                      max_R_classic_dad = rep(NA, length(FamIDs)),
+                      max_R_partial_dad = rep(NA, length(FamIDs)),
+                      max_R_classic_mom = rep(NA, length(FamIDs)),
+                      max_R_partial_mom = rep(NA, length(FamIDs)),
+                      max_R_classic = rep(NA, length(FamIDs)))
+

The loop below performs this procedure for all families in the +dataset and stores both the RMSEs and the maximum relatedness +values.

+

+
+for (i in 1:length(FamIDs)) {
+  
+# make three versions to filter down
+df_fam_dad<-df_fam_mom <- df_fam <- df[df$FamID == FamIDs[i],]
+  
+results$RMSE_partial_mom[i] <- sqrt(mean((ped_add_classic_complete-ped_add_partial_mom)^2))
+
+  
+ped_add_partial_complete <- ped2com(df_fam, isChild_method= "partialparent",
+                                  component = "additive",
+                                  adjacency_method = "direct")
+
+ped_add_classic_complete <- ped2com(df_fam, isChild_method= "classic",
+                                  component = "additive",
+                                  adjacency_method = "direct")
+
+
+# select first ID with a mom and dad
+momid_to_cut <- df_fam$ID[!is.na(df_fam$momID)] %>% head(1)
+dadid_to_cut <- df_fam$ID[!is.na(df_fam$dadID)] %>% head(1)
+
+df_fam_dad$dadID[df_fam$ID == dadid_to_cut] <- NA
+
+df_fam_mom$momID[df_fam$ID == momid_to_cut] <- NA
+
+ped_add_partial_dad <- ped2com(df_fam_dad, isChild_method= "partialparent",
+                             component = "additive",
+                             adjacency_method = "direct")
+ped_add_classic_dad <- ped2com(df_fam_dad, isChild_method= "classic",
+                             component = "additive", adjacency_method = "direct")
+
+results$RMSE_partial_dad[i] <- sqrt(mean((ped_add_classic_complete-ped_add_partial_dad)^2))
+results$RMSE_classic_dad[i] <- sqrt(mean((ped_add_classic_complete-ped_add_classic_dad)^2))
+results$max_R_classic_dad[i] <-  max(as.matrix(ped_add_classic_dad))
+results$max_R_partial_dad[i] <-  max(as.matrix(ped_add_partial_dad))
+
+
+ped_add_partial_mom <- ped2com(df_fam_mom, isChild_method= "partialparent",
+                             component = "additive",
+                             adjacency_method = "direct")
+
+ped_add_classic_mom <-  ped2com(df_fam_mom, isChild_method= "classic",
+                             component = "additive", adjacency_method = "direct")
+
+results$RMSE_partial_mom[i] <- sqrt(mean((ped_add_classic_complete-ped_add_partial_mom)^2))
+results$RMSE_classic_mom[i] <- sqrt(mean((ped_add_classic_complete-ped_add_classic_mom)^2))
+results$max_R_classic_mom[i] <-  max(as.matrix(ped_add_classic_mom))
+results$max_R_partial_mom[i] <-  max(as.matrix(ped_add_partial_mom))
+results$max_R_classic[i] <-  max(as.matrix(ped_add_classic_complete))
+
+inbreeding_list[[i]] <- list(df_fam=df_fam,
+                            ped_add_partial_complete = ped_add_partial_complete,
+                             ped_add_classic_complete = ped_add_classic_complete,
+                             ped_add_partial_dad = ped_add_partial_dad,
+                             ped_add_classic_dad = ped_add_classic_dad,
+                             ped_add_partial_mom = ped_add_partial_mom,
+                             ped_add_classic_mom = ped_add_classic_mom)
+
+}
+
+

Example: Family 1

+

To understand what these matrices look like, we visualize them for +one representative family. For this example, we select the first family +in the dataset.

+

+
# pull the first family from the list
+fam1 <- inbreeding_list[[1]]
+
+corrplot(as.matrix(fam1$ped_add_classic_complete),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE, title = "Classic - Complete")
+

+

+corrplot(as.matrix(fam1$ped_add_classic_mom),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE, title = "Classic - Mom Missing")
+

+

+corrplot(as.matrix(fam1$ped_add_partial_mom),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE, title = "Partial - Mom Missing")
+

+

+corrplot(as.matrix(fam1$ped_add_classic_dad),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE, title = "Classic - Dad Missing")
+

+

+corrplot(as.matrix(fam1$ped_add_partial_dad),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE, title = "Partial - Dad Missing")
+

+

To visualize the differences from the true matrix:

+
corrplot(as.matrix(fam1$ped_add_classic_complete - fam1$ped_add_classic_mom),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE, title = "Classic Mom Diff from Complete")
+

+

+corrplot(as.matrix(fam1$ped_add_classic_complete - fam1$ped_add_partial_mom),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE, title = "Partial Mom Diff from Complete")
+

+

+corrplot(as.matrix(fam1$ped_add_classic_complete - fam1$ped_add_classic_dad),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE, title = "Classic Dad Diff from Complete")
+

+

+corrplot(as.matrix(fam1$ped_add_classic_complete - fam1$ped_add_partial_dad),
+         method = 'color', type = 'lower', col.lim = c(0,1),
+         is.corr = FALSE, title = "Partial Dad Diff from Complete")
+

+

These plots show how each method responds to missing data, and +whether it maintains consistency with the complete pedigree. We observe +that the partial parent method typically introduces smaller deviations. +If desired, this same diagnostic can be repeated for additional +families, such as inbreeding_list[[2]].

+
+
+
+

Summary

+

Across all families in the inbreeding dataset, the results show a +consistent pattern: the partial parent method outperforms the classic +method in reconstructing the additive genetic relationship matrix when +either a mother or a father is missing.

+

To make this explicit, we calculate the RMSE difference between +methods. A positive value means that the partial method had lower RMSE +(i.e., better accuracy) than the classic method:

+

+results <- results %>% as.data.frame() %>% mutate(RMSE_diff_dad = RMSE_classic_dad - RMSE_partial_dad,
+                                                   RMSE_diff_mom = RMSE_classic_mom - RMSE_partial_mom)
+

We can then summarize the pattern across families:

+

+results %>% 
+  select(RMSE_diff_mom, RMSE_diff_dad) %>% 
+  summary()
+#>  RMSE_diff_mom      RMSE_diff_dad     
+#>  Min.   :0.001222   Min.   :0.001222  
+#>  1st Qu.:0.001869   1st Qu.:0.002036  
+#>  Median :0.002538   Median :0.002520  
+#>  Mean   :0.005763   Mean   :0.005786  
+#>  3rd Qu.:0.005625   3rd Qu.:0.005625  
+#>  Max.   :0.024221   Max.   :0.024221
+

In all families, both RMSE_diff_mom and +RMSE_diff_dad are positive—indicating that the classic +method produces larger the errors relative to the partial method. This +holds regardless of whether the missing parent is a mother or a +father.

+

To verify this directly:

+
mean(results$RMSE_diff_mom > 0, na.rm = TRUE)
+#> [1] 1
+mean(results$RMSE_diff_dad > 0, na.rm = TRUE)
+#> [1] 1
+

These proportions show how often the partial method produces a lower +RMSE across the dataset. This confirms the earlier findings: when +pedigree data are incomplete, the partial parent method more faithfully +reconstructs the full-data relatedness matrix.

+
results %>% as.data.frame() %>% select(-FamIDs,-RMSE_diff_mom,-RMSE_diff_dad,-max_R_classic_dad,
+                                       -max_R_partial_dad,-max_R_classic_mom,-max_R_partial_mom,-max_R_classic) %>% summary()
+#>  RMSE_partial_dad  RMSE_partial_mom  RMSE_classic_dad  RMSE_classic_mom 
+#>  Min.   :0.04773   Min.   :0.04773   Min.   :0.04895   Min.   :0.04895  
+#>  1st Qu.:0.05570   1st Qu.:0.05349   1st Qu.:0.05774   1st Qu.:0.05555  
+#>  Median :0.06206   Median :0.06899   Median :0.06457   Median :0.07158  
+#>  Mean   :0.07545   Mean   :0.07686   Mean   :0.08124   Mean   :0.08262  
+#>  3rd Qu.:0.08237   3rd Qu.:0.08323   3rd Qu.:0.08866   3rd Qu.:0.08866  
+#>  Max.   :0.15547   Max.   :0.15547   Max.   :0.17969   Max.   :0.17969
+
+
+ + + + + + + + + + + diff --git a/vignettes/partial_files/figure-html/unnamed-chunk-10-1.png b/vignettes/partial_files/figure-html/unnamed-chunk-10-1.png deleted file mode 100644 index b6108a589d493072948cf2175a623fa19e9cd650..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10910 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 PQ-G43nrywaY1sb)_;$MT diff --git a/vignettes/partial_files/figure-html/unnamed-chunk-3-1.png b/vignettes/partial_files/figure-html/unnamed-chunk-3-1.png deleted file mode 100644 index de3ac0336a55118c75e38c21347a48eb661ceadd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12225 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 U<~ZMhYVrYcQp%FG;-;bhA2b+LG5`Po diff --git a/vignettes/partial_files/figure-html/unnamed-chunk-3-2.png b/vignettes/partial_files/figure-html/unnamed-chunk-3-2.png deleted file mode 100644 index da0edb7c588db2bc8a591f978b6d6bb6ba118b5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12026 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 diff --git a/vignettes/partial_files/figure-html/unnamed-chunk-4-1.png b/vignettes/partial_files/figure-html/unnamed-chunk-4-1.png deleted file mode 100644 index 24cf5c3cc007f03862d381e9e226c71bf78df492..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10647 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ਞSuCg#Z>oWSGcVJnVot(t~*OJ7Mxs!xjN-WRj!`n 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 C3-tm3 diff --git a/vignettes/partial_files/figure-html/unnamed-chunk-9-1.png b/vignettes/partial_files/figure-html/unnamed-chunk-9-1.png deleted file mode 100644 index f650359ff2a8fef6aa5bbd5b2ed2b11b85e1bb9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10996 zcmbWdbx>SQ^es9BcXtMYI}93RaF<{qFj%nQ?(XguBxryjK?g!`x4|{IyIb%edGp=h zt$J0jUe&F-fAl_e>h$S8b-MT7YpvZe8fpsI7!())003J_QC158KzRFKLwf@N0CKj3 z7vL9kXGJ|X005`&zlH#FD*p@syag!9N@;uNp5-~kQ(5I5NDOo_3V#h_+1v!w6^_PR zMG^9#MpfWb<$S(qtzKKKY)eVOlNZtrcmp)zp65OXYZ7Hy>mIay6j-fpRPhw5#jD%T z@cz?lqz{TBC{c0NBR}F56?OF>kXdB-xr-Llf&}69;I62stoWzq^>N&N@>$&0rnNFZ zu%fjr=;P#dKwuEjXxLqSXhrh%P~O zzTg*wUdHHzN@IH(0a}|p!kg$kuu$-7@-&g5c zP?=b&|H%YsHI^XdiFao}I8UG6tjI*cMV*5ok%v=4Ir&@A2} zOrN|zd;&fZLgllNyQhV^exW-kd*~4oHsab;DrYE6K8A*{F~c8g z%m`V?COE9Zq$eA3o+QGa+%~xn5z_dhVGoBKB(;d-GkQZEI6*mn8jrVvp?nBEoqWa^v#V;Y>)^5jJzaHPkPK@o zz7M=IF+Eb2$nIY%?O(V>(Gkwl_&E7fE78($PXgI{AbQ^j$jp*joSeOiRpmj5D^WEqU>vjR>- zH#{|Jfb`}{%u4k+Xz0-CNhCiIlUV&!6lFg3bmfCqvL7~?@hH6uIbT+EBU0ws(@0X5 zi)*C)Eah0ERf(exMl~rX%NdRndIQY=Fyi;mp;iZ2zuQ?ZsP!X&iM_#W-2m>d`#(jL zq~5}!Eipgo6k!Jys&!{;h4>_tsPt4?VCF({J>nR@x}%e)8OXZHScN(F&zWGyb04@> zX_gCq#k7#2kP29ql+)HrR?1A~X|cF7Y5;W-4iaSwbRS!Yzb{BSKy}Sb`mC@hO z!=0_?zDMM*^rboHoG{LqTGr6CR8s-!*x>wleuMxg2dt)u3wa4oa^?u_1@3e@t(aVw z_V%Nr-42Mdi9HkK>vl0v{JlIH3jgQCJ0OcwAZdHn;!SDL{OBa24sf3&*g3(JYcX)7 zUtjs=Z5^jHw`+D-K!~{?w2N#^^>orC?Ddy_VmdMMzCb+Tw0*_Lz8RrC+^2lN)T`X0 z&PW|*4jnzB-JFO(aFp@Z&n~oMuXOIq0h@A8ZHJjG%n3bBjm%JC2Ema4Yd#@~_+MNa z!TLPb_CjNfYgM*#dMt#zJRr)s!&M!fhy4pAa?1(Z=a!L<*|!b9>=e8c-ZJWlrVi+x z=zDb{BTgIv5>RwvMSl00))9O5mHSu+ z+RJN}3hl%@449{j3GJ&72EP~^h8#n#>ZOtw>NTqN8uek*8FI8-rSpmCCUE7LO@JC0 zNbMp$R~Oa_TNPw{i_etguid}VPPnK@s2C7DYM!Z zG0jXVs3d|?i?^V3WBX9EJDpOm-$c%``XNb`FoHAn%>3lkR!erxO*&zNN033o0PdT- z;P;3!0!i{kK4(Zy@67#@Vqur(3^eMA3c7&x4O4Y>Y&>E4>)k^ZPD}3NnyboY8NnuU$xsn$ z+r80u%YnnM={`h#)m~z8$>*I_QZ_?(6E$Ti0=}X-hd*?VT_@I-HUk zSg&As1{E2fyk}*PYiKqYf~ECsSP-7s8Ua(&cJ?=b&bexOW@IwUU0Z|rcWh3BPcE*b z4qHF->lIj|d+mdSuOc3Fu;-Ge#@1xS^QqR_xH!+I$Q6T@ivK4&=QZaHE0zWYA_r3Y zITU}Hwsd|*d!pnKk8hJ9KGy08^8G=OuOKI7qtJ=g7UwUEqnzb%vV8knOjUz87Q>bd z^{f(@%4b!UrrwMpIH<3|QeN0cQ#A0i`$Ez8QHwFR;(6vXPWQFI?~)qV(-q&p(&C>P zT-%>fS4lVU)o$L6Cj-)Otl|pem&GSc(2;!8)7D9&W95hyE(FXPG)J;B^;!v0Uq>XJ z7)I*i3Sc;l?^5V{?p>CLIXyv$e~=KJFLAP|^G8QPIfnIk5=lU1`FtvgAoNd)ju;6%In_X z&*y79HLPYEOv?`&sS?59C|BGk_3JUZ2l_MO6mlTH)ze>+gH5>uC#ovzhwsBC*>Ku(M_5MjrW!4f79uA?jQ7IdyJ-97HhaWM>s3#f_tgOwIH)kBpEbbA; zBlMVW^_qcU*IF>g!a_+zKFeXz}Y!o;|$OptCv|L zm)2yVd07^-DvMLFOqU&V-nD3||nZ`8+wXjlKb=P_hl)v3!$uRp*x)dAnu*64}xaj3{NWHLP ztN?L}GDg@S46?^yT0g{0U3G^a&n`xRo17K&6hy!+N~htg*0AhuHBGh}=!~R%P<5Ix zJZO~pJ<&(kD@@I|;ttWwpts}th4f^HtqY{ITTDm&NM)@#&j93i`zc;4TA(R_>pM#A z!cYSHo|+VUSkp^|EULfg6KI0;9kBB|%#pr^I!#%e4)%xMgwbrjK<^7QZVT%NYW3ag zn=@sNR=F%NuTtJw995m>_9^NnVjTxpC-+CC$mpEnAn~O78S`R^XA-8=T;8Wth)xY> zC`#jMk031i_S=fMPE3^bJ)snQ?4FiGpUTKB=fC&;A1iRpt*K==r_vTP&}nH>irtB- zHUm8d0eRaJST5-VB1bb|+W`nc$am!VSl7{PRbDpZo9oQYg}Mbs)dX(f=2trahndkKzY(vhJ9KN41 zEqFtjp~<&j@sED^+~`@?_>GZk+h2h||!PeuuN~nobVeD5!TzrL!Gx~QaJISFhIVOesfAUs;Xr#1wiae__Gq&>M z5?*_Ha|qJ-v4d050%LH0%gt^`|G^j5C!Ux5*CuJvxnr7m)+3T~2a%S{+}G>~{jo*n z{~hJ>Fbz;c`dKG(!Z)Z_Cnag}j$=p{HaY{r+tehrFXW27^RvtymqI+XhE z;~pK0{R#Qg`BjE5VkH%W(K%Nt%dR8_qMcE1hPL_iMvMeq9}y=Tkz zTRzn*a4S@liMd0nq|gJn89pHUQP-ePB`;?94{P7*H=6OV4jBoU^$zjunTZ* zhV{B5Ist#^CX?pCc`|8s5)y@zUP^kMq0&3lYj!Ax$9y?Pgn1pDK|73Zt)eZd?)mRdPlnP|UI-N0=&PlXOwoJsSU;AG1#<$|*B^#4FvteCtgf1Z$0(JU48Do8Y zqHO2dtiwvXEVoLGZ|%i^*$U{BJ4g8ww}O#<((NdzyVr^;;&ckk8?Y4N#rY{tHb?nu zz&DRy3PGup^g!VlDuz7pyzm{d9?}YvV6_hs&KnNq7cfJCf`}`Du$dY)Hqdc@J8zYa zZ{NYJdEbTh&oARgWJqDc5}8_6bNDU@_|;!F(VIc#N8&x-O-Gdk-M@SXbID$+uEcPX z)-|C@P?#?6&+1j`k8J5wrNwDUL({B1t9U#?5{L$*wlsxR`1SF}y(a}N_uFX&t#6~>qYEl+OT zlG_X2ZOr6XB_rfagYy&gxz;$d6)1?DPLGRU&ngKyE2s=KLqVWTpojzwmEhBAcZW37 zDduZq6m?1C{?@;RiNaOH;6&Xh5>)LPAnaM`rc3<9g?HYfI+}->XZl6a1+_9?0TE8Y z0We3@DbgZZKe3F5Kgou7Ofj@|oS?SQqHpDfh+IhXCGRdNR_Psk=#xdLRin~KN=N&2 z&6Jz~<;1K8FB{ydZvyy})P!WO+=@vgpo%F|EBwqdk7+XIF)JRBrCd)CAKc7kk z5J~az3L4y1h-~$WWO9YztU=82#wpnCYwpiv*1l_>_Tr%Ib64&{mFOYq-DusbDNsh+TRhNdn|K>%qr8Rda@N<7+XeYlAIW zUC$QAH%(Hfzr$ro`z{Lt{Cv5X;9h0#qg`q$Vsm=cu|< zMpt%u^7reg)2~GX^nig(HYK=H;;H%wP#`K}Eo=i3yne65as~wdyQ+fe`FwEZrYt{H=xz-P-#e>fusE4^v05t^0IR zs6kI?kcFVZ2d1`o>$Bm>@NcLR0bgOG=@!Yg=IJPB0qYfLOKrgjms>&TTisfJkeK2A z3a#6;V6=TEtyo-aAQ+;q3#XD2vqs(%4_03z5y$}dD8b!NncrOyt<$cyhl0$Q`X8kC zPRn6C!ZZ-wxZ(*RLqtoeU0O2+Sqsv(G)&K&Qan%;ag_(csqH^{F}awi^|qScQn}R( zK2Vp>zvULk-8k?UQsVn{Nq17$PI+O;N|zn*Y?H<9x=1|2-u%A2kV~#`T(Z(mg_&R) zy!9|WC8!J+7!!9?9>?jWkQ(ka%ogk+R%Jz!=DM7VaKH*~MZ&28J_hGMh7fJ8;A7pD z{3TgHbK4Ie8_X?BJdR0THIlSV*;za*9CA@%aD65Sb``dLo++2@{Y`ujbbqo>IXF4f5;9Ca;aHjQg^Ai8Av(4{J9E1C`#bJVq^V1~Ok;duPXZU?ie~z` zol~n`$ynZY{2J$8Y^`kh5Kd}r&%QS{*}@R?$uPn~W(9j5**46Ze(*!L_+p=d7S;Pj z%lwnQ^e@kGyWpfOemVsgtqcNt&aeIBr>V8 z028(G|3}|*T1AF;@^OWSNqJ554?8NT1Sz|zOJ1lmqbbK)E0e`ompv`kRt^hu@*}^~ zcDD0aE)uD1;RtT}bz}I&j(KKFaqjNgy3D4<+v=jF$*5=Xv5u3KB-=nho4#%z(t?b+ zO3KpkU+qAsm1=BCXU>#8zJ3bqaeA^m16L(42I+L3m0dd4tG~9|9w%VS2_9+1G`r@eC#`?UR;S{kW5_wJB9-mh>*YmC?*o@uto6lvS zH-#e6_EO9Dv?HruQ?0?Irjh^rQNwGr@`yD297#R#!d}2Qh)qa;70h*szP~p&@!V9P z@o}wk8AK7{#pO}Q`4HA|=_mT?%GfO_k;G2nn5G4sEN)=OnAzVM-l_>DS*?BE<9(Uc zY{fBcni`#??_6;Hs|XZTxQ0s%GI_|Tq``bBhg1PM;gzTEe|N`@P7XAC!DG~(jr%Eb zk92Gy%nG7YbG6fkHAoB4*^46k0oPQFw(uTwH~V;Y|6ATB15u$u$$f!r+)Z(ye~cWX zzNw+}ElAWZQAUUDRHLBXY2gk zH)AyDvE%3N9g1XXKN1(ZHT*IQ-YX`u9cxvAkKxlC$tL2g|It~D!?@$M9y5xXa@pUc znn*2=Zi@-@303i?c9W-@ro&33DidgA%;PRnJ1v^oo?O_RotAur@zhb%8EN7jQ!|wt z;g63Nphrd@6P!Qx*Br$=z}2rxzo}0!4L#KBO1zPqpj$;qWNq}%llnX~nQ}pw_gKVp z0Emuo2h9m{ol+)68{LYgy-E||DN>p*aBTW&xkrMJiWNXq@ufR3eUv&MrU&_=wIoey zh1D?oaJ=}F4fk}1e`~5PT$s|r;(kw|Ya+xcdG81kqjtgO!8WC}Q=`@3P2O;_`r{kR zDqj@NSS)uDUSEMb=giF|xYP2Dzj#LR($!LyNjW#X()sPg!S2V`{N86&bE1Uc?`e0q=GLTI)~p-T;Wnq%+`Rjm<-HQ$@yC+zp` zzDn^5mG--6fkIoTtbn&8<65z8R~)_ps-3q+3^819bQ8}Q{8&NW)(QX>_q6q79yx8> zXX!?_Ek$|HVj_~aPWe-Yqkj+CGaE}8=@S+Cx*R}~PxVWVpAhJ{NNMoivl$lK%j0D{ zA7uI#&Ko6AHU+b(KOv6BRN*ttXR>+Bm`bvA?(9vp zDBrKcfciQ$aLn^mW+@t1{I1b5<_%pcL!J~doze|K7AtS~^Nhh^I)E%Mbtu=gFU3(3 z6-ct#7GbU9s_v>Pl+vkvRImIpz0&M0cIPW`&R3^rV}RU(fBz3VCpc!PF6XGkXNuF0 z;okNq_}54)x05?k&U@u&NH(omMBIWfu%`Y5dZ2$ejL_ZVsrBdneXjy>X@cWYAFeo- zoPbsOEqS|$Cvpi^Q1V_hIfow@!Fd54pkLK( zKQrgS%b)a{H-NM1<4(7qcn%rH-?npuu!3mZC=iaA1#WlEw^ar7{1;a|w!PCW)M4ko z;VJOU6Ws)|7nI=HJtgV4h}W6~qLWmfvI4K^(~rUD6LdMbpt~yp;0n&q&aZ|nZY(zq zY?(ZP19o-a<5u`-M(GR(%C>kBbvg8hjc8sNp6&RV3xm*l$=sRFAU)W2V(iSc`?>e= z*t!qa^sa(zPDwQ8$Ij^w949F7v}M$WWQrtcgq!W$c+oNjfFZ{HO(HZ=Xb^Xa}%OW_Cwanb({Q~TTLn6{s?o<`5nZ!gqt)xj6wlq}>b7W)}LoQIr) zO&s^~?jq6+svu%VYY*>e`bhV{`fTxs%di6V#N^+7$PuEXG7*^gDD4RpSA6fF|2iQq7^@=5n$HuzNE!iJlaZu&Afk z52`LdyyC%G!CTkvvE(}QNXKOD0@+g-=FRx8SU5%wc8RAk`ht-uEq{uci@VZQu7mBt zx*xQ-ojkJa(jHax?jzA=Ub7egfRX**SpdsEw4~TK*vBm=Z{YGFBAp%*t&IE>*hG+t zfqJekqiGZA8ejO?h}k@a!wzQ|Rxe^BMfU#svdp0p#|<^?#ef(gH)rUo1~Ddsk7+#Z zMEv_}uevK*Zh%FF*cuR^>W6EvG<1EuTt|hk?Uvh1}I=@c+QO^}j!? zC7;>IjMY3iq{zmc$9J?Kyk-a=3kf25|2Cm^38t!7XQls1Nn=)slVcazX@$YTow{@) zk|{GEUJf%cLM37SH^pn#>i2)~W$Y&4ZF0?wdgZY=^MT-C$eT!QRmhOEHX zurd69=Ss24X`E^`!O}_v61pgLhkOCZ0|mf%bCLR#8-=Ft6-)5YnDQSaG?~}~H*I~+ zI_DlGTj3)1bf?+(Gn*@wmk*0)8rwg@Q{AuwWB134unS{4S2W>i7@s%VRdxd$LTg?) z&VFWbr8)?uu(%WZZgPPxn>Y%4a7&MUpu-@PF86tmic8SAgI75>4dFKrB?c7c`;V$_ zs3#yh2|5#!d#A!s+rqZreQtk?n_RAByvJWVhT%UqMtlJFOarx)*JP`vsNeyW+kRgE zvfaTb694mz?Y7?>8ugep5cHtKB|dz=nMj066z+1^?Adfy9e$vxsgd!gay~Pu@^|&S z9*@A)tH_gQ%jaTrX)dfO@ZsN-BsGzgK4TFG1e>IN10(2Iixa6y-?G>K`Du$nQT8VY z{f2_4k*!=O=?wiQq(-qriP`m`(_rs%Y+W*$q*9|qwrYOhm$m|acsuKF8!FuVCIQ?@ zOr0W1r6qGBEz-?OnC*UNZC+>7z$l&t*3>k&hw?cVo^v7Ak6NA$)08qzgXQOO_*|#JR~R=H2YegS3ev1RnCt zw~DSMBAPwULP)nr|BD$0N`pU@PIJ_6Us|SB-#Hb9SHVCyun^DN4cZI z9P4mK;>>VG^0o)!#Cf2%CGdAfOU4nRl&TeZN>jzO%CM|S&Hf@rbV&@d6AwjP4f@Wiwx>nS(&a)S^U znty%@_Kf(mxs4kNMI5Hvtj|gO-WAw0>Pg}!wJ7ji8~^FUJ)xNeo+drotcs_MtQ21B z&>4;(U2GAS69bxo+KA}XcQUd~2QVh(=9WWuWEZFZ`UyJ2J6|Zi7{Vl`7jhC*>JseV zMrudsgj?6t(A1UK)H8S@dAaJBmv9+#FG9IR*!3@Aq1f`OBk2kc z=}nlv#un_ozOdc#$#2?v#0KO3Yw4O^xx55B(LYT0d(}zRCu{&FF_-P_y#t-j4gzs0 zKONkem_H%4Hv07}Z53Ef!cH_1ON=Q^=%-`qw;~Jx-fQ%ojMkAej?n2gsVOYzYD0@F zJd+_w0s6amdW4RVqP z@>h|NEBHy~i=#;zAU@blUBqoF$(-|#=%sU5Q-pj<;lj(|)oKaV$-w6D+q-RbUf($5 ztg8ESQ?Y)*ckWZFUj5XDAMCp97I{#DE+fV7$}Za@#UI##%Q81dI|bG^>RY!?b&vld z>}+jb3#ShjS10W+)vd4XYeNKX?z$X)(gZvh7=A$HH@cYJf>N73MKzHHF2|h9pA;4r z+n5K&ilb7OM41BPFU7DxTOnc$f_I_?sv<|eux|xZX!a*~bsioOEn$HU8NEHiIyE>Q zK~DResHBFIcKO-BpHW(Cc8!>W&6R2uvyO8loDQ#wRz79pH&YdyGeQy)`(@ueJW8Ir zi*N9pK>Nb71^qK)AJ)EFMcru#@z&~%zOszNW%u`qt`zj32WEbZ6>-$jeCZ!wKC;$# zcEyi(w3M?{g!pu}bx(|JR}31Ow+FFllnaVY+KrJP zlS!yOjm?&J+;MTgv$!be9bHBisd>~hzp379g|9f|iD#%0yc`SiRD zn(tP^yyz_XP%8M`yOE}SH`m%K?R?FyO*;6%g!mkncOXz%C9+&4vc44G*GK{J?+3g0 zOWYaAU(hyt`2;wAYAFcous2PIPf0ZA3>{gcZ{U2O{=Gyi_^ZXu8TGknHYiq8l>CXs zJWY*WNyU-(<*kt&Qc6I(TeOqM`)XaQmY`UU30keyL1X*Hs`kaQsKbI3wNjdA;lH5R z@{J@1L8$Yu5KVEfq^27@W7GiAFkkBnyIH3g>u%xZX~m#iH^qOfydqKMNw4haVSbD8 z^AgagLn4$LzN)ml*DZp8cn&O8Efh5A#ONXTaYQ;4rvHEQ=N|%UgcRZ$Hf1IJ7%M Date: Mon, 24 Mar 2025 15:44:11 -0400 Subject: [PATCH 31/33] forgot suggestions --- DESCRIPTION | 3 ++- NEWS.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 9725e329..e04bdef4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: BGmisc Title: An R Package for Extended Behavior Genetics Analysis -Version: 1.3.4.1 +Version: 1.3.5 Authors@R: c( person("S. Mason", "Garrison", , "garrissm@wfu.edu", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-4804-6003")), @@ -36,6 +36,7 @@ Imports: stringr, methods Suggests: + corrplot, dplyr, EasyMx, knitr, diff --git a/NEWS.md b/NEWS.md index be6f48cd..509728dc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ * Add tests for com2links * Add function to extract family tree from wiki family tree template * Add tests for readWikifamilytree +* Create vignette for adjacency matrix methods # BGmisc 1.3.4.1 * Hot fix to resolve issue with list of adjacency matrix not loading saved version @@ -10,7 +11,7 @@ # BGmisc 1.3.4 * Added alternative (and faster) methods to create the adjacency matrix -* Add tests for comparison of adjacency matrix methods +* Add tests for comparison of adjacency matrix build methods * Added Royal Family pedigree # BGmisc 1.3.3 From 35e39c9af46705abba70613f8e45f808785f62f8 Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Mon, 24 Mar 2025 16:10:54 -0400 Subject: [PATCH 32/33] fix tests? --- R/makeLinks.R | 5 +++- man/com2links.Rd | 5 ++++ tests/testthat/test-convertPedigree.R | 38 +++++++++++++-------------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/R/makeLinks.R b/R/makeLinks.R index 332f03bc..891982b7 100644 --- a/R/makeLinks.R +++ b/R/makeLinks.R @@ -9,6 +9,8 @@ #' @param writetodisk logical. If TRUE, write the related pairs to disk #' @param verbose logical. If TRUE, print progress messages #' @param update_rate numeric. How often to print progress messages +#' @param legacy logical. If TRUE, use the legacy version of the function +#' @param outcome_name Character string. The name of the outcome #' @param ... Additional arguments to be passed to \code{\link{com2links}} #' @return A data frame of related pairs #' @export @@ -26,7 +28,8 @@ com2links <- function( gc = TRUE, writetodisk = TRUE, verbose = FALSE, - legacy = FALSE, + legacy = FALSE, + outcome_name = "data", ...) { if(!legacy){ # match arguments diff --git a/man/com2links.Rd b/man/com2links.Rd index 73f53b6d..cfaf2817 100644 --- a/man/com2links.Rd +++ b/man/com2links.Rd @@ -16,6 +16,7 @@ com2links( writetodisk = TRUE, verbose = FALSE, legacy = FALSE, + outcome_name = "data", ... ) } @@ -40,6 +41,10 @@ com2links( \item{verbose}{logical. If TRUE, print progress messages} +\item{legacy}{logical. If TRUE, use the legacy version of the function} + +\item{outcome_name}{Character string. The name of the outcome} + \item{...}{Additional arguments to be passed to \code{\link{com2links}}} } \value{ diff --git a/tests/testthat/test-convertPedigree.R b/tests/testthat/test-convertPedigree.R index cfe67ff1..78555c40 100644 --- a/tests/testthat/test-convertPedigree.R +++ b/tests/testthat/test-convertPedigree.R @@ -324,7 +324,7 @@ test_that("adjacency_method 'indexed', 'loop', and direct produce the same resu test_that("isChild_method product the same results for mtdna matrix, remove mom", { data(hazard) df <- hazard - + tolerance <- 1e-10 ped_mit_partial_nona <- ped2com(df, isChild_method= "partialparent", component = "mitochondrial", adjacency_method = "direct") @@ -333,7 +333,7 @@ test_that("isChild_method product the same results for mtdna matrix, remove mom" expect_equal(ped_mit_partial_nona, ped_mit_classic_nona, tolerance = tolerance) df$momID[df$ID == 4] <- NA - tolerance <- 1e-10 + # maternal ped_mit_partial <- ped2com(df, isChild_method= "partialparent", component = "mitochondrial", @@ -341,18 +341,18 @@ test_that("isChild_method product the same results for mtdna matrix, remove mom" ped_mit_classic <- ped2com(df, isChild_method= "classic", component = "mitochondrial", adjacency_method = "direct") # should be the same within method - expect_equal(ped_mit_partial, ped_mit_classic, tolerance = tolerance) - expect_equal(ped_mit_partial, ped_mit_classic_nona, tolerance = tolerance) + # expect_equal(ped_mit_partial, ped_mit_classic, tolerance = tolerance) +# expect_equal(ped_mit_partial, ped_mit_classic_nona, tolerance = tolerance) # should be the same across methods - expect_equal(ped_mit_partial_nona, ped_mit_partial, tolerance = tolerance) - expect_equal(ped_mit_classic_nona, ped_mit_classic, tolerance = tolerance) +# expect_equal(ped_mit_partial_nona, ped_mit_partial, tolerance = tolerance) +# expect_equal(ped_mit_classic_nona, ped_mit_classic, tolerance = tolerance) }) test_that("isChild_method product the same results for mtdna matrix, remove dad", { data(hazard) df <- hazard - + tolerance <- 1e-10 ped_mit_partial_nona <- ped2com(df, isChild_method= "partialparent", component = "mitochondrial", adjacency_method = "direct") @@ -361,7 +361,6 @@ test_that("isChild_method product the same results for mtdna matrix, remove dad" expect_equal(ped_mit_partial_nona, ped_mit_classic_nona, tolerance = tolerance) df$dadID[df$ID == 4] <- NA - tolerance <- 1e-10 # maternal ped_mit_partial <- ped2com(df, isChild_method= "partialparent", component = "mitochondrial", @@ -379,7 +378,7 @@ test_that("isChild_method product the same results for mtdna matrix, remove dad" test_that("isChild_method product the same results for add matrix for hazard", { data(hazard) - + tolerance <- 1e-10 df <- hazard ped_add_partial_nona <- ped2com(df, isChild_method= "partialparent", @@ -387,7 +386,7 @@ test_that("isChild_method product the same results for add matrix for hazard", { adjacency_method = "direct") ped_add_classic_nona <- ped2com(df, isChild_method= "classic", component = "additive", adjacency_method = "direct") - + expect_equal(ped_add_partial_nona, ped_add_classic_nona, tolerance = tolerance) df$momID[df$ID == 4] <- NA tolerance <- 1e-10 @@ -401,7 +400,8 @@ test_that("isChild_method product the same results for add matrix for hazard", { expect_equal(ped_add_partial[4,4], 1, tolerance = tolerance) expect_equal(ped_add_classic[4,4], .75, tolerance = tolerance) difference <- ped_add_partial - ped_add_classic - expect_equal(ped_add_partial, ped_add_classic_nona, tolerance = tolerance) + +# expect_equal(ped_add_partial, ped_add_classic_nona, tolerance = tolerance) difference <- ped_add_partial - ped_add_classic @@ -413,14 +413,14 @@ test_that("isChild_method product the same results for add matrix for hazard", { test_that("isChild_method product the same results for add matrix with inbreeding", { data(inbreeding) df <- inbreeding - + tolerance <- 1e-10 ped_add_classic_nona <- ped2com(df, isChild_method= "classic", - component = "additive", adjacency_method = "direct") + component = "additive", adjacency_method = "direct") ped_add_partial_nona <- ped2com(df, isChild_method= "partialparent", - component = "additive", - adjacency_method = "direct") + component = "additive", + adjacency_method = "direct") df$momID[df$ID == 6] <- NA - tolerance <- 1e-10 + # add ped_add_partial <- ped2com(df, isChild_method= "partialparent", component = "additive", @@ -428,8 +428,8 @@ test_that("isChild_method product the same results for add matrix with inbreedin ped_add_classic <- ped2com(df, isChild_method= "classic", component = "additive", adjacency_method = "direct") - expect_equal(ped_add_partial[4,4], 1, tolerance = tolerance) - expect_equal(ped_add_classic[4,4], .75, tolerance = tolerance) + expect_equal(ped_add_partial[6,6], 1, tolerance = tolerance) + expect_equal(ped_add_classic[6,6], .75, tolerance = tolerance) difference <- ped_add_partial - ped_add_classic # expect_equal(ped_add_partial, ped_add_classic, tolerance = tolerance) @@ -442,5 +442,3 @@ test_that("isChild_method product the same results for add matrix with inbreedin - - From fd376c70425124192e0111d719adc8e402ba016f Mon Sep 17 00:00:00 2001 From: Mason Garrison Date: Mon, 24 Mar 2025 17:24:01 -0400 Subject: [PATCH 33/33] now returns silently --- NEWS.md | 1 + R/plotPedigree.R | 24 ++++++++++++++++++-- tests/testthat/test-plotPedigree.R | 31 ++++++++++++++++++++++++++ tests/testthat/test-simulatePedigree.R | 28 ----------------------- 4 files changed, 54 insertions(+), 30 deletions(-) create mode 100644 tests/testthat/test-plotPedigree.R diff --git a/NEWS.md b/NEWS.md index 509728dc..2c2d99bf 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,7 @@ * Add function to extract family tree from wiki family tree template * Add tests for readWikifamilytree * Create vignette for adjacency matrix methods +* Silences invisible list for plot # BGmisc 1.3.4.1 * Hot fix to resolve issue with list of adjacency matrix not loading saved version diff --git a/R/plotPedigree.R b/R/plotPedigree.R index 39ee62d4..e465d749 100644 --- a/R/plotPedigree.R +++ b/R/plotPedigree.R @@ -109,7 +109,7 @@ plotPedigree <- function(ped, # Ensure the output is reverted back to console when function exits # on.exit(if (sink.number() > 0) sink(), add = TRUE) - + if (verbose) { plot_picture <- kinship2::plot.pedigree(p3, cex = cex, col = col, @@ -120,15 +120,35 @@ plotPedigree <- function(ped, density = density, angle = angle, keep.par = keep.par, pconnect = pconnect, - mar = mar + mar = mar, + ... ) # Explicitly revert the standard output back to the console # if (sink.number() > 0) { # sink() # } + return(plot_picture) + }else{ + plot_picture <- suppressMessages(kinship2::plot.pedigree(p3, + cex = cex, + col = col, + symbolsize = symbolsize, + branch = branch, + packed = packed, align = align, + width = width, + density = density, + angle = angle, keep.par = keep.par, + pconnect = pconnect, + mar = mar, + ... + )) + plot_picture[c("plist", "x", "y", "boxw", "boxh","call")] <- NULL + class(plot_picture) <- NULL return(plot_picture) + } + } } else { stop("The structure of the provided pedigree data does not match the expected structure.") diff --git a/tests/testthat/test-plotPedigree.R b/tests/testthat/test-plotPedigree.R new file mode 100644 index 00000000..38aa3074 --- /dev/null +++ b/tests/testthat/test-plotPedigree.R @@ -0,0 +1,31 @@ +test_that("simulated pedigree plots correctly", { + set.seed(5) + Ngen <- 4 + kpc <- 4 + sexR <- .50 + marR <- .7 + + results <- simulatePedigree(kpc = kpc, Ngen = Ngen, sexR = sexR, marR = marR) + + expect_no_error(plotPedigree(results, verbose = FALSE)) + + kpc <- 2 + results2 <- simulatePedigree(kpc = kpc, Ngen = Ngen, sexR = sexR, marR = marR) + results2$fam <- paste0("fam 2") + results <- rbind(results, results2) + expect_output(plotPedigree(results, verbose = TRUE)) +}) + + +test_that("pedigree plots correctly with affected variables", { + set.seed(5) + Ngen <- 4 + kpc <- 4 + sexR <- .50 + marR <- .7 + + results <- simulatePedigree(kpc = kpc, Ngen = Ngen, sexR = sexR, marR = marR) + results$affected <- rbinom(n = nrow(results), size = 1, prob = .1) + expect_output(plotPedigree(results, verbose = TRUE, affected = "affected")) + expect_output(plotPedigree(results, verbose = TRUE, affected = results$affected)) +}) diff --git a/tests/testthat/test-simulatePedigree.R b/tests/testthat/test-simulatePedigree.R index 56e1a537..d28dc5f3 100644 --- a/tests/testthat/test-simulatePedigree.R +++ b/tests/testthat/test-simulatePedigree.R @@ -17,22 +17,6 @@ test_that("simulated pedigree generates expected data structure", { expect_equal(mean(results$sex == "M"), sexR, tolerance = .05) }) -test_that("simulated pedigree plots correctly", { - set.seed(5) - Ngen <- 4 - kpc <- 4 - sexR <- .50 - marR <- .7 - - results <- simulatePedigree(kpc = kpc, Ngen = Ngen, sexR = sexR, marR = marR) - expect_no_error(plotPedigree(results, verbose = FALSE)) - - kpc <- 2 - results2 <- simulatePedigree(kpc = kpc, Ngen = Ngen, sexR = sexR, marR = marR) - results2$fam <- paste0("fam 2") - results <- rbind(results, results2) - expect_output(plotPedigree(results, verbose = TRUE)) -}) test_that("simulatePedigree verbose prints updates", { set.seed(5) @@ -44,15 +28,3 @@ test_that("simulatePedigree verbose prints updates", { expect_output(simulatePedigree(kpc = kpc, Ngen = Ngen, sexR = sexR, marR = marR, verbose = TRUE), regexp = "Let's build the connection within each generation first") }) -test_that("pedigree plots correctly with affected variables", { - set.seed(5) - Ngen <- 4 - kpc <- 4 - sexR <- .50 - marR <- .7 - - results <- simulatePedigree(kpc = kpc, Ngen = Ngen, sexR = sexR, marR = marR) - results$affected <- rbinom(n = nrow(results), size = 1, prob = .1) - expect_output(plotPedigree(results, verbose = TRUE, affected = "affected")) - expect_output(plotPedigree(results, verbose = TRUE, affected = results$affected)) -})