From 2cc84479091655abb204413e8dfc55f0c7ab108a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Fri, 2 Jun 2023 00:01:50 -0400 Subject: [PATCH 001/385] Update NEWS.md --- inst/NEWS.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/inst/NEWS.md b/inst/NEWS.md index 57a1471f2..83ab81df0 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,13 @@ +CHANGES IN VERSION 0.99.4 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o More parameter names have been changed to follow the camelCase style. + o The function documentation has been improved. + o A wrapper function runExomeAncestry() is now available. + + CHANGES IN VERSION 0.99.3 ------------------------ From 1be911433551ede71f0bd53025d3e84d820469d7 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 2 Jun 2023 15:40:53 -0400 Subject: [PATCH 002/385] remove deprecated --- NAMESPACE | 1 - R/processStudy.R | 140 ------ R/processStudy_internal.R | 490 -------------------- man/computeKNNSuperPopSample.Rd | 46 -- man/computeKNNSuperPoprSynthetic.Rd | 45 -- man/computePCAForSamples.Rd | 40 -- man/computePCAsynthetic.Rd | 56 --- man/computePoolSyntheticAncestry.Rd | 107 ----- man/validateComputePoolSyntheticAncestry.Rd | 121 ----- tests/testthat/test-processStudy.R | 169 ------- 10 files changed, 1215 deletions(-) delete mode 100644 man/computeKNNSuperPopSample.Rd delete mode 100644 man/computeKNNSuperPoprSynthetic.Rd delete mode 100644 man/computePCAForSamples.Rd delete mode 100644 man/computePCAsynthetic.Rd delete mode 100644 man/computePoolSyntheticAncestry.Rd delete mode 100644 man/validateComputePoolSyntheticAncestry.Rd diff --git a/NAMESPACE b/NAMESPACE index a13fc8dd1..3d762a809 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -14,7 +14,6 @@ export(computeKNNRefSample) export(computeKNNRefSynthetic) export(computePCAMultiSynthetic) export(computePCARefSample) -export(computePoolSyntheticAncestry) export(computePoolSyntheticAncestryGr) export(computePrunedPCARef) export(computeSyntheticROC) diff --git a/R/processStudy.R b/R/processStudy.R index 71500cbb8..525b50c62 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -1957,146 +1957,6 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, } -#' @title TODO -#' -#' @description TODO -#' -#' @param gdsReference an object of class \link[gdsfmt]{gds.class} (a GDS -#' file), the opened Reference GDS file. -#' -#' @param gdsSample an object of class \link[gdsfmt]{gds.class} (a GDS file), -#' an opened Profile GDS file. -#' -#' @param profileID a single \code{character} string representing the -#' profile identifier. -#' -#' @param dataRef a \code{data.frame} containing the information of the -#' synthetic profiles that will be -#' -#' @param spRef TODO -#' -#' @param studyIDSyn a \code{character} string corresponding to the study -#' identifier. The study identifier must be present in the Profile GDS file. -#' -#' @param np a single positive \code{integer} representing the number of -#' threads. Default: \code{1L}. -#' -#' @param listCatPop a \code{vector} of \code{character} string -#' representing the list of possible ancestry assignations. Default: -#' \code{("EAS", "EUR", "AFR", "AMR", "SAS")}. -#' -#' @param fieldPopIn1KG a \code{character} string representing TODO . -#' Default: \code{"superPop"}. -#' -#' @param fieldPopInfAnc a \code{character} string representing the name of -#' the column that will contain the inferred ancestry for the specified -#' dataset. Default: \code{"SuperPop"}. -#' -#' @param kList a \code{vector} of \code{integer} representing the list of -#' values tested for the _K_ parameter. The _K_ parameter represents the -#' number of neighbors used in the K-nearest neighbors analysis. If -#' \code{NULL}, the value \code{seq(2,15,1)} is assigned. -#' Default: \code{seq(2,15,1)}. -#' -#' @param pcaList a \code{vector} of \code{integer} representing the list of -#' values tested for the _D_ parameter. The _D_ parameter represents the -#' number of dimensions used in the PCA analysis. If \code{NULL}, -#' the value \code{seq(2,15,1)} is assigned. -#' Default: \code{seq(2,15,1)}. -#' -#' @param algorithm a \code{character} string representing the algorithm used -#' to calculate the PCA. The 2 choices are "exact" (traditional exact -#' calculation) and "randomized" (fast PCA with randomized algorithm -#' introduced in Galinsky et al. 2016). Default: \code{"exact"}. -#' -#' @param eigenCount a single \code{integer} indicating the number of -#' eigenvectors that will be in the output of the \link[SNPRelate]{snpgdsPCA} -#' function; if 'eigenCount' <= 0, then all eigenvectors are returned. -#' Default: \code{32L}. -#' -#' @param missingRate a \code{numeric} value representing the threshold -#' missing rate at with the SNVs are discarded; the SNVs are retained in the -#' \link[SNPRelate]{snpgdsPCA} -#' with "<= missingRate" only; if \code{NaN}, no missing threshold. -#' Default: \code{0.025}. -#' -#' -#' @return A \code{list} TODO with the sample.id and eigenvectors -#' and a table with KNN callfor different K and pca dimension. -#' -#' @references -#' -#' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, -#' Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution -#' of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. -#' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. -#' -#' @examples -#' -#' # TODO -#' listEigenvector <- "TOTO" -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @encoding UTF-8 -#' @export -computePoolSyntheticAncestry <- function(gdsReference, gdsSample, profileID, - dataRef, spRef, studyIDSyn, np=1L, - listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), - fieldPopIn1KG="superPop", fieldPopInfAnc="SuperPop", - kList=seq(2, 15, 1), pcaList = seq(2, 15, 1), - algorithm="exact", eigenCount=32L, missingRate=0.025) { - - ## Assign default value is kList is NULL - if(is.null(kList)) { - kList <- seq(2,15,1) - } - - ## Assign default value is pcaList is NULL - if(is.null(pcaList)) { - pcaList <- seq(2,15,1) - } - ## Add parameter validation - validateComputePoolSyntheticAncestry(gdsReference=gdsReference, - profileGDS=gdsSample, profileID=profileID, dataRef=dataRef, - spRef=spRef, studyIDSyn=studyIDSyn, np=np, listCatPop=listCatPop, - fieldPopIn1KG=fieldPopIn1KG, fieldPopInfAnc=fieldPopInfAnc, - kList=kList, pcaList=pcaList, algorithm=algorithm, - eigenCount=eigenCount, missingRate=missingRate) - - sampleRM <- splitSelectByPop(dataRef) - - KNN.list <- list() - for(j in seq_len(nrow(sampleRM))) { - ## Run a PCA analysis using 1 synthetic profile from each - ## sub-continental ancestry - ## The synthetic profiles are projected on the 1KG PCA space - ## (the reference samples used to generate the synthetic profiles are - ## removed from this PCA) - KNN.list[[j]] <- computePoolSyntheticAncestryGr(gdsProfile=gdsSample, - sampleRM=sampleRM[j,], spRef=spRef, studyIDSyn=studyIDSyn, - np=np, listCatPop=listCatPop, - fieldPopInfAnc=fieldPopInfAnc, kList=kList, - pcaList=pcaList, algorithm=algorithm, eigenCount=eigenCount, - missingRate=missingRate, verbose=FALSE) - } - - resultsKNN <- do.call(rbind, KNN.list) - - pedSyn <- prepPedSynthetic1KG(gdsReference=gdsReference, - gdsSample=gdsSample, studyID=studyIDSyn, popName=fieldPopIn1KG) - - listParaSample <- selParaPCAUpQuartile(resultsKNN, pedSyn, - fieldPopIn1KG, fieldPopInfAnc, listCatPop) - - listPCASample <- computePCARefSample(gdsProfile=gdsSample, - currentProfile=profileID, studyIDRef="Ref.1KG", np=np, - algorithm=algorithm, eigenCount=eigenCount, missingRate=missingRate) - - listKNNSample <- computeKNNSuperPopSample(gdsSample=gdsSample, - profileID, spRef) - - return(listKNNSample) -} #' @title Select the optimal K and D parameters using the synthetic data and #' infer the ancestry of a specific profile diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index c69ef1173..8a81b1605 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -1375,162 +1375,6 @@ validateAddStudy1Kg <- function(gdsReference, fileProfileGDS, verbose) { } -#' @title Validate the input parameters for computePoolSyntheticAncestry() -#' function -#' -#' @description The function validates the input parameters for the -#' \code{\link{computePoolSyntheticAncestry}} function. -#' When a parameter is not as expected, an error message is generated. -#' -#' @param gdsReference an object of class \link[gdsfmt]{gds.class} -#' (a GDS file), the opened 1KG GDS file. -#' -#' @param profileGDS an object of class \link[gdsfmt]{gds.class} (a GDS file), -#' an opened Profile GDS file. -#' -#' @param profileID a single \code{character} string representing the -#' profile identifier. -#' -#' @param dataRef a \code{data.frame} TODO -#' -#' @param spRef TODO -#' -#' @param studyIDSyn a \code{character} string corresponding to the study -#' identifier. The study identifier must be present in the GDS Sample file. -#' -#' @param np a single positive \code{integer} representing the number of -#' threads. Default: \code{1L}. -#' -#' @param listCatPop a \code{vector} of \code{character} string -#' representing the list of possible ancestry assignations. Default: -#' \code{("EAS", "EUR", "AFR", "AMR", "SAS")}. -#' -#' @param fieldPopIn1KG a \code{character} string representing the TODO -#' -#' @param fieldPopInfAnc a \code{character} string representing the name of -#' the column that will contain the inferred ancestry for the specified -#' dataset. Default: \code{"SuperPop"}. -#' -#' @param kList a \code{vector} of \code{integer} representing the list of -#' values tested for the _K_ parameter. The _K_ parameter represents the -#' number of neighbors used in the K-nearest neighbors analysis. If -#' \code{NULL}, the value \code{seq(2,15,1)} is assigned. -#' Default: \code{seq(2,15,1)}. -#' -#' @param pcaList a \code{vector} of \code{integer} representing the list of -#' values tested for the _D_ parameter. The _D_ parameter represents the -#' number of dimensions used in the PCA analysis. If \code{NULL}, -#' the value \code{seq(2,15,1)} is assigned. -#' Default: \code{seq(2,15,1)}. -#' -#' @param algorithm a \code{character} string representing the algorithm used -#' to calculate the PCA. The 2 choices are "exact" (traditional exact -#' calculation) and "randomized" (fast PCA with randomized algorithm -#' introduced in Galinsky et al. 2016). Default: \code{"exact"}. -#' -#' @param eigen.cnt a single \code{integer} indicating the number of -#' eigenvectors that will be in the output of the \link[SNPRelate]{snpgdsPCA} -#' function; if 'eigen.cnt' <= 0, then all eigenvectors are returned. -#' -#' @param missing.rate a \code{numeric} value representing the threshold -#' missing rate at with the SNVs are discarded; the SNVs are retained in the -#' \link[SNPRelate]{snpgdsPCA} -#' with "<= missing.rate" only; if \code{NaN}, no missing threshold. -#' -#' -#' @return The integer \code{0L} when successful. -#' -#' @examples -#' -#' ## Path to the demo 1KG GDS file is located in this package -#' dataDir <- system.file("extdata/tests", package="RAIDS") -#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") -#' fileProfileGDS <- file.path(dataDir, "ex1_demo.gds") -#' -#' ## Open GDS files -#' gds1KG <- snpgdsOpen(fileGDS) -#' gdsProfile <- openfn.gds(fileProfileGDS) -#' -#' dataRef <- data.frame(test=c(1,2), stringAsFactro=FALSE) -#' -#' ## The function returns 0L when all parameters are valid -#' RAIDS:::validateComputePoolSyntheticAncestry(gdsReference=gds1KG, -#' profileGDS=gdsProfile, profileID="SampleID", -#' dataRef=dataRef, spRef=NULL, studyIDSyn="MyStudy", -#' np=1L, listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), -#' fieldPopIn1KG="SuperPop", fieldPopInfAnc="SuperPop", -#' kList=seq(2,15,1), pcaList=seq(2,15,1), -#' algorithm="exact", eigenCount=32L, missingRate=0.025) -#' -#' ## Close GDS files (it is important to always close the GDS files) -#' closefn.gds(gds1KG) -#' closefn.gds(gdsProfile) -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom S4Vectors isSingleNumber -#' @encoding UTF-8 -#' @keywords internal -validateComputePoolSyntheticAncestry <- function(gdsReference, profileGDS, - profileID, dataRef, spRef, studyIDSyn, np, - listCatPop, fieldPopIn1KG, fieldPopInfAnc, - kList, pcaList, algorithm, eigenCount, missingRate) { - - ## The gds and profileGDS must be objects of class "gds.class" - validateGDSClass(gds=gdsReference, "gdsReference") - validateGDSClass(gds=profileGDS, "profileGDS") - - ## The profileID must be one character string - if (!(is.character(profileID) && length(profileID) == 1)) { - stop("The \'profileID\' parameter must be a character string.") - } - - ## The dataRef must be an data.frame object - if (!is.data.frame(dataRef)) { - stop("The \'dataRef\' must be a data.frame object.") - } - - ## The studyIDSyn must be a character string - if (!(is.character(studyIDSyn) && length(studyIDSyn) == 1)) { - stop("The \'studyIDSyn\' parameter must be a character string.") - } - - ## The listCatPop must be a character string vector - if (!(is.character(listCatPop) && is.vector(listCatPop))) { - stop("The \'listCatPop\' parameter must be a vector of ", - "character strings.") - } - - ## The population name in 1KG must be a character string - if (!(is.character(fieldPopIn1KG) && length(fieldPopIn1KG) == 1)) { - stop("The \'fieldPopIn1KG\' parameter must be a character string.") - } - - ## The population inferred must be a character string - if (!(is.character(fieldPopInfAnc) && length(fieldPopInfAnc) == 1)) { - stop("The \'fieldPopInfAnc\' parameter must be a character string.") - } - - ## The parameters must be vectors of positive integers - validatePositiveIntegerVector(kList, "kList") - validatePositiveIntegerVector(pcaList, "pcaList") - - ## The algorithm must be a character string - if (!(is.character(algorithm) && length(algorithm) == 1)) { - stop("The \'algorithm\' parameter must be a character string.") - } - - ## The eigenCount must be a single integer - if (!(isSingleNumber(eigenCount))) { - stop("The \'eigenCount\' parameter must be a single integer.") - } - - ## The missingRate must be a numeric of NaN - if (!(isSingleNumber(missingRate) || is.nan(missingRate))) { - stop("The \'missingRate\' parameter must be a single numeric or NaN.") - } - - return(0L) -} #' @title Validate that the Profile GDS file exists for the specified profile #' @@ -1989,339 +1833,6 @@ computePCARefRMMulti <- function(gdsProfile, refProfileIDs, listRM, np=1L, } -#' @title Deprecated -#' -#' @description Deprecated -#' -#' @param listEigenvector TODO see return of computePCAsynthetic -#' -#' @param sample.ref TODO -#' -#' @param study.annot a \code{data.frame} with one entry from study.annot in -#' the gds -#' -#' @param spRef TODO -#' -#' @param kList a \code{vector} of \code{integer} representing the list of -#' values tested for the K parameter. The K parameter represents the -#' number of neighbors used in the K-nearest neighbors analysis. If -#' \code{NULL}, the value \code{seq_len(15)} is assigned. -#' Default: \code{seq_len(15)}. -#' -#' @param pcaList TODO array of the pca dimension possible values -#' -#' @return A \code{list} TODO with the sample.id and eigenvectors -#' and a table with KNN callfor different K and pca dimension. -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt add.gdsn index.gdsn -#' @importFrom SNPRelate snpgdsPCA snpgdsPCASampLoading snpgdsPCASampLoading -#' @importFrom class knn -#' @encoding UTF-8 -#' @keywords internal -computeKNNSuperPoprSynthetic <- function(listEigenvector, sample.ref, - study.annot, spRef, kList=seq_len(15), - pcaList=seq(2, 15, 1)) { - - ## The number of rows in study.annot must be one. - if(nrow(study.annot) != 1) { - stop("Number of samples in study.annot not equal to 1\n") - } - - if(is.null(kList)){ - kList <- seq_len(15) #c(seq_len(14), seq(15,100, by=5)) - } - if(is.null(pcaList)){ - pcaList <- seq(2, 15, 1) - } - - resMat <- data.frame(sample.id=rep(listEigenvector$sample.id, - length(pcaList) * length(kList)), - D=rep(0,length(pcaList) * length(kList)), - K=rep(0,length(pcaList) * length(kList)), - SuperPop=character(length(pcaList) * length(kList)), - stringsAsFactors=FALSE) - - listSuperPop <- c("EAS", "EUR", "AFR", "AMR", "SAS") - - #curPCA <- listPCA.Samples[[sample.id[sample.pos]]] - eigenvect <- rbind(listEigenvector$eigenvector.ref, - listEigenvector$eigenvector) - - rownames(eigenvect) <- c(sample.ref[which(sample.ref != - study.annot$case.id[1])], - listEigenvector$sample.id) - - totR <- 1 - for(pcaD in pcaList) { - for(kV in seq_len(length(kList))) { - dCur <- paste0("d", pcaD) - kCur <- paste0("k", kList[kV]) - resMat[totR,c("D", "K")] <- c(pcaD, kList[kV]) - - pcaND <- eigenvect[ ,seq_len(pcaD)] - y_pred <- knn(train=pcaND[rownames(eigenvect)[-1*nrow(eigenvect)],], - test=pcaND[rownames(eigenvect)[nrow(eigenvect)],, - drop=FALSE], - cl=factor(spRef[rownames(eigenvect)[-1*nrow(eigenvect)]], - levels=listSuperPop, labels=listSuperPop), - k=kList[kV], - prob=FALSE) - - resMat[totR, paste0("SuperPop")] <- listSuperPop[as.integer(y_pred)] - - totR <- totR + 1 - } # end k - } # end pca Dim - listKNN <- list(sample.id=listEigenvector$sample.id, - sample1Kg=study.annot$case.id[1], - sp=spRef[study.annot$case.id[1]], matKNN=resMat) - - return(listKNN) -} - - -#' @title Deprecated -#' -#' @description Deprecated -#' -#' @param listEigenvector TODO see return of computePCARefSample -#' -#' @param sample.ref TODO -#' -#' @param study.annot a \code{data.frame} with one entry from study.annot in -#' the gds -#' -#' @param spRef TODO -#' -#' @param kList a \code{vector} of \code{integer} representing the list of -#' values tested for the _K_ parameter. The _K_ parameter represents the -#' number of neighbors used in the K-nearest neighbor analysis. If \code{NULL}, -#' the value \code{seq_len(15)} is assigned. -#' Default: \code{seq_len(15)}. -#' -#' @param pcaList TODO array of the pca dimension possible values -#' -#' @return A \code{list} TODO with the sample.id and eigenvectors -#' and a table with KNN callfor different K and pca dimension. -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt add.gdsn index.gdsn -#' @importFrom SNPRelate snpgdsPCA snpgdsPCASampLoading snpgdsPCASampLoading -#' @importFrom class knn -#' @encoding UTF-8 -#' @keywords internal -computeKNNSuperPopSample <- function(gdsSample, listEigenvector, name.id, - spRef, studyIDRef="Ref.1KG", - kList=seq_len(15), pcaList=2:15) { - - if(is.null(kList)) { - kList <- seq_len(15)#c(seq_len(14), seq(15,100, by=5)) - } - if(is.null(pcaList)) { - pcaList <- 2:15 - } - if(length(name.id) != 1) { - stop("Number of sample in study.annot not equal to 1\n") - } - - study.annot.all <- read.gdsn(index.gdsn(gdsSample, "study.annot")) - - sample.ref <- study.annot.all[which(study.annot.all$study.id == - studyIDRef), "data.id"] - - resMat <- data.frame(sample.id=rep(listEigenvector$sample.id, - length(pcaList) * length(kList)), - D=rep(0,length(pcaList) * length(kList)), - K=rep(0,length(pcaList) * length(kList)), - SuperPop=character(length(pcaList) * length(kList)), - stringsAsFactors=FALSE) - - listSuperPop <- c("EAS", "EUR", "AFR", "AMR", "SAS") - - eigenvect <- rbind(listEigenvector$eigenvector.ref, - listEigenvector$eigenvector) - - rownames(eigenvect) <- c(sample.ref, listEigenvector$sample.id) - - totR <- 1 - for(pcaD in pcaList) { - for(kV in seq_len(length(kList))) { - dCur <- paste0("d", pcaD) - kCur <- paste0("k", kList[kV]) - resMat[totR,c("D", "K")] <- c(pcaD, kList[kV]) - - pcaND <- eigenvect[ ,seq_len(pcaD)] - y_pred <- knn(train=pcaND[rownames(eigenvect)[-1*nrow(eigenvect)],], - test=pcaND[rownames(eigenvect)[nrow(eigenvect)],, drop=FALSE], - cl=factor(spRef[rownames(eigenvect)[-1*nrow(eigenvect)]], - levels=listSuperPop, labels=listSuperPop), - k=kList[kV],prob=FALSE) - - resMat[totR, paste0("SuperPop")] <- listSuperPop[as.integer(y_pred)] - - totR <- totR + 1 - } # end k - } # end pca Dim - listKNN <- list(sample.id=listEigenvector$sample.id, matKNN=resMat) - - return(listKNN) -} - - -#' @title Deprecated - Project patients onto existing principal component -#' axes (PCA) -#' -#' @description This function calculates the patient eigenvectors using -#' the specified SNP loadings. Deprecated -#' -#' @param gds an object of class -#' \code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, a SNP -#' GDS file. -#' -#' @param pathProfileGDS the path of an object of class \code{gds} related to -#' the sample -#' -#' @param listSamples a \code{vector} of string representing the samples for -#' which compute the PCA. -#' -#' @param np a single positive \code{integer} representing the number of -#' threads. Default: \code{1L}. -#' -#' @return The integer \code{0L} when successful. -#' -#' @details -#' -#' More information about the method used to calculate the patient eigenvectors -#' can be found at the Bioconductor SNPRelate website: -#' https://bioconductor.org/packages/SNPRelate/ -#' -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom SNPRelate snpgdsPCASampLoading -#' @importFrom S4Vectors isSingleNumber -#' @encoding UTF-8 -#' @keywords internal -computePCAForSamples <- function(gds, pathProfileGDS, listSamples, np=1L) { - - ## Validate that np is a single positive integer - if(! (isSingleNumber(np) && np > 0)) { - stop("The \'np\' parameter must be a single positive integer.") - } - - for(i in seq_len(length(listSamples)) ){ - - gdsSample <- openfn.gds(file.path(pathProfileGDS, - paste0(listSamples[i], ".gds"))) - study.annot <- read.gdsn(index.gdsn(gdsSample, "study.annot")) - - if(length(which(study.annot$study.id == "Ref.1KG")) == 0) { - stop("The study Ref.1KG is not define you must run the ", - "function addStudy1Kg \n") - } - - sample.Unrel.All <- study.annot$data.id[study.annot$study.id == - "Ref.1KG"] - - listPCA <- computePrunedPCARef(gdsSample, sample.Unrel.All, np) - - listPCA[["samp.load"]] <- projectSample2PCA(gdsSample, listPCA, - listSamples[i], np) - closefn.gds(gdsSample) - - saveRDS(listPCA, file.path(pathProfileGDS, paste0(listSamples[i], - ".pca.pruned.rds"))) - - } - - return(0L) -} - - -#' @title Deprecated Function -#' -#' @description Deprecated -#' -#' @param gdsSample an object of class \code{gds} opened related to -#' the sample -#' -#' @param pruned TODO -#' -#' @param sample.id TODO -#' -#' @param sample.ref TODO -#' -#' @param study.annot a \code{data.frame} with one entry from study.annot in -#' the gds -#' -#' @param algorithm a \code{character} string representing the algorithm used -#' to calculate the PCA. The 2 choices are "exact" (traditional exact -#' calculation) and "randomized" (fast PCA with randomized algorithm -#' introduced in Galinsky et al. 2016). Default: \code{"exact"}. -#' -#' @param eigen.cnt a single \code{integer} indicating the number of -#' eigenvectors that will be in the output of the \link[SNPRelate]{snpgdsPCA} -#' function; if 'eigen.cnt' <= 0, then all eigenvectors are returned. -#' Default: \code{32L}. -#' -#' @return A \code{list} TODO with the sample.id and eigenvectors. -#' -#' @references -#' -#' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, -#' Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution -#' of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. -#' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt add.gdsn index.gdsn -#' @importFrom SNPRelate snpgdsPCA snpgdsPCASampLoading snpgdsPCASampLoading -#' @encoding UTF-8 -#' @keywords internal -computePCAsynthetic <- function(gdsSample, pruned, sample.id, - sample.ref, study.annot, - algorithm="exact", eigen.cnt=32L) { - - if(nrow(study.annot) != 1) { - stop("Number of sample in study.annot not equal to 1\n") - } - - sample.pos <- which(sample.id == study.annot$data.id[1]) - sample.Unrel <- sample.ref[which(sample.ref != study.annot$case.id[1])] - - g <- read.gdsn(index.gdsn(gdsSample, "genotype"), - start=c(1, sample.pos), count=c(-1, 1)) - - listPCA <- list() - - listPCA[["pruned"]] <- pruned[which(g != 3)] - rm(g) - - listPCA[["pca.unrel"]] <- snpgdsPCA(gdsSample, - sample.id=sample.Unrel, - snp.id=listPCA[["pruned"]], - num.thread=1, - algorithm=algorithm, - eigen.cnt=eigen.cnt, - verbose=TRUE) - - listPCA[["snp.load"]] <- snpgdsPCASNPLoading(listPCA[["pca.unrel"]], - gdsobj=gdsSample, - num.thread=1, - verbose=TRUE) - - listPCA[["samp.load"]] <- snpgdsPCASampLoading(listPCA[["snp.load"]], - gdsobj=gdsSample, - sample.id=sample.id[sample.pos], - num.thread=1, verbose=TRUE) - - listRes <- list(sample.id=sample.id[sample.pos], - eigenvector.ref=listPCA[["pca.unrel"]]$eigenvect, - eigenvector=listPCA[["samp.load"]]$eigenvect) - return(listRes) -} - - #' @title Compile all the inferred ancestry results done on the #' synthetic profiles for different D and K values in the objective of #' selecting the optimal D and K values for a specific profile @@ -2507,4 +2018,3 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, return(res) } - diff --git a/man/computeKNNSuperPopSample.Rd b/man/computeKNNSuperPopSample.Rd deleted file mode 100644 index 57ef92610..000000000 --- a/man/computeKNNSuperPopSample.Rd +++ /dev/null @@ -1,46 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy_internal.R -\encoding{UTF-8} -\name{computeKNNSuperPopSample} -\alias{computeKNNSuperPopSample} -\title{Deprecated} -\usage{ -computeKNNSuperPopSample( - gdsSample, - listEigenvector, - name.id, - spRef, - studyIDRef = "Ref.1KG", - kList = seq_len(15), - pcaList = 2:15 -) -} -\arguments{ -\item{listEigenvector}{TODO see return of computePCARefSample} - -\item{spRef}{TODO} - -\item{kList}{a \code{vector} of \code{integer} representing the list of -values tested for the _K_ parameter. The _K_ parameter represents the -number of neighbors used in the K-nearest neighbor analysis. If \code{NULL}, -the value \code{seq_len(15)} is assigned. -Default: \code{seq_len(15)}.} - -\item{pcaList}{TODO array of the pca dimension possible values} - -\item{sample.ref}{TODO} - -\item{study.annot}{a \code{data.frame} with one entry from study.annot in -the gds} -} -\value{ -A \code{list} TODO with the sample.id and eigenvectors -and a table with KNN callfor different K and pca dimension. -} -\description{ -Deprecated -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{internal} diff --git a/man/computeKNNSuperPoprSynthetic.Rd b/man/computeKNNSuperPoprSynthetic.Rd deleted file mode 100644 index d4f087ac5..000000000 --- a/man/computeKNNSuperPoprSynthetic.Rd +++ /dev/null @@ -1,45 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy_internal.R -\encoding{UTF-8} -\name{computeKNNSuperPoprSynthetic} -\alias{computeKNNSuperPoprSynthetic} -\title{Deprecated} -\usage{ -computeKNNSuperPoprSynthetic( - listEigenvector, - sample.ref, - study.annot, - spRef, - kList = seq_len(15), - pcaList = seq(2, 15, 1) -) -} -\arguments{ -\item{listEigenvector}{TODO see return of computePCAsynthetic} - -\item{sample.ref}{TODO} - -\item{study.annot}{a \code{data.frame} with one entry from study.annot in -the gds} - -\item{spRef}{TODO} - -\item{kList}{a \code{vector} of \code{integer} representing the list of -values tested for the K parameter. The K parameter represents the -number of neighbors used in the K-nearest neighbors analysis. If -\code{NULL}, the value \code{seq_len(15)} is assigned. -Default: \code{seq_len(15)}.} - -\item{pcaList}{TODO array of the pca dimension possible values} -} -\value{ -A \code{list} TODO with the sample.id and eigenvectors -and a table with KNN callfor different K and pca dimension. -} -\description{ -Deprecated -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{internal} diff --git a/man/computePCAForSamples.Rd b/man/computePCAForSamples.Rd deleted file mode 100644 index 08fd6625a..000000000 --- a/man/computePCAForSamples.Rd +++ /dev/null @@ -1,40 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy_internal.R -\encoding{UTF-8} -\name{computePCAForSamples} -\alias{computePCAForSamples} -\title{Deprecated - Project patients onto existing principal component -axes (PCA)} -\usage{ -computePCAForSamples(gds, pathProfileGDS, listSamples, np = 1L) -} -\arguments{ -\item{gds}{an object of class -\code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, a SNP -GDS file.} - -\item{pathProfileGDS}{the path of an object of class \code{gds} related to -the sample} - -\item{listSamples}{a \code{vector} of string representing the samples for -which compute the PCA.} - -\item{np}{a single positive \code{integer} representing the number of -threads. Default: \code{1L}.} -} -\value{ -The integer \code{0L} when successful. -} -\description{ -This function calculates the patient eigenvectors using -the specified SNP loadings. Deprecated -} -\details{ -More information about the method used to calculate the patient eigenvectors -can be found at the Bioconductor SNPRelate website: -https://bioconductor.org/packages/SNPRelate/ -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{internal} diff --git a/man/computePCAsynthetic.Rd b/man/computePCAsynthetic.Rd deleted file mode 100644 index a168afc32..000000000 --- a/man/computePCAsynthetic.Rd +++ /dev/null @@ -1,56 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy_internal.R -\encoding{UTF-8} -\name{computePCAsynthetic} -\alias{computePCAsynthetic} -\title{Deprecated Function} -\usage{ -computePCAsynthetic( - gdsSample, - pruned, - sample.id, - sample.ref, - study.annot, - algorithm = "exact", - eigen.cnt = 32L -) -} -\arguments{ -\item{gdsSample}{an object of class \code{gds} opened related to -the sample} - -\item{pruned}{TODO} - -\item{sample.id}{TODO} - -\item{sample.ref}{TODO} - -\item{study.annot}{a \code{data.frame} with one entry from study.annot in -the gds} - -\item{algorithm}{a \code{character} string representing the algorithm used -to calculate the PCA. The 2 choices are "exact" (traditional exact -calculation) and "randomized" (fast PCA with randomized algorithm -introduced in Galinsky et al. 2016). Default: \code{"exact"}.} - -\item{eigen.cnt}{a single \code{integer} indicating the number of -eigenvectors that will be in the output of the \link[SNPRelate]{snpgdsPCA} -function; if 'eigen.cnt' <= 0, then all eigenvectors are returned. -Default: \code{32L}.} -} -\value{ -A \code{list} TODO with the sample.id and eigenvectors. -} -\description{ -Deprecated -} -\references{ -Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, -Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution -of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. -doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{internal} diff --git a/man/computePoolSyntheticAncestry.Rd b/man/computePoolSyntheticAncestry.Rd deleted file mode 100644 index 17bee4431..000000000 --- a/man/computePoolSyntheticAncestry.Rd +++ /dev/null @@ -1,107 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy.R -\encoding{UTF-8} -\name{computePoolSyntheticAncestry} -\alias{computePoolSyntheticAncestry} -\title{TODO} -\usage{ -computePoolSyntheticAncestry( - gdsReference, - gdsSample, - profileID, - dataRef, - spRef, - studyIDSyn, - np = 1L, - listCatPop = c("EAS", "EUR", "AFR", "AMR", "SAS"), - fieldPopIn1KG = "superPop", - fieldPopInfAnc = "SuperPop", - kList = seq(2, 15, 1), - pcaList = seq(2, 15, 1), - algorithm = "exact", - eigenCount = 32L, - missingRate = 0.025 -) -} -\arguments{ -\item{gdsReference}{an object of class \link[gdsfmt]{gds.class} (a GDS -file), the opened Reference GDS file.} - -\item{gdsSample}{an object of class \link[gdsfmt]{gds.class} (a GDS file), -an opened Profile GDS file.} - -\item{profileID}{a single \code{character} string representing the -profile identifier.} - -\item{dataRef}{a \code{data.frame} containing the information of the -synthetic profiles that will be} - -\item{spRef}{TODO} - -\item{studyIDSyn}{a \code{character} string corresponding to the study -identifier. The study identifier must be present in the Profile GDS file.} - -\item{np}{a single positive \code{integer} representing the number of -threads. Default: \code{1L}.} - -\item{listCatPop}{a \code{vector} of \code{character} string -representing the list of possible ancestry assignations. Default: -\code{("EAS", "EUR", "AFR", "AMR", "SAS")}.} - -\item{fieldPopIn1KG}{a \code{character} string representing TODO . -Default: \code{"superPop"}.} - -\item{fieldPopInfAnc}{a \code{character} string representing the name of -the column that will contain the inferred ancestry for the specified -dataset. Default: \code{"SuperPop"}.} - -\item{kList}{a \code{vector} of \code{integer} representing the list of -values tested for the _K_ parameter. The _K_ parameter represents the -number of neighbors used in the K-nearest neighbors analysis. If -\code{NULL}, the value \code{seq(2,15,1)} is assigned. -Default: \code{seq(2,15,1)}.} - -\item{pcaList}{a \code{vector} of \code{integer} representing the list of -values tested for the _D_ parameter. The _D_ parameter represents the -number of dimensions used in the PCA analysis. If \code{NULL}, -the value \code{seq(2,15,1)} is assigned. -Default: \code{seq(2,15,1)}.} - -\item{algorithm}{a \code{character} string representing the algorithm used -to calculate the PCA. The 2 choices are "exact" (traditional exact -calculation) and "randomized" (fast PCA with randomized algorithm -introduced in Galinsky et al. 2016). Default: \code{"exact"}.} - -\item{eigenCount}{a single \code{integer} indicating the number of -eigenvectors that will be in the output of the \link[SNPRelate]{snpgdsPCA} -function; if 'eigenCount' <= 0, then all eigenvectors are returned. -Default: \code{32L}.} - -\item{missingRate}{a \code{numeric} value representing the threshold -missing rate at with the SNVs are discarded; the SNVs are retained in the -\link[SNPRelate]{snpgdsPCA} -with "<= missingRate" only; if \code{NaN}, no missing threshold. -Default: \code{0.025}.} -} -\value{ -A \code{list} TODO with the sample.id and eigenvectors -and a table with KNN callfor different K and pca dimension. -} -\description{ -TODO -} -\examples{ - -# TODO -listEigenvector <- "TOTO" - -} -\references{ -Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, -Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution -of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. -doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} diff --git a/man/validateComputePoolSyntheticAncestry.Rd b/man/validateComputePoolSyntheticAncestry.Rd deleted file mode 100644 index 9aba6e559..000000000 --- a/man/validateComputePoolSyntheticAncestry.Rd +++ /dev/null @@ -1,121 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy_internal.R -\encoding{UTF-8} -\name{validateComputePoolSyntheticAncestry} -\alias{validateComputePoolSyntheticAncestry} -\title{Validate the input parameters for computePoolSyntheticAncestry() -function} -\usage{ -validateComputePoolSyntheticAncestry( - gdsReference, - profileGDS, - profileID, - dataRef, - spRef, - studyIDSyn, - np, - listCatPop, - fieldPopIn1KG, - fieldPopInfAnc, - kList, - pcaList, - algorithm, - eigenCount, - missingRate -) -} -\arguments{ -\item{gdsReference}{an object of class \link[gdsfmt]{gds.class} -(a GDS file), the opened 1KG GDS file.} - -\item{profileGDS}{an object of class \link[gdsfmt]{gds.class} (a GDS file), -an opened Profile GDS file.} - -\item{profileID}{a single \code{character} string representing the -profile identifier.} - -\item{dataRef}{a \code{data.frame} TODO} - -\item{spRef}{TODO} - -\item{studyIDSyn}{a \code{character} string corresponding to the study -identifier. The study identifier must be present in the GDS Sample file.} - -\item{np}{a single positive \code{integer} representing the number of -threads. Default: \code{1L}.} - -\item{listCatPop}{a \code{vector} of \code{character} string -representing the list of possible ancestry assignations. Default: -\code{("EAS", "EUR", "AFR", "AMR", "SAS")}.} - -\item{fieldPopIn1KG}{a \code{character} string representing the TODO} - -\item{fieldPopInfAnc}{a \code{character} string representing the name of -the column that will contain the inferred ancestry for the specified -dataset. Default: \code{"SuperPop"}.} - -\item{kList}{a \code{vector} of \code{integer} representing the list of -values tested for the _K_ parameter. The _K_ parameter represents the -number of neighbors used in the K-nearest neighbors analysis. If -\code{NULL}, the value \code{seq(2,15,1)} is assigned. -Default: \code{seq(2,15,1)}.} - -\item{pcaList}{a \code{vector} of \code{integer} representing the list of -values tested for the _D_ parameter. The _D_ parameter represents the -number of dimensions used in the PCA analysis. If \code{NULL}, -the value \code{seq(2,15,1)} is assigned. -Default: \code{seq(2,15,1)}.} - -\item{algorithm}{a \code{character} string representing the algorithm used -to calculate the PCA. The 2 choices are "exact" (traditional exact -calculation) and "randomized" (fast PCA with randomized algorithm -introduced in Galinsky et al. 2016). Default: \code{"exact"}.} - -\item{eigen.cnt}{a single \code{integer} indicating the number of -eigenvectors that will be in the output of the \link[SNPRelate]{snpgdsPCA} -function; if 'eigen.cnt' <= 0, then all eigenvectors are returned.} - -\item{missing.rate}{a \code{numeric} value representing the threshold -missing rate at with the SNVs are discarded; the SNVs are retained in the -\link[SNPRelate]{snpgdsPCA} -with "<= missing.rate" only; if \code{NaN}, no missing threshold.} -} -\value{ -The integer \code{0L} when successful. -} -\description{ -The function validates the input parameters for the -\code{\link{computePoolSyntheticAncestry}} function. -When a parameter is not as expected, an error message is generated. -} -\examples{ - -## Path to the demo 1KG GDS file is located in this package -dataDir <- system.file("extdata/tests", package="RAIDS") -fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") -fileProfileGDS <- file.path(dataDir, "ex1_demo.gds") - -## Open GDS files -gds1KG <- snpgdsOpen(fileGDS) -gdsProfile <- openfn.gds(fileProfileGDS) - -dataRef <- data.frame(test=c(1,2), stringAsFactro=FALSE) - -## The function returns 0L when all parameters are valid -RAIDS:::validateComputePoolSyntheticAncestry(gdsReference=gds1KG, - profileGDS=gdsProfile, profileID="SampleID", - dataRef=dataRef, spRef=NULL, studyIDSyn="MyStudy", - np=1L, listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), - fieldPopIn1KG="SuperPop", fieldPopInfAnc="SuperPop", - kList=seq(2,15,1), pcaList=seq(2,15,1), - algorithm="exact", eigenCount=32L, missingRate=0.025) - -## Close GDS files (it is important to always close the GDS files) -closefn.gds(gds1KG) -closefn.gds(gdsProfile) - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{internal} diff --git a/tests/testthat/test-processStudy.R b/tests/testthat/test-processStudy.R index 598aad88a..3b6f300ff 100644 --- a/tests/testthat/test-processStudy.R +++ b/tests/testthat/test-processStudy.R @@ -2160,175 +2160,6 @@ test_that(paste0("computeAncestryFromSyntheticFile() must return expected result -############################################################################# -### Tests computePoolSyntheticAncestry() results -############################################################################# - -context("computePoolSyntheticAncestry() results") - - -test_that("computePoolSyntheticAncestry() must return error when gdsReference is a character string", { - - dataDir <- system.file("extdata/tests", package="RAIDS") - fileGDS <- file.path(dataDir, "1KG_Test.gds") - - gdsF <- openfn.gds(fileGDS) - withr::defer((gdsfmt::closefn.gds(gdsF)), envir=parent.frame()) - - dataRefDemo <- data.frame(sample.id=c("SampleA", "SampleB", "SampleC", - "SampleD"), - pop.group=c("TSI", "TSI", "YRI", "YRI"), - superPop=c("EUR", "EUR", "AFR", "AFR")) - - error_message <- paste0("The \'gdsReference\' must be an object of ", - "class \'gds.class\'.") - - expect_error(computePoolSyntheticAncestry(gdsReference="toto.gds", gdsSample=gdsF, - profileID="test", dataRef=dataRefDemo, spRef="TODO", - studyIDSyn="synthetic", - np=1L, listCatPop="EUR", fieldPopIn1KG="superPop", - fieldPopInfAnc="SuperPop", kList=seq(2, 15, 1), - pcaList=seq(2, 15, 1), algorithm="exact", - eigenCount=32L, missingRate=0.025), error_message) -}) - - -test_that(paste0("computePoolSyntheticAncestry() must return error when gds is a numerical value"), { - - dataDir <- system.file("extdata/tests", package="RAIDS") - fileGDS <- file.path(dataDir, "1KG_Test.gds") - - gdsF <- openfn.gds(fileGDS) - withr::defer((gdsfmt::closefn.gds(gdsF)), envir=parent.frame()) - - dataRefDemo <- data.frame(sample.id=c("SampleA", "SampleB", "SampleC", - "SampleD"), - pop.group=c("TSI", "TSI", "YRI", "YRI"), - superPop=c("EUR", "EUR", "AFR", "AFR")) - - error_message <- paste0("The \'gdsReference\' must be an object of ", - "class \'gds.class\'.") - - expect_error(computePoolSyntheticAncestry(gdsReference=31, gdsSample=gdsF, - profileID="test", dataRef=dataRefDemo, spRef="TODO", - studyIDSyn="synthetic", - np=1L, listCatPop="EUR", fieldPopIn1KG="superPop", - fieldPopInfAnc="SuperPop", kList=seq(2, 15, 1), - pcaList=seq(2, 15, 1), algorithm="exact", - eigenCount=32L, missingRate=0.025), error_message) -}) - - -test_that("computePoolSyntheticAncestry() must return error when profileGDS is a numerical value", { - - dataDir <- system.file("extdata/tests", package="RAIDS") - fileGDS <- file.path(dataDir, "1KG_Test.gds") - - gdsF <- openfn.gds(fileGDS) - withr::defer((gdsfmt::closefn.gds(gdsF)), envir=parent.frame()) - - dataRefDemo <- data.frame(sample.id=c("SampleA", "SampleB", "SampleC", - "SampleD"), - pop.group=c("TSI", "TSI", "YRI", "YRI"), - superPop=c("EUR", "EUR", "AFR", "AFR")) - - error_message <- paste0("The \'profileGDS\' must be an object of ", - "class \'gds.class\'.") - - expect_error(computePoolSyntheticAncestry(gdsReference=gdsF, gdsSample=33, - profileID="test", dataRef=dataRefDemo, spRef="TODO", - studyIDSyn="synthetic", - np=1L, listCatPop="EUR", fieldPopIn1KG="superPop", - fieldPopInfAnc="SuperPop", kList=seq(2, 15, 1), - pcaList=seq(2, 15, 1), algorithm="exact", - eigenCount=32L, missingRate=0.025), error_message) -}) - - -test_that("computePoolSyntheticAncestry() must return error when profileID is a numerical value", { - - dataDir <- system.file("extdata/tests", package="RAIDS") - fileGDS <- file.path(dataDir, "1KG_Test.gds") - - gdsF <- openfn.gds(fileGDS) - withr::defer((gdsfmt::closefn.gds(gdsF)), envir=parent.frame()) - - dataRefDemo <- data.frame(sample.id=c("SampleA", "SampleB", "SampleC", - "SampleD"), - pop.group=c("TSI", "TSI", "YRI", "YRI"), - superPop=c("EUR", "EUR", "AFR", "AFR")) - - error_message <- "The \'profileID\' parameter must be a character string." - - expect_error(computePoolSyntheticAncestry(gdsReference=gdsF, gdsSample=gdsF, - profileID=22, dataRef=dataRefDemo, spRef="TODO", - studyIDSyn="synthetic", np=1L, listCatPop="EUR", - fieldPopIn1KG="superPop", fieldPopInfAnc="SuperPop", - kList=seq(2, 15, 1), pcaList=seq(2, 15, 1), algorithm="exact", - eigenCount=32L, missingRate=0.025), error_message) -}) - - -test_that("computePoolSyntheticAncestry() must return error when dataRef is character string", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - gdsF <- openfn.gds(fileGDS) - withr::defer(closefn.gds(gdsF), envir=parent.frame()) - - error_message <- "The \'dataRef\' must be a data.frame object." - - expect_error(computePoolSyntheticAncestry(gdsReference=gdsF, gdsSample=gdsF, - profileID="test", dataRef="test", spRef="TODO", - studyIDSyn="synthetic", - np=1L, listCatPop="EUR", fieldPopIn1KG="superPop", - fieldPopInfAnc="SuperPop", kList=seq(2, 15, 1), - pcaList=seq(2, 15, 1), algorithm="exact", - eigenCount=32L, missingRate=0.025), error_message) -}) - - -test_that("computePoolSyntheticAncestry() must return error when studyIDSyn is numeric value", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - gdsF <- openfn.gds(fileGDS) - withr::defer(closefn.gds(gdsF), envir=parent.frame()) - - dataRefDemo <- data.frame(sample.id=c("SampleA", "SampleB", "SampleC", "SampleD"), - pop.group=c("TSI", "TSI", "YRI", "YRI"), - superPop=c("EUR", "EUR", "AFR", "AFR")) - - error_message <- "The \'studyIDSyn\' parameter must be a character string." - - expect_error(computePoolSyntheticAncestry(gdsReference=gdsF, gdsSample=gdsF, - profileID="test", dataRef=dataRefDemo, spRef="TODO", - studyIDSyn=33, - np=1L, listCatPop="EUR", fieldPopIn1KG="SuperPop", - fieldPopInfAnc="SuperPop", kList=seq(2, 15, 1), - pcaList=seq(2, 15, 1), algorithm="exact", - eigenCount=32L, missingRate=0.025), error_message) -}) - - -test_that("computePoolSyntheticAncestry() must return error when fieldPopIn1KG is numeric value", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - gdsF <- openfn.gds(fileGDS) - withr::defer(closefn.gds(gdsF), envir=parent.frame()) - - dataRefDemo <- data.frame(sample.id=c("SampleA", "SampleB", "SampleC", "SampleD"), - pop.group=c("TSI", "TSI", "YRI", "YRI"), - superPop=c("EUR", "EUR", "AFR", "AFR")) - - error_message <- "The \'fieldPopIn1KG\' parameter must be a character string." - - expect_error(computePoolSyntheticAncestry(gdsReference=gdsF, gdsSample=gdsF, - profileID="test", dataRef=dataRefDemo, spRef="TODO", - studyIDSyn="synthetic", - np=1L, listCatPop="EUR", fieldPopIn1KG=33, - fieldPopInfAnc="SuperPop", kList=seq(2, 15, 1), - pcaList=seq(2, 15, 1), algorithm="exact", - eigenCount=32L, missingRate=0.025), error_message) -}) ############################################################################# From 712d01c41fac30859727a8917577af2b07a1a863 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 5 Jun 2023 13:42:49 -0400 Subject: [PATCH 003/385] New vignette step by step --- vignettes/Ancestry_Inference_Step_by_Step.Rmd | 764 ++++++++++++++++++ 1 file changed, 764 insertions(+) create mode 100644 vignettes/Ancestry_Inference_Step_by_Step.Rmd diff --git a/vignettes/Ancestry_Inference_Step_by_Step.Rmd b/vignettes/Ancestry_Inference_Step_by_Step.Rmd new file mode 100644 index 000000000..328392c82 --- /dev/null +++ b/vignettes/Ancestry_Inference_Step_by_Step.Rmd @@ -0,0 +1,764 @@ +--- +title: "Genetic Ancestry Inference Step by Step (optional)" +author: Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +output: + BiocStyle::html_document: + number_sections: yes + toc: true + pkgdown: + number_sections: yes + as_is: true +urlcolor: darkred +linkcolor: darkred +vignette: > + %\VignetteIndexEntry{Genetic Ancestry Inference Step by Step (optional)} + %\VignettePackage{RAIDS} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r style, echo=FALSE, results='hide', warning=FALSE, message=FALSE} +BiocStyle::markdown() + +suppressPackageStartupMessages({ + library(knitr) + library(RAIDS) +}) + +set.seed(121444) +``` + +
+**Package**: `r Rpackage("RAIDS")`
+**Authors**: `r packageDescription("RAIDS")[["Author"]]`
+**Version**: `r packageDescription("RAIDS")$Version`
+**Compiled date**: `r Sys.Date()`
+**License**: `r packageDescription("RAIDS")[["License"]]`
+ +# Introduction + + +This is an overview of genetic ancestry inference from cancer-derived +molecular data: + +```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference process.", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_v01.png") +``` + +The main steps are: + +1. Format reference data from the 1000 Genomes (1KG) (optional) +2. Format cancer-derived data set starting from BAM files +3. Optimize ancestry inference parameters +4. Infer ancestry for the subjects of the external study + +All steps included from Step 2, sub-step 4, to Step 4 can be run through a +wrapper (as described in [Main vignette](RAIDS.html) or can be run separately. +Running those steps separately has the advantage of allowing finer parameter +selection. + +This vignette describes, in details, the process done by the wrapper from +Step 2, sub-step 4, to Step 4. + +
+
+ +## Step 1 - Format reference data from the 1000 Genomes (optional) + + +```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from 1000 Genomes (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_Step1_v01.png") +``` + + +The available pre-processed files are described in +the [main vignette](RAIDS.html). + +The detail execution of this step is explained in +the [Formatting the information from 1000 Genomes (optional)](Create_1KG_GDS_file.html) +vignette. + +
+ +## Step 2 - Prepare cancer-derived data for ancestry inference + +Molecular profiles in a cancer-derived data set must be formatted +following a series of sub-steps. + +```{r graphStep2, echo=FALSE, fig.align="center", fig.cap="Step 2 - Formatting the information from an external study", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_Step2_v01.png") +``` + +
+ +These are: + +1. Create a directory containing the 3 reference files from 1KG +2. Make a SNP pileup file for the profile +3. Create an RDS file containing information about the samples +4. Create a Sample GDS file (1 GDS file per sample) +5. Generate a pruned subset of the single nucleotide variants (SNVs) +6. Estimate the allelic frequency for the pruned SNVs + +The first steps, from Sub-step 1 to Sub-step 3, are described in the +[Main vigette](RAIDS.html). + +### Sub-Step 2.4 Create a profile GDS file (1 GDS file per profile) + +From here, you can run directly the [wrapper](#wrapper) function +or you can run each step separately as explained here. + +This step requires 3 files as input: + +- The **1KG GDS file** +- The **Profile SNP pileup file** (one per profile present in the study) +- The **Profile PED RDS file** (one file with information for all profiles in the study) + +A *data.frame* containing the general information about the study is +also required. The *data.frame* must contain those 3 columns: + +- **study.id**: The study identifier (example: TCGA-BRCA). +- **study.desc**: The description of the study. +- **study.platform**: The type of sequencing (example: RNA-seq). + +Using all those inputs, the *createStudy2GDS1KG()* function will +generate a **Profile GDS file**. One **Profile GDS file** is created for each +sample passed to the *listSamples* argument. + +```{r appendStudy2GDS1KG, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +################################################################# +## Load required package +################################################################# +library(RAIDS) + +################################################################# +## The 1KG GDS file and the 1KG SNV Annotation GDS file +## need to be located in the same directory +## Note that the 1KG GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +################################################################# +dataDir <- system.file("extdata", package="RAIDS") +path1KG <- file.path(dataDir, "example", "gdsRef") + +gds1KG <- file.path(path1KG, "ex1kg.gds") + +################################################################# +## The Profile SNP pileup files (one per sample) need +## to be located in the same directory. +################################################################# +pathGeno <- file.path(dataDir, "example", "snpPileup") + +################################################################# +## The path where the Profile GDS files (one per profile) +## will be created need to be specified. +################################################################# +pathProfileGDS <- file.path(dataDir, "example", "out") + +################################################################# +## The path and file name for the PED RDS file +## will the information about the analyzed samples +################################################################# +filePED <- file.path(dataDir, "example", "pedEx.rds") +ped <- readRDS(filePED) +head(ped) + +################################################################# +## A data frame containing general information about the study +## is also required. The data frame must have +## those 3 columns: "study.id", "study.desc", "study.platform" +################################################################# +studyDF <- data.frame(study.id="MYDATA", + study.desc="Description", + study.platform="PLATFORM", + stringsAsFactors=FALSE) + +################################################################# +## The list of profiles to analyzed is passed to the function. +## The profiles must be present in the Profile PED RDS file see +## sub-step 4 and must have an associated Profile SNP pileup file. +## Not all profiles present in the Profile PED file need to +## be selected. +################################################################# +listSamples <- ped[, "Name.ID"] + +################################################################# +## This function creates one Profile GDS file for each +## profile present in the 'listProfiles' parameter. +################################################################# +createStudy2GDS1KG(pathGeno=pathGeno, + pedStudy=ped, + fileNameGDS=gds1KG, + listProfiles=listSamples, + studyDF=studyDF, + pathProfileGDS=pathProfileGDS, + genoSource="snp-pileup") + +################################################################# +## The Profile GDS file has been created in the +## directory pathProfileGDS using the name of the sample (ex1) +################################################################# +list.files(path=pathProfileGDS) +``` + +
+ +### Sub-Step 2.5 Generate a pruned subset of the single nucleotide variants (SNVs) + +The initial list of 1KG SNVs is pruned, using linkage disequilibrium analysis, +and a profile-specific subset of SNVs is retained for each profile. This +information is added to the **Profile GDS file**. + +The __pruningSample()__ function requires the **1KG GDS file** as input. It +also requires the path to the **Profile GDS file(s)**. + +Note that this step can require large disk space. + +```{r pruningSample, echo=TRUE, eval=TRUE, warning=FALSE, message=FALSE} +############################################################## +## Load required package +############################################################## +library(RAIDS) + +############################################################## +## The 1KG GDS file is required (demo version) +## Note that the 1KG GDS file used for this example is a +## simplified version and CANNOT be used for any real analyses +############################################################## +path1KG <- file.path(dataDir, "example", "gdsRef") + +fileGDS <- file.path(path1KG, "ex1kg.gds") + +## Open the 1KG GDS file (demo version) +gds1KG <- snpgdsOpen(fileGDS) + +############################################################## +## The pruning function is called with one profile as input at the time +############################################################## +for(i in seq_len(length(listSamples))) { + ## Compute the SNV pruned subset + ## studyID: Study identifier as defined in the preceding sub-step 4. + ## The study identifier must be the same that the one present in + ## Profile GDS file. + ## pathProfileGDS: All Profile GDS files must be in the same directory + ## sub-step 4. + pruningSample(gdsReference=gds1KG, + currentProfile=listSamples[i], + studyID=studyDF$study.id, + pathProfileGDS=pathProfileGDS) + + ## Profile GDS file for the current profile + ## The file name corresponds to the path + profile identifier + ".gds" + fileGDSProfile <- file.path(pathProfileGDS, paste0(listSamples[i], ".gds")) + + ## Add the genotype information for the list of pruned SNVs + ## into the Profile GDS file + ## The genotype information is extracted from the 1KG GDS file + add1KG2SampleGDS(gdsReference=gds1KG, fileProfileGDS=fileGDSProfile, + currentProfile=listSamples[i], + studyID=studyDF$study.id) + + ## Add annotation from the 1KG GDS file to the Profile GDS file + ## This is required. + addStudy1Kg(gdsReference=gds1KG, fileProfileGDS=fileGDSProfile, + verbose=FALSE) +} + +## Close the 1KG GDS file (it is important to always close the GDS files) +closefn.gds(gds1KG) +``` + +
+ +### Sub-Step 2.6 Estimate the allelic fraction for the pruned SNVs + +The __estimateAllelicFraction()__ estimates the allele fraction for all +SNVs present in the pruned SNV dataset. Note that the function requires +different inputs for DNA and RNA profiles. + +For the DNA samples, these 2 files are required: + +1. The **Profile GDS file** +2. The **1KG GDS file** + +For the RNA samples, these 3 files are required: + +1. The **Profile GDS file** +2. The **1KG GDS file** +3. The **1KG SNV Annotation GDS file** + +In both cases, the other required input is: + +1. The information about the length of the chromosomes +2. The profile identifier (it corresponds to the Profile GDS file name) +3. The study identifier (it should correspond to the one used previously) + +The information about the length of the chromosomes must be assigned into a +*vector* object. This is an example on how to retrieve the information. +There are alternative ways to retrieve this information, e.g., + +```{r extractChrLength, echo=TRUE, message=FALSE, warning=FALSE, collapse=TRUE} +################################################################### +## Load required library +################################################################### +library(BSgenome.Hsapiens.UCSC.hg38) + +################################################################### +## The length of each chromosome is required +## Chromosomes X, Y and M need relabeling (see below) +## There are alternative ways to retrieve this information +################################################################### +chrInfo <- integer(25L) +for(i in seq_len(22L)) { + chrInfo[i] <- length(Hsapiens[[paste0("chr", i)]]) +} +chrInfo[23] <- length(Hsapiens[["chrX"]]) +chrInfo[24] <- length(Hsapiens[["chrY"]]) +chrInfo[25] <- length(Hsapiens[["chrM"]]) + +chrInfo +``` + +
+
+ +The __estimateAllelicFraction()__ function processes one profile at the time, +as shown in this example. + + +```{r estimateAllelicFraction, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +##################################################################### +## Load the required packages +##################################################################### +library(RAIDS) +library(gdsfmt) + +##################################################################### +## The 1KG GDS file is required +## The 1KG SNV Annotation GDS file is only required for RNA profiles +##################################################################### +path1KG <- file.path(dataDir, "example", "gdsRef") + +file1KG <- file.path(path1KG, "ex1kg.gds") +fileAnnot1KG <- file.path(path1KG, "exAnnot1kg.gds") + +## Open the 1KG GDS file +gds <- snpgdsOpen(file1KG) + +##################################################################### +## The information about the length of the chromosomes +##################################################################### +head(chrInfo) + +##################################################################### +## The function must be called for each profile +## This example only uses one profile +##################################################################### +## The first profile is used in the demo +profileName <- listSamples[1] + +##################################################################### +## The Profile GDS file is required +##################################################################### +## The name must correspond to the profile identifier +fileProfile <- file.path(pathProfileGDS, paste0(profileName, ".gds")) + +## Open the Profile GDS file in writing mode +gdsProfile <- openfn.gds(fileProfile, readonly=FALSE) + +################################################################### +## The estimation of the allelic fraction +################################################################### +## Estimate the allele fraction of the pruned SNVs +## The current example is for a DNA sample +## In the case of RNA sample, the function needs different inputs +## such as the 1KG Annotation GDS file and +## The 'blockID' should be as listed in the 1KG Annotation GDS file +## for the gene annotation of the SNVs +estimateAllelicFraction(gdsReference=gds, gdsProfile=gdsProfile, + currentProfile=profileName, + studyID=studyDF$study.id, + chrInfo=chrInfo) + +## Close both GDS files (important) +closefn.gds(gdsProfile) +closefn.gds(gds) +``` + +This step must be executed for each profile present in the study. + +
+ + +## Step 3 - Optimize the ancestry inference parameters + +At this step, optimization of the parameters is required to maximize the +the ancestry inference accuracy (next step). + +```{r graphStep3, echo=FALSE, fig.align="center", fig.cap="Step 3 - Find the optimized parameters for the ancestry inference", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_Step3_v01.png") +``` + +Two inference parameters to be optimized: + +- _K_: the number of neighbors used to call the ancestry +- _D_: the number of PCA components retained + +The accuracy is evaluated using a synthetic data set created from merging one +cancer profile with multiple 1KG samples of known ancestry. Using the synthetic +profiles, a range of _K_ and _D_ values are tested. Through that process, the +_K_ and _D_ values are tuned to maximize accuracy. + +This step consists of two sub-steps: + +1. Generate the synthetic dataset +2. Compute the PCA-KNN ancestry call for each synthetic profile + +
+ +### Sub-Step 3.1 Generate the synthetic dataset + +A synthetic profile is generated through the merging of one cancer profile +with one 1KG sample of known ancestry. Multiple 1KG samples of different +ancestry are required to create a synthetic data set that will be able to +show the specific accuracy for each super-population. All the synthetic +profiles are saved in the **Profile GDS file** corresponding to the +cancer profile used to generate the synthetic data set. + +In summary, a fixed number of profiles for each super-population is extracted +from the 1KG study. The information is saved in the **Profile GDS file** +associated to the selected cancer profile. A synthetic profile is created for +each combination of one 1KG sample and cancer profile. All synthetic profiles +are then saved in the **Profile GDS file**. + +The three functions _select1KGPop()_, _prepSynthetic()_ and _syntheticGeno()_ +are used for the synthetic data synthesis. + +These 3 files are required: + +1. The **Profile GDS file** +2. The **1KG GDS file** +3. The **1KG Annotation GDS file** + + +```{r generateSynthetic, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +#################################################################### +## Load required packages +#################################################################### +library(RAIDS) +library(gdsfmt) + +#################################################################### +## Randomly extract a fixed number of profiles for each +## subcontinental population present in the 1KG GDS file. +## When not enough profiles are available, all profiles are selected. +#################################################################### +gds1KG <- snpgdsOpen(file1KG) + +#################################################################### +## Fix seed to ensure reproducible results +#################################################################### +set.seed(3043) + +#################################################################### +## Select the profiles from 1KG for the synthetic data. +## Here we select 2 profiles from 1KG for each subcontinental-level +## Normally, we use 30 profiles from 1KG for each +## subcontinental-level but it is too big for the example. +## The 1KG GDS file in this example only has 6 profiles for each +## subcontinental-level (for demo purpose only) +#################################################################### +dataRef <- select1KGPop(gds1KG, nbProfiles=2L) + +## Extract the list of selected 1KG sample identifiers +listProfileRef <- dataRef$sample.id + +#################################################################### +## A data.frame with the description of the study for the synthetic +## data is required. +## The column names must be as shown +#################################################################### +syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", + study.desc="MYDATA synthetic data", + study.platform="PLATFORM", + stringsAsFactors=FALSE) + +## The Profile GDS file is needed +fileProfile <- file.path(pathProfileGDS, paste0(profileName, ".gds")) + +#################################################################### +## The prepSynthetic() function prepares the annotation for +## the synthetic data +## The information is saved into the Profile GDS file +#################################################################### +prepSynthetic(fileProfileGDS=fileProfile, + listSampleRef=listProfileRef, + profileID=profileName, + studyDF=syntheticStudyDF, + prefix="1") + +#################################################################### +## Both the 1KG GDS file and the 1KG Annotation GDS file +## are required +#################################################################### +path1KG <- file.path(dataDir, "example", "gdsRef") +fileRefAnnot <- file.path(path1KG, "exAnnot1kg.gds") + +## Open 1KG Annotation GDS file +gdsRefAnnot <- openfn.gds(fileRefAnnot) + +#################################################################### +## The syntheticGeno() function generates the synthetic profiles. +## The synthetic profiles are saved in the Profile GDS file +#################################################################### +resG <- syntheticGeno(gdsReference=gds1KG, + gdsRefAnnot=gdsRefAnnot, + fileProfileGDS=fileProfile, + profileID=profileName, + listSampleRef=listProfileRef, + prefix="1") + +## Close both GDS files +closefn.gds(gds1KG) +closefn.gds(gdsRefAnnot) +``` + +
+ + +### Sub-Step 3.2 Perform the PCA-KNN ancestry call for each synthetic profile + +The ancestry is inferred for each synthetic profile. As the ancestry of origin +of the 1KG profile used to generate the synthetic profile is known, the +accuracy of the calls will be assessed for different parameters. + +```{r PCA.KNN.Synthetic, collapse=TRUE, echo=TRUE, eval=TRUE, warning=FALSE, message=FALSE} +##################################################################### +## Load required packages +##################################################################### +library(RAIDS) +library(gdsfmt) + +#################################################################### +## The 1KG GDS file is required +##################################################################### +## Open the 1KG GDS file +gds <- openfn.gds(file1KG) + +##################################################################### +## The path to the directory where the PCA results will be saved +## in RDS files. +## The directory must exist. +##################################################################### +pathOut <- file.path(pathProfileGDS) + +if(! file.exists(pathOut)) { + dir.create(pathOut) +} + +##################################################################### +## Get the super-population information (known ancestry) for the +## reference profiles. This is the ground truth for the 1KG profiles. +##################################################################### +refKnownSuperPop <- getRef1KGPop(gds, "superPop") + +##################################################################### +## Fix the RNG seed as in step 6 to ensure the same results +##################################################################### +set.seed(3043) + +## Select the 1KG samples used to generate the synthetic dataset +## Already done in step 6, no need to repeat if the results have been saved +dataRef <- select1KGPop(gds, nbProfiles=2L) + +##################################################################### +## The function splitSelectByPop() generates a matrix with the +## reference samples split by sub-continental population +##################################################################### +sampleRM <- splitSelectByPop(dataRef) + +## Loop for all cancer samples with associated synthetic data +for(i in seq_len(length(listSamples))) { + + ## The Profile GDS file associated to the cancer profile + fileProfile <- file.path(pathProfileGDS, + paste0(listSamples[i], ".gds")) + + ## A sub-directory is created for the cancer sample + ## Beware that the number of files created will correspond to the + ## number of rows in the sampleRM matrix + pathOutProfile <- file.path(pathOut, listSamples[i]) + if(! file.exists(pathOutProfile)) { + dir.create(pathOutProfile) + } + + ## Open the Profile GDS file + gdsProfile <- snpgdsOpen(fileProfile) + + ## For each row of the sampleRM matrix + for(j in seq_len(nrow(sampleRM))) { + ## Run a PCA analysis using 1 synthetic profile from each + ## sub-continental ancestry + ## The synthetic profiles are projected on the 1KG PCA space + ## (the 1KG reference profiles used to generate the synthetic profiles + ## are removed from this PCA) + ## The K-nearest neighbors analysis is done using + ## a range of K and D values + syntKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, + sampleRM=sampleRM[j,], + studyIDSyn=syntheticStudyDF$study.id, + np=4L, + spRef=refKnownSuperPop, + eigenCount=15L) + + ## Results are saved + saveRDS(syntKNN$matKNN, file.path(pathOutProfile, + paste0("KNN.synt.", listSamples[i], ".", j, ".rds"))) + } + + ## Close Sample GDS file (important) + closefn.gds(gdsProfile) +} + +## Close 1KG GDS file (important) +closefn.gds(gds) +``` + + +
+ +## Step 4 - Run the ancestry inference in the input data set + +The ancestry inference is done with the optimized _K_ and _D_ parameters. More +specifically, a PCA is generated using the 1KG reference samples and the +cancer sample. The _D_ parameter specifies the number of dimension for the +PCA. Then, the ancestry of the cancer sample is inferred using +a k-nearest neighbors classification method. The _K_ parameter specifies the +number of neighbors used for the classification. + + +```{r graphStep4, echo=FALSE, fig.align="center", fig.cap="Step 4 - Run the ancestry inference on the external study", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_Step4_v01.png") +``` + +
+ +The PCA of the sample and KNN sample and Call the ancestry with the optimal +_K_ and _D_ parameters. + +Note: The formal selection of _K_ and _D_ parameters is done at this step but +all the synthetic data are prepared in the step 3. + + +```{r PCA.KNN.Sample, warning=FALSE, message=FALSE, collapse=TRUE, echo=TRUE, eval=TRUE} +#################################################################### +## Load required packages +#################################################################### +library(RAIDS) +library(gdsfmt) + +#################################################################### +## The reference 1KG GDS file is required +#################################################################### + +## Open the 1KG GDS file +gdsReference <- openfn.gds(file1KG) + +## A directory where result files are going to be saved, +## where a sub-directory will be set up for each input profile +pathOut <- file.path(pathProfileGDS) + +if(! file.exists(pathOut)) { + dir.create(pathOut) +} + +#################################################################### +## The getRef1KGPop() function extract the known super-population +## of the reference samples. +## We expect the ancestry call from a synthetic profile to +## correspond to the known ancestry of the reference sample used to +## synthesize it. +#################################################################### +refKnownSuperPop <- getRef1KGPop(gdsReference, "superPop") + +## Loop on each profile +## Can also be run in parallel or on different clusters... +for(i in seq_len(length(listSamples))){ + + ## Extract the GDS file name and path for the current profile + fileProfile <- file.path(pathProfileGDS, paste0(listSamples[i], ".gds")) + + ## Directory where the KNN results of the synthetic profiles have been saved + pathKNN <- file.path(pathOut, listSamples[i]) + listFilesName <- dir(file.path(pathKNN), ".rds") + + ## List of the KNN result files from PCA run on synthetic data + listFiles <- file.path(file.path(pathKNN) , listFilesName) + + ## Open the Profile GDS file + gdsProfile <- snpgdsOpen(fileProfile) + + ## Select the optimal K and D parameters from the synthetic data results + ## Use those parameter to infer the ancestry of the specific profile + resCall <- computeAncestryFromSyntheticFile(gdsReference=gdsReference, + gdsProfile=gdsProfile, + listFiles=listFiles, + currentProfile=listSamples[i], + spRef=refKnownSuperPop, + studyIDSyn=syntheticStudyDF$study.id, + np=1L) + + saveRDS(resCall, file.path(pathOut, + paste0(listSamples[i], ".infoCall", ".rds"))) + + write.csv(resCall$Ancestry, + file.path(pathOut, paste0(listSamples[i], ".Ancestry",".csv")), + quote=FALSE, row.names=FALSE) + + ## Close the Profile GDS file (important) + closefn.gds(gdsProfile) +} + +## Close the 1KG GDS file (important) +closefn.gds(gdsReference) + +#################################################################### +## Show the ancestry inference (SuperPop) and +## optimal number of PCA components D +## optimal number of neighbours K +#################################################################### +resAncestry <- read.csv(file.path(pathOut, + paste0(ped$Name.ID[1], ".Ancestry.csv"))) +resAncestry + +## Clean-up demo files +unlink(fileProfile, force=TRUE) +unlink(pathOut, recursive=TRUE, force=TRUE) +``` + + +The *computeAncestryFromSyntheticFile()* function generates 3 types of files +in the *OUTPUT* directory. + +* The ancestry inference CSV file (".Ancestry.csv" file) +* The inference information RDS file (".infoCall.rds" file) +* The parameter information RDS files from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory) + +In addition, a sub-directory (named using the *profile ID*) is +also created. + + +# Session info + +Here is the output of `sessionInfo()` in the enviroment in which this document was +compiled: + +```{r sessionInfo, echo=FALSE} +sessionInfo() +``` + +
+
+ + +# References + From f810c40bde3ecbb3304c0763902360ae9493fc44 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 5 Jun 2023 17:26:01 -0400 Subject: [PATCH 004/385] Remove numbers in toc and update text in vignette --- vignettes/Ancestry_Inference_Step_by_Step.Rmd | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/vignettes/Ancestry_Inference_Step_by_Step.Rmd b/vignettes/Ancestry_Inference_Step_by_Step.Rmd index 328392c82..308d36c63 100644 --- a/vignettes/Ancestry_Inference_Step_by_Step.Rmd +++ b/vignettes/Ancestry_Inference_Step_by_Step.Rmd @@ -3,10 +3,10 @@ title: "Genetic Ancestry Inference Step by Step (optional)" author: Pascal Belleau, Astrid Deschênes and Alexander Krasnitz output: BiocStyle::html_document: - number_sections: yes + number_sections: no toc: true pkgdown: - number_sections: yes + number_sections: no as_is: true urlcolor: darkred linkcolor: darkred @@ -52,9 +52,9 @@ The main steps are: 3. Optimize ancestry inference parameters 4. Infer ancestry for the subjects of the external study -All steps included from Step 2, sub-step 4, to Step 4 can be run through a -wrapper (as described in [Main vignette](RAIDS.html) or can be run separately. -Running those steps separately has the advantage of allowing finer parameter +All steps from Step 2, sub-step 4, to Step 4 can be run through a +wrapper (as described in [Main vignette](RAIDS.html). Those steps can also be +run separately; this has the advantage of allowing finer parameter selection. This vignette describes, in details, the process done by the wrapper from @@ -71,13 +71,14 @@ knitr::include_graphics("MainSteps_Step1_v01.png") ``` -The available pre-processed files are described in -the [main vignette](RAIDS.html). - -The detail execution of this step is explained in +The detail execution of this step is presented in the [Formatting the information from 1000 Genomes (optional)](Create_1KG_GDS_file.html) vignette. +In addition, the available pre-processed files are described in +the [Main vignette](RAIDS.html). + +
## Step 2 - Prepare cancer-derived data for ancestry inference @@ -105,9 +106,6 @@ The first steps, from Sub-step 1 to Sub-step 3, are described in the ### Sub-Step 2.4 Create a profile GDS file (1 GDS file per profile) -From here, you can run directly the [wrapper](#wrapper) function -or you can run each step separately as explained here. - This step requires 3 files as input: - The **1KG GDS file** @@ -123,7 +121,7 @@ also required. The *data.frame* must contain those 3 columns: Using all those inputs, the *createStudy2GDS1KG()* function will generate a **Profile GDS file**. One **Profile GDS file** is created for each -sample passed to the *listSamples* argument. +profile passed to the *listProfiles* argument. ```{r appendStudy2GDS1KG, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ################################################################# @@ -132,8 +130,7 @@ sample passed to the *listSamples* argument. library(RAIDS) ################################################################# -## The 1KG GDS file and the 1KG SNV Annotation GDS file -## need to be located in the same directory +## The 1KG GDS file location ## Note that the 1KG GDS file used for this example is a ## simplified version and CANNOT be used for any real analysis ################################################################# @@ -143,7 +140,7 @@ path1KG <- file.path(dataDir, "example", "gdsRef") gds1KG <- file.path(path1KG, "ex1kg.gds") ################################################################# -## The Profile SNP pileup files (one per sample) need +## The Profile SNP pileup files (one per profile) need ## to be located in the same directory. ################################################################# pathGeno <- file.path(dataDir, "example", "snpPileup") @@ -214,16 +211,16 @@ also requires the path to the **Profile GDS file(s)**. Note that this step can require large disk space. ```{r pruningSample, echo=TRUE, eval=TRUE, warning=FALSE, message=FALSE} -############################################################## +############################################################################# ## Load required package -############################################################## +############################################################################# library(RAIDS) -############################################################## +############################################################################# ## The 1KG GDS file is required (demo version) ## Note that the 1KG GDS file used for this example is a ## simplified version and CANNOT be used for any real analyses -############################################################## +############################################################################# path1KG <- file.path(dataDir, "example", "gdsRef") fileGDS <- file.path(path1KG, "ex1kg.gds") @@ -231,16 +228,15 @@ fileGDS <- file.path(path1KG, "ex1kg.gds") ## Open the 1KG GDS file (demo version) gds1KG <- snpgdsOpen(fileGDS) -############################################################## +############################################################################# ## The pruning function is called with one profile as input at the time -############################################################## +############################################################################# for(i in seq_len(length(listSamples))) { ## Compute the SNV pruned subset - ## studyID: Study identifier as defined in the preceding sub-step 4. + ## studyID: Study identifier as defined in the preceding sub-step. ## The study identifier must be the same that the one present in ## Profile GDS file. - ## pathProfileGDS: All Profile GDS files must be in the same directory - ## sub-step 4. + ## pathProfileGDS: All Profile GDS files must be in the same directory. pruningSample(gdsReference=gds1KG, currentProfile=listSamples[i], studyID=studyDF$study.id, @@ -269,10 +265,16 @@ closefn.gds(gds1KG)
+The nodes, with the genotype information for the pruned SNVs, are created in +the **Profile GDS file**: 'sample.id', 'snp.id', 'snp.chromosome', +'snp.position', 'snp.index', 'genotype' and 'lap'. + +
+ ### Sub-Step 2.6 Estimate the allelic fraction for the pruned SNVs The __estimateAllelicFraction()__ estimates the allele fraction for all -SNVs present in the pruned SNV dataset. Note that the function requires +SNVs present in the pruned SNV list. Note that the function requires different inputs for DNA and RNA profiles. For the DNA samples, these 2 files are required: @@ -286,7 +288,7 @@ For the RNA samples, these 3 files are required: 2. The **1KG GDS file** 3. The **1KG SNV Annotation GDS file** -In both cases, the other required input is: +In both cases, the other required inputs are: 1. The information about the length of the chromosomes 2. The profile identifier (it corresponds to the Profile GDS file name) @@ -749,8 +751,8 @@ also created. # Session info -Here is the output of `sessionInfo()` in the enviroment in which this document was -compiled: +Here is the output of `sessionInfo()` in the environment in which this +document was compiled: ```{r sessionInfo, echo=FALSE} sessionInfo() @@ -760,5 +762,3 @@ sessionInfo()
-# References - From daa42367b185a908a7584620abcc7d9c7e591d61 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 5 Jun 2023 19:51:49 -0400 Subject: [PATCH 005/385] Update doc for add1KGSampleGDS() function --- R/processStudy.R | 7 +++++-- man/add1KG2SampleGDS.Rd | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 525b50c62..065f22d26 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -580,7 +580,9 @@ pruningSample <- function(gdsReference, #' #' @description The function extracts the information about the pruned SNVs #' from the 1KG GDS file and adds entries related to the pruned SNVs in -#' the Profile GDS file. +#' the Profile GDS file. The nodes are added to the Profile GDS file: +#' 'sample.id', 'snp.id', 'snp.chromosome', 'snp.position', 'snp.index', +#' 'genotype' and 'lap'. #' #' @param gdsReference an object of class #' \link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file. @@ -600,6 +602,7 @@ pruningSample <- function(gdsReference, #' #' ## Required library for GDS #' library(gdsfmt) +#' library(SNPRelate) #' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") @@ -663,7 +666,7 @@ add1KG2SampleGDS <- function(gdsReference, fileProfileGDS, currentProfile, gdsSample <- openfn.gds(fileProfileGDS, readonly=FALSE) ## Extract needed information from 1KG GDS file - snp.id <- read.gdsn(index.gdsn(gdsReference,"snp.id")) + snp.id <- read.gdsn(index.gdsn(gdsReference, "snp.id")) ## Extract list of pruned SNVs from the GDS Sample file pruned <- read.gdsn(index.gdsn(gdsSample, "pruned.study")) diff --git a/man/add1KG2SampleGDS.Rd b/man/add1KG2SampleGDS.Rd index a1b526309..cb66868ce 100644 --- a/man/add1KG2SampleGDS.Rd +++ b/man/add1KG2SampleGDS.Rd @@ -27,12 +27,15 @@ The function returns \code{0L} when successful. \description{ The function extracts the information about the pruned SNVs from the 1KG GDS file and adds entries related to the pruned SNVs in -the Profile GDS file. +the Profile GDS file. The nodes are added to the Profile GDS file: +'sample.id', 'snp.id', 'snp.chromosome', 'snp.position', 'snp.index', +'genotype' and 'lap'. } \examples{ ## Required library for GDS library(gdsfmt) +library(SNPRelate) ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata/tests", package="RAIDS") From b827e18a5aa9f8ee82bd261222a40df4a46412e6 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 5 Jun 2023 20:46:21 -0400 Subject: [PATCH 006/385] Update doc for estimateAllelicFraction() function --- R/allelicFraction.R | 2 +- man/estimateAllelicFraction.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index 640becc19..56d072c83 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -161,7 +161,7 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' profile #' #' @description The function estimates the allelic fraction of the -#' SNVs for a specific prfile and add the information to the associated +#' SNVs for a specific profile and add the information to the associated #' Profile GDS file. The allelic fraction estimation method is adapted to #' the type of study (DNA or RNA). #' diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index e4fd8a310..3a96ed2bc 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -87,7 +87,7 @@ The integer \code{0L} when successful. } \description{ The function estimates the allelic fraction of the -SNVs for a specific prfile and add the information to the associated +SNVs for a specific profile and add the information to the associated Profile GDS file. The allelic fraction estimation method is adapted to the type of study (DNA or RNA). } From ca1b0c9a448e3329d1db463263d72d2ca44e733a Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 6 Jun 2023 01:02:47 -0400 Subject: [PATCH 007/385] Update step by step vignette --- vignettes/Ancestry_Inference_Step_by_Step.Rmd | 64 ++++++++++++------ .../ProfileGDSdemo_after_add1KG2SampleGDS.png | Bin 0 -> 10931 bytes ...eGDSdemo_after_estimateAllelicFraction.png | Bin 0 -> 11186 bytes vignettes/ProfileGDSdemo_when_created.png | Bin 0 -> 7848 bytes 4 files changed, 43 insertions(+), 21 deletions(-) create mode 100644 vignettes/ProfileGDSdemo_after_add1KG2SampleGDS.png create mode 100644 vignettes/ProfileGDSdemo_after_estimateAllelicFraction.png create mode 100644 vignettes/ProfileGDSdemo_when_created.png diff --git a/vignettes/Ancestry_Inference_Step_by_Step.Rmd b/vignettes/Ancestry_Inference_Step_by_Step.Rmd index 308d36c63..40fd01602 100644 --- a/vignettes/Ancestry_Inference_Step_by_Step.Rmd +++ b/vignettes/Ancestry_Inference_Step_by_Step.Rmd @@ -97,14 +97,14 @@ These are: 1. Create a directory containing the 3 reference files from 1KG 2. Make a SNP pileup file for the profile 3. Create an RDS file containing information about the samples -4. Create a Sample GDS file (1 GDS file per sample) +4. Create a Profile GDS file (one GDS file per profile) 5. Generate a pruned subset of the single nucleotide variants (SNVs) 6. Estimate the allelic frequency for the pruned SNVs -The first steps, from Sub-step 1 to Sub-step 3, are described in the +The first steps, from Sub-step 1 to Sub-step 3, are described in the [Main vigette](RAIDS.html). -### Sub-Step 2.4 Create a profile GDS file (1 GDS file per profile) +### Sub-Step 2.4 Create a Profile GDS file (one GDS file per profile) This step requires 3 files as input: @@ -199,6 +199,16 @@ list.files(path=pathProfileGDS)
+A **Profile GDS file** is created for each profile. The GDS file contains those +nodes: + +```{r graphStep24, echo=FALSE, fig.align="left", fig.cap="Step 2.4 - The nodes present in the newly created Profile GDS file (one GDS file per profile).", out.width='100%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("ProfileGDSdemo_when_created.png") +``` + +
+ + ### Sub-Step 2.5 Generate a pruned subset of the single nucleotide variants (SNVs) The initial list of 1KG SNVs is pruned, using linkage disequilibrium analysis, @@ -210,7 +220,7 @@ also requires the path to the **Profile GDS file(s)**. Note that this step can require large disk space. -```{r pruningSample, echo=TRUE, eval=TRUE, warning=FALSE, message=FALSE} +```{r pruningProfile, echo=TRUE, eval=TRUE, warning=FALSE, message=FALSE} ############################################################################# ## Load required package ############################################################################# @@ -265,9 +275,12 @@ closefn.gds(gds1KG)
-The nodes, with the genotype information for the pruned SNVs, are created in -the **Profile GDS file**: 'sample.id', 'snp.id', 'snp.chromosome', -'snp.position', 'snp.index', 'genotype' and 'lap'. +The nodes, with the genotype information for the pruned SNVs, are added into +the **Profile GDS file**: + +```{r graphStep25, echo=FALSE, fig.align="left", fig.cap="Step 2.5 - The nodes added to the Profile GDS file are in light blue.", out.width='100%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("ProfileGDSdemo_after_add1KG2SampleGDS.png") +```
@@ -277,12 +290,12 @@ The __estimateAllelicFraction()__ estimates the allele fraction for all SNVs present in the pruned SNV list. Note that the function requires different inputs for DNA and RNA profiles. -For the DNA samples, these 2 files are required: +For the DNA profiles, these 2 files are required: 1. The **Profile GDS file** 2. The **1KG GDS file** -For the RNA samples, these 3 files are required: +For the RNA profiles, these 3 files are required: 1. The **Profile GDS file** 2. The **1KG GDS file** @@ -374,7 +387,7 @@ gdsProfile <- openfn.gds(fileProfile, readonly=FALSE) ## The current example is for a DNA sample ## In the case of RNA sample, the function needs different inputs ## such as the 1KG Annotation GDS file and -## The 'blockID' should be as listed in the 1KG Annotation GDS file +## the 'blockID' should be as listed in the 1KG Annotation GDS file ## for the gene annotation of the SNVs estimateAllelicFraction(gdsReference=gds, gdsProfile=gdsProfile, currentProfile=profileName, @@ -386,8 +399,17 @@ closefn.gds(gdsProfile) closefn.gds(gds) ``` +
+ This step must be executed for each profile present in the study. +The information is added into the 'lap' and 'segment' nodes: + +```{r graphStep26, echo=FALSE, fig.align="left", fig.cap="Step 2.6 - The information is added into the nodes in light blue.", out.width='100%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("ProfileGDSdemo_after_estimateAllelicFraction.png") +``` + +
@@ -406,9 +428,9 @@ Two inference parameters to be optimized: - _D_: the number of PCA components retained The accuracy is evaluated using a synthetic data set created from merging one -cancer profile with multiple 1KG samples of known ancestry. Using the synthetic -profiles, a range of _K_ and _D_ values are tested. Through that process, the -_K_ and _D_ values are tuned to maximize accuracy. +cancer profile with multiple 1KG profiles of known ancestry. Using the +synthetic profiles, a range of _K_ and _D_ values are tested. Through that +process, the _K_ and _D_ values are tuned to maximize accuracy. This step consists of two sub-steps: @@ -420,20 +442,20 @@ This step consists of two sub-steps: ### Sub-Step 3.1 Generate the synthetic dataset A synthetic profile is generated through the merging of one cancer profile -with one 1KG sample of known ancestry. Multiple 1KG samples of different +with one 1KG profile of known ancestry. Multiple 1KG profiles of different ancestry are required to create a synthetic data set that will be able to show the specific accuracy for each super-population. All the synthetic profiles are saved in the **Profile GDS file** corresponding to the -cancer profile used to generate the synthetic data set. +cancer profile used to generate the synthetic dataset. -In summary, a fixed number of profiles for each super-population is extracted -from the 1KG study. The information is saved in the **Profile GDS file** +In summary, a fixed number of profiles for each super-population are extracted +from the 1KG study. The information is saved into the **Profile GDS file** associated to the selected cancer profile. A synthetic profile is created for -each combination of one 1KG sample and cancer profile. All synthetic profiles -are then saved in the **Profile GDS file**. +each combination of one 1KG profile and cancer profile. All synthetic profiles +are then saved into the **Profile GDS file**. The three functions _select1KGPop()_, _prepSynthetic()_ and _syntheticGeno()_ -are used for the synthetic data synthesis. +are required to process the synthetic data synthesis step. These 3 files are required: @@ -648,7 +670,7 @@ The PCA of the sample and KNN sample and Call the ancestry with the optimal _K_ and _D_ parameters. Note: The formal selection of _K_ and _D_ parameters is done at this step but -all the synthetic data are prepared in the step 3. +all the synthetic data are prepared in the previous step. ```{r PCA.KNN.Sample, warning=FALSE, message=FALSE, collapse=TRUE, echo=TRUE, eval=TRUE} diff --git a/vignettes/ProfileGDSdemo_after_add1KG2SampleGDS.png b/vignettes/ProfileGDSdemo_after_add1KG2SampleGDS.png new file mode 100644 index 0000000000000000000000000000000000000000..e4e0560c93bad9948c42e202b2aa9bf1a7d58fa0 GIT binary patch literal 10931 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 literal 0 HcmV?d00001 diff --git a/vignettes/ProfileGDSdemo_after_estimateAllelicFraction.png b/vignettes/ProfileGDSdemo_after_estimateAllelicFraction.png new file mode 100644 index 0000000000000000000000000000000000000000..5856f1671c0f7d7cb90efc7d576a0f0e054c465e GIT binary patch literal 11186 zcma)iXH-+$+Vw^cdPD^qpn!s+qM&e4AaoQ38`483L6P2TXdxUCQII0NqbM~%K%@tP zQl%q=NbdwgPY93@l5gX=_kGXzj&sMjKQfY?tew5ev*t7BeAa7i&3i{V_&5LnIQroJ zU0nd!=LG<4S-#?;Cr7 zO&j-KY^^SN&j3K|-h;ch^?hK=V=CdohJ35*B>#!V$4eGRW1gRxgIzp`Q1x;VI(>}O zG48>GV7@mE`#IQQ$M%aReT+Y(@W*pD_6!4Ah>^5H_2}(KlSjQ{cFu_-dvNrAQh`0R zO9%aMcei2qyUtJjd|t+e$3tYG2m*oN1b`9}Dhah80Q~bX0Py1;k{xJJCW!&SrVgA9 zD2bwT071wBLjYL%P`?kb5TtSgz|OCxh&FnS+oFi>*jUor&z--i*QNSiuoXUp2aJle}<=eZ!Qj3HA10g5udP*Nl)Ip(I!tc z_l}MEncdVXGw~dObp3SC*Bnx*HO}w*zS+uG@z{8@YB`lx@8)R0`<8PauX?gYK1p%` zr|^v_fX0T$jIml)fcC{c_Nv7)39cypGCGPg0?K9K8T z@WoG4&??=Z?q{fI^?Zm^(aZ5?Vm3vB@q9{dReq-z|HwQHxSCPDC{O0GS32%}@~1Obx$SVOVtG6!a(seb5 zA;ET4EObQfqrP)tZ)51hmUQUBFKpTBW%4@~rMxF8T3Ah;E18;?A+@_cSZ`gQ*@Gtb zuPz(ntL-Q`qk%Ehc$3|QYTP~ zRxWa;m9cci$)e?@n zEflXsci46fIq%ZlE|2WWg7sue!UKsEs&)v(4x| z+O(!&c=o34_Ss@Zn^x?-v=PDa`r~%vB}!3Ss-smUJSzM*4bXUb!zd(n(yxiXbINo} zE!eop*CE}4+1ncCR@HL}Nn_yvZ8MQ+)I2U#%UKxbEY-y%$hAS3EcUguvpz^8q*nW& zVE+Y`PWXXj8(@tg@Cn5ZOd2WWu0q&=HT{3w4HA!#V^vf$#)HSU1lW@;v&1SzeE@L$ zX2q(ptaqHb@%c`#-=x`69Fs3I)bE)1rE@@JUtb|tBHwOlrFs38tUljtYeI0SZ(ixw zlhtGIT%y|E;@4GcOh|(!f<>*1=B%Tz+fWHJvmKg>@9)C0LG# z@2qcl);XzJ@e3kHhGb9}ASZdx+e-}o4x1_# zuJ09c3ibhELXQHwUz%wFz=^Y66GQ-r7M{iJ!PD-4L@sy&z2@5krh|{*OwmPw)%XB2 z5nyuY*U~Z3C}_hOD^#YL*N#V z8V2(TyUCyRWLX7f(N8RjVQ~O$Ef0~8lPP?VVt%D3TMR<8t$|YkGWtR-VInUoCO-MemJg zNwWOvQEJ2(QayephQ${kXC%na5p2E_h5Vw_z5T0?z+g1^{2*iqYexV8++TrR1fd!X z<^O=<9lCG`tqn!36yq#Kn$NcF18(fifdkW_#4C2(>#FFgmuU?aTCV3_0@de?<~*gju$_~cqK!sqgA^FH9?43@>0+>;VlIV`)FnnbXo%u9KU zU69}b-Wlg(LOW0qapyBZWE>b2Q9M)JY2>$e(-ASMv{g5{j$!zSXN`&cym}qZ_pV9(j ze6c-zv6ZBWgGF8~hU8LK^X&C0y#>QY;eEcP0Pynnqls3;#;2;E0&iXCb*`}$Ps zWa!VZRrr+`T$O?)->_7pmW# zhPJ5t0nQIU78{-G#?A8-QnF+8-0bmTe1lmYy24}w{;mRB-LB*OeL3TYgP_+77nL1h zg7dhXgef{37(E-S5NNuu>2*v-oEqv(L6A)_N#i;;!KT{+na|%712H)_exxORG5iz# ztImx3@J5bZPwM`4)dhczPa$Tp%SA2|rd+5$#6Q-8BhZOv)dZ_m z29AiV@&F~ZSzDMLD?Tk661}+z9|VA7QUA?W@b5;AZ7~jJGiOCS>I*OAykgOek_3UZ zxeP0o$!LJFn#OV5P)G=k4S+{dr=H1mBuewc6c^ya#DjnUCsq2v3fT%u?hO_gN&?%2 z>b(Nj#OZ(5c|WANWxg+lT$1rD{L0mi_s;!@?bkEdy$zEQwQ{ga+jc{0O%h z!tp4wprz7WfQ5vSpk_iDgHV-5urR|OV~(9C(X-e1o6fh^!T{i)D)Mm*`0I}}Lxj|7 zs^hy_E8GoIiaZ~3cT1!u)j(h$8_-apI$&59VR66e(UC_2kh4#pP~bE3LsezpngY(f z50FnDU68XZhHHBMe0A+$_^G8ThO2ZU0wW2o!YRvFZ4X-KQejd zM#MwDEG;s{X7ko(#O=={*bA~pOum+1HkWz$B1iMU3kn=Ly=@^S8}2h8S=MG}|3z`D zcy_#2`1OJE!84e;{EEmZI?HPLEOys2LMbt&S#fhT)hO_JuiY~UEH+c?ND)6&iH*rd~=xjN&a*mQ}B^_HPmE!TURZPkh48G$7_EK$cPmf zG=$>C)!(y%Vp%C&S*96vr<1hgkH&ie4fS)S_3ahT*!ISkTeNmmd~tIrze@pEnf=YF zt>CWZ0s|$nj+E=gHjAI#2!ihi971?c$$S!2DceZ}00F_V(T^v*GJE8GYhB^QD%5_- zFI9s-J+T#9HC$)TB}%j@ButrBlX&JE`Qu0>J2ND2*M(E_ zSbEzZ6mee>{rtV`;kH&Sj6v-jZu|0$V99cIJ7n#;gC)7TXe;V)HD9G#jqY3oT$jj6 ztOBJjWA`Ve4ovhyZYJ~(ap07pG9ffu*Tr`uzA50iLnXtoGSJcMh(MRx(!M1tuSGBayQAXob4^;{|~q z9^8dSZ5(!+c?e$l-FfCL1_-%?nZqH@BV4bNWzg39{o`X#c0=&z<(~eSh%&sq^qUhY zYa|1bOaEc#p)AEu35S?@+0W#Us}=l8EU%AyMU>Si+YDjl@KmkLEx);i!*vBIUF4Y- z_G;;86EAkJ<;GWwuSiM%Yc3$$ zK^c(5XoY;fXaLwt9JF>D~QJCi<^vJI}2x754C24pz*n0sum?-%j= zUtRh)32T*)N!>q(J4eF49>`o%bb=MiS}}U20K$I2=M_`>;-i(NV&76857XwWGmzRJ zR6kG#t0B8C-jFbO1qLG$Vdm^GyM72e`+j+1|8(&|5XlD!N1l?OhU75_A4dnO`dy#DsYuUkWkF_Lnh>{`oayVW12 zvL3>&0RqID0<4{V^yLl z&BYUjt@G6d=Am7Oz1*rG0x3DQcbv9P1XZB8el>haPf?R~r8=9qF^*C#$!2@O*$xIL zb85wQ95SSY=m@kLKsuTmUIN~N*^Oqn@Gpk!#6)wL)otuEOxLxoleyeeKESVUlj}#? z?5$4OoLy*1e|&j9K$YfsqxylolK=?#LMRS%IQWGANSk(4gh|KaHV-E=l1Cw-KfzU2J$;kmh&)=bre$!$)cxr0$i2vyYxc)vsaC}NO6DGrnp0n z&jl&Dy8a~R?XyulTl&7GqPz>!e(v_;Q_EI`Epz$!on4y;gjkte9w0-Bc65b?$-1mISIr?w!)O*=3Ny~1 zmQA<*FdGL?dO}mh8IrS1drUs9w0w%^6_cVD4Ygqrk}2ibhCkaDOMPH~j|{kETuCgx zc%mo?;mAZEm7zRscKN+qTYSTL^!?5Iks3naFuq$NWy2Q~3EK>U525UBt>o5Ch@dsz zT6d~Ffw#5>NpCRHa|5>8t2}}HkUVhc;vMul5B0D}rRA*Gp zumK6$@S8@SBb1zPzUeZ=#@A;Ii>5)lj3Fc^a)H;teeq6g<;~@Z?#t!tCQ>Qc=UoTb2dDNyvp zABT&x)ls2BHEm`;A{0DKl$74)6$JZtbf$mF4$ST=EMW5rkp9e%deAZ)pv^8L6D6ZQ z40g{BjHQB=rE}?9G46W;MAW}KB>n=$_T)#Ub3iobV&l(m^=`A5K0EP59jI%W`EM>R&p(@S6~wOFMEdmIK()3) z6>KI`M1!Yrl>!5gEBk1)n?VYb{0LXEbgVCg~QLEJ8LC^lWC468XrHBlSE2@%Q)< zO1iV_0N?hKU#!4vfyK%w2?2>^HB)mxuT z%;bC9BRcH7uD`00hq$(Zu3`<$HXhKy+-@lJF;4q}6;>RbL$CpD5_|iXmj9MkDBlAW z6gnAD{9HhOcY~g#gtgOb_UyMd#&^0lERB7h_7QOfJw*C1-X7z>ACQAC(Cs%dT!#>^ zpS+%_`Ets;6BU2yrl^Xva;CJglcG6H=HYb2C8`$p9}eH)Au)Mh?M02yt>4w;5wHd@Cc9PbcwFyuDLlH>r$I?=VmjN}alvMbVp~7>D4C0-lt) zF6KtfVcUa-!Yd$s>SG?z-OrA%>S}9%ATtm^Po`(`CH9!egD~!HRjG(Q^F{%dfi}TJ zn#4Jq6`Ni@z4>wUT>a_7x&s07RcA=+u{H2nHlX^>e}|+TI`Bg|`+-v$33U4GT(Re% zyZ7+7%7y{h$=jS-JWs>6S@3I}T)+==$-kKV)6ZKGY#<%0x!qzW8qwieqIns{dF$d~ zP>^{W#_eFTnX=f*)h}vuxB`KU@WpTWfnP>ewU4H@%6}2bo4%dlkaukn;&YGIGvFY( zft^Y&Zv&;@j$zU&?sz`ljhrv*G|W^I;TP>$@U+B7!3=sK2hSHy!qvXQbbol+MFFnw8W|R6lGiG^xxBKz2<<}N>!qkJ=+^uwQ_26gVh_u+*hOoTu1D3+CcV@ToDk*e zm;!BQF zxdJB%y!#PWue?Nkk#*j4F6Ri$*1lJ4ur|kFF)7Uta^tvk9MJ?JxO|<; z5^W#tEmCQ=F}xqeiVh><9d-t~F(VDd!wN=9YMCKd>qfiCS}>gFcZiK!L$;u9*Bukp|RoV3n^ zMZ=B0KUv_fgwZ!+pv$yDTNq z`|2PNbU_TpbVvhnQ#sZQ^y*f)Yf;?T)w};jP9ed+miX(|-Vz`CPrQ8=_cE{UGG}zC zM;>J#;2qP!EWf`OZnbEOnY@ire@Wlko$uf;n*|Mvjq=_2qt8u)8=z-<%i?hm8Ye!;*IK=v3IR5mnB#gEQC-rG|F(=zS08=+4Z09L)VwEzY|i9jqg;-LsSeozND5i~^rwE~a7K6IJps+D*B2$9n;Ypf0)@^GQU8BFeoA4_j4Kp$^Z6x_AT?aD zJt|k-4W^L*DOUi{K4m~c6Vll|kq_lElv&a;hII7SD^yA{f=>I zf9pgznoN7Q906j<@5I7`#i}$1`PJO;Wyv7PwRF`TZVJhSCgbirT2Nio? zb-}-^_lPO$Dd*NQ^+)l-{IQ1}?t-`YU%bZyXj`bU0`>68sUef(-ZKl&)^%NmP2%zU zoc&j%Ov}I7jg7s^F=$y%`kMQ40QYz5y_;v;YOvbB_$9|)Mm#q-^*!J5)*UsNDX3hh z=a2VG)pfY^qy|S;DKhUK1R_;SDR8Ir;PWgD`*sWux4mTtjQ$(p-vhdD#?heHaQ|xJ zu0tRh9)F;^2ndP;^Mb%zR)M9D#&@*eM~HN1425)Q*OB1wZpsF{20avE3j9%B_Cvq; zLzu5nFKK=vOYZia^fKbs5s9(@H7*3hH2cJ8p5y{GxS ziKnOB08RB#lRfrw&|rx=1^R^-56NL>EA|0}SHZx%Kn9JPx&Sw)=jOcTb;C=@+gEQ8 zp~98ifJGOj9d(Jw4XjCpjpK4|fdz%hZ-1GYJ$ZZe$#2^KRFwy7Tl7&fymG-Q2JwS< z2v`f4`-JK;W-jui_gH3tUU>GxVk2mEA7!r#s|>sOn@ctId!Xu}62CiYZoR6Rmwc{z zrh6G4EwJo@dh^ny9<(|f&oq1>huXGWCR+l)NBt#w%_@W7+PetS%@;D{OtVqPE{Qga zcj#`an!itfoK3P!2Z_7-J!ll|zYfZVYyACtd3MSf* z**B_S#yBndL7d-&Ey!se_sQ-R%Xx?9)(&mem|rxrIvr)=g?D*{z^{+%p}mT+;U{jg zyBx_Lb28tqYrN2gND19)?vij);y#zwB5o4Xx=HK?W9bdI@i}t%>-Fp*_ zP*Q}2F|ZFww8q0-BPxf023}#%Tmg2%m|JpJ_g38J#xKKg;wA}Pai1Ii$@y2NFbJJI z=4Xm5GnRyw*MT5L8(7Y3^J0Q9-BBCrZ(4Qx@>oS1D7e5%40TFr9(Va%=8a6~!N&HV zs=4~Ser`%~cudHaawOOxS(i~FJ0PH4y0{3Vz)wbMrS=q@3}!@xAC2cd)tzuy*YQGB zl-ys9qW8*ArflY+x{-_O8nWqmPDipo?z{4+<9}*UpKV~SY2A~b-Vg4Ti1>Q#ivlsv z2F)JXT#tpElOSzJD4;o?hm6F$`9OOoYVwt8bPNSMKM&?~&c=txh;JT`6*4*)ggCOd z5)jmQWs|;^L4k+l&GgTgDL?f>kH23j^xicV{@Cpcb~%z%@!eP@l|k5^(VHvt<30X+ z_le(1S3Cond`~J%0F&BnsK=_H;U<)t#X@RwIJYwhpIi3>lYdQmh7LI44YBY4&k2`b zq_Z9@!BaZPa9(3~BmB7z#uF|;(GV;HdL*!h+hQ6;$2VO0FM|?Y=dam)2>Y&8H7+t& zo4&F3t24oABZM#Wob@;UJhnLJF6a8vYNdW( z!}=dbp?r%(uqvJ2nDPf}SIUr@^3yDs_gPs%cbXIz@NV)in)hqE#eIu`pj_2oa!%<3 z=!*o2-1*0YM#iMY`Q$m!(2X__-ytZ@;cB*m=fPu1YG6?nB(gf}=GCZ@tDQQ&X!#5g z`AR5ufon&B9St!v)6%3KW{x-cU0~^t-&8_+);m4}A2<0b-~2@Xw|-`0dFha+(aQWH z&SCWDZ>w;)m;B{=^|Q|^&hm&HisV8GRYP6Z9Ir(}xbCc+y(IX(us5?E z`+(2j!bWO%;a@_Ee(FJGDD2mV*eZ8JtlTc`{VMg#9l@;a9mkOSJceUtvUXUV!r(ER zRTfpHOBkqq|9_4sfR@-UgUMj*+E8Xolu&hl%NXJoB3Ul z9S{}wPpilwHt zMk3%klgMQJ76wOusKO+zVwiMZcCg%h(0DWPnAaLFv8$GlqcODgbD4(1O(2;E3Bsf; zuzo~LB}}v*Uni}?aXUXvXCM^!dAcFeNbtaS`R}V-_k2;zcBvZTYS%F^$J`F& z3~B|-CU*Z}FG@g>yJ?vg@&G`-27UxbofgH)Y1jv>z4Baagx3X9x@sr3>Mt=t512+_ zDq3D-116I`*0JdLEh1_+<-_!r+$o}8;EIdDx^bMX5|*1niU=3ohOHD|p;+Mcq?wzs zfn%7rI+TFH+n?xXNpBG)0aIg{C`MuH%}^FtACsVNrPllH&ggwEsiiTPiBYH>o!07l z+6q5Pn6-stE$$%f^;@ukyE~?Oh>1*=JtvB?i&9~(lNpr=44kzw0xma;K9U-ROIJ`~ zExjVJXc6Cv!qbRo!s>v+?AzzEKNw%n!?w5A8FMPk{7Bv(W2b?P>tZ`xD8C&NQKi%J z@xW;vGu_B=Uz86oXYKI~{^{3DGErr~A6Cz3jdBT$dFy$c;zMCgWBs>=-@L9Qol-=Z znGtaH{Ri7eYcQ7cIyS#QUuO8mZ4q5wV;k3>ur3P~IqnFzt8VPJW^R^iF?YktV|y}H zSUX#S%FN{t*D}ewDm1Tw#ESYr{+nD>?jG=UUyMpGAusPuYfNx$$!br}MBsOaGPoRE zK>|lJIf~jDg9!Fas2DXeNmMc72gFG#We2`m*?auyyl)en1uv41aY*yEF0AJ0%Ln*+#~?FRd3bP zqk}GB=hOp(n_>9X;?J=X`!U{=jO1u*5>fmM@9w*f<;qBmRM zuDrGHA2r(ullcb#Y`gzsP5*ySsXBV3vAEDFLTCEUhvC6)WG`+a_&_w#+<-}{HpxXt~!oY!@n=W!nAaXmB8(`IKm!U6yQyAJA# zApkJK0Dys)`7rpG%%*HH@PonKP+J2i>=IrCA0RgBy6ON>9Lq|vU;>|EE+`Xs0N`k* z|1h*V=UM@Ph>Fe?_1ivXD`O0Cd1tu7rc8|ZXMIg|FU&l2vxPVo-F!JKzI1RWd;CUp zWLLqE_PO;vMgWlGf&)PCGaR_+4J-rz%#S0%UwIG=0Pu<#4C><*6!BkEk`t3~IZyzvJWScfnwBq-8fOK)E?&a)eqZG8l*-D@(7c9a&#` zKoXf!R<0gDSoJ=?O=#`^zV7Qmu<4CvZD@J3H~8*av1d!Ub$n~Aa~kiwo)Oi;$CJ~OVuxi*f4sxwYl;M&oex^G)%rIvW*O*`}i@ zrauR^-U=V=F#&r;YRI+&isnWe8Z&0=NeP;U!#zkPtKK)yymRya^aS&83aVO^rF zu>z}8aR>yJ#p>>Q0C#^!tI@qfL!zdpfi1mt@7RY)_?l*7V$?=*ux+yBK5gV#k;naS zv{|nx-nB*QdR(xaqdyz$LCL}Mj|so1TYrEV_OZGGw{Ahv7smhDAPX4pZ6Pdb?{)ee z3g&lrW&(5XbKoT~4TIMZ|2`Sdhhc98cAH*38Xda+C!z6Js+OEkPb;S}FFyddFwAqn zpxXX7NYZcjj{U5!74=d~dA@#SKke-)Mqo7pC$?DyqnI9^OFsv?fEWUV>O|>BS#WP>K2$7fLUf(sAOB=<>lieHH;|^ zcQis-S)N70qOT#vkhhFFb_a6f?(^KxA;-T-PlJl`_WQGyG*Fbk#sk3c<`bM8Cnlx- z;Y~YJvr2fP(aJ!P?3+GcOrwmWn&gKF%_igZD61L}<;>WeYH?(~v;bI>9}`J?NVbya zS>{f>8@XqZy!Um%nxrs0DJX7|l@m6MaiY|#urW56<^s0~{|rUF9ie=PJH^1g22rS{ z{6J|maC2sa19r)ya;`9KQ33$Gy&G_ogUL>a8(L=R*HJ-98FE2g$8z$jUG-_Dt|tB` z@0e6JttOcm{a6frRzfwK*lbH&h6>bio%!TBw)^149^QSv37TG%?i_b%9EobHVqIIF z7XW~#UB^I%_}KcJQr@4YBe?t@=mbR2J&;MB!;KdTm%pkj#daCoYg(!jQdr3KEKBp5 z<%`^I_O0H#Rh+MC7=WU=3WWMMkqBuS$7W?!m_W6}@ml`3@`TS30juZ-@@P$r@gv*# zaeU{YDK(zEF&&~0F8nA#FV$vKfncRdTNJM9$Taq4@=FKUpX31 z;bAb#M%lQTKaRY0j_Su^%jZHs3LSRqNXHIq;cKItDD5}{hx1@6ub*%dgy$bu84qlW z`tFPB(IS=4$d1=P4evQoGFpgznUx#y9&c$us2bxM5>2=4zE)EA0ar8-2z(qHlSCqk zXCA)rU{b{B9~7c(i$$#_T$3TuT7OJ?ghD;#KO5qtsw z0^6%Jo5r~Xj*UGM5~)(;-3<5c3~>4GD*lSh02HoyA=LX2h;n%;Hw*sH9);LIkqf`p zHkN#AQbp8)LhWlr22FNzH1(>eCHffI3I#ncJ`#75TD8OQqlW(X7r_`$a>1jgE6z8@ z88^g$EWzx!r{JMs!rn|`>ZT+V!hqlDa8B+EwPz#YfZ{(}IpQ9i{D} z)*yM#5EfY9?#?JQQ(7tX$_B-G_nfdAxZ!|Nd1UlTV6~x8VA7k{d<*50wk8eA3~>-f zm88Z={+f_{V#8yiylE{Ef~|J1$C9YFDP->bc}I(2c^p>qY7=MiA-H0ree$)%^G;)|u= z-FJ~9$NpM7A|)KVI`AI4M~i!-x*1klW~%n;RLAVKQL1uzi?7SqAg_@W0}cj@w3f}E zfwV|G=^ib71`3QefkiQLjO`*w$DCNK>{E1#Fxs7{3IGjR{|)^)2QkGF%m+`g&2Asw zywkO^bx=h;1gJ*gdZt4|5p~|H5To3Ndsz*2LBL0DES4W^5bH|=MQxmWTjv;VTO@WU zmWK$J(o{G)UzRl=;rA^LP*Ko)eBBYT*Q|4t{Csei6HsK=(1;2}SUBvtzn0VauG7Z4 zeNR6mADtT3i!NWT;*W;C<6lv|z>^(7lcc{M#u^SW%4)jfv>&NesnTcdvocMFg$;<anXL(u1JKVpBP`p2R!wf|DbAZol!eiMR^)>im1@!O&1zX~#I$ zjhT5_DzSBMD{0?!g~kA=J;%A&Ks7mlNfBn40&l|wA;R{>FaWsz-_V~w(M zSH}O~ncdwbJEcc|j_;Wa(J1qzl&GjMB%<*z5Db$IHRdQ>h&;Nbi(m{nnj}!TJ(r+6 zTiLXtiMEx{^7c?fN-+kPzWQ*H4%f;1B-wP)0A>4D*$$8U48VkjzDATvOSzTcsB3Mp zMCKW!V&DAk_Ho4&(uB#ZK&x8egwI_D!1*$WfgEx>woGYEpEb=>v(0AuUG`Je(F7k; zO*(#r(RnY_ivgqWpH>b#vq9?|NXp@e?c7<0hkoSEno+$|BbNd(T^dAN=5EFQy?&5o zpMXi>f?6<3;~nf7qb2c} ztW?D!%4tFV*#|vpO;uG>2m9IyMAoj5I2)Xup?*OTMZFA?g#Jk`^v zCkJ1l&=cRzXpcZVWWZRE4cC-9sni-)pVSKQayCw%U40DErVaFaBn1L`;ytZrrJEz`rl z(`TqK%bJ>HuVNbkVI;2hOIe2GXw|f~r`vUBL&CI&Iv_Dm>H>dFv}Oz@e3z1N{;;f5 zr1@n!nNRd}N%G0L)SBSw`Ik7R)jwu}PG&_flSfX^O}rwTbXkmF1uCm~BCx%*=7Gs+ zz9>CIi`rBc`=dL}RilkszR6 z76$p1QnhpEOv&I$aBkR3Q%3q%v1e~i0Kk|__!nh?kJ7rMSi{@W`M`EvMuCatUUngf9SqQ;Dx2`2}>VVD^$Jh!jv(n)YRmGQ}2sqStcGs_eh3$QxNh?w&J=6WeYQ_m}#1E|cpj)nY)4-9ibH|iHovyOoZ*8VXI zT?ADBhml+t@q}=BkonN|x~Dquv7N4?h1qgHjsIdBY+t|*vB1_;)Idh{=)>XINy~xh zpO%w~$us8aOMDSC36_HmtxulCc^Nk!m#t9ae8@{Q86$ChS9(=3(LHy`Y5A*l^ARH% z(E>L6TGv2OKDu_`PJ58<$yt)#@?HJf?SXCBJm&-*zMd- zj+oxd3g9wu#8H>2j?#o=v1jQJpt7D53o$Z?mi&SV!GD?ylQh8$pub%Enlcn`0^5OT zfb>ul5|wV!)1mRCyz2}=c!sX->ae>yQ3Z(eT8 z4NqNk_w(aMUa1NxFw`9v0Zog^V@^WwETy_Wt-BTRd{@WjWDwIE3i{dwv3@==Do5Ra zr%KO1Q{|u3Wz{kaL9P1~wKxtobP z`dBi?E{dKMKS~rVxEaMQj#*Zv?zxhj@DJ8@WgB9(?#phee_T7^KNw(c|LgHwV~hC? z1ps8GMiEm#vU=QT0H79$TW8v^kDrlT{ssjmwa@(r`uc6kynBaRUm;vJn~{7K_9QVd z*#C|@nL={{^|&K5OnUr+U|e)hC83QrI0_?^IDwx5V9V0h3_0&mDpO*i8g7drOb2(4 zO-|^e7fsnDmxtsc?Cw^41C`9skb(Rn5%O76@cCW-;;Jqt&EMQY7Vc|zTviqyR zRt=bBkr9NOa_TN?(jX7G@iYsQ!_Cy>6vV9YlF%)ZV1N&+W%hF7k*E8 zQD<1H1a2roFw@OD)oLONUm7IPHM!pjWSJryp7oUAIYbU2=@MDP*Zmvik)1r6>~;37 z`1>}LY`Xv=a{JXwKje?Cny+-R%>^#V0*l$1#8ZS>3WSF|@-mju`UifO?$3&mIq<)( zM|zFz*AJ7sXAy{cd_({I1$rEZ|Ms%}n;8{S&xmo9Kij|i%UbLtPe5oWG!K~oGMJ=ZkwPX?Bnwjif-g|7Q ztkBbcu&5L4N|nODd%rrPM$(N6u?M@pPGJ_WGjveIhV%?u<<ZCB{B-peCy96qMZLcu=g?j;)s}JV9{;WpOK@t41 zCFyuaMPSqk2<|uz9*Q75t7r+zc`%#Vl0Ppd6Cc5Wr|tbp4jboNlrcdIIKEI5TA5Bf z>;Zx&uA&}qyt7CaU7fcI$&y1ipZl?Kj#E>ZR>|7&0FihByEl8QF6dxmiM$?Y{OEkC z4=v6jsWme*FSbOEb?#jGpJo0ckM4b&Qk(BmzeBzc)@LrbBB+X@SJLMVaj@6D7|w9p z5D5g2Mz)rhR8iorHjHJ}COHogc$K98Z1YKd#Rc)~d@EuHEz^ku1w4EL_KX zcOAZz z3(S#tbapUolmis+A_7Wm3mUSBg(=mfRa=Mnpj|Qh=DTD%V?EaTr&d>~ToAoU=s-wPn2kz%C7Ry>vy&PnSuu6MJ1zcRQ*eIa}4M9Rt(AIdJ|9wll zxBF+Z6g9~VlQQ7^3jmcee;4_`dfT7@GAW5$<2rm&zJ65#&8NJzkyZyT>J8=%RNK@v z?kkfJ4*;y+2T3$093o_fIdTs5-Ly?3M6}Sy)X7P$b6&2X;Z>{H(cWSG(`g(Nl!X$D z_~zGdrv~yYVyz3G4$Q62+p5Bf2WSO5;2=U5y9Ov6W8wU9<}EHktrCC#!r?q(_I)+I zRph5C&L-$6l#11{Q&K&Zdm)-f{7Z*G^Kr64Urk*&I-urz72GO4TxEsu0313VfMs8p z5hmHc%|}Q)n$#f`{e82{K)|F?qx(lLZ#RKV8I2b++7B~1{?-9sGL}`~Tb1uD{1oyG z!vjCEP4iqxPB;kYF93Ui3`oYtOhMP(Q8=!*zAUL(3kONK3^q4bOSHbmL+b$Gqc=GB z2*Y5sGxyLJ*J{TmH81}~0M&&OL{=8!(MUw&NcEUlhte@atAG>6FKMdf%ZGq^`tWLi za`|1zqP$JrQAV}L0jQj{t;vGZLsXg4phL8_(e~8 zs9T}GEGPi{=L9k2XfT$!iw7{5)o9Xcmk#&ImZ@V;Jqdg?)1@w%ATnE~K;7f_BT!Gm`V423RIAil%X<#1*N+c`1~{ncqH!h_Cp1MP z=1Kz8(Ae6wq;?9YZ#`7S;auohhK~>EXTb)utij)!N`S>|L-gt<-Nujl5XDajQ&FH@qTcG#j1*x1?+8A=BVM<=DDs_olTEr^lcuR&hKUt z`gb7Oe7DXIg+s{BC&*@}f40o@sc?f{WrjqiRx#Jwq|91`*$$GDgEMg2x%w3JX%2&% zXvB#Tc|5!uMxA;ZGroIij;?|87e!#j*fvGEG$V;Uki35pI-*KF{EvK&(A3ylii1K2 zRt^&=lWznf_sa^mue8nk-ybb0N)OCV<5}E2K)yt>w~0D<%#S!uM%f$z)|vhunf{|& zD8UA6b}K@Fwc@3Vn7WTvpUsQ)!!{$X})mK zuFU-brBBkAh~C5(NYAcTwmJ&M?Cmj8;Im=`c97)DKrrQ_J~ug9<&^Xg=i$%ti_cut^c{;ugtzez zcEw+6UN*KVR{kw??DoJKw-sQ9HT1>wT@-W!fIXLIxZr^4A@P|6)gTQZIQul+5?=m4 z?fG|y5bB4grk?qLHMDA=&xj6ChN|^u?tiePj)L~1aQ&E==5FHEC337FTW)7}(s~O< z8US*Mv?cX+Bc3R}*-q!fkZMZ=|T*;@4xJouxBo;tJn*a;MF;dqr$h zCSu21uaU1@GB)%%i<9~~#E#?AQ;n5z zX^dK+l^ghdv!U8=HLp)xsb!`62`Z*W@lI*J^SLV_e@@>nIL(w1xr-TeWdw>eZ-JKa zzQCHFC@5E1U~V^#w(R5~GT#JNr6KiAO(?pdA{b1>umK zRj*KGitRRVMY6SGKs6S;6L{P&3^#4xH*;=k#7&Y?RVrUO*{p~8EPeLYnov6`cHQ*y z(=~F& Date: Tue, 6 Jun 2023 10:48:00 -0400 Subject: [PATCH 008/385] Update main vignette --- vignettes/RAIDS.Rmd | 657 +------------------------------------------- 1 file changed, 5 insertions(+), 652 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index c2675356c..c1e06467c 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -3,10 +3,10 @@ title: "Accurate Inference of Genetic Ancestry from Cancer-derived Sequences" author: Pascal Belleau, Astrid Deschênes and Alexander Krasnitz output: BiocStyle::html_document: - number_sections: yes + number_sections: no toc: true pkgdown: - number_sections: yes + number_sections: no as_is: true urlcolor: darkred linkcolor: darkred @@ -195,7 +195,7 @@ genome used for the mapping must be the same as the one used to generate the
-### Sub-Step 1. Create a directory containing the 3 required reference files +### Sub-Step 2.1 Create a directory containing the 3 required reference files The 3 required reference files may be downloaded: @@ -225,7 +225,7 @@ see the vignette
-### Sub-Step 2. Generate a SNP pileup file (1 file per profile) +### Sub-Step 2.2 Generate a SNP pileup file (1 file per profile) This step requires installation of the external code [snp-pileup](https://github.com/mskcc/facets/tree/master/inst/extcode) which @@ -276,7 +276,7 @@ snp-pileup -g -d5000 -q15 -Q20 -r0 path1KG/snvSel0.01.vcf.gz pathOut/Name.ID.tx
-### Sub-Step 3. Create a profile PED RDS file containing the information about the profiles +### Sub-Step 2.3 Create a profile PED RDS file containing the information about the profiles An RDS file describing all the profiles to be analyzed is required. @@ -333,653 +333,6 @@ rm(demoPEDFile)
- -### Sub-Step 4 Create a profile GDS file (1 GDS file per profile) - -From here, you can run directly the [wrapper](#wrapper) function -or you can run each step separately as explained here. - -This step requires 3 files as input: - -- The **1KG GDS file** -- The **Profile SNP pileup file** (one per profile present in the study) -- The **Profile PED RDS file** (one file with information for all profiles in the study) - -A *data.frame* containing the general information about the study is -also required. The *data.frame* must contain those 3 columns: - -- **study.id**: The study identifier (example: TCGA-BRCA). -- **study.desc**: The description of the study. -- **study.platform**: The type of sequencing (example: RNA-seq). - -Using all those inputs, the *createStudy2GDS1KG()* function will -generate a **Profile GDS file**. One **Profile GDS file** is created for each -sample passed to the *listSamples* argument. - -```{r appendStudy2GDS1KG, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -################################################################# -## Load required package -################################################################# -library(RAIDS) - -################################################################# -## The 1KG GDS file and the 1KG SNV Annotation GDS file -## need to be located in the same directory -## Note that the 1KG GDS file used for this example is a -## simplified version and CANNOT be used for any real analysis -################################################################# -dataDir <- system.file("extdata", package="RAIDS") -path1KG <- file.path(dataDir, "example", "gdsRef") - -gds1KG <- file.path(path1KG, "ex1kg.gds") - -################################################################# -## The Profile SNP pileup files (one per sample) need -## to be located in the same directory. -################################################################# -pathGeno <- file.path(dataDir, "example", "snpPileup") - -################################################################# -## The path where the Profile GDS files (one per profile) -## will be created need to be specified. -################################################################# -pathProfileGDS <- file.path(dataDir, "example", "out") - -################################################################# -## The path and file name for the PED RDS file -## will the information about the analyzed samples -################################################################# -filePED <- file.path(dataDir, "example", "pedEx.rds") -ped <- readRDS(filePED) -head(ped) - -################################################################# -## A data frame containing general information about the study -## is also required. The data frame must have -## those 3 columns: "study.id", "study.desc", "study.platform" -################################################################# -studyDF <- data.frame(study.id="MYDATA", - study.desc="Description", - study.platform="PLATFORM", - stringsAsFactors=FALSE) - -################################################################# -## The list of profiles to analyzed is passed to the function. -## The profiles must be present in the Profile PED RDS file see -## sub-step 4 and must have an associated Profile SNP pileup file. -## Not all profiles present in the Profile PED file need to -## be selected. -################################################################# -listSamples <- ped[, "Name.ID"] - -################################################################# -## This function creates one Profile GDS file for each -## profile present in the 'listProfiles' parameter. -################################################################# -createStudy2GDS1KG(pathGeno=pathGeno, - pedStudy=ped, - fileNameGDS=gds1KG, - listProfiles=listSamples, - studyDF=studyDF, - pathProfileGDS=pathProfileGDS, - genoSource="snp-pileup") - -################################################################# -## The Profile GDS file has been created in the -## directory pathProfileGDS using the name of the sample (ex1) -################################################################# -list.files(path=pathProfileGDS) -``` - -
- -### Sub-Step 5. Generate a pruned subset of the single nucleotide variants (SNVs) - -The initial list of 1KG SNVs is pruned, using linkage disequilibrium analysis, -and a profile-specific subset of SNVs is retained for each profile. This -information is added to the **Profile GDS file**. - -The __pruningSample()__ function requires the **1KG GDS file** as input. It -also requires the path to the **Profile GDS file(s)**. - -Note that this step can require large disk space. - -```{r pruningSample, echo=TRUE, eval=TRUE, warning=FALSE, message=FALSE} -############################################################## -## Load required package -############################################################## -library(RAIDS) - -############################################################## -## The 1KG GDS file is required (demo version) -## Note that the 1KG GDS file used for this example is a -## simplified version and CANNOT be used for any real analyses -############################################################## -path1KG <- file.path(dataDir, "example", "gdsRef") - -fileGDS <- file.path(path1KG, "ex1kg.gds") - -## Open the 1KG GDS file (demo version) -gds1KG <- snpgdsOpen(fileGDS) - -############################################################## -## The pruning function is called with one profile as input at the time -############################################################## -for(i in seq_len(length(listSamples))) { - ## Compute the SNV pruned subset - ## studyID: Study identifier as defined in the preceding sub-step 4. - ## The study identifier must be the same that the one present in - ## Profile GDS file. - ## pathProfileGDS: All Profile GDS files must be in the same directory - ## sub-step 4. - pruningSample(gdsReference=gds1KG, - currentProfile=listSamples[i], - studyID=studyDF$study.id, - pathProfileGDS=pathProfileGDS) - - ## Profile GDS file for the current profile - ## The file name corresponds to the path + profile identifier + ".gds" - fileGDSProfile <- file.path(pathProfileGDS, paste0(listSamples[i], ".gds")) - - ## Add the genotype information for the list of pruned SNVs - ## into the Profile GDS file - ## The genotype information is extracted from the 1KG GDS file - add1KG2SampleGDS(gdsReference=gds1KG, fileProfileGDS=fileGDSProfile, - currentProfile=listSamples[i], - studyID=studyDF$study.id) - - ## Add annotation from the 1KG GDS file to the Profile GDS file - ## This is required. - addStudy1Kg(gdsReference=gds1KG, fileProfileGDS=fileGDSProfile, - verbose=FALSE) -} - -## Close the 1KG GDS file (it is important to always close the GDS files) -closefn.gds(gds1KG) -``` - -
- -### Sub-Step 6. Estimate the allelic fraction for the pruned SNVs - -The __estimateAllelicFraction()__ estimates the allele fraction for all -SNVs present in the pruned SNV dataset. Note that the function requires -different inputs for DNA and RNA profiles. - -For the DNA samples, these 2 files are required: - -1. The **Profile GDS file** -2. The **1KG GDS file** - -For the RNA samples, these 3 files are required: - -1. The **Profile GDS file** -2. The **1KG GDS file** -3. The **1KG SNV Annotation GDS file** - -In both cases, the other required input is: - -1. The information about the length of the chromosomes -2. The profile identifier (it corresponds to the Profile GDS file name) -3. The study identifier (it should correspond to the one used previously) - -The information about the length of the chromosomes must be assigned into a -*vector* object. This is an example on how to retrieve the information. -There are alternative ways to retrieve this information, e.g., - -```{r extractChrLength, echo=TRUE, message=FALSE, warning=FALSE, collapse=TRUE} -################################################################### -## Load required library -################################################################### -library(BSgenome.Hsapiens.UCSC.hg38) - -################################################################### -## The length of each chromosome is required -## Chromosomes X, Y and M need relabeling (see below) -## There are alternative ways to retrieve this information -################################################################### -chrInfo <- integer(25L) -for(i in seq_len(22L)) { - chrInfo[i] <- length(Hsapiens[[paste0("chr", i)]]) -} -chrInfo[23] <- length(Hsapiens[["chrX"]]) -chrInfo[24] <- length(Hsapiens[["chrY"]]) -chrInfo[25] <- length(Hsapiens[["chrM"]]) - -chrInfo -``` - -
-
- -The __estimateAllelicFraction()__ function processes one profile at the time, -as shown in this example. - - -```{r estimateAllelicFraction, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -##################################################################### -## Load the required packages -##################################################################### -library(RAIDS) -library(gdsfmt) - -##################################################################### -## The 1KG GDS file is required -## The 1KG SNV Annotation GDS file is only required for RNA profiles -##################################################################### -path1KG <- file.path(dataDir, "example", "gdsRef") - -file1KG <- file.path(path1KG, "ex1kg.gds") -fileAnnot1KG <- file.path(path1KG, "exAnnot1kg.gds") - -## Open the 1KG GDS file -gds <- snpgdsOpen(file1KG) - -##################################################################### -## The information about the length of the chromosomes -##################################################################### -head(chrInfo) - -##################################################################### -## The function must be called for each profile -## This example only uses one profile -##################################################################### -## The first profile is used in the demo -profileName <- listSamples[1] - -##################################################################### -## The Profile GDS file is required -##################################################################### -## The name must correspond to the profile identifier -fileProfile <- file.path(pathProfileGDS, paste0(profileName, ".gds")) - -## Open the Profile GDS file in writing mode -gdsProfile <- openfn.gds(fileProfile, readonly=FALSE) - -################################################################### -## The estimation of the allelic fraction -################################################################### -## Estimate the allele fraction of the pruned SNVs -## The current example is for a DNA sample -## In the case of RNA sample, the function needs different inputs -## such as the 1KG Annotation GDS file and -## The 'blockID' should be as listed in the 1KG Annotation GDS file -## for the gene annotation of the SNVs -estimateAllelicFraction(gdsReference=gds, gdsProfile=gdsProfile, - currentProfile=profileName, - studyID=studyDF$study.id, - chrInfo=chrInfo) - -## Close both GDS files (important) -closefn.gds(gdsProfile) -closefn.gds(gds) -``` - -This step must be executed for each profile present in the study. - -
- - -## Step 3 - Optimize the ancestry inference parameters - -At this step, optimization of the parameters is required to maximize the -the ancestry inference accuracy (next step). - -```{r graphStep3, echo=FALSE, fig.align="center", fig.cap="Step 3 - Find the optimized parameters for the ancestry inference", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step3_v01.png") -``` - -Two inference parameters to be optimized: - -- _K_: the number of neighbors used to call the ancestry -- _D_: the number of PCA components retained - -The accuracy is evaluated using a synthetic data set created from merging one -cancer profile with multiple 1KG samples of known ancestry. Using the synthetic -profiles, a range of _K_ and _D_ values are tested. Through that process, the -_K_ and _D_ values are tuned to maximize accuracy. - -This step consists of two sub-steps: - -1. Generate the synthetic dataset -2. Compute the PCA-KNN ancestry call for each synthetic profile - -
- -### Sub-Step 1. Generate the synthetic dataset - -A synthetic profile is generated through the merging of one cancer profile -with one 1KG sample of known ancestry. Multiple 1KG samples of different -ancestry are required to create a synthetic data set that will be able to -show the specific accuracy for each super-population. All the synthetic -profiles are saved in the **Profile GDS file** corresponding to the -cancer profile used to generate the synthetic data set. - -In summary, a fixed number of profiles for each super-population is extracted -from the 1KG study. The information is saved in the **Profile GDS file** -associated to the selected cancer profile. A synthetic profile is created for -each combination of one 1KG sample and cancer profile. All synthetic profiles -are then saved in the **Profile GDS file**. - -The three functions _select1KGPop()_, _prepSynthetic()_ and _syntheticGeno()_ -are used for the synthetic data synthesis. - -These 3 files are required: - -1. The **Profile GDS file** -2. The **1KG GDS file** -3. The **1KG Annotation GDS file** - - -```{r generateSynthetic, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -#################################################################### -## Load required packages -#################################################################### -library(RAIDS) -library(gdsfmt) - -#################################################################### -## Randomly extract a fixed number of profiles for each -## subcontinental population present in the 1KG GDS file. -## When not enough profiles are available, all profiles are selected. -#################################################################### -gds1KG <- snpgdsOpen(file1KG) - -#################################################################### -## Fix seed to ensure reproducible results -#################################################################### -set.seed(3043) - -#################################################################### -## Select the profiles from 1KG for the synthetic data. -## Here we select 2 profiles from 1KG for each subcontinental-level -## Normally, we use 30 profiles from 1KG for each -## subcontinental-level but it is too big for the example. -## The 1KG GDS file in this example only has 6 profiles for each -## subcontinental-level (for demo purpose only) -#################################################################### -dataRef <- select1KGPop(gds1KG, nbProfiles=2L) - -## Extract the list of selected 1KG sample identifiers -listProfileRef <- dataRef$sample.id - -#################################################################### -## A data.frame with the description of the study for the synthetic -## data is required. -## The column names must be as shown -#################################################################### -syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", - study.desc="MYDATA synthetic data", - study.platform="PLATFORM", - stringsAsFactors=FALSE) - -## The Profile GDS file is needed -fileProfile <- file.path(pathProfileGDS, paste0(profileName, ".gds")) - -#################################################################### -## The prepSynthetic() function prepares the annotation for -## the synthetic data -## The information is saved into the Profile GDS file -#################################################################### -prepSynthetic(fileProfileGDS=fileProfile, - listSampleRef=listProfileRef, - profileID=profileName, - studyDF=syntheticStudyDF, - prefix="1") - -#################################################################### -## Both the 1KG GDS file and the 1KG Annotation GDS file -## are required -#################################################################### -path1KG <- file.path(dataDir, "example", "gdsRef") -fileRefAnnot <- file.path(path1KG, "exAnnot1kg.gds") - -## Open 1KG Annotation GDS file -gdsRefAnnot <- openfn.gds(fileRefAnnot) - -#################################################################### -## The syntheticGeno() function generates the synthetic profiles. -## The synthetic profiles are saved in the Profile GDS file -#################################################################### -resG <- syntheticGeno(gdsReference=gds1KG, - gdsRefAnnot=gdsRefAnnot, - fileProfileGDS=fileProfile, - profileID=profileName, - listSampleRef=listProfileRef, - prefix="1") - -## Close both GDS files -closefn.gds(gds1KG) -closefn.gds(gdsRefAnnot) -``` - -
- - -### Sub-Step 2. Perform the PCA-KNN ancestry call for each synthetic profile - -The ancestry is inferred for each synthetic profile. As the ancestry of origin -of the 1KG profile used to generate the synthetic profile is known, the -accuracy of the calls will be assessed for different parameters. - -```{r PCA.KNN.Synthetic, collapse=TRUE, echo=TRUE, eval=TRUE, warning=FALSE, message=FALSE} -##################################################################### -## Load required packages -##################################################################### -library(RAIDS) -library(gdsfmt) - -#################################################################### -## The 1KG GDS file is required -##################################################################### -## Open the 1KG GDS file -gds <- openfn.gds(file1KG) - -##################################################################### -## The path to the directory where the PCA results will be saved -## in RDS files. -## The directory must exist. -##################################################################### -pathOut <- file.path(pathProfileGDS) - -if(! file.exists(pathOut)) { - dir.create(pathOut) -} - -##################################################################### -## Get the super-population information (known ancestry) for the -## reference profiles. This is the ground truth for the 1KG profiles. -##################################################################### -refKnownSuperPop <- getRef1KGPop(gds, "superPop") - -##################################################################### -## Fix the RNG seed as in step 6 to ensure the same results -##################################################################### -set.seed(3043) - -## Select the 1KG samples used to generate the synthetic dataset -## Already done in step 6, no need to repeat if the results have been saved -dataRef <- select1KGPop(gds, nbProfiles=2L) - -##################################################################### -## The function splitSelectByPop() generates a matrix with the -## reference samples split by sub-continental population -##################################################################### -sampleRM <- splitSelectByPop(dataRef) - -## Loop for all cancer samples with associated synthetic data -for(i in seq_len(length(listSamples))) { - - ## The Profile GDS file associated to the cancer profile - fileProfile <- file.path(pathProfileGDS, - paste0(listSamples[i], ".gds")) - - ## A sub-directory is created for the cancer sample - ## Beware that the number of files created will correspond to the - ## number of rows in the sampleRM matrix - pathOutProfile <- file.path(pathOut, listSamples[i]) - if(! file.exists(pathOutProfile)) { - dir.create(pathOutProfile) - } - - ## Open the Profile GDS file - gdsProfile <- snpgdsOpen(fileProfile) - - ## For each row of the sampleRM matrix - for(j in seq_len(nrow(sampleRM))) { - ## Run a PCA analysis using 1 synthetic profile from each - ## sub-continental ancestry - ## The synthetic profiles are projected on the 1KG PCA space - ## (the 1KG reference profiles used to generate the synthetic profiles - ## are removed from this PCA) - ## The K-nearest neighbors analysis is done using - ## a range of K and D values - syntKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, - sampleRM=sampleRM[j,], - studyIDSyn=syntheticStudyDF$study.id, - np=4L, - spRef=refKnownSuperPop, - eigenCount=15L) - - ## Results are saved - saveRDS(syntKNN$matKNN, file.path(pathOutProfile, - paste0("KNN.synt.", listSamples[i], ".", j, ".rds"))) - } - - ## Close Sample GDS file (important) - closefn.gds(gdsProfile) -} - -## Close 1KG GDS file (important) -closefn.gds(gds) -``` - - -
- -## Step 4 - Run the ancestry inference in the input data set - -The ancestry inference is done with the optimized _K_ and _D_ parameters. More -specifically, a PCA is generated using the 1KG reference samples and the -cancer sample. The _D_ parameter specifies the number of dimension for the -PCA. Then, the ancestry of the cancer sample is inferred using -a k-nearest neighbors classification method. The _K_ parameter specifies the -number of neighbors used for the classification. - - -```{r graphStep4, echo=FALSE, fig.align="center", fig.cap="Step 4 - Run the ancestry inference on the external study", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step4_v01.png") -``` - -
- -The PCA of the sample and KNN sample and Call the ancestry with the optimal -_K_ and _D_ parameters. - -Note: The formal selection of _K_ and _D_ parameters is done at this step but -all the synthetic data are prepared in the step 3. - - -```{r PCA.KNN.Sample, warning=FALSE, message=FALSE, collapse=TRUE, echo=TRUE, eval=TRUE} -#################################################################### -## Load required packages -#################################################################### -library(RAIDS) -library(gdsfmt) - -#################################################################### -## The reference 1KG GDS file is required -#################################################################### - -## Open the 1KG GDS file -gdsReference <- openfn.gds(file1KG) - -## A directory where result files are going to be saved, -## where a sub-directory will be set up for each input profile -pathOut <- file.path(pathProfileGDS) - -if(! file.exists(pathOut)) { - dir.create(pathOut) -} - -#################################################################### -## The getRef1KGPop() function extract the known super-population -## of the reference samples. -## We expect the ancestry call from a synthetic profile to -## correspond to the known ancestry of the reference sample used to -## synthesize it. -#################################################################### -refKnownSuperPop <- getRef1KGPop(gdsReference, "superPop") - -## Loop on each profile -## Can also be run in parallel or on different clusters... -for(i in seq_len(length(listSamples))){ - - ## Extract the GDS file name and path for the current profile - fileProfile <- file.path(pathProfileGDS, paste0(listSamples[i], ".gds")) - - ## Directory where the KNN results of the synthetic profiles have been saved - pathKNN <- file.path(pathOut, listSamples[i]) - listFilesName <- dir(file.path(pathKNN), ".rds") - - ## List of the KNN result files from PCA run on synthetic data - listFiles <- file.path(file.path(pathKNN) , listFilesName) - - ## Open the Profile GDS file - gdsProfile <- snpgdsOpen(fileProfile) - - ## Select the optimal K and D parameters from the synthetic data results - ## Use those parameter to infer the ancestry of the specific profile - resCall <- computeAncestryFromSyntheticFile(gdsReference=gdsReference, - gdsProfile=gdsProfile, - listFiles=listFiles, - currentProfile=listSamples[i], - spRef=refKnownSuperPop, - studyIDSyn=syntheticStudyDF$study.id, - np=1L) - - saveRDS(resCall, file.path(pathOut, - paste0(listSamples[i], ".infoCall", ".rds"))) - - write.csv(resCall$Ancestry, - file.path(pathOut, paste0(listSamples[i], ".Ancestry",".csv")), - quote=FALSE, row.names=FALSE) - - ## Close the Profile GDS file (important) - closefn.gds(gdsProfile) -} - -## Close the 1KG GDS file (important) -closefn.gds(gdsReference) - -#################################################################### -## Show the ancestry inference (SuperPop) and -## optimal number of PCA components D -## optimal number of neighbours K -#################################################################### -resAncestry <- read.csv(file.path(pathOut, - paste0(ped$Name.ID[1], ".Ancestry.csv"))) -resAncestry - -## Clean-up demo files -unlink(fileProfile, force=TRUE) -unlink(pathOut, recursive=TRUE, force=TRUE) -``` - - -The *computeAncestryFromSyntheticFile()* function generates 3 types of files -in the *OUTPUT* directory. - -* The ancestry inference CSV file (".Ancestry.csv" file) -* The inference information RDS file (".infoCall.rds" file) -* The parameter information RDS files from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory) - -In addition, a sub-directory (named using the *profile ID*) is -also created. - - - - # Wrapper function to run ancestry inference in one command The Steps 1 to Step 2 Sub-step 3 ( [Main Step](#mains) ) are required before From 4b0833b560b45d0d91a19dd5897c565cdc541c93 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 6 Jun 2023 12:28:50 -0400 Subject: [PATCH 009/385] Update main vignette; add figure --- vignettes/MainSteps_Wrapper_v01.png | Bin 0 -> 37510 bytes vignettes/RAIDS.Rmd | 20 +++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 vignettes/MainSteps_Wrapper_v01.png diff --git a/vignettes/MainSteps_Wrapper_v01.png b/vignettes/MainSteps_Wrapper_v01.png new file mode 100644 index 0000000000000000000000000000000000000000..4fa2ffee9749da6e37a97945a1c16ac1e7c7da3a GIT binary patch literal 37510 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 literal 0 HcmV?d00001 diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index c1e06467c..4236cc3a1 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -333,12 +333,22 @@ rm(demoPEDFile)
-# Wrapper function to run ancestry inference in one command +## Final Step - Wrapper function to run ancestry inference in one command -The Steps 1 to Step 2 Sub-step 3 ( [Main Step](#mains) ) are required before -this section. +The final step can be run with a wrapper function +that encapsulates multiple steps of the workflow. -The wrapper function requires 4 files as input: +```{r graphWrapper, echo=FALSE, fig.align="center", fig.cap="Final step - The wrapper function encapsulates multiple steps of the workflow.", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_Wrapper_v01.png") +``` + +As a complement, the companion vignette +[Ancestry Inference Step by Step (optional)](Ancestry_Inference_Step_by_Step.html) +describes all steps covered by the wrapper function. + +
+ +The wrapper function, called _runExomeAncestry()_, requires 4 files as input: - The **1KG GDS file** - The **1KG SNV Annotation GDS file** @@ -455,7 +465,7 @@ list.files(file.path(pathOut, ped$Name.ID[1])) #################################################################### ## Show the ancestry inference (SuperPop) and ## optimal number of PCA component D -## optimal number neighbour K +## optimal number of neighbours K #################################################################### resAncestry <- read.csv(file.path(pathOut, paste0(ped$Name.ID[1], ".Ancestry.csv"))) From 5adb6c0df41a6a83831b71e20090ecdcb6f58607 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 6 Jun 2023 13:08:25 -0400 Subject: [PATCH 010/385] Update vignette --- vignettes/RAIDS.Rmd | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 4236cc3a1..cd3b180dc 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -346,6 +346,10 @@ As a complement, the companion vignette [Ancestry Inference Step by Step (optional)](Ancestry_Inference_Step_by_Step.html) describes all steps covered by the wrapper function. +In summary, the wrapper function generates the synthetic dataset and uses it +to selected the optimal parameters before calling the genetic ancestry on +the current profiles. +
The wrapper function, called _runExomeAncestry()_, requires 4 files as input: @@ -450,6 +454,14 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## chrInfo[24] <- length(Hsapiens[["chrY"]]) ## chrInfo[25] <- length(Hsapiens[["chrM"]]) + +#################################################################### +## The wrapper function generates the synthetic dataset and uses it +## to selected the optimal parameters before calling the genetic +## ancestry on the current profiles. +## All important information, for each step, are saved in +## multiple output files. +#################################################################### runExomeAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, @@ -480,7 +492,7 @@ unlink(pathOut, recursive=TRUE, force=TRUE)
The *runExomeAncestry()* function generates 3 types of files -in the *OUTPUT* directory. +in the *pathOut* directory. * The ancestry inference CSV file (".Ancestry.csv" file) * The inference information RDS file (".infoCall.rds" file) From 1f43c252f3df5aa0aec67d27fceb0adfc5ab9a23 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 6 Jun 2023 15:16:39 -0400 Subject: [PATCH 011/385] Update main vignette --- vignettes/RAIDS.Rmd | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index cd3b180dc..e9d024a07 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -177,14 +177,11 @@ knitr::include_graphics("MainSteps_Step2_v01.png")
-These are: +These sub-steps are: 1. Create a directory containing the 3 reference files from 1KG -2. Make a SNP pileup file for the profile -3. Create an RDS file containing information about the samples -4. Create a Sample GDS file (1 GDS file per sample) -5. Generate a pruned subset of the single nucleotide variants (SNVs) -6. Estimate the allelic frequency for the pruned SNVs +2. Make a SNP pileup file for each profile +3. Create an RDS file containing information about the profiles Note that a mapped BAM file is needed for each sample (step 2). The reference @@ -475,9 +472,9 @@ list.files(pathOut) list.files(file.path(pathOut, ped$Name.ID[1])) #################################################################### -## Show the ancestry inference (SuperPop) and -## optimal number of PCA component D -## optimal number of neighbours K +## The file containing the ancestry inference (SuperPop column) and +## optimal number of PCA component (D column) +## optimal number of neighbours (K column) #################################################################### resAncestry <- read.csv(file.path(pathOut, paste0(ped$Name.ID[1], ".Ancestry.csv"))) @@ -506,7 +503,7 @@ also created.
-# Pre-processed files are available +# Pre-processed reference files are available Pre-processed files, such as the 1KG GDS file, are available at this address: From cfbaa805c9f5b956193c358dae61a29f263def4d Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 7 Jun 2023 19:56:05 -0400 Subject: [PATCH 012/385] Update vignette' --- ...teps_Step2_SubStep2_SNP-Pileup_v01.mod.png | Bin 16840 -> 0 bytes ...ainSteps_Step2_SubStep2_SNP-Pileup_v02.png | Bin 0 -> 21595 bytes vignettes/RAIDS.Rmd | 159 ++++++++++-------- vignettes/aicsBiblio.bibtex | 10 ++ 4 files changed, 100 insertions(+), 69 deletions(-) delete mode 100644 vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v01.mod.png create mode 100644 vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v02.png diff --git a/vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v01.mod.png b/vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v01.mod.png deleted file mode 100644 index c87e15cfb837f7c974e379c1fcd45bcc798ed790..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16840 zcmb8WcU%)q)HbY$QdF77XzY!e+T`o48RATcM8lNIKcEXK;Iz%8-ze%;0GiWb$?$;D99o4 z{s9t-dJ+l>9zH%YFqDUvp9j`o1_uuSZUN7+co+(Sg2R57QIJzmkd{-EmQ%C=o+|3d zs{$tlB^d=dkkjw-9$s+Vp9(=TazF)A_9z?-PxJ>ap*FxtUJkge2nMcz2g*vnFN2ho z&H;CHe0(r)d$^|w3TPbyQdE&qR0eKKnHbubnMx?=0@oOnHyrq90Ke*u-+x6H>4(Px zcOdd|N-}aXAbEKO8F{(=o?Ck$Jp54qvmSkz*S`hj71R`ERDcfd7lj9Sc>VrB122ez zrJcLAys5vZ9?B{RL4*Tc-7iCc`}w2rxWD5dqadUD`#}K72mbr67as400r~=rj6N{N ze+CnH7xicO%>402fqFPwe+MW+8fIap6AU%{T?x(u_=tbRU;&JvwEXW%RP1n`o&o+! z`WA8?IuZ(C1wCCg`2Y(wUvn(c7>dH`swwL_S%7U7t@M$BCh`yyTVRwRips{;4km#Z zpCAukn6a0Ry)F_=G)JnMJ6)A?^fpt`!^y#wJ-mWZs!ldaC>>P-5k|C7@xX$ee6Ua_ zpdE-E8feTS;HsGqUMbL8&r1OcGx4$4HAay11E8jsazQpA6A!$vu9>wl(E$w8wF0_= zM>*=@OrZe|_KHwzLq$6S9c#R?9a7g4>Sv8m(IF5qL}eIW-WsUh%K>Sm8)Ogll2g;i zLv-ye1FiKfkpA{ThE6CYeKn90$(R6k2ms+xcqOo15D5-bvp^dwUo|44O}v$z91V$v zdWt{~oj~TEhQYvCfmNIkHu6ReN=8Iw13!e7g^HuUg%Jj5is0aI)d@n!>|tK_F*iNKg( zEc^mNFcnW5jGw860}kO72(#3&2I|5i5UN240?|{^A3;QUt0*DN&6LdS@PWu6UmXvi z17JIpjgNu65)xu6P57<5Hdi=7O80A1-G@rdZL`r!Elm+2O4`7=c58sF~frcEtN5z`sQjd zoSYp}-_e>F>`Sz=Blx1>P^c*wW`u!(J%a*JUQUidB&cpMFfIMi7!#1bk9RN;=cND) zI>Zrd;0t^q5~B;(^_PR$8Xye43``X55msoJk*WU|+xiMntfaJsPB9s{;Ho z_6jyJwK4H4D`8a~P-Ye|q^XmkoV>jiU^2kw zHYga$Th-e}E!Yx;CV_N7dMe(yeR*1Y2ca$P(H^P@d8jZ#%f92inmG>8%KK+6QStxJt0_2=+H{(lc1_fA*&CYK+UgR6j6lFMKRZ1&;E8Dv)(C3k9jp+Da6$&E z`B_5bEETK`bc{eyFGY-rDHd*^Ou+lvE88loC}8w#Z7hwUNG~)Ju0}*40L8Jm8UP|G z!h-Ar5C%bJ3f5{64{tcp5TiLr1SsomhDJD86AXPl3_%!geOomY!p_^)*2&691?mCT@iO-{ z57Ncj;JraM=5}UY7T6)A7NXIoTT`?RA1Yu|7Js zrhY^-yWpz?6Of&r70lKN1XBnO_S46q9iU3)z6$2@LV$*&`#bn!5paJ$OBGWBF%T$- z0tJI`$~Z!hhaU)|rVj^J3y8V5KSl|7Mvy1js>1iHgChX3LL3}|b>TQmGmMoHFmhlc zs5w&EOA+g7qimu>R5tNP>#Et<_Y8FxH+#PzzFUBmlp3 zboN(^{R3DOA%9nzf0iBK_n*~WQU3%61Gosn2aNP|Y=YeAkBJ_M3u^ji8n>P={PJ#%TZjk>b0$&yut8l+41wN5{jbhSH1$=stQ1+N z>!AlKGTAGiNHJeK@b|bj%G~(sKK;B6v*#wZfxGV|Zs4lwJTIH*hAZM!2|G-GjY zbh!FtCH^tD*=5YiGp4xYZi>c7sY#K@!#Wyx%Pc5RPfx^LdfQ&Vi=MV+;bLyDNtTU$9px-Z}c3@gT>6e~u_m2KmL40!8Py7Fb79 z=3?{{4R%Qhe*R?S@OKwMhSf^J(hb!wTg06Kz*Aeiz z0+rN@gRSiy?%XTC%g{V?j`G=64%bGO9cp4etI^v1uv(yri&BK?%DExF_xal8^a z{ATr-Lq*mZwTFBvDB~qJH?%RuvBCuU_(_Z7l9aM?T<3$V{GYjz))zLQDACw+>n)f`=dT=c(zM(2#(8ay*H@L$&F^e~?<-Xb>pj)_ zQ1$WP>)Ku$SP0!2-yKJHR_d8bR1P+)58wXeks9^N)$2%>QuUXcUC2SHtv$~x_IGA@ z|5K-1H?&QgZp4=~9a}hgk8%<99>Zr8ZHGm6%)wZKK}7ID_&n*#G;| zYuCg%ddMB@=ZJETG}X=X;(~@_#jEvMMQQ7p|EBo?W(SDy7kIjnuTltjlR4O*e)hc! zR_1G77^S+wQ0(P*#cTKeofq1|NJarknvU4Si+dt8Hh#GP-oMj8_&kd?Mex%11Z*Um zK+W;L%FbcSC`@A$#5GfNnb<~;{Hv~IfP)buMhh)8-M#Th=3_~l#>>8sP)_I7 zm&h{5*QOV8BgP-UnE#l@Ufc3m@#Yb>uy*}-uOCBE1!{+=ls@DW+5cp5#q^Cbxs=yy z;raQ`+e_;`?~U$Ng$k^E`#9v5Dd{$7@NvK(wZOQ(8ul`X)H2u5yX9@)bMw$0+h~mc zX#8@mYjOynEzW{Lhp0^ke18Y@0ONOapxTbY-V6INV_vBC!!)tiv z?b@Scx{%7q;lHvyz>qC|--^~_cmS9dmQ^7z^|NR16c=a6s$Znh7sn^M z9l2hQYQA{RuS3ZtZvXtYU;N5`chqC=u!mj8Y#q38Ehm9~;PdUDcFlxS6S=70L&(cO zNx-grGaTz19{oULn3{t1R8XrMotI9#&Rqxn($3KS=z=o{`n;r(Q)~c<>0hO#ENaLH z-=G{8Nu9tlJ6E7{>3gMG5Y6sVMiJWexZ>(95!#e0wUir1!-?J4-5(t7WiFp&Oyt#v zd8X!Bj|(0niq81>lh-f2lnwfN*331|Z>UXqO(SfCo6Z^3@IxC~cncGWP}ZjCzNgOF z3DfLO=!gCO`duz&L&`u@86Vx2{bpjBKa&@*TID_MFoKY>!U>l&G=uAcb~+@Yi~d-I zSjw zg;`}PL%7~N$1@4<>8mwgarers3x;(rZC~6til~WFS`*va@Iubv-MIr>mDj0x79sbs z&(}r=+O{;!&d z*HI#MP9*bEp18&Eaif0mY>LE64i_Ml5RM4L-;7_Ht#f=CyHZb+S~Z{}tX z({o}iPu_Zt(kO0G){>0gd(>B;=e~lH`Ney!KoXjJTTQW1vH9!hfD%_Y4n)STR+td` z7|DWZ>>Mz4rHoSCVKO#uW-c}oN!z{O{}QWcjLI~Or=PFEXbo-opYT|_B(w_Fl(Qp&199u^(>H~6V zs$*qFjHn6KPOMWwTG#k>GWJ}*OWAN${NU@aNlg>drMent-5{T4J&8e7j!w) z-Y65#VyV8t%(lt{C31v8v5`u5~~X?_=& zGqx@3dha-}KHSJzyCh5-J57Db2%{|(eyjU=T0&C7!s%lQK|pi)ZWQZUnEnTeNhM!H z`yYTe;G=r50Ztolrl?R;&I!(5EwH)ocL7erz|ti$WTB|U)LNwaVuGmtv`30L5}T%{zt!MF8gtOb*Pu@ z-(Rx#HHROaZpRLIm`!>^SPigO{m%8^vHoH7w?bJ%MplAQc2i(k&Q{2k_8YfO4cyS~ zW?>Yk=`6ZN@g*=#G=E4JK`TE&a8TKpvu4wEMQ9_ZQ;_uwvwb(+cKgnY6ki-e!_wfX z5h+&fdsET5lUCgu;}_fdre$*K92+X5yb3a6{`KSFnsrx&4SlyKo{gJ9GxSZE zXy9#{lxCpQw&)M)*r7WO+=fMfiSe7g@5a%02iks4YW6WTAfwrmt&`%bBVd6-+Ofx}l zcDDd`0q&etUJ7~Y7+%ofs;8e7q4Vf#xHRKKS#y-I)r-`o$sIO!hAA zWyniJ`guXck#cK+h&V#DYi^xQ}H!QBBlFK3y! z+OdMQPbyIQ?kgbE>|awq#<~ zQ@H-3mE!VHiYWDxtKza|=GsR>mE@}j^xHKuwGkU&N=X}~N0XLuAZ03VK=Tm+1%x?EAuV;e&H- zgE6{ci;0|KD8IqWR%@+O3cnnPfmt|Bhp9B4bK+~?ru@nkKK7-X@EmQ$KOYr`7AJ4P zhf3`mhC>t>WET@72X5gW7FWU6WZjzys$NXPcQCpXv03XYYl~Zkp0QpBuV3MK5sRs+ zel8d*q><5o^NKO_F^5&yPq0MC!(^S)Clrk`?Wj4n{31Por*ZGTz{WCU#UX%*5-)pw zIUe?UYwdf^?ENNWfwiWFpWMC=M&O9OSa62k$u!uWrSYK2td$3QXP*4e2fHX9qAMH( zv_(BhlLe4jy!c=c4+ry+gS2J>`2C&a^!xgum&8q;1)BzMP|KZQX}Qz|8BNY#>o4Db z;WiYbp3x$m?MMgdXFytdFe`HDP?gbVg5#awvMEvtSujTDM*;L7A@7{F9k~j`Yk*o7 zSHmKM0ky<4L1qpye|q#gZr51-EbTFyTce$%{sdB_cH?3$HG_wIb&E$jP>*1jHTJfw z?L8_67P9sy#;<>@Z*xTJDS3AxPOre%_+^O4L#Vv(fB_0>g)djwIv zgKy=l;-{ZCFf?DAoC5O%Y)C65jjdV3#+qSeeBQ_`J^Ibvx^FtL%|p%Wdl%NrazcN) ztF^Tm-`z7N0j{hJ2W&HouX*Clz2KtprMdYDsNgM(K^KuXQ%QlP5q5F?6}tVin+NHV zEoJ8}#$Vj|!4GXQS|-ey!775KJHj%O%X93Wbj6QH>R@V~IaY__>Px!BVugEOwfoh) z(X6g5@^X@Ey=2w;{mQv`FCir~*Gc-`yL`*Bw~a_9uD~sgtRn-u9)Wml^`W~xcT?;t zr%TT?Q+8m^_g0swB$>BtkDg2Jq0b!>+-5}AoN35Z(Mq3FG3?)EXoWAAm1DgAM0uk0 z1lg64^oYR*SyWL`)Yz1R)OaK&GD&%u;ov+=RP*ZRkXkEDX-R3>s7Y)wCZv_B>A3x% zEj4!={4J^?8QVEOH3I>#7+jyB>K@IylcG+Y3V9_x2I*!~qw&gynP1RcKbA=6Xm_{} z?>#NOyZq|{Jb3-uR>hh_Uh4C3cV-p$y3z5XKCcghq`Ea__h4#@L2=uf?Z$($pJ5Ae zD0c4r+Es?qp>e>`SiO%;@mwiO9nsB|QjBOAADoxjgtZ-^hu9l~WCH*f`^?Vw%y5}^ zV}-t4*bD0phOZJa^M}+Eun}60uh<#2-v}|t%kIL7wgvNL**s?a>;4hiYcp%q)e8Q* z+b2X-r1qAj4u>o?#YYikPj8p(Wt;J9a?hU4@X`4kWz$woc6nh*sa$m4V!g1fQ2tswy;xpPkXpy{B+gd9il19?Kg0Xq%zZ z5NA9dy5(BgCsrL}DfkOX3=43SrG;J&Dcg;Y-kn=}of3jx3h^7qg>h%Dv7|;0|2Q+g z-5$~TSf^~8bh3pqN~d*Tr+0kwky{-gAynPNo5Ql8UOb@_OrcBC6h^D=?aPn|AX8`mFciAo3iM5?}9jE$sISEZ=AQ*?za{k%}+Eu zhp>DAF5yb${5l>(N)B&;Ri1q@CQ5@abgmSWU7ZMVsypHltN6y22chexetl=bzgAZK z=UPVEy`;82*cYuyyXtYfVRJ1#5B)TGyUdbnXeKt{&a=+Tbh_G$?Lz@H+MQ367NQ-c zsZ}++J7d6v4tyE3<=-m~qlJ^DLmFqp1(+vHa6{)mq~A^x8@|{p5c3CSF^#HDroR<~ z^n9sP13zPrAXy|g0Ny9IBepgJ8<=iyPL>{;YTljOni*H|yh0R-6_*Qt#n1T8On7Rh zWyv-o2(Ja8uuiYGZmgPdtuGCOHvy=$(6%r5>>_j6OJp)u18(b}F^O3ULyMl6HL!jZSHE=W$C{u{Er$%J2pSHa^BI&7!J0El_QHvONe?+c@Y6I&ldkFKke zc1ezmZIPl}&WPz_>`KXes!_}OVdH3M3rHmao3)2OtO7*zjE}A*?B@iKvzs?XYdVr{ zwPi8_-H*y0e!oS@T`lFJQ(Gd|&hx?3;g%2V6%(;3L&u$2Z+~hv>8MIkqh(~iB}?mH zUTK;y!i8devucw$b6L0yVa`+DCM;E=WIB{GP+ua@0S(?aiZrR5c7}Syio#3y_|xO_ zCD@q)KkTbbd((ew4W z*$W)Q{^p+-Y3x>>k4t7#iLPEDradyW2fQ-(T;SF4tlDOZ+ZECk$2WbFuZ4N+i#e|b zN^-f~I+r`O+e#_Oz=FnI2D|8H>9vN@LFJ6ob#)a^T460zQ=SM9E%^NbnBH? z<>#xdr+R5MtYOcL8oHEaFY8;^qZfh9n)Q!WCv5)4pd%baqtoB0GF* zt{(Nf{+050D|9%v(G`ernNZ?WTECX2I&u@m46H_L0*~Wat1#&iT*)>704y)0{f5fu z0^9mBd0}}jWUHuY05tP_VF<{X9J$&S5%lTDERd?%y0F}MNKlG`IL^P^8p4|)N>jkj z4LalVtH#4?(*m|cX=6oC^a`2vy!nh=Tm*K0yk}Pm-wsN4qm99o^jvXOl3}q5mX=4uMwdgG%c1J zW2Lf*g(@9q;Ng%<#)_Q&FDX`Og3@a-<0|w8hdMyhDn6?TS{}|iMtWLzqh97*fo$9Z zD=VE=~~a~5n&OL>z$9)r%NA}j+;ZFPaDi+?*O=Ya*X;%a@hMa!B0Ph z12^VM%FeoFbw8Uv)l5h@#Z>OJA3hD20U-ZQlX&+T(gSSRA^Y%k-ho$hlGiEGTY-$C zu@^*X55G)^b95xqA+dZt)N-%G;d+$!YDY`G`N>#86Ulx?D&d{f#-KqKoK`hwdC7?d zQ0T;R!AFWpz_9pJB+b&qd5oMA%Xi{mXIT#Vo1^dNS>AuT>@o;8#wCinZLOyJD|v0I z&UMcs__iHt+F+aOxob#wOOc&RR~20A11yu(1AZ)_Psl70%es$0uGzfI867W_Z$IVL zbN{PCk=xFZoL!Ol*qd5Q4U^zn z??h;!F_(p2yblQ^HqhDTMkHbv>i2j($A16`s$3xN#<*>H1H%;4ZF%xxBK9?M{M2w3|3^k$kw zRi64{_?yEu&$i;Sc6g;Dq*IN}vvM+tt0xnGIaPYzF075lxYq5vue7@&IJ&& zV!BJZ8h55noZE1!4ZgcxRxnfBBfrcm>vj#Jz9a^Vb_0-D5TEpI`&N+Ff#~JyhnN}} z^ldXXRy^L{L6x;Ab#HD7n5|o9b5Z%quIeATvvMUTgQ(I!ET|6Of+hh@hJ_ z#970yPrD>nd<5|s-&eycAe7g!Hv!Z8aF+SXfdi*W`&@vR0riz%Y*Q;Z!*;BqnAil3 z78`1B@F^Sjej8z>PW5xt!vY@XuVYYmIdCa>F)GeKj7elz(7I3Qx;@(5b8aZLg zx3bLb+fXp09=&>NnKLIov{l?)+NrXLhiYfunOuNSHbl-~UsbGeQk7%Ri?Rma$L1DR zhW_a9w{fcWlc0ZksT)<9=9I(xi(PBmB3ZsBPrR+ZaHSC3S@iJYIE{imL8o}HeLeT> zQ*7gd^P)7)pFI`hy4sZYif09i!m%ItL^|D1X62yNqLDvjH?8*Si3yii>zvU{@B2AP zp<9hT?@=?lYg|H9x6ru?)q{#M6uY1^&0TgPw5HFYiP-1YC2S$Yjp^`1kXL#&`56CT zW_Pr4)M@He1$SIb3F$L=8d4-uEak5zMx7ek+nuO&V$6sbT(cgVhEm|q)eO2Nn0CuF zTf53$`Uq(e9`=4T<1}cShu3xl(xc*2%!SnT^OBptPD^@qcpIVOi(|?D(Szwi7@?@~rUT?5N;6^)|&leAlilYB~4N?Cou>zOOg8qU~aTRa9e| zk_B2Ht0k@%2AyV!#4ve0d1sSfMwYHEGH8%Sibi`%- zXZgwgmsqAfN@^2NNhd5XXIyWlXeyLauAYs(x4MUZzcZ>rd*2r5H!vY$ z+>VPOPRUY}j#JL_SuRs{_I7q?^~7cc1h1hV>2!;-7|lU=Hf&di@>&thqQ$ID*|~=3 zk-pfHCA2O1AmiK#PP#}yI=W^gFSimAzMOe7xpZj9_mor>d=PDoDlu3qn!+Pt_pX~R~1lzFk7UWSnb)k4}D z2vyydqX1@>V8iP@7ol_I?%u3MgOB3@>etm;eWmoQ^eq`{c#P=8oOZB@SkE-Ze*;vK zib6>s&K?G2E0Ju;Vz}|(=vmT4jwPC<@b;Yp`$?AE=O+Of-PwNk!9ex%t8MVa}K6{c|@$_|jz0XdfuPPt@y-{b?E^?0t~h>8s3)(bPelS0~Zjg07lx_e1nUy5{%8S+OH z^vt->k*}DpgP5pnF+vM$F$Z7(FJST54a}Aa+ZvG4ewacZ;Aiil>_`?}r6H1gFDLSW zq6(Zq-q)@~vAEQP-Zt*C?d~}NuUPChs;Sgf|RzToq`|YjzoG(d! zX{vc8^sS>*$_@ugFu6AMn2?Va2tdyTgWjtrsjl1rV8h3kh_Rc;sd0Hdjpce`2SsQZ zm#pl3Z*S(g^2Qz$SZV*0q@kFfyN*#uJE0yA;7`o77YP4(cfS*U0N%HrsBLQGs6UXQ zLg>xisSyioJXn6i+IY8O)jF8a+(B_uVxg|$6@C`QzTVW5!7cpBSq#KQpWH%7s$juD zN{M$7ZniCy+9zE5dyOmTXB+Bk)h{m^tt>4L)XrpfEW-)5l1N6Co3WyRfq@*4h~jBK zB|A5{>qF8MpT=yE_!Kt|r)hd52gS#Ss`Lr%F+T!G1jnh$D%Kg6tch5!80!}y)q#sf zn_Hb<8`B*=(Z84pga`W{o$D!jG+Kj*-fi5*znv&n9N*Q}z@xFzY}qHqSh&Ayf@A01 z^w-v2EItIRPJC|tt@EW9+uDFq+@zWM+FK*PK9Jia!B5SDbqqo7Hz8&@k&6u`%_`&N zK!9v1BST3sIboHNIth<{k0bNeogd5k@y*99b3iExNW&!m&L`xhw3vY=?A!QTDAe6` zX!ACZVQi*sP(AmO60lqGmM=n@b9Sm8yY~r>4qGiXt=t&R=vv8AT{^xq9;drpo?dp{ zhrc`eQF*ABty2NFG49LAwrQ5v?e};o&9F??wKJ803jlPwX7n@_>v(fl&oE5fkyZX^ zP3@&uGAURdOk7Hdq)}%_=pC|qsI6YHEp^xDs~xXzYT{4F`%T^7s3e>i4YBoAU1W)< z4d~yLSM-hvfF@}{-Y$5oW@+ZrYF)iddQ!SN-@QhCOjTOxS$Nwt@oMvG(=@gi%zC%H z$?R!TyV)X^7N<+u;pgjoG}Y|Wvn$)2T5+7zSd&bj&J2!m+gLj9RI!Zh;fzBRR3M=y z_GNuJV+vZd`xth9#eqp3)ym0Ak~K(;mPv-o3T_ z(w0RsbezWOaEs7%uAt!yukKftQ;LY)rs5cp)dv*joe{=u2SQeN0{vQ~L*6X`O}p<& zQy$_~Xz@pfopv1Qw>8Pq5q6V~Le!~MH4XjO{i7zYw9x4;otOv)$#3;XfD8}+SRiXe z%dx5U@_L-)wnX1%0VFmU2$#INSb)6CM|L2?cU}Dl`dDQ{gn=Pn-y$OrXcMZ06U8P@ z7_jq_J|X-lRnJIf7ct8cUg^2LF7@mEs3eql-4*MpyFk3(FA+In8gYZ=BpGW;932$9 z1-kS$gETlq2QCJ+K)%^B6$Oi8AXy$-33S^;9M4_z7|t9eD%uGXhDI^rhVQv0Sl(ot`398SQ7#yk@_ zK&9Ntt#SfO)5bOd-cxGW%Si@<+{ebD*dbSv`{q^KbjXS}Wwh@@HS7MD57LwUPd*Dn z_w&%n9bFMWKI`x)Avq?er;pAm`|D6TEWoF;05>4)-6YWiAVkan8Ty~B_Na_g0y4j* zXo0L|(-&m=zJRt0 z!(R{gi&cWyl*)U!r~4EC9}IwZ`oes0=UAJFl>z(Y#6+Fy>S|HRblGq%NlAk!P{UKe z2Z4`{FLPgL0({BCALRNEQrV6NG!u}j&ZDd_nt&zr9F?*s9*CjESfxo?Dm=QYV3vq6l8gL#FX!@+Z$cb1z}pY zDApIiyQ8ny6tR&7`8w^Y7^uqT$-HJfyScYkg`^9TezDdBY%ndU&PDq1jsdq1pl@|Nt2p8 z1h5e$uLHnn9JmVA2l;L)%4^DV@?>Ir-zpDvYD-a3(Ws*@Zn$|hG2%>KfdSjoLs^TQ zOY48qW%puty3X7MLa`@~kG`HOLirm5?9%kbtgxB~XJ(1&8av+uQir;Jvp=K#0A{H1 zBs^aR+sryOC7T`2&MvZ`ySmiX-9KJ$SX#Ct&ua)69k1SZYJDYPP2XNmZ2kav4!URl zAN{?L#fx@aeS7q5UtiyGf69dm7jEY*eKD?1zdM4KQ&Ur`5v5sG6m)g&$GcIac0Xso zxm(dbM)EM|gdbneTZL=j!<7f{35I=$>6);|aA(=Ri{BK_!Y!H_O)XO; zsZ(pVE$q`wP|9&CTZh#DW+nlEh8Y=Kk&tMulOp3Bf}3>A_pLPx%rs#TSG zEnW|Nzv^Ae$?|2 z>L2ATD@=L!mg80XHq}~RFFl_$@N4MYS1L-hLl07i|K1NcQOQv== zg7qk+S-3=T+F+kfY_@Rs?%iSwrJKt898uvJMo~-3O|}lm@msbOiO5R)Yn>Cl22nz^ z@lRC!I>$n_oDR{Bo|zFfMdau1kGCG0P|sZU4Zcs>MFg+@-Nl$nPkFFf%)tzZpac? z$DfsrdZ%oVmlu_PMn;KfN zAb80+IBoU&`FWsknec^#?k}y2e=5;@PH!4niM>E*;;EKiwjIfL~mxKjEh@y-x6oRo|41zk}CFZXe`BnKfQkiv|iWUOE0`PGhuKh|JI%3l{?idlXNA*KI8JpCc__k z>|3z|RJJoTi+&70bujBkvuJy2uxZWZ%*XE2V#E2zmgY%IZh z#_2CnYlB0SK8F%X8!$yz{&3Hczm(a32&P_L?6g)2x3}htv&za)3&g>O(jnL7mXzcD z0C|A^g5Qw>eH^@89= zG+b`7Q`vY)6-WOFC0l}{g*;kI#PeMWC_LJ|?+Eqgo7~-_y_kp?T)3T56Ie=xP*&7v z7rOx_2Kp%fq$gyhXP+8eBn~9?=3cMo3nWJF?55d@DvSZ9)B{r|o$a z{J6IO9;qJVW^UkOH?_B~!plCJfX6{o+)?5JRL$`3FWN-SYGYJkG#Rn$;eTky+CD6L z<(Mk`cxF?~Y2C2RFSY;HEKv0Gwc4zKFiX;V23n^nBDyssEL0`_yrV>x3 zTfGkJ-sZ~uhn>weje*jv*}sXZKLuvh2xX3pZ4Jf zlz|NF*vnhF^AZJ6Bue7#4wCd7a3i3b01@f;{s6Fn@GwAFta_QK5m&wTx2?3?zB`JW&8KUM7E~pVhio0sV;_9Z#T5#W zYW7Jso9w5~w${>GyG%Qk@jC?z5YJR@uJG_?!c6_QZmvJG>ehX2alj#CFaq7XDArzl ziod0l+lS{{BJ!ce*s_Z0O)GOaQK4_2vC#8G_7XQAPo?MNo(0L&7z6vY8>(u0Y?`~SArxF=J zBd2Py#<~=&BKOSSeNv1M4!~%EFZ0x?DMe?-VCiiqd3kH~D5J-pq}7(D;_3|^_z`;n zPh{?+SkMCiwfV>c`ZHy(JqD(%D_p%>iOaoDJ4hyoCUSdzq>fac{YIBUUq=1PmQBD4 zUCI8t#Y^=e(2^~s1Aw#E=9F7orm%-eZ^hilcr1#0mH~vg8!qHiiQCDXaM|CaAp{Vc z|K|n{A;8~^T^nJ8&1>xphF=zUreJzjS5kht+SrIgOd2Ym3@bNeJ$R6Rw>CUTgr*4% zs^yNv(BR_T?0*bCv&?nFWcp{Wa(g;J;fal$9n+?m<$`toJoZrnjB{=zJ4zfX2sCYN zz_#;u@5uOmWbqYV)fLnp|6_B>wRiyc)nq7l z{Q2-FDZTg%edsZI;F(AH^KA76=6$qi9~wzZALCE>tBs( zty?&9iQ#ZkpI2_lni<-^KHi9N1M(fm*qfynxUX z0K%AZS^8Q2+jk*+h4VLU006)&|8RKq2XfM`aDH-Fmyl>0dU7yq_(%y$|6jYe-^>+G z08MhS{|}l%Sq>C7p&9;QQ{T|e$9Y!%+bW`+z>Fk^{hx&DtHdPXgKGs&P(i9wz^%>* zYa_8OV&3LY&`!~jwf{Cl0MyEd*Ur+&uK#y{w8+8Es`BxF2S_4;;>W&TJNxg3A8la{ zh5=am1$9?9quYB@**gYpMR|2MWL$Se5|n+)g#K3ybn8PxxLl+3e`CpkW7uPt+<5oY UA}$Gj0QfV~hw42CU%B!B0XD8de*gdg diff --git a/vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v02.png b/vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v02.png new file mode 100644 index 0000000000000000000000000000000000000000..494b45024ee4c0e1b8012d80e98abc53e394db7a GIT binary patch literal 21595 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 @@ -280,13 +269,13 @@ is required. The PED RDS file must contain a *data.frame* with these 5 columns: -- **Name.ID**: The unique sample identifier. The profile VCF file +- _Name.ID_: The unique sample identifier. The profile VCF file should be called "Name.ID.txt.gz". -- **Case.ID**: The patient identifier associated to the sample. -- **Sample.Type**: The information about the profile tissue source +- _Case.ID_: The patient identifier associated to the sample. +- _Sample.Type_: The information about the profile tissue source (primary tumor, metastatic tumor, normal, etc..). -- **Diagnosis**: The donor's diagnosis. -- **Source**: The source of the profile sequence data (example: dbGAP_XYZ). +- _Diagnosis_: The donor's diagnosis. +- _Source_: The source of the profile sequence data (example: dbGAP_XYZ). Important: The row names of the *data.frame* must be the profiles' **Name.ID**. @@ -365,71 +354,71 @@ also required. The *data.frame* must contain those 3 columns: ```{r runExomeAncestry, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -#################################################################### +######################################################################### ## Load required packages -#################################################################### +######################################################################### library(RAIDS) library(gdsfmt) ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata", package="RAIDS") -################################################################# +######################################################################### ## The path and file name for the PED RDS file ## will the information about the analyzed samples -################################################################# +######################################################################### filePED <- file.path(dataDir, "example", "pedEx.rds") ped <- readRDS(filePED) head(ped) -################################################################# +######################################################################### ## The 1KG GDS file and the 1KG SNV Annotation GDS file ## need to be located in the same directory ## Note that the 1KG GDS file used for this example is a ## simplified version and CANNOT be used for any real analysis -################################################################# +######################################################################### path1KG <- file.path(dataDir, "example", "gdsRef") fileGDS <- file.path(path1KG, "ex1kg.gds") fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") -################################################################# +######################################################################### ## The Sample SNP pileup files (one per sample) need ## to be located in the same directory. -################################################################# +######################################################################### pathGeno <- file.path(dataDir, "example", "snpPileup") -################################################################# +######################################################################### ## The path where the Sample GDS files (one per sample) ## will be created need to be specified. -################################################################# +######################################################################### pathProfileGDS <- file.path(dataDir, "example", "out.tmp") pathOut <- file.path(dataDir, "example", "res.out") -################################################################# +######################################################################### ## A data frame containing general information about the study ## is also required. The data frame must have ## those 3 columns: "study.id", "study.desc", "study.platform" -################################################################# +######################################################################### studyDF <- data.frame(study.id="MYDATA", study.desc="Description", study.platform="PLATFORM", stringsAsFactors=FALSE) -#################################################################### +######################################################################### ## Fix RNG seed to ensure reproducible results -#################################################################### +######################################################################### set.seed(3043) -#################################################################### +######################################################################### ## Select the profiles from 1KG for the synthetic data. ## Here we select 2 profiles from 1KG for each subcontinental-level ## Normally, we use 30 profiles from 1KG for each ## subcontinental-level but it is too big for the example. ## The 1KG files in this example only have 6 profiles for each ## subcontinental-level (for demo purpose only) -#################################################################### +######################################################################### gds1KG <- snpgdsOpen(fileGDS) dataRef <- select1KGPop(gds1KG, nbProfiles=2L) closefn.gds(gds1KG) @@ -452,13 +441,16 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## chrInfo[25] <- length(Hsapiens[["chrM"]]) -#################################################################### +######################################################################### ## The wrapper function generates the synthetic dataset and uses it ## to selected the optimal parameters before calling the genetic ## ancestry on the current profiles. ## All important information, for each step, are saved in ## multiple output files. -#################################################################### +## The 'genoSource' parameter has 2 options depending on how the +## SNP pileup files have been generated: +## "snp-pileup" (snp-pileup software) or "generic" (other software) +######################################################################### runExomeAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, @@ -471,11 +463,11 @@ runExomeAncestry(pedStudy=ped, studyDF=studyDF, list.files(pathOut) list.files(file.path(pathOut, ped$Name.ID[1])) -#################################################################### +######################################################################### ## The file containing the ancestry inference (SuperPop column) and ## optimal number of PCA component (D column) ## optimal number of neighbours (K column) -#################################################################### +######################################################################### resAncestry <- read.csv(file.path(pathOut, paste0(ped$Name.ID[1], ".Ancestry.csv"))) resAncestry @@ -514,10 +506,39 @@ Beware that some of these files are large.

+ +# Frequently asked questions + +## How to generate a SNP pileup file with snp-pileup? + +This is an example of the command line to run with +[snp-pileup](https://github.com/mskcc/facets/tree/master/inst/extcode): + +```bash +##################################################################### +## Description of the parameters +## -g : Compresses the output file with BGZF +## -d5000 : Sets the maximum depth to 5000 +## -q15 : Sets the minimum threshold for mapping quality to 15 +## -Q20 : Sets the minimum threshold for base quality to 20 +## -r0 : Sets the minimum read counts for a position to be output to 0 +## path1KG/snvSel0.01.vcf.gz : The SNP Retained VCF file containing the +## positions of all retained 1KG SNPs +## pathOut/Name.ID.txt : The name of the output Sample VCF file that will be +## compressed by the application +## FILEBAM.bam : The aligned reads from the sample used as input +##################################################################### +snp-pileup -g -d5000 -q15 -Q20 -r0 path1KG/snvSel0.01.vcf.gz pathOut/Name.ID.txt FILEBAM.bam +``` + +
+
+ + # Session info -Here is the output of `sessionInfo()` in the enviroment in which this document was -compiled: +Here is the output of `sessionInfo()` in the environment in which this +document was compiled: ```{r sessionInfo, echo=FALSE} sessionInfo() diff --git a/vignettes/aicsBiblio.bibtex b/vignettes/aicsBiblio.bibtex index fdbb5a2ac..b421e5961 100644 --- a/vignettes/aicsBiblio.bibtex +++ b/vignettes/aicsBiblio.bibtex @@ -77,3 +77,13 @@ year = {2016} } +@article{Morgan2023, + author = {Morgan, M and Pagès H and Obenchain V and Hayden N}, + doi = {10.18129/B9.bioc.Rsamtools}, + edition = {2023}, + journal = {Bioconductor}, + title = {{Rsamtools: Binary alignment (BAM), FASTA, variant call (BCF), and tabix file import. R package version 2.16.0}}, + url = {https://bioconductor.org/packages/release/bioc/html/Rsamtools.html}, + year = {2023} +} + From 99db28af15e95be1ab703b91384fc7a28ad2d07a Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 7 Jun 2023 20:56:29 -0400 Subject: [PATCH 013/385] Update vignette --- vignettes/RAIDS.Rmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index c2dcc5c40..ae1ac5f0b 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -348,9 +348,9 @@ The wrapper function, called _runExomeAncestry()_, requires 4 files as input: A *data.frame* containing the general information about the study is also required. The *data.frame* must contain those 3 columns: -- **study.id**: The study identifier (example: TCGA-BRCA). -- **study.desc**: The description of the study. -- **study.platform**: The type of sequencing (example: RNA-seq). +- _study.id_: The study identifier (example: TCGA-BRCA). +- _study.desc_: The description of the study. +- _study.platform_: The type of sequencing (example: RNA-seq). ```{r runExomeAncestry, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} From e2d9a049e05e001b29d170e9fad2f804af037457 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 7 Jun 2023 21:18:40 -0400 Subject: [PATCH 014/385] Update doc for validateEstimateAllelicFraction() function --- R/processStudy_internal.R | 3 ++- man/validateEstimateAllelicFraction.Rd | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 8a81b1605..32dbfbecf 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -333,7 +333,8 @@ validateComputePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, #' @param minCov a single positive \code{integer} representing the minimum #' required coverage. #' -#' @param minProb a single \code{numeric} between 0 and 1 representing TODO. +#' @param minProb a single positive \code{numeric} between 0 and 1 that +#' represents the probability that the genotype is correct. #' #' @param eProb a single \code{numeric} between 0 and 1 representing the #' probability of sequencing error. diff --git a/man/validateEstimateAllelicFraction.Rd b/man/validateEstimateAllelicFraction.Rd index 535de6b5a..6d71268e0 100644 --- a/man/validateEstimateAllelicFraction.Rd +++ b/man/validateEstimateAllelicFraction.Rd @@ -48,7 +48,8 @@ way the estimation of the allelic fraction is done. Default: \code{"DNA"}.} \item{minCov}{a single positive \code{integer} representing the minimum required coverage.} -\item{minProb}{a single \code{numeric} between 0 and 1 representing TODO.} +\item{minProb}{a single positive \code{numeric} between 0 and 1 that +represents the probability that the genotype is correct.} \item{eProb}{a single \code{numeric} between 0 and 1 representing the probability of sequencing error.} From 038b61a22afab7e2a16f0a9c2f8610d51ef75ae8 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 8 Jun 2023 01:24:38 -0400 Subject: [PATCH 015/385] Update documentation for readSNVPileupFile() and readSNVFileGeneric() functions --- R/synthetic.R | 2 +- R/tools_internal.R | 116 +++++++++++++----- .../example/snpPileup/ex1.generic.txt.gz | Bin 0 -> 484 bytes man/readSNVFileGeneric.Rd | 51 +++++--- man/readSNVPileupFile.Rd | 49 ++++++-- man/syntheticGeno.Rd | 2 +- 6 files changed, 159 insertions(+), 61 deletions(-) create mode 100644 inst/extdata/example/snpPileup/ex1.generic.txt.gz diff --git a/R/synthetic.R b/R/synthetic.R index 7aa708127..c28b22a5d 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -370,7 +370,7 @@ prepSynthetic <- function(fileProfileGDS, listSampleRef, #' Default: \code{0.01}. #' #' @param minProb a single positive \code{numeric} between 0 and 1 that -#' represents the probability that the genotype is correct. TODO. +#' represents the probability that the genotype is correct. #' Default: \code{0.999}. #' #' @param seqError a single positive \code{numeric} between 0 and 1 diff --git a/R/tools_internal.R b/R/tools_internal.R index c6f0716c5..39ad201cc 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -246,28 +246,53 @@ processBlockChr <- function(snp.keep, PATHBLOCK, superPop, chr) { } -#' @title TODO +#' @title Read a SNP-pileup file #' -#' @description TODO +#' @description The function reads a generic SNP pileup file and +#' returns a data frame +#' containing the information about the read counts for the SNVs present in +#' the file. #' -#' @param fileName Output from snp-pileup -#' must csv with the columns: -#' Chromosome,Position,Ref,Alt,File1R,File1A,File1E,File1D +#' @param fileName a \code{character} string representing the name, including +#' the path, of a text file containing the SNV read counts as generated by +#' snp-pileup software. The text file must be comma separated. +#' The text file must contain those columns: Chromosome, Position, Ref, Alt, +#' File1R, File1A, File1E and File1D. #' -#' @param offset TODO +#' @param offset a \code{integer} representing the offset to be added to the +#' position of the SNVs. The value of offset +#' is added to the position present in the file. Default: \code{0L}. #' #' @return the a \code{data.frame} containing at least: #' \itemize{ -#' \item{Chromosome} {TODO} -#' \item{Position} {TODO} -#' \item{File1R} {TODO} -#' \item{File1A} {TODO} -#' \item{count} {TODO} +#' \item{Chromosome}{ a \code{numeric} representing the name of +#' the chromosome} +#' \item{Position}{ a \code{numeric} representing the position on the +#' chromosome} +#' \item{Ref}{ a \code{character} string representing the reference nucleotide} +#' \item{Alt}{ a \code{character} string representing the alternative +#' nucleotide} +#' \item{File1R} { a \code{numeric} representing the count for +#' the reference nucleotide} +#' \item{File1A} { a \code{numeric} representing the count for the +#' alternative nucleotide} +#' \item{File1E} {a \code{numeric} representing the count for the +#' errors} +#' \item{File1D} {a \code{numeric} representing the count for the +#' deletions} +#' \item{count} { a \code{numeric} representing the total count} #' } #' #' @examples #' -#' # TODO +#' ## Directory where demo SNP-pileup file +#' dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") +#' +#' ## The SNP-pileup file +#' snpPileupFile <- file.path(dataDir, "ex1.txt.gz") +#' +#' info <- RAIDS:::readSNVPileupFile(fileName=snpPileupFile) +#' head(info) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn @@ -277,6 +302,13 @@ readSNVPileupFile <- function(fileName, offset = 0L) { matSample <- read.csv(fileName) + # Check if the mandatory column are there + if (!(all(c("Chromosome", "Position", "Ref", "Alt", "File1R", + "File1A", "File1E", "File1D") %in% colnames(matSample)))) { + stop("The SNP-pileup file must contain all those columns: ", + "\'Chromosome\', \'Position\', \'Ref\', \'Alt\', \'File1R\', ", + "\'File1A\', \'File1E\', \'File1D\'.") + } matSample[, "Chromosome"] <- as.integer(gsub("chr", "", matSample[, "Chromosome"])) @@ -288,33 +320,50 @@ readSNVPileupFile <- function(fileName, offset = 0L) { } -#' @title TODO +#' @title Read a generic SNP pileup file #' -#' @description TODO +#' @description The function reads a generic SNP pileup file and +#' returns a data frame +#' containing the information about the read counts for the SNVs present in +#' the file. #' -#' @param fileName File name with the path to a -#' csv with at least the columns: -#' Chromosome,Position,Ref,Alt,Count,File1R,File1A -#' where Count is the deep at the position, -#' FileR is the deep of the reference allele, and -#' File1A is the deep of the specific alternative allele +#' @param fileName a \code{character} string representing the name, including +#' the path, of a text file containing the SNV read counts. The text file must +#' be comma separated. The text file must +#' contain those columns: Chromosome, Position, Ref, Alt, Count, +#' File1R and File1A. #' -#' @param offset TODO +#' @param offset a \code{integer} representing the offset to be added to the +#' position of the SNVs. The value of offset +#' is added to the position present in the file. Default: \code{0L}. #' #' @return a \code{data.frame} containing at least: #' \itemize{ -#' \item{Chromosome} {TODO} -#' \item{Position} {TODO} -#' \item{Ref} -#' \item{Alt} -#' \item{File1R} {deep of the reference allele} -#' \item{File1A} {deep of the alternative allele} -#' \item{count} {Total deep at the position} +#' \item{Chromosome}{ a \code{numeric} representing the name of +#' the chromosome} +#' \item{Position}{ a \code{numeric} representing the position on the +#' chromosome} +#' \item{Ref}{ a \code{character} string representing the reference nucleotide} +#' \item{Alt}{ a \code{character} string representing the alternative +#' nucleotide} +#' \item{File1R} { a \code{numeric} representing the count for +#' the reference nucleotide} +#' \item{File1A} { a \code{numeric} representing the count for the +#' alternative nucleotide} +#' \item{count} { a \code{numeric} representing the total count} #' } #' #' @examples #' -#' # TODO +#' +#' ## Directory where demo SNP-pileup file +#' dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") +#' +#' ## The SNP-pileup file +#' snpPileupFile <- file.path(dataDir, "ex1.generic.txt.gz") +#' +#' info <- RAIDS:::readSNVFileGeneric(fileName=snpPileupFile) +#' head(info) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn @@ -323,7 +372,14 @@ readSNVPileupFile <- function(fileName, offset = 0L) { readSNVFileGeneric <- function(fileName, offset = 0L) { matSample <- read.csv(fileName) - # Check if the mendatory column are there + + # Check if the mandatory column are there + if (!(all(c("Chromosome", "Position", "Ref", "Alt", "File1R", + "File1A", "Count") %in% colnames(matSample)))) { + stop("The generic SNP pileup file must contain all those columns: ", + "\'Chromosome\', \'Position\', \'Ref\', \'Alt\', \'File1R\', ", + "\'File1A\', \'Count\'.") + } matSample[, "Chromosome"] <- as.integer(gsub("chr", "", matSample[, "Chromosome"])) diff --git a/inst/extdata/example/snpPileup/ex1.generic.txt.gz b/inst/extdata/example/snpPileup/ex1.generic.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..48192f0940e5a099580f4a9e0c9375d87f2ef22f GIT binary patch literal 484 zcmVj)c-D@d*gEC78+6LO``>(WN zVtLXT2qy5eog;YBBEb+^kiY{l*Y0z<~FQ0>YoFlAiTde%Z(&C(iL zPfO*%oG}&b*aF*tqa@F(atP-zI2SHm+76pQPwL*eHBJ?~?iLRl?JhRGU2k*Twwy!6 z4V*E1nYLC8j01M}x6=~X?qO?XbG}Q90V8#M9hiYoe_NuNLM*yp6DWmiz2-;P)11Ll_I z`+9&)B>MbP@36)km^AFlHL#9Y>b82^+INNIii%N>jG`u#Yob`oHsBlu=QiL-`o%hu a&iQdAgxm9P%Bd!owfGO&(sHs*1^@uMIr&Hc literal 0 HcmV?d00001 diff --git a/man/readSNVFileGeneric.Rd b/man/readSNVFileGeneric.Rd index 39458b9d8..38319b2f4 100644 --- a/man/readSNVFileGeneric.Rd +++ b/man/readSNVFileGeneric.Rd @@ -3,38 +3,55 @@ \encoding{UTF-8} \name{readSNVFileGeneric} \alias{readSNVFileGeneric} -\title{TODO} +\title{Read a generic SNP pileup file} \usage{ readSNVFileGeneric(fileName, offset = 0L) } \arguments{ -\item{fileName}{File name with the path to a -csv with at least the columns: -Chromosome,Position,Ref,Alt,Count,File1R,File1A -where Count is the deep at the position, -FileR is the deep of the reference allele, and -File1A is the deep of the specific alternative allele} +\item{fileName}{a \code{character} string representing the name, including +the path, of a text file containing the SNV read counts. The text file must +be comma separated. The text file must +contain those columns: Chromosome, Position, Ref, Alt, Count, +File1R and File1A.} -\item{offset}{TODO} +\item{offset}{a \code{integer} representing the offset to be added to the +position of the SNVs. The value of offset +is added to the position present in the file. Default: \code{0L}.} } \value{ a \code{data.frame} containing at least: \itemize{ -\item{Chromosome} {TODO} -\item{Position} {TODO} -\item{Ref} -\item{Alt} -\item{File1R} {deep of the reference allele} -\item{File1A} {deep of the alternative allele} -\item{count} {Total deep at the position} +\item{Chromosome}{ a \code{numeric} representing the name of +the chromosome} +\item{Position}{ a \code{numeric} representing the position on the +chromosome} +\item{Ref}{ a \code{character} string representing the reference nucleotide} +\item{Alt}{ a \code{character} string representing the alternative +nucleotide} +\item{File1R} { a \code{numeric} representing the count for +the reference nucleotide} +\item{File1A} { a \code{numeric} representing the count for the +alternative nucleotide} +\item{count} { a \code{numeric} representing the total count} } } \description{ -TODO +The function reads a generic SNP pileup file and +returns a data frame +containing the information about the read counts for the SNVs present in +the file. } \examples{ -# TODO + +## Directory where demo SNP-pileup file +dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") + +## The SNP-pileup file +snpPileupFile <- file.path(dataDir, "ex1.generic.txt.gz") + +info <- RAIDS:::readSNVFileGeneric(fileName=snpPileupFile) +head(info) } \author{ diff --git a/man/readSNVPileupFile.Rd b/man/readSNVPileupFile.Rd index cfbd187e1..30ce01657 100644 --- a/man/readSNVPileupFile.Rd +++ b/man/readSNVPileupFile.Rd @@ -3,33 +3,58 @@ \encoding{UTF-8} \name{readSNVPileupFile} \alias{readSNVPileupFile} -\title{TODO} +\title{Read a SNP-pileup file} \usage{ readSNVPileupFile(fileName, offset = 0L) } \arguments{ -\item{fileName}{Output from snp-pileup -must csv with the columns: -Chromosome,Position,Ref,Alt,File1R,File1A,File1E,File1D} +\item{fileName}{a \code{character} string representing the name, including +the path, of a text file containing the SNV read counts as generated by +snp-pileup software. The text file must be comma separated. +The text file must contain those columns: Chromosome, Position, Ref, Alt, +File1R, File1A, File1E and File1D.} -\item{offset}{TODO} +\item{offset}{a \code{integer} representing the offset to be added to the +position of the SNVs. The value of offset +is added to the position present in the file. Default: \code{0L}.} } \value{ the a \code{data.frame} containing at least: \itemize{ -\item{Chromosome} {TODO} -\item{Position} {TODO} -\item{File1R} {TODO} -\item{File1A} {TODO} -\item{count} {TODO} +\item{Chromosome}{ a \code{numeric} representing the name of +the chromosome} +\item{Position}{ a \code{numeric} representing the position on the +chromosome} +\item{Ref}{ a \code{character} string representing the reference nucleotide} +\item{Alt}{ a \code{character} string representing the alternative +nucleotide} +\item{File1R} { a \code{numeric} representing the count for +the reference nucleotide} +\item{File1A} { a \code{numeric} representing the count for the +alternative nucleotide} +\item{File1E} {a \code{numeric} representing the count for the +errors} +\item{File1D} {a \code{numeric} representing the count for the +deletions} +\item{count} { a \code{numeric} representing the total count} } } \description{ -TODO +The function reads a generic SNP pileup file and +returns a data frame +containing the information about the read counts for the SNVs present in +the file. } \examples{ -# TODO +## Directory where demo SNP-pileup file +dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") + +## The SNP-pileup file +snpPileupFile <- file.path(dataDir, "ex1.txt.gz") + +info <- RAIDS:::readSNVPileupFile(fileName=snpPileupFile) +head(info) } \author{ diff --git a/man/syntheticGeno.Rd b/man/syntheticGeno.Rd index c2d9e1af8..d8b5b15fe 100644 --- a/man/syntheticGeno.Rd +++ b/man/syntheticGeno.Rd @@ -49,7 +49,7 @@ represents the frequency of phase switching in the synthetic profiles, Default: \code{0.01}.} \item{minProb}{a single positive \code{numeric} between 0 and 1 that -represents the probability that the genotype is correct. TODO. +represents the probability that the genotype is correct. Default: \code{0.999}.} \item{seqError}{a single positive \code{numeric} between 0 and 1 From 463f6a1795fd8dbeee4dfbd97ac6097c10a1a9ce Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 8 Jun 2023 12:36:27 -0400 Subject: [PATCH 016/385] Correct indent in code --- R/allelicFraction_internal.R | 4 ++-- R/synthetic_internal.R | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index ba8a780c5..3af519bfc 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -1056,11 +1056,11 @@ testEmptyBox <- function(matCov, pCutOff=-3) { ## Always use the small count as input vCur1 <- ifelse(matCov$cnt.alt[i] <= matCov$cnt.ref[i], - matCov$cnt.alt[i], matCov$cnt.ref[i]) + matCov$cnt.alt[i], matCov$cnt.ref[i]) ## Calculate the probability with assumption 0f 0.5 ratio pCur <- pbinom(q=vCur1, size=matCov$cnt.ref[i] + matCov$cnt.alt[i], - prob=vMean) + prob=vMean) ## Ensure value is not below 0.01 pCurO <- max(1 - max(2 * pCur, 0.01), 0.01) diff --git a/R/synthetic_internal.R b/R/synthetic_internal.R index bfa45543a..a60d54cfa 100644 --- a/R/synthetic_internal.R +++ b/R/synthetic_internal.R @@ -322,7 +322,7 @@ validateComputeSyntheticRoc <- function(matKNN, matKNNAncestryColumn, pedCall, ## The pedCallAncestryColumn must be a column in the pedCall data frame if (!(pedCallAncestryColumn %in% colnames(pedCall))) { stop("The \'pedCallAncestryColumn\' must be a column in the ", - "\'pedCall\' data frame.") + "\'pedCall\' data frame.") } ## The listCall must be character string From 04789f96d2a7239be783049789ffc32714649ddd Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 8 Jun 2023 13:44:13 -0400 Subject: [PATCH 017/385] Update version to 0.99.5 --- DESCRIPTION | 2 +- inst/NEWS.md | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 575cab2fd..ea8ac6256 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.4 +Version: 0.99.5 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index 83ab81df0..0fd98426a 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,12 @@ +CHANGES IN VERSION 0.99.5 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o The function documentation has been improved. + o New vignette has been created. The vignette covers the steps done by the runExomeAncestry() function. + + CHANGES IN VERSION 0.99.4 ------------------------ From 9d4b962f5fdd63de2980fcc62828257ac29b1eea Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 20 Jun 2023 20:21:32 -0400 Subject: [PATCH 018/385] Change the way the chrInfo variable is created --- DESCRIPTION | 1 + vignettes/Ancestry_Inference_Step_by_Step.Rmd | 12 ++---------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index ea8ac6256..74d66390d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -42,6 +42,7 @@ Suggests: testthat, rmarkdown, BiocStyle, withr, + GenomeInfoDb, BSgenome.Hsapiens.UCSC.hg38 BugReports: https://github.com/KrasnitzLab/RAIDS/issues URL: https://krasnitzlab.github.io/RAIDS/ diff --git a/vignettes/Ancestry_Inference_Step_by_Step.Rmd b/vignettes/Ancestry_Inference_Step_by_Step.Rmd index 40fd01602..57a130b76 100644 --- a/vignettes/Ancestry_Inference_Step_by_Step.Rmd +++ b/vignettes/Ancestry_Inference_Step_by_Step.Rmd @@ -316,21 +316,13 @@ There are alternative ways to retrieve this information, e.g., ## Load required library ################################################################### library(BSgenome.Hsapiens.UCSC.hg38) - +library(GenomeInfoDb) ################################################################### ## The length of each chromosome is required ## Chromosomes X, Y and M need relabeling (see below) ## There are alternative ways to retrieve this information ################################################################### -chrInfo <- integer(25L) -for(i in seq_len(22L)) { - chrInfo[i] <- length(Hsapiens[[paste0("chr", i)]]) -} -chrInfo[23] <- length(Hsapiens[["chrX"]]) -chrInfo[24] <- length(Hsapiens[["chrY"]]) -chrInfo[25] <- length(Hsapiens[["chrM"]]) - -chrInfo +chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] ```
From 05df6af18b74bde1b49af7a9a1d30b61192eeef3 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 20 Jun 2023 20:25:05 -0400 Subject: [PATCH 019/385] Update generateGDSSNPInfo() example --- R/gdsWrapper.R | 33 ++++++++++++++++++--------------- man/generateGDSSNPinfo.Rd | 33 ++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 53b25dee0..db7862b6f 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -75,27 +75,30 @@ appendGDSSampleOnly <- function(gds, listSamples) { #' @examples #' #' ## Required package -#' library(withr) +#' library(gdsfmt) #' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") +#' ## Only execute code if withr package is available +#' if (requireNamespace("withr", quietly = TRUE)) { +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") #' -#' ## Temporary Reference GDS file -#' file1KG <- local_file(file.path(dataDir, "1KG_TEMP_002.gds")) -#' filenewGDS <- createfn.gds(file1KG) +#' ## Temporary Reference GDS file +#' file1KG <- withr::local_file("1KG_TEMP_002.gds") +#' filenewGDS <- createfn.gds(file1KG) #' -#' ## The RDS file containing the filtered SNP information -#' fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") +#' ## The RDS file containing the filtered SNP information +#' fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' -#' ## Add SNV information to Reference GDS -#' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, -#' fileFREQ=fileFilerterSNVs, verbose=TRUE) +#' ## Add SNV information to Reference GDS +#' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, +#' fileFREQ=fileFilerterSNVs, verbose=TRUE) #' -#' ## Close GDS file (important) -#' closefn.gds(filenewGDS) +#' ## Close GDS file (important) +#' closefn.gds(filenewGDS) #' -#' ## Remove temporary files -#' deferred_run() +#' ## Remove temporary 1KG_TEMP_002.gds file +#' withr::deferred_run() +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn diff --git a/man/generateGDSSNPinfo.Rd b/man/generateGDSSNPinfo.Rd index c13e993cc..d3b0829b5 100644 --- a/man/generateGDSSNPinfo.Rd +++ b/man/generateGDSSNPinfo.Rd @@ -27,27 +27,30 @@ GDS file. \examples{ ## Required package -library(withr) +library(gdsfmt) -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", package="RAIDS") +## Only execute code if withr package is available +if (requireNamespace("withr", quietly = TRUE)) { + ## Path to the demo pedigree file is located in this package + dataDir <- system.file("extdata", package="RAIDS") -## Temporary Reference GDS file -file1KG <- local_file(file.path(dataDir, "1KG_TEMP_002.gds")) -filenewGDS <- createfn.gds(file1KG) + ## Temporary Reference GDS file + file1KG <- withr::local_file("1KG_TEMP_002.gds") + filenewGDS <- createfn.gds(file1KG) -## The RDS file containing the filtered SNP information -fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") + ## The RDS file containing the filtered SNP information + fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") -## Add SNV information to Reference GDS -RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, - fileFREQ=fileFilerterSNVs, verbose=TRUE) + ## Add SNV information to Reference GDS + RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, + fileFREQ=fileFilerterSNVs, verbose=TRUE) -## Close GDS file (important) -closefn.gds(filenewGDS) + ## Close GDS file (important) + closefn.gds(filenewGDS) -## Remove temporary files -deferred_run() + ## Remove temporary 1KG_TEMP_002.gds file + withr::deferred_run() +} } \author{ From dbae3c29cc9e9072e507fc726d89b1fdb043f4c8 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 20 Jun 2023 20:27:37 -0400 Subject: [PATCH 020/385] Update runExomeAncestry() doc --- R/processStudy.R | 12 ++++-------- man/runExomeAncestry.Rd | 12 ++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 065f22d26..b069df4d8 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2458,7 +2458,7 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' dataRef <- select1KGPop(gds1KG, nbProfiles=2L) #' closefn.gds(gds1KG) #' -#' ## Chromosome length information +#' ## Chromosome length information for hg38 #' ## chr23 is chrX, chr24 is chrY and chrM is 25 #' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, #' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, @@ -2466,14 +2466,10 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, #' 156040895L, 57227415L, 16569L) #' -#' ## A formal way to get the chormosome length information +#' ## A formal way to get the chromosome length information for hg38 +#' ## library(GenomeInfoDb) #' ## library(BSgenome.Hsapiens.UCSC.hg38) -#' ## chrInfo <- integer(25L) -#' ## for(i in seq_len(22L)){ chrInfo[i] <- -#' ## length(Hsapiens[[paste0("chr", i)]])} -#' ## chrInfo[23] <- length(Hsapiens[["chrX"]]) -#' ## chrInfo[24] <- length(Hsapiens[["chrY"]]) -#' ## chrInfo[25] <- length(Hsapiens[["chrM"]]) +#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' #' \dontrun{ #' runExomeAncestry(pedStudy=ped, studyDF=studyDF, diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index 9a08e1e34..b45307584 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -164,7 +164,7 @@ gds1KG <- snpgdsOpen(fileReferenceGDS) dataRef <- select1KGPop(gds1KG, nbProfiles=2L) closefn.gds(gds1KG) -## Chromosome length information +## Chromosome length information for hg38 ## chr23 is chrX, chr24 is chrY and chrM is 25 chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, @@ -172,14 +172,10 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) -## A formal way to get the chormosome length information +## A formal way to get the chromosome length information for hg38 +## library(GenomeInfoDb) ## library(BSgenome.Hsapiens.UCSC.hg38) -## chrInfo <- integer(25L) -## for(i in seq_len(22L)){ chrInfo[i] <- -## length(Hsapiens[[paste0("chr", i)]])} -## chrInfo[23] <- length(Hsapiens[["chrX"]]) -## chrInfo[24] <- length(Hsapiens[["chrY"]]) -## chrInfo[25] <- length(Hsapiens[["chrM"]]) +## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] \dontrun{ runExomeAncestry(pedStudy=ped, studyDF=studyDF, From c0778473f54f53acf350f4ef24b62570780f987b Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 20 Jun 2023 20:28:22 -0400 Subject: [PATCH 021/385] Change indent in code --- R/process1KG_internal.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index 19568222f..0d98476b2 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -257,7 +257,7 @@ generateGeneBlock <- function(gdsReference, winSize=10000, EnsDb) { length(startIndex))) # List of SNV in the gene listP <- which(matFreq$pos[listPos[startIndex[vStart]:startIndex[vEnd]]] >= dfGenneAllChr$start[genePos] & - matFreq$pos[listPos[startIndex[vStart]:startIndex[vEnd]]] <= dfGenneAllChr$end[genePos]) + matFreq$pos[listPos[startIndex[vStart]:startIndex[vEnd]]] <= dfGenneAllChr$end[genePos]) # if SNV in the gene if (length(listP) > 0) { From 2962f51cb126f12ade90b10fb6bd1be9271de418 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 20 Jun 2023 20:34:57 -0400 Subject: [PATCH 022/385] Update doc for functions using chrInfo variable --- R/allelicFraction.R | 25 ++++++++----------------- R/allelicFraction_internal.R | 2 +- man/computeLOHBlocksDNAChr.Rd | 2 +- man/estimateAllelicFraction.Rd | 25 ++++++++----------------- 4 files changed, 18 insertions(+), 36 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index 56d072c83..31541835b 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -227,22 +227,17 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' #' The `chrInfo` parameter contains the length of the chromosomes. The #' length of the chromosomes can be obtain through the -#' \code{\link[BSgenome]{BSgenome-class}} +#' \code{\link[GenomeInfoDb]{seqlengths}} #' library. #' -#' As example: +#' As example, for hg38 genome: #' #' ``` #' -#' library(BSgenome.Hsapiens.UCSC.hg38) -#' -#' chrInfo <- integer(25L) -#' -#' for(i in seq_len(22L)){ chrInfo[i] <- length(Hsapiens[[paste0("chr", i)]])} -#' -#' chrInfo[23] <- length(Hsapiens[["chrX"]]) -#' chrInfo[24] <- length(Hsapiens[["chrY"]]) -#' chrInfo[25] <- length(Hsapiens[["chrM"]]) +#' if (requireNamespace("GenomeInfoDb", quietly = TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly = TRUE)) { +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' } #' #' ``` #' @@ -280,13 +275,9 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' 156040895L, 57227415L, 16569L) #' #' ## A formal way to get the chormosome length information +#' ## library(GenomeInfoDb) #' ## library(BSgenome.Hsapiens.UCSC.hg38) -#' ## chrInfo <- integer(25L) -#' ## for(i in seq_len(22L)){ chrInfo[i] <- -#' ## length(Hsapiens[[paste0("chr", i)]])} -#' ## chrInfo[23] <- length(Hsapiens[["chrX"]]) -#' ## chrInfo[24] <- length(Hsapiens[["chrY"]]) -#' ## chrInfo[25] <- length(Hsapiens[["chrM"]]) +#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' #' ## Estimate the allelic fraction of the pruned SNVs #' estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 3af519bfc..94318035f 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -306,7 +306,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' ## Open the reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Chromosome length information +#' ## Chromosome length information for hg38 #' ## chr23 is chrX, chr24 is chrY and chrM is 25 #' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, #' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, diff --git a/man/computeLOHBlocksDNAChr.Rd b/man/computeLOHBlocksDNAChr.Rd index 9a21e5076..7a68e9587 100644 --- a/man/computeLOHBlocksDNAChr.Rd +++ b/man/computeLOHBlocksDNAChr.Rd @@ -87,7 +87,7 @@ fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") ## Open the reference GDS file (demo version) gds1KG <- snpgdsOpen(fileGDS) -## Chromosome length information +## Chromosome length information for hg38 ## chr23 is chrX, chr24 is chrY and chrM is 25 chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index 3a96ed2bc..a57935145 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -94,22 +94,17 @@ the type of study (DNA or RNA). \details{ The `chrInfo` parameter contains the length of the chromosomes. The length of the chromosomes can be obtain through the -\code{\link[BSgenome]{BSgenome-class}} +\code{\link[GenomeInfoDb]{seqlengths}} library. -As example: +As example, for hg38 genome: ``` -library(BSgenome.Hsapiens.UCSC.hg38) - -chrInfo <- integer(25L) - -for(i in seq_len(22L)){ chrInfo[i] <- length(Hsapiens[[paste0("chr", i)]])} - -chrInfo[23] <- length(Hsapiens[["chrX"]]) -chrInfo[24] <- length(Hsapiens[["chrY"]]) -chrInfo[25] <- length(Hsapiens[["chrM"]]) +if (requireNamespace("GenomeInfoDb", quietly = TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly = TRUE)) { + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +} ``` } @@ -147,13 +142,9 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 156040895L, 57227415L, 16569L) ## A formal way to get the chormosome length information +## library(GenomeInfoDb) ## library(BSgenome.Hsapiens.UCSC.hg38) -## chrInfo <- integer(25L) -## for(i in seq_len(22L)){ chrInfo[i] <- -## length(Hsapiens[[paste0("chr", i)]])} -## chrInfo[23] <- length(Hsapiens[["chrX"]]) -## chrInfo[24] <- length(Hsapiens[["chrY"]]) -## chrInfo[25] <- length(Hsapiens[["chrM"]]) +## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] ## Estimate the allelic fraction of the pruned SNVs estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, From 61dae91a236c29b52bb0a75bff5139407cce7321 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 20 Jun 2023 20:38:14 -0400 Subject: [PATCH 023/385] Remove section about snp-pileup and update chrInfo variable creation --- vignettes/RAIDS.Rmd | 62 +++++---------------------------------------- 1 file changed, 6 insertions(+), 56 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index ae1ac5f0b..dcffb7c89 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -194,27 +194,8 @@ genome used for the mapping must be the same as the one used to generate the ### Sub-Step 2.1 Create a directory containing the 3 required reference files -The 3 required reference files may be downloaded: - -```bash -#################################### -## The 1KG GDS file -#################################### -wget https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper/matGeno1000g.gds - -#################################### -## The 1KG SNV Annotation GDS file -#################################### -wget https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper/matAnnot1000g.gds - -#################################### -## The 1KG SNV Retained VCF file -#################################### -wget https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper/snvSel0.01.vcf.gz -``` - -The 3 files should be stored in the same directory. In the example below, -this directory is referred to as **path1KG**. +The 3 required reference files should be stored in the same directory. In the +example below, this directory is referred to as **path1KG**. For more information on creating your own reference files, see the vignette @@ -423,7 +404,7 @@ gds1KG <- snpgdsOpen(fileGDS) dataRef <- select1KGPop(gds1KG, nbProfiles=2L) closefn.gds(gds1KG) -## Chromosome length information +## Chromosome length information for hg38 ## chrInfo[23] is chrX, chrInfo[24] is chrY and chrM is chrInfo[25] chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, @@ -431,14 +412,10 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) -## A formal way to get the chormosome length information +## A formal way to get the chormosome length information for hg38 +## library(GenomeInfoDb) ## library(BSgenome.Hsapiens.UCSC.hg38) -## chrInfo <- integer(25L) -## for(i in seq_len(22L)){ chrInfo[i] <- -## length(Hsapiens[[paste0("chr", i)]])} -## chrInfo[23] <- length(Hsapiens[["chrX"]]) -## chrInfo[24] <- length(Hsapiens[["chrY"]]) -## chrInfo[25] <- length(Hsapiens[["chrM"]]) +## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] ######################################################################### @@ -507,33 +484,6 @@ Beware that some of these files are large.
-# Frequently asked questions - -## How to generate a SNP pileup file with snp-pileup? - -This is an example of the command line to run with -[snp-pileup](https://github.com/mskcc/facets/tree/master/inst/extcode): - -```bash -##################################################################### -## Description of the parameters -## -g : Compresses the output file with BGZF -## -d5000 : Sets the maximum depth to 5000 -## -q15 : Sets the minimum threshold for mapping quality to 15 -## -Q20 : Sets the minimum threshold for base quality to 20 -## -r0 : Sets the minimum read counts for a position to be output to 0 -## path1KG/snvSel0.01.vcf.gz : The SNP Retained VCF file containing the -## positions of all retained 1KG SNPs -## pathOut/Name.ID.txt : The name of the output Sample VCF file that will be -## compressed by the application -## FILEBAM.bam : The aligned reads from the sample used as input -##################################################################### -snp-pileup -g -d5000 -q15 -Q20 -r0 path1KG/snvSel0.01.vcf.gz pathOut/Name.ID.txt FILEBAM.bam -``` - -
-
- # Session info From 803f2d83ae80d148fc60e3f17fa1643253b0cc47 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 21 Jun 2023 12:12:43 -0400 Subject: [PATCH 024/385] Update figures and text in main vignette --- vignettes/MainSteps_Step1_v02.png | Bin 0 -> 54308 bytes ...ainSteps_Step2_SubStep2_SNP-Pileup_v03.png | Bin 0 -> 23180 bytes vignettes/MainSteps_Step2_v02.png | Bin 0 -> 54686 bytes vignettes/MainSteps_Wrapper_v02.png | Bin 0 -> 58039 bytes vignettes/MainSteps_v02.png | Bin 0 -> 51294 bytes vignettes/RAIDS.Rmd | 84 +++++++++--------- 6 files changed, 43 insertions(+), 41 deletions(-) create mode 100644 vignettes/MainSteps_Step1_v02.png create mode 100644 vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v03.png create mode 100644 vignettes/MainSteps_Step2_v02.png create mode 100644 vignettes/MainSteps_Wrapper_v02.png create mode 100644 vignettes/MainSteps_v02.png diff --git a/vignettes/MainSteps_Step1_v02.png b/vignettes/MainSteps_Step1_v02.png new file mode 100644 index 0000000000000000000000000000000000000000..0a479cd4b31341164b93f5eb37e758c761e074ed GIT binary patch literal 54308 zcmeEu2Rzkn|38vQ-~9u##Mx_w(9=9bbAR12==S1 z!A}zq>_QO`5Z)st0axOC#Lt00gdV3=6$y%89vvqjP-OE|HuiM(wRLc^Az%|$+Wf>O zBw&yB@MIH)vk3`VxVrLLJ6PDcTR400x!8DuOW?jU+ST z1O>olVMXu>+z=Dl{OBttaspgYaCLREF|x7LZ~)^_5fv8a6BYxPIW^SuwKUm;l)z^v z2S*$5N7cs45e>bfWbcl423J%B1x5Hk)A&C1ENm^@9e!*=+1hUB8Nri6!hE8Fn!|}U2p}{`qdNA1wAVZAh;jjgRUAmSbN%UUOg$gH9Y9LnvH{<{dUiS0$X>SEw&%t zy5M1N0d#Kjef*{0%W+$p?r1b;aNZ?34fg_GBoa5pb_c=~Ni+a2xYVvXP8(0=r> zckr~)bG5L79`^zI1+Lk9Iy-@HV9P541aVSAJE7h2G8I-)Q4vysUb98Jc>ZwR7XJ@i z_waN_JKFqkM@&Tk{M)&+y}sh$inWD@J$@WeM*xVd9e`Z6Uv)vdfDr+>fE3i#;=9PU zqzLw=r_I(5z+d|NOS!%3U=P^<-0*bw1I=!|&I{dyy4l)35?fz=zU!j!w#M22poc=j zTMt@n>A&4h(@<-FL`T3gTPpVVhyN2zG(YL6Z)NOi1$U8fSMnASakbIY;}zaQf*+RK z#v1Ikt<^`nd)lMz&@L8E02jBfD*jp_zCWXhMgwiYs{zW!)6;JYI4rz8(O_kMP!bzo z2T$XzC!x2urY3JG%avHz;Rx!X8dcsh9h z*ou(AzeRcAmM0Zm?5vgDPWtM(DqDH`XzQr+0zpEu{P*b2cYT4h078U6Uw1a=_nUS6 zDZ2b=%7e$_zrVMC3Qhkxs`Ar4u?@mMni(-Cu#519;a5r|=H>+%TKo-O4?OpPXp*3a zt1p|-_D%4~4thuz?dk>X5kR_x1Ww!7+5p@Kn^;HyZs7^28WKyaIy{a}Lxx6RFuHc0G0&IAc< zanFA-jQkCAf(Md6!<_s>Ga>R*borm$`hTSD@8F_~c7XQGHt7);-5l?h!ioG=kv0)< z>!m+NXSVyolbRix_4h|941BvknF9S=&Dgf#f{fUAllGm?azQ0l09SGdk+LJ+Rp{R7`YhYj1Tb48jw?>2wnu{(_rj zYp?vuUHmibxU#ROjXQ8N0N&_%dV#pamg%;1|8BL#ES!ORq3B}i0sZ;^%)sy9?O)Hp z3yW{=xPP&M|8M!2K*8`%m;uJHb94LJuW$tKcX+s3Kt98FrQCKcAXnkHeg{P2x9@NF`$t`m z&5kzRmF?mDQ=R{==j~R$Pf7*t4nmur4lW>gy$Q$P?{T7CA^*t22}Hqn{GneD3ZiS@ z1tIj^AA(rNKj#nG+S-U&{nQ__7MHNZ2lh6X^nchN`bkV~hYbAa5AB48xB0-oKPD&m z7mUgMb9nhTHQ*oO;})~}hxoWUxIIi+X+WwoAQ4qQV?ZR!! zDDmg<)Gd!`XHI{Apntx9wY6kFf$%>G1p%z#V?kSnK{f0@m~kQt$^7-1VN#HJqrGNSmKsI zegZL@ao-=v%{Ghs8O!_IMC&&YBm4&;M%MyVOV|L<_V>sF@~{rh4*pxA>)+ze_VWO3 z{$S+#ugBE3lBvRiTUxqh`h-qy#Y%p}9)T@?=SSxDpNBmnTUn0(eC)ydw)kY~uZbH7 z^8Tx`savc54?%2eZ~qIK+`k9Iw&d}rW7rmj0d*7q7h3xbx8Fh_!R=JWHu)CaiP!#! zLE9O&A2DeA&Ho(!BLcjL-?;Ptq5S7>VUWd8(#i;kR$j%MZXn5DF-O4fGY27K|vuXqqPU69lzzuKlt&#N*(=i z?)=xQ`q)w;agkq#jf8#{_1sph|7^P@yv6$ey4?9+XSTNe`hRG*{tfB+e-C-ymdH;m z*MBd_xaFqf+4GJ!@39R+e>@oYmxY*}yz{nu{uhRrzr1_?FNBz_9MnIAm~G?#zurIJ z#?qfa%>PV~QREK>8Gm3&>MlD4u)k$VKS0+1_K2d`_SuVV$odOM6t}V&KT*2hl{oxi zEfoD(A+@FrIGG1xM4Ni^JMO%5`G;%R84~icBELr=Tb^b2zzbvT{-v;w7gb)$iGIu{L*mfZ8#|7J7=l`Gu z+j5(J0ucW_JosnAG5`IY?_^^OVaH!>-=F-o`z-=aDdU5$Kd8}PWZ(ZRg!4D|{a-fM z_`7{C@%sh)>AnY|fTZyswD13fbkR?FfUY|l1l@l0aQ`k{{J*WgdHzb|CvNe-YwP1n zxc77Yc^R+c2mEr zr)0yD_1PCk=IQE#oo1Mj)20bcbyVKg1SFw9{nDi(r=EDvLbg#rl{=IaP{4__e; zM+yx{pCR8K76H*TWe8RQSKg!EqT9RFK)zQeJS9+2Rr`m@iHBaoh<&Pet8P{bf-YYd z3ZOLIerJ>HJByB`L2@Dv!fZI+RlpE6NjK zs4p;K$aXqN0QYz-o+yJ0pn1fc(jnbFJ8g=Cn|&G4LSRl#%mj$C-K;`{TiwA(2?)cH z1Q#xGT_7Mm1Kw29*&Ycjd~fI}$JyBz3ylf4S-H472YSB|jA7-Kr4$H=Z-I6^!noac zZ@2S>G4#~%@Gy=VM%o@^81BfT66UImJ5~2B z&Fs7*jg5^>2k%sh!b>Nz+j7Dd4gu&-d|bRT>eu>vqVE-$Pqam141eJuK#&LRYbV;) zs?Z0-XDBMh(LvfV?h~h*#I#_M;V{nr$}6W988Z<}mCmdh*`8wc8Lm2gKJqFQ!lRKxauEV}nuqFm!WRrKH|zj4du!RRY*{mp3f znXG}jGm~?s?4S`7m8(83jBo9Fn2axdxazIPw~RK_J@&kVx$U)oGzFfnWK|B^S)_Ha z$>wx;6iunZk@iZToS!nG`e#+gckW-M#Fn%3mz?3xoIHv!NnWpf`$o{=@KxH1@-LU! z1>w9Rne#?UOsMt9J*b@#oZ}8X^)!MnGUdj?9jc~Iu6>vU>PN4RhhZkhbYuiWUJqBoIuatty?kpOkHTA}7CC8m z?z<7eM4KqG2*T-BLRi7GSI;Tu?hJn&0xH#`if75gk=Uo7P=l|vd25W#R7emiHs1p8 zubnsgbm7U)P~;!06J=6Y#BrQ*nEw)5?$Vli_{fMhXSTvcRmtau%>f_ggvTy^j1h5O zWO;EXKK^b^UGWNQ(V0j3bz;foSH+LV5HX<~9xHVmA!0>!UDdEQ^y~A8m8aMqDgiN( zDibBc94nq)YR4?M zb)>zM8oyfoxy!Crwr@>Vi%$GjTAEO*%b06ff-HI-UA{3~V}P)trJpU7_4iaZNk9L< zWTX1)+k*I#rk2L%4yhu}+MT1dNA+wgCPcBmgHrR)U$-LH=YsC@sOY{MKYdsu6ziuf zdwy6E_k>2ToOFApkCO=CQ+tw;b9uuLZ=rl_=;e-F9yk-$u9!{^(K&M`+4vC|;;E7JUZ9$YaG_q(ZG-cem_;Is{Yt+UV$kM>bX?N~_Qh)^$%u>C z56ydtXn;9=MYS^oj3U!4hP~}-L>%*NLIdf%aeSgwrL+stkV$_f7#|o=ov% zbVuL;l7Ec{H7ndzuO4Ts!MOa2 zlKV=8t7-j-gg05#2_>Ap%v2%ROt~F`1-}dy^okmXWLo+``VVom8((ILrcleiK|%bC zscq>M4;TF<-M^mOjTm$s-s4)9F(Z3&;nMSt!2$a`ahINXm(xviN;u4HMU0CSGpapC z26j3Q@+Iq@uw(^-TPf-+NpWr}EpLN=4kQ;i$eH1YA=B_Ky;5;+5Nn@s`;& zlmNb8hHzWqn7Dv=0S>H6LI@pu0&tgP-K@+lalrh5J$>dwI7)aI+q(Lh?=fK=lv=;uR+d)3W^|} zAcW?<2!z|yc1VIGRX)dkIWJ0hfa11{m1z{f=FEMbDzFOqD{V&cSFp=mN3r`L^ZW+l zE!^7H)I>y&@c3kvCdEEym~LZBO};GQ0QO__^n_cw38i@upIjO5*<%59y*YABZ=W{; zIcC!r)c~PKiX#CFf$;)S*f-D@iE_Y55ubXh&7+OULJN)RLfP73-G$3ZgEIq%c~IPm z{5cL~Gzi-wp4tn3S;0zI4l-cBEcx=DbGwXP=6{4mSOVCche1Li+<-u)9uL}^+r8~X5LlL>OWG=gw#23gTsCs}A^D*YL z{doPpThiR!*$y5lvY%}pWmbZ6YgR6W&I?C#+73oFM!^R9fb4*W(FklrIDIfBSxMRUS!*fOtHq^c%rs9 zS0+#6RuV#w(X!~&fv6To4YLmA=(!Jdfx0z_^wJy3v2u2_EiWCi1NpL5TfXKGKmS}( zop~`~u{1NQ!bFMn!wn^R9UPpYfhSq=DSLwEi;fe;qA8gome-Lq7qK}n_K$N>8cS7t z`N$|N6fVT|>2vk)=&nuQMm_{^8=|Aq`tK-+LJx@=@I((Ox47?b#j4zbSAfmvGM1FJgFav@>uFllH?=2~@ zB5r8d7c)F@x&ae$n30VsfujJE%SU#|FLF4t0Gr=TZL?A%{Yn#OtLb-2<4IY-MDrcK z@yL{#me^*o6hz#oH&23l5PK`DiA4Y+y_RHStJz znXq@pwh#BsTG7A77H3?En;nwzj+nqSp6uUM(#86%OFC+VFSo9Eoi!qkvtiVvg1>uc zF7BXs=XLXi_Q=6nhbkQ!)HS*5yM?;eNe~+GM>`a7ul7Kw$s`Fx+8!Z_M8$-ZD7PZ1 zT;m6To~|9s40(M}7)7}MXu*DHoQ=@dqGf_rvfSY%=4VIkPvESkR*ABXe4nVEB*Vn#jMzn_Z)8cja9m!r7f;fW^b zb!2QM+ZiUBPR!!ewc~`z*MnKG^b@{XgKYKKp{t;0iK{15b_17~)~B2f%)A`j$lT9M zm%subFY^8M7D+HGFT)2yWI%)0Z_;JuGGuiPJylvRB{7eb*Iih}k!z<}8UQ)!zkE5$& z7~-f)AYX`~1g#x2VV4tskaAC={PWDyTC79;yU}4!~<>*$;)v)@>eEAnAR4UWD`9!2gb;3w;mXv~{72JjPHyfv7l-bBdGcWo zXlC7;mMW()9UXD=W4Bv53s-WOU3gPQ#6ls*o;o>J;ilURyvJpE*~Mtj@TQCS2JAmu zR!!@}dx?s}QnFco2I4d05LsG;Fl)N0fL&`5_(3jp~kO)fgPCT09EOp>jEAOXs zRaT@QCz{x!u?A8u6}ItBGBnSxX(`;^WFLos-g=V3zMNCh;=6J1$ccWp=*rJh>U*vQ ztJ*!P`+Aaqm?Md}z$`_fr-DE0wUO=VCTgSi@2{T=6NFWSL7I*|4zYu55FALL6g$3G zkkH5ur`RIs(#h3Tpf&6uJHiy%_sSL~fOoCHLK1|20ekJTc%{7w3MgH^TiLC>7+c!I ze8hx$U@Us@2YBC>2-=x%US)nf0M$9K4Gy>#aj$$nhbB^U4IN?I#if0i~5)(6BBgf=6mfm77nqg8dwmI;;;9ZN|DXlO};NB(pr( z4K#!aW(-vHaoB;wKH)%dneVcghNnCYi4DvKxXNsYv@ZsnF81%ba%oF=S z2|Rru^l**Mt+U)^u-W>8e!{TyaYra zfWJzPc51(e14BGLXe)6T-YUd(hLk85w3-|4N(jxJI04N4Zl+QL0}y=~?PN>Uoc)ub z6Z4uu$My$*bfd(GtuE8pJN*I&e#p^p-ea&-4P|d8*tR7EQKoQqFcXo%tAp z+>-W+oLIxscHKc-EYQza+;fltGwHuDHn}v=nctZ=K4w(SS!S#Cx7*=>Rp0@o$!0YC z#f$m-?;5WXRv#jbZspIQ^%&`>@)+e57LLOJ~7e!Pz9d6#v!%Ua;V;$RQPL^U_g{;BDfHlvzMX&8=GzCD;;?zXksGonNL8n z`3gneMhO)c&VZSDkV>=_wB8a{m9OYba!^!{$Q3o#x13OT>O`+SH!!l0q%qWP z<=sH(TBCI%)6=E>A}7vz9lkB$kx<@Ke%Ac7E&F0_PB_(bd3mscN~*sdD_+-co|-gx z+ApHfkM2MwZ!URCSpHbzg3IV@b`xs*h7Z9Lu zA`LWR?vUKxC1yfZ<*Bl6$JM*fu{UUli^l`{qAU@%No4x@r}P)@3EYP{gUBO6s2Vgk zu0H!ayNRww^@_@fnPN%!$b>`N4854bkx8tRh__6rW1*^$Ml!wM2h54^nOH|xpzasw zs~_WzVyKgJcNbznjIe>c0&gX$AS9uHg@chOU2}y5>{j2-1N6G}K~@)NB@d{sZKxvPbLIVB(Ljsj~6-K>Z zW6Sv1-UhRhv)Jp+#*F&qYC78SAY#thURMxr;edb3dl;ogWea*e+5T>IL19AF z{?K9cyW+Dmz8hxqiXV)p268yG+mq}@I`p2BoE{A8sa!mWa9OP^nxA#zeSEP6ESdZ@ z#aLJcC!E$9+QBd|&`TF$a*+T7qArd{2gj>yZM&W9^vOl5PgglT8ou3l;g&&*L<`N|TWa_u73P=NyO!ciF<17za3z_MlP zg~;=O)lj(hp0wp%KkaU4SGePJk!iDL7VAFNb zGBc~{ues*|x3O7y>tfZE-8I{0R-)BC|K^tAF|*^;m`e94{~}*zGYsEsG_oi~R3v{e zF)7gW?)-kO_g@=?t-H^5Dy~kVKf7SeF1qL2uL;nJJ_z28FfE<vat;N6Q*p$Dz90Fz0b zc`hp-N@`G^J8k#6UNeaY)nK|&)OsVI|IuQec*R951x11^a)s|B#u}*S4YsgP`0;cD z)qQl}AlE1%G_Wzt1kDzAHsIcrQH|F-(c9v99yhWvor?#G$#vq)9>`>b0zyj;PtsMV z0qyKNS7@2L*XUjVt{8h(LyGxy%Olz;1XY)Ab0v!p-(up;NZ^Q_dUO359_(PUQ1T*F z9w5eUt~1y>eq@~yys}HQdH8CeU-O3W5vXP_o)fw zhF0uA9RJaYi!=~ohsXqf{#;dJp#mN>0_f;De+*!!cU{w;Bjc6XZ@UF#_pc z6htIyN*doRDO*JTK9z7DXKLKr|Mp?jDGi;DEFZC~I}?fQcNpNUs=p{1K(yd7*v+D; zp)A#p0hQk^dubgV(v1=O*4mbj&^|lyCO2ZkLb*Jw;q9XC^L18{iT(swMff722%ba& z4`A1K--TZ}CQ<5`ln0qt)eNfXZ3IyV>zBn`{;|k{Q7XQR_0dTG=vd$&5D>2cqA)T# zmf^C=ePt|d{Mk_FUDeuOY`h8yK-arB5zI@NkyL$c)w=n1uF37-kx=Yzrt4T1NY2@S zWG1kjJWkFFkOM^H)5HAOP=%F~c~1vyUKNR-8D>0!RaYdUmtDItan?{prg!v+*&c+_ z9{gtgf!QhYqCV1Eb9Wb)$aA!pwVYORxP@Ao(-^C5W$gTDvV7B^(Duol&f zwAhPodsRyDm%w9|a=mIENr)Dt+xWy?Pgf#7bs+xqjH=Y&w82F{1CRCKjl@B)W6r~f z^?xxUW?@DhT$t8g^7&kFaR5N(RFz#|klUUZy1s$-kmIbT1y~8BAdT?SDV)lqHNga# zhezzBA}O00?WFr&3rK~hFx-sYgJ%TWPD>3dOdVm>$D?aLeIk=)Zxd>MIdFPNqPI?} z(ou_>T05_Ce_2G1%lo+9DPyf??%wpC?pIwSa1>N(RQ+<0Uhd+E<}vl#z2*<9&Re$V zPX$Y$4RE+U4pH|a@2{H%Kd$`x){%RIQkb42&$)m8l)ue%eUgx)eo3yJaccAE6}RRK z69(dQr?!(PsYb0TRVOHu<|gDErZec7P$y=Ugdk%<$_183m-ULj6kv{v7d3fT=OoX* zG%l_WAZaT@)6|b%s3{F+IO(Y$S21ON-oXU7zBtXUMRNIEL~`w-v#G=BMEmiql!TJ_ zxsQ^y3oq;DYlg*KZ`Ynzz|~|k*4zWuDT)?_cc8oh%=aiz_+5&CBLC9iDNFfYPCiBK zmR4c=UfHGB_g9)qmgns8U$1#GI?F@n6J~9T!@Xo}d(=QxArYt2em5_V3dCFrPUOXJ zwAvhLo%ic86lh#`CBB07%695Cy?x za5LOVk%?dERjx#cpmfcD2#LRZi!N}TV2w&y(-d{<$nNP-l`XG-VZqWz?H0+lh^0`# ztx0`3UO)@yO>$Ezg3JID;7ApoWGsPiNcE9%iAKfZ1wUlSDwY5Z>;%j%FJ4tLqM^kY zlXHz_1Ku<@XTf@2XmE{(eBtMf&&T zr3v^=ekGflZ}i!y5X~Q4W=56P?#3j%yx&w^4io+SCd(Qxm>WPa8Y`S{uMz*q$gNCe zYNqBEBjbCd7x+@8t3zlGpcvJWU1qN zXy8~}5lsTY=w^})wJ}0lz@{nzJ&IQYNd$fjnA3o(o6Q;8U95`Y{)2Z{zzm`jgD;JosHWYi*+mCBGZm7U-G^! zJ=o;Mnc`~^QI>N5jL&*>vvlCfAzR$hjm8WRYxs?~rS#eLmb|{QR`|6^WAKOr=V~3JxzECnQt{kIo#g&cr2n_f(2iIWi%89-; zaG|QR+$MGH<2~hfav=W}LpLi>;nYQf8Tl$svKwz$MSw`~(Irfn?0e==fvA*+s#Eb059OV>3 zk1a~+sjyyI)U5r)oy*n+IOALO?&?{)6zZL5_~VDV`5A*+JXM^VM$=Kk)+{l7&c1%^ zb-0U49Wv4NsBTRF7MjNl3MdU~TTqn`4nWpW{_!a2OZFhFU=)g!eR`HdWEQmnUJF)Yxk9-gudkb9MP#&*fsi+D zk0E)eqi)?*wsy6VU%F+lB`&&70n3@&P&Rv_&`_)Pp-y!2sXYf6ia>s3$^zs^a*jFA z9IXI4P;``?g`YqAzAA4l_W5`N*;T^?*;$XSuPdU#$YQxUExx)==d%@~_206sIGlTO z%nwk7VsrZKVkz-VLK`rNCDP0w7b?JnaStrS^2^YcjZ^jcojAu= zoLv16&sx!c{(NoebB+e1M$0d(O=Gv0n)5I{UWRWa&uk)sLu}^SzD^I~@;9BJy2?v}PKvrdh z-z3wHc{ctnv+oz>T`EIy(g7#B1#e#+$3^#oFvnQCDv7RbYt$32ZjbFenBKwzhoW#g z4l$`TIR?bw+VB;ZvW!w3+49G>VLeuQ5hrWk$RS2EvyA(CJem5RUaGG6OnO#V=4naG zzoobf2VQ}8tnwrL(x3sO3vSv|;gJp{X$)KG@JX7J=A1_hL6RnUJ4tgP2R+8pxcp_H z|Lt0-tQA`nOYlpfH&}(hDGz2D%SIhuouGlzcNNH9K_wFVX2FC1lET4((-r^Sv+X>UXj= zuMD*4+IPtW9|NT64e$qy4u{%e#72^MBrwB6cgyKk$l`24m-k(DDcX zZLgFd6ktjLC;<8O4C(Sra4lKQ`WN@$6;%@!EIh0;^${Dzd>$gHXHVM|;-p*Pyoj^7 zO5?LDoWxqsI7V6dOZDw=mog$`9N*S`?RZUFVOZxq?dbcQE%DXz+~@)k6boA#nAw|b z2t8%ZTC;C`YV|`Rwiw&Wc|`xJ?dz^PN7-lX>sGB2{N2+c5@hLkr$plP%KTrXOG#yU zA7+s8*5p1QjCu}lsOy%L$THN`%@93`85#JRWee1`9r!X)E|cxbo z4pNQJMM=$5QQAldQ*y7L?@8|-cTXCVhw+)e)VU??;CU|GSd6xWZ=7{P9_H^JWYt@nrqZ(%VMfwApHWNi@Q#Y{= zd9n%di0SYTCl>^}-hUMU?${Ltg?PL%fMPu~Oj+Ub6kjT^yCaWt(Iv7u;Z#@wCY!?Kc7gT|NUz3#C_!4YNiDsHAs#raYElGFl;PPdG=NGJx z%PV&Do*6Ksk#te*9~*d8d9AWO+_c7V*t^i3liad)WxwT%@FsGM?d!NN5_qc_LJxG< zMOTGZ0Ww9W%ZZTP0#UtJQU~%7O2=~V^d{? zzy}$f9ii*7zGYZfT2hm-GozS0O<`AatNr`(+NPnzblNSuPay3m8goqcdi_AdzBK!8 zP`y*}X{!cDQ{3}G&x~0(Exy_wHWuqPm%sruR&i6~L zItqI2O1g6${hhSA4<0`t8+tdYcU+HSJn!~roNdEboAUWmV0}cHKPK`xtfh5|t|Q7W zX&fC~Aj+Z@bt`&i^el-d_SSR-8^6PB7siIW$VDb#sWV$!4GAi31aH{s`*8S!1T7*UC8N(O;G!jujV>t6H154I4(GUxl~6eB_wxW{IW~%pyqCde zK%=O*HtltZDMMMkV7qLkPNmtc7{lE*<|Y&U3TF zSu0QlycWo!eqO>yhtGNzL(#@a`pdgRCxzWArTX4~5b;$oJz_904Plp{4@vdj0 zOEb-2B)MTf&f0A^Jewm}W(TXt2wK%e<4O4eK+0V$FQ+_IVw%S+zL@QTB8@XjdEXX= zs6^|!#Jg7HaePNRn9V-=In27NWDPDi+*8Y{b!Oq`Zkj8+$I+j7Y@_ju0ENL(<-l)u z=iR1oPomxluwLZMy0`ua)Mh)-@N#m#Dt_MFEL=-X1F=^E(gz?@G{T3zITB11OC!px z0b&l_n1!8ysdU!D+Q;GEy2N7RqCjthIFpl%nSbD1h7>Bjf^q3Ed z20se1n>#k;Be(xZtPZ9xFHA-eT|37Qaho<_j_P9Btj6G5x+3Ytb(L(bx9aq(bM5ZG z6r|*8W16)Sb=1#G5iJ;>nkkS{#91n9QC((SjC_92cK)$r*&d^&fcF(E8BP-D{?tYe z$yruHC@(KomM6PMyT7^dLgOAxORB{4c-9rFDFi*D(7Vq?x=?z$O3j}R6oh3Fyue4; zJpgujs61dn60`846ftzTlC0;^D{0D8nVD2$r9n%dnvds!kSmo?LKzg%oiQU#t2tA; z&}HNx#6CM(+|bQ$yh2hd z4W?1HY%OY?l84^<@K)|e7Th!#>dJ7839bw zG?ZI@@I>_qm{x03^9GenQ&_e8qvx7dG!q_P(>(hUOYL&p-B4MpsF}(t7u8etz^&Fd zSEq%fpkv%7F%0XcF6V2bgu6f^j5`8t=t&T>EW5}uOG*{`Dhi2_K^1tqof|gcEyOfx zP}0bx<~=u)Mp)%jYOtk>*9zs(R=_ch%X9ZMmqQMj4Ao2m2bF((Pl;1F@{45{-9?}* zAq)UOy>;QoEC7JU**4vRi89+;%JnSrKf>9K-#EKMiqM!Y6!-jaMP%}qw>LB{70Q78 z(3~_e7O!c(ia^uIybn!S5yet(ar#ehrhAhH7poZ0jb{Z6kc6iM+?nDb!`O0Y4ef?J z&tIV07418^dOoCZBo3HzOPgy*7R2B#xyF688I06VK3`*yvsmp=J<5K1hI|*o!wyzj zeJDKT9Xys1(r)65AYy#PO_BESiSuDOG;7=Wo$Htsr zwxV(%8aY&Q+?m}UX%iE_!J2-l&L*OsN}@}rQ42{ zO6|sKoNQnvkgO1Y^ua67kml6PDO_&dvcy*GZ`jrYVMwD+BeTR$I4kpO0JU~A)plUwm5wM;#VP|j|yZg8cmK|DyHz39axq(#FKx%j49ZgeT zPT`I`pN(PjoNQsk4L24BYLXgQ5uwp57mBg|Y5qQ_Lo}p|*vt|Lq2zr534KCuTFxU1 zUdKIPHlQS~IV4)l{=J$2UgVaaN*sBAD)YuS)sNF!R9>OjD%!(0@frjjx~OWV&sk32 zEXVK{ZT?=4VMs0;P%Cz})5-(scQQ7K@c^$}wq%!3J>fAB6+Jd5?>H0kNq?^5hPLeR zOhXRZUR`DXG@32{Q@1ZKDrX=_hyPJU)V+H`;|boau6wgT$uI?l*7VKP7FA=*=a0+y z+X=rY2y%GRtAIOyNLqh4v?-mS(j!{Vd*sr;ItlUSHK$x8U31rUH)RoDdGx6zINSi| zw9Af})dcs|y}H*rb1a*G28n}T_M;tIO=rvzRPn;POwnDh%+5*H$2DGy?cnr$VwY8!0~opNi=U&b!~gOjE0S($MZ@ z@F!7DqkxiQj%^2HUKSf&kzH9DEeGkKZ*#AW%po7qF?i6Z{j0^id|SF+i9(iI3pQVM zM6SOs(X2SBt9rdRLBwPIH1D;vcamH2>DF3ejheET3iR@a zSCnxN%+5bno4IOL9yp*b>ANN+IrpuB*1GP?-T;~3R7=#$oU9Mu1?Qct-8BVLli{E` z0eLg)S|vS2_)RQrYe?z)A?-A!l9t=p*1P$iFY^=`8)x&PZ_3f!vn`*Wv6HJsP*ssE ze6n|Ee?k4(1b2*1GIYA;8~fB;tvMs^cu5=o^s58`_bTB1cQt4{%f?>eLfr}i;b{@U zrI~WOy;JK2U)6DwF7&e=pcta{Y(M9IXc_xJag9fu*o(bHp=uE+T*8WJF5|DnY=dbu zDC>+fhJxn?hD5F{f?Sp$D=4TXALY$GOrEC)GLFa~9=oTFZ5a}As;JKmbq$o76+BhD z$YQC=yb7=lj!}$~%<$HO2vSuBP!18!io{nGg_Z4z=ZdXi-E&i(X@Z!A4K=~cQm_{O z@-Zc3jnCqWQ60~8hxVq^(HY^Ofcj_W^^>+IFg%fl$}yjw2nT&Uj8=(}(>d;M=Iyyz zhrQUFf0>5t}jliqw`Jg;~UVopy)Q9lu1d6=MokqM>#;YkBt??9|QrSJj5 z7?hlx!r^E|>-Ylo?Is>DCi4akIRfGpf<9Vc59Nvid19&XL@oqKdXIwq;q%H&r!lsk z@54Yn-`AUJ%XcXRxs3{KV;&(%yJCfcUNZUvT1` zh%=y+z+=DY-o2z?nUFQ3X~_(2ZF&3&M^C~VOz#_=d}Pjp7|NPUrxOzZ(OD`6b{6f+ zL$xkzNFh6n_s8s$qLg{EBt!IJC`sUrj2tx`!pHRaU`Y}l>{>|zp=o|2v~;rPPm&>0 zWdg)v7^D)|wNl`9-=@%Kv1E}1gu#?RN!>_q1okJHCsGx>dp@@88Z_?yCTk>7?b4lN zu!`%u54D0*R^fD^aU43QL6I%iwlzgR=hR_I-!Duyc6OaTWp?AZd_B+kF~p0OmS{Ta zavEY!qF5@?Gy{5};&76KW6tA#Rtm5R>$gMR8&|MZTGA}T3OE)@dl7)zOfAH|BTkLc zw4T#_5?U{e`?-vYHCa`!X6NhiOY@QO!@{{jpGDB^LCWYKM|=T`RLd0wj9DrS-1xTSIi8brJhd8@_G$2PvjkY! zpcu{YiQNctgupi(u>a|p(1-ZukYET?v8u;12R7E1-lQf_s~vD8|Y3+{2pGh(zrf6KmYr~XqeO3(lH<(bdd+$@lG_=M6_a<-CbFD1d z7cIJ28jaMBe?2sO_DqJk_f_m2O}kgllS$>i=NJ8*HCywP1&&5A1L(;5j3h+NomIPF z$lNEro7WOs0;RAG%^w?6-SJ({uZ$0)YIvtE^QnHOeBuQrjD}Po)Nv)ZI}sdq*(^=S zR)73iT<6N8<%CE%8MU`Q!Ag7TB(&^anyoR5w&t={DH9nKTI((ji($Ej`Lc6 zD>e3QYBgUg>L{xB%iaRhY7&E@)3m>MCPQ_WW6x$f%U3^H0jn1Du*wUZR_k~&jMV1= z5fVSr8wDW)jdaoc>X+L}ql%*W!TEtN_)w85=;LSu{pFT#-gEUW8anAYGy{DqCKUyp zyxrm#Z!Ke4XSKQl7^g5DR0ADZOO=^-=nSL_L8L=?{>0(Q#8Q$$jZ+^y*bp@{yD=ks zgAReR-E&d^qNdcc5;DzQ(yXUD&A)}v*_dlHycLN+o+Rq*|L7cm9eOVgvQz24hIZj8 zc4K;6Z}_eDHzwYEGKymHIuA%mB;#dJjF_!-4)V;NL!o^>zTKY^($Ohi3JRg#ph6>U zydwWhNNS!w)-SP_G zz~0GziVhg8edKq8zI>wgtmjv2+IPLh$x~DCu$QnmcfDx3np-lC-G9I+462?4y||3< z&1fsXt~%cU8uGX*=nhUr-c1HLZJR;S_VQCI2d&&^hH>AsdMJH4?vDsE?Kur7Z_QCH z(^E(S_`lqT6n_~oM>50U5519KNvLbyWHvIvOo+^)dY{K}oDdck<_nhVlb-sv!n8mq z5*c~lrF){M^sFPY)KyZ{C8?-;^#{K5y7bX}eNw(i@bkUA8$U1>tKpm*rQPB>?zdHC zmvndnG}*$B2dZ%>m|c0&uSj~Q{M69l5K ziP?1uRC}mh2uZ{ko<6O3_MvCyqrlbEE-uBHcl`qA^!+~`g1lqkWM9kVYNpdbmMBzR z?QaREXRo3Rx+z+MPP3L(Nx87|rw=$yMcjt_c7P&J? zl(}LbC}8U7FUyWdggqb+t~*K2vBAPSYEq`+g?wmPkx;W$<#TzA%w%n-jA8yoUxcTP zc4dNi9WJ@{xZ>w$Ic5XW3b>h3T(AGya2oGaOZ=~>zbR@<|Whm0&~hO zSXxhyX#U0ErFYLLFe4;3Hv#ILqbHPtJAYeQz*TunXv9M*xN(sphGe8Vhu3FrQZQ?)n>6Y2++o+Ny|2rTvL??mn z1T_M~*E&E%|Hkp_#aK7Dk0vN}>LPQO<0u~IT_pRyT*kU7$1H|N^za*`MHk2KzP8bd zfg--+!j>Pq=T-Jkm`WapuYKetw<=hh(i~lAjq9WCQ|qBMS(=T!hxLnkGpjz$!I@Acq+SO`YI3d?JZOmHWH##?2l2O?=r_jmL5rRARtH1` z-*%4JjxMf@kO`w)RNf}v!*HR3jyN)*UayKk#e#BY$slH_O9RwLkH{<%3A;LKl%C1H z%OFv9)~+VcN~NFF-*yqR_ew;#dG`I_nVg`>3c3v6D-lQD$>(!unkAJ+1wKl3*mHN8 zC_JTAo;B&LzH%$SRZQQozTY9QdSfL(aYo*QU$%X^j<9eZLQp7_xo0M{o5tldU)oE~ zHs6SgD)kgADhHoyFZu?xOW2sir4NRsatxM~n2MhcKD(ew2c5lSOW8bWiI4KmKDhT~ znHEY`>I+Os^lmJe(Fxr>C?n=6@~&%8w%PB?W#|;tRYHKu7)v|kqYs{w(a4%|?!;QfU|+w`1no6T{=|T<@7I%(W!uf%iXJ!&u7uwkHm|?zI^9zn z2c4t6=Rrp?;AyGC`z~$J%s*Q6WvLjw`PWt9YR+pa(P`LL_d?;Jwc29CT9U))^H+RT zBF&*RcKY}YyTY$!(7CqtcfzaFFRUVuI3mlPa$>kYuD%?UU!@N|Rl*mfz`fc!ym4iE zvOjJyaWW=3_L}(1=Qhv05;tBBhQah*+OpkP%S+Mi5<& z&$V;+lS;MWudziDhQjv3DE$AMP>jH{xZt3bKRv-!M@#kfjy370s0g34jQ-H0RHbz*A<^@G)uX^Z z#(?PALB>+bnAF*hXK=Z+h=-0CLo>4=1n%W|RnNs}51HK(P#9634lrNnko8_-%)R;c zu`rd(v12M)T4;9Et@}yOPoq`7CQg*HlC*#6BP!af5&(Qg*(^2-Kif*>H$(jW~YAOa4ZlF~y+ zgNlF*0@4kFBHcK2NDeLCV35)U~D!D?G0 zKmxIIa5xfcJQ(A18jD86=(4tU-7^!K_o=Upz|VlI_JykIm$WC!%!S;e*)h+b--_o{ zk&}oG>`3%-8DU@O{t7@eV-a9r|N1RKEuFZFXG~PnKu(5^C)?ptkQi< zXx#Xzabi&uG3^vOG^Cfp7w#u{7lcKRh~%apeg&>mwMECtq;ox+!Qw6GY_<-nSbk8wPTt5XGa}?OY)|;@g z@PJr|kEgQ0;kjJT{pgwA_O(*hR79(X%=@}6zLe~U9XLOg?Bq)y14bxG`O?+cWf1)5 z+v}-;X9$9lIPsia3ZPn0(~enzkMT(Uw^wZa{XeQ4TW%gH!l~2CXoHiwJL;>2`VcYO zdOgeM@+xHVQ6&iooV-_K`6^#6;EO9bCYJG@%GiuF*7C1Q;*GmD2UK>ZvD#<$i4UCcRcJ&w7hS!3bx=9@ z&_qwqWITk`lDLSarS=<01T-dp6hZl8?xg25MAK9y15H~2`u5am1-WAD z#j^>rNHX1p%@kqWa%WP*rH{^CGd8blTg)Q2a?d3#%eRVkckh0OALRv!*@)urukS_9 zH1TqHycV*}e5*oC+h@yvopoH>{hWG3#?T1|5fun1t^+RIT+lg_DpT*DRWr^(bXZT1 zn9$VKJm^ZVrT((~reoB_xUnT76Lu`P_Ln|^BEd8Q7BtdIz4%T>_=f%vV9!_f>Bi#U z5t7?#xIzQeebw_2S5;>t_m|5UAkmZt&-u%QsWi!H#p}QLSwGl~sZ?p@dc$^i`OAJs z%!&S;-GgLfE|c@s`+eBo%iruy50?dmr4=to0C=+99RKI}hkEyeRjnsaFs7Qf}f_`$fvDh%xs3cHLZzW+hUJJ5_L#IdlYjgCuGj>aW&0BvjQ8fZ$e$lEn7xHu3lB_aF4Ns|NePEOK=XU}? zC0?npeSr7f|C-brjrDNSXxSVekRFpMa$Rd?ciBy*7?@3pM-fs5q&*$Vo~}@zF3l#$ z%FYE4b;Z{}XYpJ49NAP;Mr{13APBm>%O5)=?sq)*TDW`DY-evSagEpp3SK>%vse~z z0C`pSa^_refu|Xp&RzmY&twqab$J|)Sy-MQ@3g43%v{NZ(@-+K@~(>lm04SMszHf* zK0A+)$7kNCtRP@mK=SIcr461FMYAY}lAjAS?TO&D z*lnKU(jgY`BiKK$Weu_)<9DpRsVC^Qmqn&qZDSi$nywhkEy zkC$+u<>B4z&^apRRc@A&(F~A;uQDEZSfb_Q3iXMH`Ui%@w8u0z*0V1L(9{Y)r-_Pt z-DTQRe>G0!azmL`Db&1c-cHHLKa!QKtMey?l^<`D?tAl@N10yLWYL(5#HP@4-3uU7 zGBn<)$!To8QD!sO4z1pqD>8bua}P-(%H>Qt)YUKHb?g<a32V-CKy+{!^;$Z}tk6;r1ub(^B;1h4A{efoUxAwmu!M zKJZhzU;C~%O`>E;55S9cSC?mbn_&?ra>!TKuRHkWsPo*eezulAXcYu5EO0<2jRfj2r(;t)1wC(_2&y?@@4E{U z5E6?W=Oh=Om?GE!-N&piz9B+o-Dj>20X&t47YPPsuSkEoov9Sx_m~&1<3T|rLmf}m zi~tMV-f{K@2|5OvVyVaz1+s-pOY(18dpjD)&=>ck0LM!}Q5)GZDDT!6{9WDXH2$Tf zDTS={NTJ?Co5>oqfzsSrXcN(U^+$I# z&&O*RW1WY&hCP$(+{$<}%`0Y7Z8K)MytHhaT7tsz0DYm6r6Ef}yjw<0^fOR3G4nCb zr4!GX^7OZk(2rF!Q#v@i{m$|C_Oyc)@;oozR3RPhn6}GY_`Vz8Vu`%2Ak*Zph8HH} z`mW?dd+z9yOBVC7EcflmF+i<|P;2?1mgrdSBg6$WzW~^mdBp|?2N$%wgsKAvmH7B7 z^*JwzjUyxHj%|+sbAvLpBhtN`$=i%f-WX_xu)oB-+RJdx&m7>MpZ!GO6p<*1A^Fpa z5w2yg_uO)kw9;zDo|Ue)XEcx{=~*&VX+cOn&zl3eMAmuI(RWu7;v+C9RHezk7#f;9Xt&!&zqHQ zqa@sVRUE<-zU}&rJJT%ICX9VYIO_Lc7X~MuCd<}}?UoPBRt~Lg6`gttRHn`*SOF?^ zo)2^CaEA|JT1ddFT;97s+$cz7xISRhm z5fk|LdeuduR69Ntiq^NSQHvMgxhNvLzqjj}%H2J5AcJ`GXOef_sbw{efIMj@&kT6P zCOy8kWz7iXbAM2EOkHg^zAme;DG&JE0Kd-&w?fhU=;<+D@7<1+yiiv`p+WjjY_kdp zRUOM)nh*Iep?s(y@N%v6e9az2gd2Rlrh_#^NT9l*zyI|r@)+XP7Mr__;>r{-Tv0Xt zjX}pPW~oxYOzaJ--b-|y(MynPHV)a9rOZ`LNoTlz*3V|ZO(Vf=jy9a|sB--uciS;J z$JiMkMR(p9Yt-zLujsicT`&qz`{><6VdMKNt(FlP!+-k4kQxlnfyjASOv9Y!B-em*|#E15`%0zE$H@6a~&U*BiBKO_6t@yTrWVog*X1AKX zU^g$)TDc=BB3v7m2g*xEssOcW#AkBWZWG8gCH^oQ`5v6t2NXoq0Y@uery1>FeUI?3 z7?Obr>1R*!?v$KzzOyGFV-@!ib-n|YiWCUI>pDqQA83k7|IB@Btoj*y#s z&j~Y3HKgNV-HjKppX7UQntc4RTT$X2Lhs|d-wH~fK`uX0R$aWd8x;r0hS@R(vxW`W zzCk|dU}TX|xn$96G;R#yInCC)l+|m(nQZ{o0r^UF&2bB%U2#WF51wM9F3!+9 zDj*DbQsgPNsAH4cqHG3O8=Y}uOT*jlg^%Ts@6Yoi7*yQk^g~&W4lk!Gynn97k5xK0 zRj(58&w3R1DtD4(W>O=t$RnZ*+o+ddU>zP0)n==XP@U~=*q<^AX~Z<5Fw&(fhq|xW2;iud=kBz zP}U@Ct>;OOTydtS7&m0rWE=o&R`c%PyO@g}RJa4y;Jv(;CgjXeO&`f1a-p4+Sc1D6 z7GE__rt$;qD7f^r+67Br2?OfuIR446+fk_{QAdb`9>k8uYwu18`c8>^of51&uYMJT zn55(Mbq~Om_1&b9h3a1+sQl$qP`%p2csI>(5kPIBUu>Y|yIn;!LA-UHJj4(N@kik` zm%EpEnJD@Ut5V81OQ_8;lA2K{OuyT7k0s242+P^Om?Fd6hP z7Gk;@ey`_He457Ij)RY<3^N}zsOONLt`_}!lw ztoW_V2cNI$KfKcO5~`$~o{-6K1~AG^r5wOdZs2(|<-m5h8LUayV~&zh3AS63n2;C{ zz67zF!m1q;kar0ue+dB`AZd(sLdZdal;Q9Ty20=A&@KYs1q%ke|CDZ3tK=W7mPbY_ zavBwiV_}~b_G&e5T?yLA326nMamF{PZKxZW~O+NPfp!`l(rDuGQCnHsP zlm({j1&Z5s8B*anmp%0$fmS?P(T7Ko#2kd5W2U=5SR}A|?vF^J;>_zRPX7?#TyLZXY&2k_+&3^L?(q0_%nWJ5c}~eI4A=h|X!6j7=fdfL?jVLK zM(?zv&rb6wA&})mLz>Fur=2OG(w4_uCf?Ud21*uIzj>tm$h`rr{}JMLo(LFnWMWD3 zVbtdJ7fy#xZoq_e2I@C_lW`4wdh&~D{e&evSI11*h&W;WXyjEyV#8Kg`T!Ta_-2V)2fnY9Xmt)7j9rcRqz zmOlbU{i_pL>QQX!|98$Jn+Y~Mx{NAO1Cfi)FRngG93p_l>m=4bW#5==jBs~eQx36M z7z)zN%>%KJR)bSLygk@oHa5mcCk;B+ywh_#msYe&z5cz$`svY%6aijJ`U1-p)qQj1 z;$J5nl?%yB^5hz|1Hsbi(sS0xy^a)7`LlY&5~$RMZTUxjAMJ1puA2H=@&IouHdzBE z-ChyNcxC29BpEBC68Pg_v??oMFRslq?Fy9YtpYX+o5@4(c>eI6y{`G@J=Ydff@ar- z4nS>z114jmkJ+Y79WR@R`FXSs$u`B#POiu@h>Z{I6k?ff!rP-3RZ5V%w+pa|hg(Hj8+G&1N-yU-qDbFy z(L(tQQtw{r_uxIHoEt?&wk9PfIZL2=ysoen=r&pEcC-|x#JARGICF88=tHdf-w>TJ zzvBT!hEmRa6f4E1V}7?BHjK3GZwb=_#b@VZWfCPr6O7H|*4D`MrV)N`y9>Z!B;i|& zS5yb%;fKg3hWKO$B_cXa1B7oN_+XrJ{(EF=(^gKQnmRWTN?gNqCGXw^@%Zm8(Y<*W zijuhsslF6>W|X|C4Hg+8B$tUs!Y37~d{`kLMJ>})U-J=^r}FRm7$kxmuu8Wwaa-JO7LK6gmArD&2S-dFNl;>gNzY4GHF&-&;NZ6_H?9P; z!PM}m5sz~x$!b+W6z1mNw=pgN5*NV9dh_;;#sVTJv2IlR4%Q1OiNvuevc6tijz`#y zM!lUdb78F>;e_tWTa%xy6;PIh%{AU6o=2EsqtT{b9d zdb_%mRRTo>rCXz5ZZJ|MrKF_vt#vD25^YRWN1y_rg>PSK* z1PK|gWINdcV9;j?pFTEd_7-yjYcRLF3Rfg*Y^CX)(pfJl~2{_)ms zm}UbdByb$l@3>WDp(HC8hXEEOtCGsDbKQ&?_UJU!FTXddKteSEKv;ExKZEFDswDUp zmxPtC+enK*ZLtD9>>O%rY^)fXYK{)}-|<#8P#(R3q%-YT{UBiSBQ>f-q9aU==D0FS8fU3kOAVKCP)I~jp+6xC{)fTot05wk&(5K6b*fy{DDS18paMeH47hGT;qAfm@WDpE-_@$Gb1`wBI!0&^PBwBn*%g&S=vUzW8ia;Hw!&s;?5T_8iC6Yma%2A%W!sCJQ2kC6 z1YYxXlNKX`hs0gVd6Jh+JegO8?UQ_A{*a7@*?DeFTjc2sjJgi9fF_6nQ1Tq!DZjr zhFEkZ^GzO1VKdB?CxP1SS2aKPktM(_ZLKN#aHBaEG&uJblJ>OI3k z`#sfK`>SM}KDQLONxP!$>0YTFaF=Yl7csz!nbZm-e3|7SrRc&MSHfgI3kqF z3QYxCYc+oeL*tt=o*wX4{$0w^%iGRO*xSK0vwCgjMg<2#s+ zJ#ke85Jh^U1cu zKG9gj^uL5ajIzYAt&RD5Z@%DlI`1F3nl7xk=Y=~`gy{O1^0HxA(RDf!RO$~ARYn-$ zo;!?2e2B^7^+*D6v;sK=-a2*GmLAQ!->8D*fPf0Ac_`#da9kQ}tp)*@yX9%)A$6{j z*RIE6^+U6OPBWG8d*y4UB&X8qUsJ<9_}b?J24>YhHvvZaj^n{c?&E5w*q(*!|UDo$L{k{ z^2Esid{RF+ru)YQPzb)(mor?T6VaP2B&}WWB>P(cf$0-2cE1|ILNLY8 z!U`kC7qFlnTQL{=r_xhT%lR-gVL*XV*E zK6=KY;PcxcV!DR@nB>=31tp((KcFw>0ln3S_VWte`7A0#IA4K423Z^8v`__5cc!b? zvt7i;)m)rUd4`)aa{89jg#*GWdJ1Pe%DW3#o{a>b}aJDCCgCpY#OiZV5ZB#sV*AV)_yeXq^eMyE2S~*#G6a zv%@suw>8g3R1j`+b>gh=@_BqyJRPgKF$0!vKz=^N7Rnn?jIiP31Bm$N<2#$utjK+^+Z{=qb9}i7T zAiD5`_G9QqT`=(ftEa8O_?gd=gjKoUy!Sl;o$7~s+8MjM_KARex}!YN5=2s&0BMk< z&j*tT4QmM5I8;P>A1!TYRjXRVytJ!Aie#ZHgg-79q=fDF1us^~i-tN`ZS(^ZnRKIm zR~r0yBpH~7vrKe&kPa%l2$&_x@7c%QTe6NU6bHE?-Hn6B`z=O?0P>H^Tz*%_y|>^ht5(g~83XOV2M^jGT2f8%9_TVK;9)h!QZ37hZ_|+j279{%d|^vcURR?Z^NXp7Em3Wf6p>orDS57=jk%b29+_IZbpH4`k&O(BGM z2r{C`GlbYEVZDCF_ou=@9+{PhtXyYSZ8cijX(dxP=WdHKX_40%0j%8doLGrm_Rem% zK?6Om+kD?}qrIxjEs?zd#MooLa{!Bcr8BJ{M8OfEU;bXg>rE_fPjS^whSkP~uVt_W9 zK5xZqE)>-I4y76;S}LQo4$6K)zCpzeWxBmVsXqgXl4N?=SQ@KGRQcdBl}t}6H!RlP z_n*8RxRe6$@uh9A0oho}L$uORsBtvnvgZ}hXes>xs?MtG_IX}K-++FLi~(|602FyG z_WS2h#X&T7G92qn;F<|K-TXfF7@`88rOhW^<+B-UNF`j1`1*`-R;B}pz~uEH^u(0k z?P(u%2DxvG*8s^DLy>3ECQ{?&@3SKgy`E)8f_UbyIF)2Nfaa*&F|k_!X7gAy^o5GJ zHT2R@)FdpX-9y2-3=|nf%LeN2niw4j!B83z61&gXhDlkBSu|&QY8G8U_%G$GfJJLUMoCBO*RGR#hvCf&+5isYf7@AizkMx~b)l(VjtB12nw_LTfj9j+9jK_2G{c6I_gKljF*MXV{O>86p zxq!kU=v7bq7pY-Uuo4{zMSxeB!P+vj>EUk0`?1La>S5iflo%M4{f<)(C31h2M99Km z!TAJtQFTaW4X|($vlhgS5S;^^B-sz$k0tSlxot(AR%O0sN7x&SPGl<*$9Wz1qj7P2 z+fAkU)N$oBWz-j#wHxT?^&;}hU)$5Zdv(+Mk)lBrEOU4T1*dYp4Xv&q$yofA{;u%1 zt!)R>CytMwzlZ~-kL^dMHX_X&8F~n)3B2QKEL{UYctq!iZFX?TJ6FMn@SY!s~>^FLCBZ_;GA2D~{k#SAz_{;NDPe_b+EMun8QwD3U` zV#i`PT3P62v*$6->e$l9n^*zyk28`38kjYWVF{rKYoITW8TG-U=f&7Mz&{g@kq_Ko zeqo#7$wNMbjX_}Nm3IuXJnKD^|j<~fZK7v%8ea+tM~!H88o`! zAKri-FRcS)W7K7OiUDuM9O-JA?mp>VrbM^!O>q7*C2e;Uh=uE9G<%g&^_1mMC}|lY zi1ND?C|h0~DKL39#x!~z=)&j_|JH?h!;Pw*iF+oMEy_%&3-vHPm<9-$p|seP+Xb z`FwK@J|u|tl^rVLw#y9M&$gnn0S6>8msf>-eBi0_gG@0Pm}wf$uO2lmzvW8G=C==I zW7?Jj-cs~<2c7c7YT=VW7gR|h-pz|@T?d+X7rtrzPH?cl&;SN*f_{}|E0P41RZmOK z|5pF`f+`%4OIBAp!p6`?8tXMBlJ$Mh)k;-cbb;~_bHaxJA)2#GKVG&dE9+gI7l-Ru;~pJ|OmGll|VlRG$8G_(D8Uz#)1jFG|e)aQHAACBk!M==HMN zb6;ZAq}OM;184uxpdi})S7n1l*d9sQ2S9vL=><@3b|-~I@Eem8|Gnjsf-8hXmce4X zn-h>3IlPO0^6{rR!I!qsM2{=1H_<2q_gM|>5bxj{tFwU6MOKL-ZeuD<_qWP*jDa-d z062qQ0-lEct>89-On`012*>=V=$Wc_?N^lPe(xEb`p(Ek#q(!GD2*?K+yU%#`dIj~ zKK>&~``*@Mqgt1ADiL22G(>=;?Z6cj>ei*Vam;;Beg%XlW1r~M8lz-oP?geWsgrWK z!daSpFr#|sY&>fIewH}HN1zU;kp2}=SQ{3fPohBs>B69;p}af>fWWk%6hG++{}fCT zZ+r>?mFQs%rSaP#{z`C~%cO>VsKR(W!}W&)#2PM20ab}Dd4p`b=6WPuL??+LAuNwl zS_9|#ptLmGOX9mr?JKTiug}O$SPf4p)R4N}thYg-NZ(=t+-?@R5}zH>J&OV+=Ytk9 z%M8bdOXoe4i7Qo-_$|v})81!XAVN@?c*BVcFu|agIdN><00$b+?4Znm-!aWXU2x=^ z4vslYh&`fO69b(KwsQ#f1@C)S^W@WmRn>x##)2&z%{cM07hbiwGHFsImj1UJt9H40 z`1JBIg4gCYMCSU;pvu}{NAZ0(LuBMQGis}*tiIrcmBh`9L|>lP7--^=#U#D@K-uG?q*q2JYIRj?By)uN0! zkCe-{bem|D=(sY!`s35}5qw6ifotfOC^<#jSL%GW*zb&y??mxDf87D_yQROF>8z_a z6H$zGbRl9x!u1`JQbI&VrFRYpbSmnC`B8@*B<&ax~DQp&6$wrcGC+PRDm zc1~#JHch?Mnkzwe-WM{?9(AsG=sWtnlQAUCmF1pv@pbO7^A(ki3Lt<#hYkmsL!7K% zGg|E~uocrXf(GY&FX#CJaXOXxldb@|Oh3y$y?c*DmFq0Fyd8BS&N#Do=41i>B8TaO z(qBYd0#k@mr1z7h|CB+-**#EP1Xvz&5QX-=as=?EbV6fsc0lskmqqU_BH;kr^UoD1 zzbwGPBq5LGvrVTLm)Rkghy+`UlJ>?0}c_U?Ylrk`x=HQs2$!DymoiW z1(>!b+{efFFra)9mZH$PSkwg{VLnLZI3Bn6VMC1|v#rvEGU}a)x~F%UxsF!8QgqIV z=Kf)acXKR$Ati(mq-QFicEvVI1(m?>&Anq3+@>>wZDB?aTeMSQh6Rb6QYJmL5fl?M zbH;@7-TSb2n(oRZ(<91UgN|yDk-9Il^$&%l`+nBOBuyrGSZt=yZJjf9ia9JM zk0yAeo$VwG%{@fq=~bmQewsw+a$8jNB38;*7h>wC#-5$8j7)6OBUtE&73tqxL&tuh z`z9U!?6vBW2by2vR>0k3JZA8rw1^TNn~KM0-5Yu6iTDO*;;toQln@8Wp`${cOt>fK zU0?7heIzZKpT6^?P=OC7Htdo%slOsL9qxH|;}z@RRUO*yufoT?<*$ri@kPSn;x<$J zxOw``!ZwGf@BHrR6gx$ZmsWDTwT>Ds3MbHw2VC? z)i)<~ZDg{1q-=Omt5-=~so31Y!+Q-s^7QDv<^hfX2~^7Zq#W0*GuSD5x>6FkHMB+B zHP}A?O$rBtQ1Y5DCpICn>`gDb7Z>4adKK(~J9{_5C$3?#s);)Ag;b9Vo@%KSM&{M!O(PIp0-#Jq~&90Q1xV6T0I(EQw za_|WCBlMx@7?lsg?|CW8)9*^D1Z3x5O_>X-o~V{`8f~ZV*g`T73>VzzrV9kl2VFOI zH-FB5lcuBeF{rYCyEBc~7uR+9)+e^?N_R2~-|8a&O=3@ysCPwd_o>UkQi{mj9k-Lp z>a4>Qu~OkZ5tqOoK>rfgXi_e&J-z7$8-rzbBYf_Vkw5C;3tX+N60**+?rkl-%yRgc z<-jS$MccSctE3(>6+dJO8Y+oHh^)aU3?vV9R3BonCk6UMbV#%HDCq{J zwRRVC2tcWS*iOSLRI0W8C5P|Rj(30IGa#3c;xgF%BFZhr6+b6eKm?}45iFdQoA#bR zFdoq%gV{bnDEVlOwc_nlNA*iBKrUwT3}b-9b7^ z_$xD*_>n;|*hqi&jgf|r0YB4o;LOFYr%c z&Xl3-2n>jYZR1(m6f0lb&*gP`MGGUa*$x=e(Xi>?NIt>9hUq<9$`U67!6z1f>8n)ST-c*^@WVIxLN2O5vHH`m@4hfSn5XJ<#`U&>7E z`E2A*>G^zesoI1lopcxQZfsJ|#a;02Zsa1SY;MY$nN zmIxK9ffRes}YS5^^@HR~EH9w#UA z+}m?LzM#@4hQvph<;c6f+*q+T?{wf(K03-rx4- zS`+JjqV92aF;{jVApc^%=c3F;^7=YXLxofIq^D7n;nlF}A%6O8(3v-qFTs?3q*N51 zjlL$;!=jLHX-sb*rBb=P^Py7XM|J)Fz2(n@Cx%abe&USPE=7v&r!b~f$1b8~4%_v2 z>puv;<&;#%-Cf4a+8Db9YZlpN(`!8OVsBcY+SK0LImp;lnb`hb&+C1xv#^>PcT$u6 z5D(0oZuFX~YbsyWm#Z3k90ht>b?9UR6b~&rL{2jz?Yz9f zaIb07QKiYV{1ZJ@N=_VT{55nH(0aq$*e$qV+cS!icQ~tS(iToR$#`FW$I?KS)O&6O zd)C$*kc({zu)Wm##hrGk;(hjoDDS72!e-sVP0DczI^N$#6dSyOQS{hR?Bg}5Fx+nr zXc8EZ;ZBm=OU5fr4~43$O@!l?eO^VE6;n}@Yt+)k62=a?#noW~QXn}>T3)U5b3uKF z1gTRTew^_wlHUW{0_*@$^R;Df5;Q+5a{ncCZyZ=%riH{={d!SBoGDvhhso7p?VmT9 zoX+|W)_PH|X!fh>8|`Dd0=o{z=mDyC*#GI>wt@Oy!?$GAC#a8UK$B@=>?AwD4>8a^ zm2iwmUkrez|+D4k+*g}Iwg?PBh02m?JbxQvNjzn4^WM}h8_+c3hxx8pGQx{ zs>JtV4M>jMWFZkOJ!-dK$a3fm-Vy%uJ!~0pn3BzW$z8+26vczFO{HRqpud+4Sfi6g z|Jx42mrvfLx3&68HoVD|;#&QYBw!0CVv_5~QAv7nygdV5O27KkB=EaZVOH1BlF%_A zN$PpGsYP8sH5`l>WLz3(YQ`v%(!51&4%Et$c?3{9gB#5{a zcPB!WP>K?6vq5ZGA3sWw-8a0;XVL4p6RPF^uhSSNpcCgjSy-DlA7m~T=RzlH?B-td zBtqJnd+3B0n>}9Z=ga(?d~^=5=hpiNUPpi)-}$l%JL%t{h+qBJliTQ?7B^cT4C0W3 zdA|RgH9weuHo`aW&fh6}#PHcANBtI4%4;ZCC5)_6J*LX};9id3TcQ6ZA@Y$(g(Igd z7_s2j&IEJP?Zvkj{wzsJ`tRV?!Mn>tNAF0)*H4!>{J#W*S2rQU|8`@B@Rx|DU|W=N z4cliBv%_($W~JLrpZ@3V>e$;U?6P4_A4;q_4i#r+;{TBZlTHt|E9_n{P3@U zNcVB36FR}9lwIHNeqd{$>kh77%+YIpWZzHzS!3X!TVoS zz~@PcIII7ko$m}yY>(H9_&ahR!NT-+ez~F>43^>Tne{tu0pUjM-+!B0V5nm;k9%(~ z4CHR%uzCJC7?{9)OF(Pul}G!xXJ1iM`Z|=U@wFPb6Y+?XWTYh^y#4ck-;SD>*=NbZ zPWhY$Rm%LYe$Z#iN8r!v+D_I$gF`~hKyI?kab-~Qkbydk72#Ic`@bG1k>a{dUKWz_ zd)^TD{`bg$lcXlnXdMGJD}MiX*Rsix`@4^fl)(Lrv2b|Xy`q8wJ~-XT$cQ2o8pUbc zpljY8|E!@Hu1$9Pwt}?u+t}Dx1#RsQJ1*L)%{ktqT@Q4M4cS*c>yn)wXV!A%hkI<+ z$^#SAHYgvkW$c$I{UEpXq~GqIoZH`(5SRhxN`nA45^0WSwHTRWLjBM{O-F1wB2zb=$gbkmAiME7REB-Ia+OD0dJ>tnlW0i(R+i z0(YXJ9Ws@O^d*CaHpn{2|;7L*RsEN-{Y_r9M z$dL!t&Kvrf${BRDpB&ZsMosY@fSwG$-$b!dedr!OC2tEN+=x!oLz)Ds;ZW{%n@+eY z?{47VB}GIACjGTv;t3QD1F|($0sg!SOZ?xa0`v^r?fSClaoSyRUZ4VyB>2)o8bW%}Mn~I39@;ZZvW#QmfVoG|OIpby{ zEe>o`kF_x9e?O0Wn>emNO%>Ul*wee>d9seQ-F~ywe}2jON;FbWp2a48^E?KV-4c z&b z4Ep<)F<|D*G}9bFN%0==`b91W`*E&aBl3DIBc+updXX?`h-{Cz$W^&>^HtGLjtz(V z&ndG4+O)!cKQ5^Y4v%M)k56ad;OJJdrqO6J&y5YG>9CitmgAH>K$t~-;I@t{v-5xT zfH>VQGw;ueeF0(wIG$7QiUpe5+wq*$>$^K_X_bj>ufy_ z|B4Qr!f9I-TrCgqLaO4Y{P1+LZoACkzkSyLagm9Ee+8Gw)!k`|euFya?n z5X=6tPk}YyB)r6wR4=zBosY(-q>nI`99LDx?T{Q${xkYzcfp4dbZzM){r&VTEG!z@ z+QS$b4Go5hN=h5oFEZyBdy>rh)1{*0$h+nJiI6k|LRf;}KoTO&6#dhX0TNV0_8wqW zev}Sq^DnEb6K21EAO7|0BfUDuJnO9B;G22H#qjUn75(%XE7J{Ss^pXX*g-t5@qCW{ zPa_yvKqDk3rB1>(=0(y|q2)Iq*&3RfOn~(OIBxvz`!5aDF)EprZA@g61TG%sOpEZ( z=-D=I;Oo`A^f!#2I7co)gP;N0-P>AklPp=0w8sRpb~S z+jqE0BZbIDv*(d`LiM(M+t%p;)U>T@o5&>xSs`!XGcBk(nxMggPhh{x>ZA*4{pUF` zgV8^`zH;dD>deCV$zZ3;XAq1EuK}U1u$VQy$}nmHDn9E)x<(ld{|bOt&t)4ox_9Pl z7i8H^H>tp%kdcyhzQ?1^N>Bf+*UqaYtgb|-tzG~?B1?L!-rhcdoqSpgdEb#`Nzj7H zcMx*(*TD;Om;+SYXQRECLii-_)c9%(XeV@~P!w|IUb*Sg}k z1s)}wCOOIVQ0;3NX;}Ki4sui0rRSK3IycvA!V7iTPKAmka+Xwk|G*Yv^+foh z-hTO)_nhcYkNxOi7H$f@ms~vv$Wh|uS#yt<;bpnK<*TZq^(ai<=SU;D>CJi{=U4Al zDo-}X6LsSu)wx%d*RveF1y+9Kg@jUxeC%9Lz4^5(&4{90>1tQlYU(r*}}^%C%eqJ%Jtc&O9Z7m;0a`pnj1#Z^I9CN!>?^&mVKX z%wvEaH14dze@ts7m^4;QVGGC;_`G;mQ5HZ>@#XPoZn!4j^WRWkc0?W5MKSv;XT1!- zi>SO<69w$lFc!}Lx_q5L>{)kjg2lGh^v$M0KK{(55f%k?2c>BDKN}3Y1hv6_ z5F>l1SFWi%Rs>*SbWUZzn97X%6?znddsHYhDc>xw6!6 zbyFql*U1-Uj|n=d0&})h;4}FAtjGFnFO6EP-X|g*eo6g->TlEPQBA{^=RxF+m2`18 zPyQg%u)SaAbLDONmgu4y4lbS9>4I~S?0H#sBf{zjF16#bvSNVr!g_z7vF;s%Swwyn z7*^hqp?nrU*n7_5baNxsJON=#OSzu$8+&c+r>@#cdU5LFw5goNH+J%J=!An2Th)0yp^(m| zSvASe;X=24iokR!fd6>FpMT85q;^3@z5I%c118neTP9ao8#pe>JRk-O3kz#&V{%yR z4%(o~6X0GM%*N$|9db7=D&-I(yZNkx{1PD@@qIRp(@KrzKOqC6nIqX&0&}T6P7+Dt zB{86AM@%4~ltI9I2=plRqsV^1-Vt&|@3BCe(&$IOaWlM$*?du#O+z^!9k#B0p_r6D z0_zOCC2r|8-IFgY*w#0{LR6_qOy)Wblbbf%kCX|grKMi)4?6w$^sLNj?TJ9M-@B^f zyO@-&>Mq8iOO@$=JEOqo7Z*LEOIQC)CM%}8IYw>Jxlj=%LUWyCQsE2i&rjCx* zdF#ZAU*xkzZ~--4CEIKHQvU)$8Rl-OqWt{)PKvdKutjpmehnW@0PgbMi(h$Q-sGd= zUwMA+Ij8puR-1JSMN{F*euyRBY-H$LFV8i0cs{c526kh8ZcaX|N3`(h*-BY;7!66% zV_qy)5vg|3%pAW&w^5l!&w<{-_CjLVKlt9X=8aNf_mZa z8Qo-^IZZ96zITT0HYpBaS{k;As9V8+L|{ezC-BxlAFdDYfT#Gx+TL2;==zlNXuLq= zu(QbD1pe`2j|swW;|vGbr}^jAGVz9qf<+Q!Lv*(B-$4q@e{<8SWW6wE?!dxRzCX{1 zx;FdMn@IR#2O)A0V}5%c1cvi+vA?mQKYu=h2zkzZ+Yq?BLOg8${Qx@wguySaueNUz zBF_cyRp9(JvjBGM0|%T$gsQ^0oH}l&@Q4!mWFeFd4lUXlChZN03ah@%YtbtMRf;3#(Rk2iy6sv z-+|TFv<pkzwSARW|bu|D>>xXw;MaQ1n>y`^jE*hs5`ujyNk%X z7fw?ggF3ssj{5k`I~^$|b_>W&E$(`}@STKQdhmKI$_)7E_#{2tK!f)2aim-t2|2!Q zhBkRb7;BWyW7gVyej32FZ(?VTJQrZC!2Wl>pzxB-A3~NwQawTNz=r@9hpg7Vz%*H* z#5G-{5o{QKd%*19 zW&B3+2k>*B(LM9iS7dr+0Z1!L%2*F+s}8-kjm!C9ivX+FGnM1Yo|*aUasgCpAN|=a z7#<#;hK2^CwzjrPTZvAIaT#p*9wqM!h2{2RE6d1u1kf=yYW`P|etv#| zp}b0Tv;-9?8z)5~lB?6ys>5uP$}*Uh3w`%vSvW=>dyk?+o7I|KIKkH<@Ui~-@ZkDh za&UKBK|w*x?Cf)(pb{Q>M@;zq`gz11-ps|&*thxsZBR}Ygxb{1+(;0x zO+`!}C{FnytC8A8apRo9w?{qzT`(J=>sf1b_JvGZ?je7?d3lfp8t+#>3cZBfILDutwQ#8T&BHTV(2ZzrwTllv0)8sVqi_WsdnT1TicJ& zpWy>vjD!cAif6-xeEM|_H`VF9L7j4nNOh~nWMLOs&(aWZ)Xbu}LLPGGDKC{VBeFBw zORGT8RuzBu-QNHe`v);SqScmj5S$uaBrzcWw7EQxX~zfa!FzXN46%Bu*&cu0sLnSm z-F$6B@}nbodS%(}AFxYL2%^Ri0@%uZFJ-fp=Vd8(wNr+NhpWDtIE)HNg}F5SpTQEg zi~_(=>42y+>vL~1gA9-Uo4B}PJyJ-uvL3naa#v8y7v|BMRBN-wH|3N3eW(p0)86<93?}R@NK~`S-w&hSv@6{CngLHCVU;w=YZr zfM@A?LCJ1X9LwjonxnMUst&O z$Ubn3K)@s#!*G_Nzb@|iFo97RwN$vax94cB^k~dwswtCCtMXRkg7kWHd k$6y7X7=-wH+kyX#jO(tl-I!AMmjMVoUHx3vIVCg!04X!gx&QzG literal 0 HcmV?d00001 diff --git a/vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v03.png b/vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v03.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd98046bb25e4dc8f589b9a9dd26aaa4e7e86ab GIT binary patch literal 23180 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 literal 0 HcmV?d00001 diff --git a/vignettes/MainSteps_Step2_v02.png b/vignettes/MainSteps_Step2_v02.png new file mode 100644 index 0000000000000000000000000000000000000000..1b89ee0fe42128995ddc15411cdcf8edd467041d GIT binary patch literal 54686 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 nXDK&%wf}ntex*#PY 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

32bh*lulFJ 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 M)a6U%9=-Vg0F`+gn*aa+ literal 0 HcmV?d00001 diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index dcffb7c89..a0f5622ab 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -110,12 +110,12 @@ This is an overview of genetic ancestry inference from cancer-derived molecular data: ```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference process.", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_v01.png") +knitr::include_graphics("MainSteps_v02.png") ``` The main steps are: -1. Format reference data from the 1000 Genomes (1KG) (optional) +1. Format reference data from the population reference dataset (optional) 2. Format cancer-derived data set starting from BAM files 3. Optimize ancestry inference parameters 4. Infer ancestry for the subjects of the external study @@ -129,11 +129,11 @@ in one command with the [wrapper](#wrapper) function.

-## Step 1 - Format reference data from the 1000 Genomes (optional) +## Step 1 - Format population reference dataset (optional) -```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from 1000 Genomes (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step1_v01.png") +```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from the population reference dataset (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_Step1_v02.png") ``` @@ -141,12 +141,12 @@ knitr::include_graphics("MainSteps_Step1_v01.png") At this step three important reference files are created: -- The 1KG GDS File -- The 1KG SNV Annotation GDS file -- The 1KG SNV Retained VCF file +- The population reference GDS File +- The population reference SNV Annotation GDS file +- The population reference SNV Retained VCF file Note that these pre-processed -files are available at: +files are available for 1000 Genomes (1KG), in hg38, at: [https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper](https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper) @@ -161,7 +161,7 @@ hg38 [@Lowy-Gallego2019a]. This section can be skipped if you choose to use the pre-processed files. -The execution of this step is explained in the [Formatting the information from 1000 Genomes (optional)](Create_1KG_GDS_file.html) +The execution of this step is explained in the [Formatting the information from the population reference dataset (optional)](Create_1KG_GDS_file.html) vignette.
@@ -172,34 +172,32 @@ Molecular profiles in a cancer-derived data set must be formatted following a series of sub-steps. ```{r graphStep2, echo=FALSE, fig.align="center", fig.cap="Step 2 - Formatting the information from an external study", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step2_v01.png") +knitr::include_graphics("MainSteps_Step2_v02.png") ```
These sub-steps are: -1. Create a directory containing the 3 reference files from 1KG +1. Create a directory containing the 3 reference files from the population reference 2. Make a SNP pileup file for each profile 3. Create an RDS file containing information about the profiles Note that a mapped BAM file is needed for each sample (step 2). The reference genome used for the mapping must be the same as the one used to generate the -1KG GDS file. The 1KG GDS file available for download ( -[https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper](https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper) -) is based on the hg38 genome build. +population reference GDS file.
### Sub-Step 2.1 Create a directory containing the 3 required reference files The 3 required reference files should be stored in the same directory. In the -example below, this directory is referred to as **path1KG**. +example below, this directory is referred to as **pathReference**. For more information on creating your own reference files, see the vignette -[Formatting the information from 1000 Genomes (optional)](Create_1KG_GDS_file.html). +[Formatting the information from the population reference dataset (optional)](Create_1KG_GDS_file.html).
@@ -207,22 +205,23 @@ see the vignette A file containing the read counts for the reference and alternative nucleotides at each SNP position present in the -reference **1KG GDS file** must be created for each profile. This file is -refereed as a **SNP pileup file**. +**population reference GDS File ** must be created for each profile. +This file is refereed as a **Profile SNP pileup file**. ```{r graphStep2SubStep2, echo=FALSE, fig.align="center", fig.cap="Generate a Profile SNP pileup file (1 file per profile)", out.width='100%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step2_SubStep2_SNP-Pileup_v02.png") +knitr::include_graphics("MainSteps_Step2_SubStep2_SNP-Pileup_v03.png") ``` The read counts can be extracted using different software such as Bioconductor [RSamtools](https://bioconductor.org/packages/release/bioc/html/Rsamtools.html) -package [@Morgan2023] and [snp-pileup](https://github.com/mskcc/facets/tree/master/inst/extcode), +package [@Morgan2023] and +[snp-pileup](https://github.com/mskcc/facets/tree/master/inst/extcode), which is associated to the facets package [@Shen2016] -The generic **SNP pileup file** format is coma separated and the +The generic **Profile SNP pileup file** format is coma separated and the mandatory columns are: * _Chromosome_: The name of the chromosome @@ -233,8 +232,9 @@ mandatory columns are: * _File1R_: The count for the reference nucleotide * _File1A_: The count for the alternative nucleotide -Beware that the starting position in the **1KG GDS file** is zero (like BED -files). The **SNP pileup file** should also start at position zero. +Beware that the starting position in the **population reference GDS File** is +zero (like BED files). The **Profile SNP pileup file** should also start +at position zero. Note that the name assigned to the **Profile SNP pileup file** has to correspond to the profile identifier (Name.ID) in the following analysis. @@ -243,7 +243,7 @@ associated to the "Sample.01" profile.
-### Sub-Step 2.3 Create a profile PED RDS file containing the information about the profiles +### Sub-Step 2.3 Create a Profile PED RDS file containing the information about the profiles An RDS file describing all the profiles to be analyzed is required. @@ -306,7 +306,7 @@ The final step can be run with a wrapper function that encapsulates multiple steps of the workflow. ```{r graphWrapper, echo=FALSE, fig.align="center", fig.cap="Final step - The wrapper function encapsulates multiple steps of the workflow.", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Wrapper_v01.png") +knitr::include_graphics("MainSteps_Wrapper_v02.png") ``` As a complement, the companion vignette @@ -321,10 +321,10 @@ the current profiles. The wrapper function, called _runExomeAncestry()_, requires 4 files as input: -- The **1KG GDS file** -- The **1KG SNV Annotation GDS file** -- The **Sample SNP pileup file** (one per sample present in the study) -- The **Sample PED RDS file** (one file with information for all samples in the study) +- The **population reference GDS file** +- The **population reference SNV Annotation GDS file** +- The **Profile SNP pileup file** (one per sample present in the study) +- The **Profile PED RDS file** (one file with information for all profiles in the study) A *data.frame* containing the general information about the study is also required. The *data.frame* must contain those 3 columns: @@ -353,15 +353,15 @@ ped <- readRDS(filePED) head(ped) ######################################################################### -## The 1KG GDS file and the 1KG SNV Annotation GDS file -## need to be located in the same directory -## Note that the 1KG GDS file used for this example is a +## The population reference GDS file and SNV Annotation GDS file +## need to be located in the same directory. +## Note that the population reference GDS file used for this example is a ## simplified version and CANNOT be used for any real analysis ######################################################################### -path1KG <- file.path(dataDir, "example", "gdsRef") +pathReference <- file.path(dataDir, "example", "gdsRef") -fileGDS <- file.path(path1KG, "ex1kg.gds") -fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +fileGDS <- file.path(pathReference, "ex1kg.gds") +fileAnnotGDS <- file.path(pathReference, "exAnnot1kg.gds") ######################################################################### ## The Sample SNP pileup files (one per sample) need @@ -393,12 +393,14 @@ studyDF <- data.frame(study.id="MYDATA", set.seed(3043) ######################################################################### -## Select the profiles from 1KG for the synthetic data. -## Here we select 2 profiles from 1KG for each subcontinental-level -## Normally, we use 30 profiles from 1KG for each +## Select the profiles from the population reference GDS file for +## the synthetic data. +## Here we select 2 profiles from the simplified 1KG GDS for each +## subcontinental-level. +## Normally, we use 30 profile for each ## subcontinental-level but it is too big for the example. ## The 1KG files in this example only have 6 profiles for each -## subcontinental-level (for demo purpose only) +## subcontinental-level (for demo purpose only). ######################################################################### gds1KG <- snpgdsOpen(fileGDS) dataRef <- select1KGPop(gds1KG, nbProfiles=2L) @@ -472,7 +474,7 @@ also created.
-# Pre-processed reference files are available +# Pre-processed reference files are available for 1000 Genomes (1KG) in hg38 Pre-processed files, such as the 1KG GDS file, are available at this address: From 5f94a4733d3d7b181c59e9d943a989096f80f706 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 21 Jun 2023 12:16:10 -0400 Subject: [PATCH 025/385] Remove old figures --- vignettes/MainSteps_Step1_v01.png | Bin 37466 -> 0 bytes .../MainSteps_Step2_SubStep2_SNP-Pileup_v02.png | Bin 21595 -> 0 bytes vignettes/MainSteps_Step2_v01.png | Bin 35992 -> 0 bytes vignettes/MainSteps_Step3_v01.png | Bin 35431 -> 0 bytes vignettes/MainSteps_Wrapper_v01.png | Bin 37510 -> 0 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 vignettes/MainSteps_Step1_v01.png delete mode 100644 vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v02.png delete mode 100644 vignettes/MainSteps_Step2_v01.png delete mode 100644 vignettes/MainSteps_Step3_v01.png delete mode 100644 vignettes/MainSteps_Wrapper_v01.png diff --git a/vignettes/MainSteps_Step1_v01.png b/vignettes/MainSteps_Step1_v01.png deleted file mode 100644 index dc47f16a344e96ba7f1e4e78cc8eb78d009f25b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37466 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 diff --git a/vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v02.png b/vignettes/MainSteps_Step2_SubStep2_SNP-Pileup_v02.png deleted file mode 100644 index 494b45024ee4c0e1b8012d80e98abc53e394db7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21595 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
jo_8Sq7@?O?T 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 From facb5ca1348e0ce5b7786d5ed4aab8f2757caadb Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 21 Jun 2023 12:16:57 -0400 Subject: [PATCH 026/385] Remove old figure --- vignettes/MainSteps_v01.png | Bin 34846 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 vignettes/MainSteps_v01.png diff --git a/vignettes/MainSteps_v01.png b/vignettes/MainSteps_v01.png deleted file mode 100644 index 0e20f15602892a0ec6ed787112afb94700cede85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34846 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 From 9ce53ef3324c7b83683a2ced392d8199abc092ed Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 21 Jun 2023 12:53:30 -0400 Subject: [PATCH 027/385] Update second vignette --- vignettes/Create_1KG_GDS_File.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/Create_1KG_GDS_File.Rmd b/vignettes/Create_1KG_GDS_File.Rmd index e5b3ae3d5..b26731a66 100644 --- a/vignettes/Create_1KG_GDS_File.Rmd +++ b/vignettes/Create_1KG_GDS_File.Rmd @@ -53,7 +53,7 @@ from cancer-derived molecular data: ```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from 1000 Genomes (optional)", out.width = '120%', results='asis'} -knitr::include_graphics("MainSteps_Step1_v01.png") +knitr::include_graphics("MainSteps_Step1_v02.png") ``` From e81611c497540e51ea0e6c655713a7d1e56d6a0e Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 21 Jun 2023 17:05:33 -0400 Subject: [PATCH 028/385] Update third vignette --- vignettes/Ancestry_Inference_Step_by_Step.Rmd | 12 ++++++------ vignettes/MainSteps_Step3_v02.png | Bin 0 -> 54865 bytes 2 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 vignettes/MainSteps_Step3_v02.png diff --git a/vignettes/Ancestry_Inference_Step_by_Step.Rmd b/vignettes/Ancestry_Inference_Step_by_Step.Rmd index 57a130b76..523bd20e2 100644 --- a/vignettes/Ancestry_Inference_Step_by_Step.Rmd +++ b/vignettes/Ancestry_Inference_Step_by_Step.Rmd @@ -42,7 +42,7 @@ This is an overview of genetic ancestry inference from cancer-derived molecular data: ```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference process.", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_v01.png") +knitr::include_graphics("MainSteps_v02.png") ``` The main steps are: @@ -66,8 +66,8 @@ Step 2, sub-step 4, to Step 4. ## Step 1 - Format reference data from the 1000 Genomes (optional) -```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from 1000 Genomes (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step1_v01.png") +```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from the population reference dataset (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_Step1_v02.png") ``` @@ -87,7 +87,7 @@ Molecular profiles in a cancer-derived data set must be formatted following a series of sub-steps. ```{r graphStep2, echo=FALSE, fig.align="center", fig.cap="Step 2 - Formatting the information from an external study", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step2_v01.png") +knitr::include_graphics("MainSteps_Step2_v02.png") ```
@@ -411,7 +411,7 @@ At this step, optimization of the parameters is required to maximize the the ancestry inference accuracy (next step). ```{r graphStep3, echo=FALSE, fig.align="center", fig.cap="Step 3 - Find the optimized parameters for the ancestry inference", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step3_v01.png") +knitr::include_graphics("MainSteps_Step3_v02.png") ``` Two inference parameters to be optimized: @@ -420,7 +420,7 @@ Two inference parameters to be optimized: - _D_: the number of PCA components retained The accuracy is evaluated using a synthetic data set created from merging one -cancer profile with multiple 1KG profiles of known ancestry. Using the +cancer profile with multiple population referecne profiles of known ancestry. Using the synthetic profiles, a range of _K_ and _D_ values are tested. Through that process, the _K_ and _D_ values are tuned to maximize accuracy. diff --git a/vignettes/MainSteps_Step3_v02.png b/vignettes/MainSteps_Step3_v02.png new file mode 100644 index 0000000000000000000000000000000000000000..4d061705d0ad507a7c8580bb20f21ce6b04be619 GIT binary patch literal 54865 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 Date: Thu, 22 Jun 2023 15:43:37 -0400 Subject: [PATCH 031/385] Remove old figure --- vignettes/MainSteps_v02.png | Bin 51294 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 vignettes/MainSteps_v02.png diff --git a/vignettes/MainSteps_v02.png b/vignettes/MainSteps_v02.png deleted file mode 100644 index 891b3dfe2d3055da53a4c30a428d7bf31a8253eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51294 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

32bh*lulFJ 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 M)a6U%9=-Vg0F`+gn*aa+ From 0bbdcfa11603881cb673a53bc794bd0ede897061 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 22 Jun 2023 16:32:54 -0400 Subject: [PATCH 032/385] Update main step 3 figure --- vignettes/Ancestry_Inference_Step_by_Step.Rmd | 2 +- vignettes/MainSteps_Step3_v02.png | Bin 54865 -> 0 bytes vignettes/MainSteps_Step3_v03.png | Bin 0 -> 55514 bytes 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 vignettes/MainSteps_Step3_v02.png create mode 100644 vignettes/MainSteps_Step3_v03.png diff --git a/vignettes/Ancestry_Inference_Step_by_Step.Rmd b/vignettes/Ancestry_Inference_Step_by_Step.Rmd index 710a265c9..2314d7b43 100644 --- a/vignettes/Ancestry_Inference_Step_by_Step.Rmd +++ b/vignettes/Ancestry_Inference_Step_by_Step.Rmd @@ -653,7 +653,7 @@ number of neighbors used for the classification. ```{r graphStep4, echo=FALSE, fig.align="center", fig.cap="Step 4 - Run the ancestry inference on the external study", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step4_v01.png") +knitr::include_graphics("MainSteps_Step4_v02.png") ```
diff --git a/vignettes/MainSteps_Step3_v02.png b/vignettes/MainSteps_Step3_v02.png deleted file mode 100644 index 4d061705d0ad507a7c8580bb20f21ce6b04be619..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54865 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

BA<GgCMmts0!B=_R0Ca*jg=M9YF346nIo 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 diff --git a/vignettes/MainSteps_Step3_v03.png b/vignettes/MainSteps_Step3_v03.png new file mode 100644 index 0000000000000000000000000000000000000000..b0fd6e2e4f0238f6f6d48e253a96e2f8b0f511b9 GIT binary patch literal 55514 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 literal 0 HcmV?d00001 From 1358b25e24085f4ad6d620a31efebd6a36a2fe41 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 22 Jun 2023 16:45:31 -0400 Subject: [PATCH 033/385] Update figure step 4 in vignette --- vignettes/MainSteps_Step4_v01.png | Bin 35211 -> 0 bytes vignettes/MainSteps_Step4_v02.png | Bin 0 -> 54409 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 vignettes/MainSteps_Step4_v01.png create mode 100644 vignettes/MainSteps_Step4_v02.png diff --git a/vignettes/MainSteps_Step4_v01.png b/vignettes/MainSteps_Step4_v01.png deleted file mode 100644 index e1958a4097e8b2092229af93f156f863ad59b027..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35211 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 Date: Thu, 22 Jun 2023 17:01:04 -0400 Subject: [PATCH 034/385] Update wrapper figure in vignette --- vignettes/MainSteps_Wrapper_v02.png | Bin 58039 -> 0 bytes vignettes/MainSteps_Wrapper_v03.png | Bin 0 -> 58841 bytes vignettes/RAIDS.Rmd | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 vignettes/MainSteps_Wrapper_v02.png create mode 100644 vignettes/MainSteps_Wrapper_v03.png diff --git a/vignettes/MainSteps_Wrapper_v02.png b/vignettes/MainSteps_Wrapper_v02.png deleted file mode 100644 index f6e395bd199d9e2da44a3017271a9ab1c9422cca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58039 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

}(4B#cHV3^+1s=igXdI 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 z�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ô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 w-!Xc^x7LZE7LR;i4{ktRtH#UyFNB$N&HU literal 0 HcmV?d00001 diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 0a627c718..504ea23d1 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -306,7 +306,7 @@ The final step can be run with a wrapper function that encapsulates multiple steps of the workflow. ```{r graphWrapper, echo=FALSE, fig.align="center", fig.cap="Final step - The wrapper function encapsulates multiple steps of the workflow.", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Wrapper_v02.png") +knitr::include_graphics("MainSteps_Wrapper_v03.png") ``` As a complement, the companion vignette From 4b15eda88e24cb1559b013810a6e27fd7efa2aea Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 22 Jun 2023 17:17:58 -0400 Subject: [PATCH 035/385] Update vignette --- vignettes/Ancestry_Inference_Step_by_Step.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/Ancestry_Inference_Step_by_Step.Rmd b/vignettes/Ancestry_Inference_Step_by_Step.Rmd index 2314d7b43..7920f2bae 100644 --- a/vignettes/Ancestry_Inference_Step_by_Step.Rmd +++ b/vignettes/Ancestry_Inference_Step_by_Step.Rmd @@ -411,7 +411,7 @@ At this step, optimization of the parameters is required to maximize the the ancestry inference accuracy (next step). ```{r graphStep3, echo=FALSE, fig.align="center", fig.cap="Step 3 - Find the optimized parameters for the ancestry inference", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step3_v02.png") +knitr::include_graphics("MainSteps_Step3_v03.png") ``` Two inference parameters to be optimized: From 43695c2ed64311fef058fb8186b5f502c0c3ff35 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 27 Jun 2023 16:43:19 -0400 Subject: [PATCH 036/385] Update example in generateMapSnvSel() function to be able to run with and without withr library --- R/process1KG.R | 65 ++++++++++++++++++++++++++-------------- man/generateMapSnvSel.Rd | 55 +++++++++++++++++++++++----------- 2 files changed, 81 insertions(+), 39 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index eb7742ae7..0a9862d57 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -155,28 +155,49 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' #' @examples #' -#' ## Needed package -#' library(withr) -#' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") -#' -#' ## Demo SNV information file used as input -#' snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") -#' -#' ## Temporary output files -#' ## The first file contains the indexes of the retained SNPs -#' ## The second file contains the filtered SNP information -#' snpIndexFile <- local_file(file.path(dataDir, "listSNP_TEMP.rds")) -#' filterSNVFile <- local_file(file.path(dataDir, "mapSNVSel_TEMP.rds")) -#' -#' ## Create a data.frame containing the information of the retained -#' ## samples (samples with existing genotyping files) -#' generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, -#' fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) -#' -#' ## Remove temporary files -#' deferred_run() +#' ## Only execute code if withr package is available +#' if (requireNamespace("withr", quietly = TRUE)) { +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## Demo SNV information file used as input +#' snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") +#' +#' ## Temporary output files +#' ## The first file contains the indexes of the retained SNPs +#' ## The second file contains the filtered SNP information +#' snpIndexFile <- local_file(file.path(dataDir, "listSNP_TEMP.rds")) +#' filterSNVFile <- local_file(file.path(dataDir, "mapSNVSel_TEMP.rds")) +#' +#' ## Create a data.frame containing the information of the retained +#' ## samples (samples with existing genotyping files) +#' generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, +#' fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) +#' +#' ## Remove temporary files +#' deferred_run() +#' } else { +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## Demo SNV information file used as input +#' snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") +#' +#' ## Temporary output files +#' ## The first file contains the indexes of the retained SNPs +#' ## The second file contains the filtered SNP information +#' snpIndexFile <- local_file(file.path(dataDir, "listSNP_TEMP.rds")) +#' filterSNVFile <- local_file(file.path(dataDir, "mapSNVSel_TEMP.rds")) +#' +#' ## Create a data.frame containing the information of the retained +#' ## samples (samples with existing genotyping files) +#' generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, +#' fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) +#' +#' ## Remove temporary files +#' unlink(snpIndexFile, force=TRUE) +#' unlink(filterSNVFile, force=TRUE) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom S4Vectors isSingleNumber diff --git a/man/generateMapSnvSel.Rd b/man/generateMapSnvSel.Rd index 2ff5932d0..eabf355c9 100644 --- a/man/generateMapSnvSel.Rd +++ b/man/generateMapSnvSel.Rd @@ -57,28 +57,49 @@ of the SAS super population.} } \examples{ -## Needed package -library(withr) +## Only execute code if withr package is available +if (requireNamespace("withr", quietly = TRUE)) { + ## Path to the demo pedigree file is located in this package + dataDir <- system.file("extdata", package="RAIDS") -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", package="RAIDS") + ## Demo SNV information file used as input + snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") -## Demo SNV information file used as input -snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") + ## Temporary output files + ## The first file contains the indexes of the retained SNPs + ## The second file contains the filtered SNP information + snpIndexFile <- local_file(file.path(dataDir, "listSNP_TEMP.rds")) + filterSNVFile <- local_file(file.path(dataDir, "mapSNVSel_TEMP.rds")) -## Temporary output files -## The first file contains the indexes of the retained SNPs -## The second file contains the filtered SNP information -snpIndexFile <- local_file(file.path(dataDir, "listSNP_TEMP.rds")) -filterSNVFile <- local_file(file.path(dataDir, "mapSNVSel_TEMP.rds")) + ## Create a data.frame containing the information of the retained + ## samples (samples with existing genotyping files) + generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, + fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) -## Create a data.frame containing the information of the retained -## samples (samples with existing genotyping files) -generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, - fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) + ## Remove temporary files + deferred_run() +} else { + ## Path to the demo pedigree file is located in this package + dataDir <- system.file("extdata", package="RAIDS") -## Remove temporary files -deferred_run() + ## Demo SNV information file used as input + snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") + + ## Temporary output files + ## The first file contains the indexes of the retained SNPs + ## The second file contains the filtered SNP information + snpIndexFile <- local_file(file.path(dataDir, "listSNP_TEMP.rds")) + filterSNVFile <- local_file(file.path(dataDir, "mapSNVSel_TEMP.rds")) + + ## Create a data.frame containing the information of the retained + ## samples (samples with existing genotyping files) + generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, + fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) + + ## Remove temporary files + unlink(snpIndexFile, force=TRUE) + unlink(filterSNVFile, force=TRUE) +} } \author{ From 58484678d2c0361585b6d95b16376ca2d9e7697e Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 27 Jun 2023 16:44:25 -0400 Subject: [PATCH 037/385] Update example in generateMapSnvSel() function to be able to run with and without withr library --- R/process1KG.R | 2 +- man/generateMapSnvSel.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index 0a9862d57..ecffd523b 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -155,7 +155,7 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' #' @examples #' -#' ## Only execute code if withr package is available +#' ## Differnt code depending of the withr package availability #' if (requireNamespace("withr", quietly = TRUE)) { #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") diff --git a/man/generateMapSnvSel.Rd b/man/generateMapSnvSel.Rd index eabf355c9..96f95e12d 100644 --- a/man/generateMapSnvSel.Rd +++ b/man/generateMapSnvSel.Rd @@ -57,7 +57,7 @@ of the SAS super population.} } \examples{ -## Only execute code if withr package is available +## Differnt code depending of the withr package availability if (requireNamespace("withr", quietly = TRUE)) { ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") From 9f64147b1af5906662c3750e5164721fa946fe07 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 27 Jun 2023 16:45:37 -0400 Subject: [PATCH 038/385] Update example in generateMapSnvSel() function to be able to run with and without withr library --- R/process1KG.R | 2 +- man/generateMapSnvSel.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index ecffd523b..df976a205 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -155,7 +155,7 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' #' @examples #' -#' ## Differnt code depending of the withr package availability +#' ## Different code depending of the withr package availability #' if (requireNamespace("withr", quietly = TRUE)) { #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") diff --git a/man/generateMapSnvSel.Rd b/man/generateMapSnvSel.Rd index 96f95e12d..080138ac6 100644 --- a/man/generateMapSnvSel.Rd +++ b/man/generateMapSnvSel.Rd @@ -57,7 +57,7 @@ of the SAS super population.} } \examples{ -## Differnt code depending of the withr package availability +## Different code depending of the withr package availability if (requireNamespace("withr", quietly = TRUE)) { ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") From 663bffc9449e5224aaad0e7b3ad495bda7039044 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 27 Jun 2023 16:49:41 -0400 Subject: [PATCH 039/385] Update example in generateMapSnvSel() function to be able to run with and without withr library --- R/process1KG.R | 12 +++++++----- man/generateMapSnvSel.Rd | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index df976a205..eac1e1054 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -166,8 +166,10 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' ## Temporary output files #' ## The first file contains the indexes of the retained SNPs #' ## The second file contains the filtered SNP information -#' snpIndexFile <- local_file(file.path(dataDir, "listSNP_TEMP.rds")) -#' filterSNVFile <- local_file(file.path(dataDir, "mapSNVSel_TEMP.rds")) +#' snpIndexFile <- withr::local_file(file.path(dataDir, +#' "listSNP_TEMP.rds")) +#' filterSNVFile <- withr::local_file(file.path(dataDir, +#' "mapSNVSel_TEMP.rds")) #' #' ## Create a data.frame containing the information of the retained #' ## samples (samples with existing genotyping files) @@ -175,7 +177,7 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) #' #' ## Remove temporary files -#' deferred_run() +#' withr::deferred_run() #' } else { #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") @@ -186,8 +188,8 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' ## Temporary output files #' ## The first file contains the indexes of the retained SNPs #' ## The second file contains the filtered SNP information -#' snpIndexFile <- local_file(file.path(dataDir, "listSNP_TEMP.rds")) -#' filterSNVFile <- local_file(file.path(dataDir, "mapSNVSel_TEMP.rds")) +#' snpIndexFile <- file.path(dataDir, "listSNP_TEMP.rds") +#' filterSNVFile <- file.path(dataDir, "mapSNVSel_TEMP.rds") #' #' ## Create a data.frame containing the information of the retained #' ## samples (samples with existing genotyping files) diff --git a/man/generateMapSnvSel.Rd b/man/generateMapSnvSel.Rd index 080138ac6..3714fe93d 100644 --- a/man/generateMapSnvSel.Rd +++ b/man/generateMapSnvSel.Rd @@ -68,8 +68,10 @@ if (requireNamespace("withr", quietly = TRUE)) { ## Temporary output files ## The first file contains the indexes of the retained SNPs ## The second file contains the filtered SNP information - snpIndexFile <- local_file(file.path(dataDir, "listSNP_TEMP.rds")) - filterSNVFile <- local_file(file.path(dataDir, "mapSNVSel_TEMP.rds")) + snpIndexFile <- withr::local_file(file.path(dataDir, + "listSNP_TEMP.rds")) + filterSNVFile <- withr::local_file(file.path(dataDir, + "mapSNVSel_TEMP.rds")) ## Create a data.frame containing the information of the retained ## samples (samples with existing genotyping files) @@ -77,7 +79,7 @@ if (requireNamespace("withr", quietly = TRUE)) { fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) ## Remove temporary files - deferred_run() + withr::deferred_run() } else { ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") @@ -88,8 +90,8 @@ if (requireNamespace("withr", quietly = TRUE)) { ## Temporary output files ## The first file contains the indexes of the retained SNPs ## The second file contains the filtered SNP information - snpIndexFile <- local_file(file.path(dataDir, "listSNP_TEMP.rds")) - filterSNVFile <- local_file(file.path(dataDir, "mapSNVSel_TEMP.rds")) + snpIndexFile <- file.path(dataDir, "listSNP_TEMP.rds") + filterSNVFile <- file.path(dataDir, "mapSNVSel_TEMP.rds") ## Create a data.frame containing the information of the retained ## samples (samples with existing genotyping files) From 6db8e71d17c88b72085c45883b2cb8bb87e84403 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 27 Jun 2023 17:22:04 -0400 Subject: [PATCH 040/385] Update example in generateGDS1KG() function to be able to run with and without withr library --- R/process1KG.R | 37 ++++++++++++++++++++++++++----------- man/generateGDS1KG.Rd | 37 ++++++++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index eac1e1054..631378908 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -295,9 +295,6 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { #' #' @examples #' -#' ## Required package -#' library(withr) -#' #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' @@ -310,16 +307,34 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { #' ## The RDS file containing the filtered SNP information #' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' -#' ## Temporary GDS file containing 1KG information -#' gdsFile <- local_file(file.path(dataDir, "1KG_TEMP.gds")) +#' ## Different code depending of the withr package availability +#' if (requireNamespace("withr", quietly = TRUE)) { +#' +#' ## Temporary GDS file containing 1KG information +#' gdsFile <- withr::local_file(file.path(dataDir, "1KG_TEMP.gds")) #' -#' ## Create a temporary GDS file containing information from 1KG -#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, -#' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, -#' fileNameGDS=gdsFile, listSamples=NULL) +#' ## Create a temporary GDS file containing information from 1KG +#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +#' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, +#' fileNameGDS=gdsFile, listSamples=NULL) #' -#' ## Remove temporary files -#' deferred_run() +#' ## Remove temporary files +#' withr::deferred_run() +#' +#' } else { +#' +#' ## Temporary GDS file containing 1KG information +#' gdsFile <- file.path(dataDir, "1KG_TEMP.gds") +#' +#' ## Create a temporary GDS file containing information from 1KG +#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +#' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, +#' fileNameGDS=gdsFile, listSamples=NULL) +#' +#' ## Remove temporary files +#' unlink(gdsFile) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' diff --git a/man/generateGDS1KG.Rd b/man/generateGDS1KG.Rd index eba1b9cd2..3cf2275c2 100644 --- a/man/generateGDS1KG.Rd +++ b/man/generateGDS1KG.Rd @@ -64,9 +64,6 @@ https://bioconductor.org/packages/gdsfmt/ } \examples{ -## Required package -library(withr) - ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") @@ -79,16 +76,34 @@ snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") ## The RDS file containing the filtered SNP information filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") -## Temporary GDS file containing 1KG information -gdsFile <- local_file(file.path(dataDir, "1KG_TEMP.gds")) +## Different code depending of the withr package availability +if (requireNamespace("withr", quietly = TRUE)) { + + ## Temporary GDS file containing 1KG information + gdsFile <- withr::local_file(file.path(dataDir, "1KG_TEMP.gds")) + + ## Create a temporary GDS file containing information from 1KG + generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, + fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, + fileNameGDS=gdsFile, listSamples=NULL) + + ## Remove temporary files + withr::deferred_run() -## Create a temporary GDS file containing information from 1KG -generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, - fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, - fileNameGDS=gdsFile, listSamples=NULL) +} else { -## Remove temporary files -deferred_run() + ## Temporary GDS file containing 1KG information + gdsFile <- file.path(dataDir, "1KG_TEMP.gds") + + ## Create a temporary GDS file containing information from 1KG + generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, + fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, + fileNameGDS=gdsFile, listSamples=NULL) + + ## Remove temporary files + unlink(gdsFile) + +} } \author{ From dacb8b0e7c61342957416cc88d2a5d170aa43666 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 27 Jun 2023 18:34:59 -0400 Subject: [PATCH 041/385] Update example in generateGDSSNPinfo() function to be able to run with and without withr library --- R/gdsWrapper.R | 30 ++++++++++++++++++++++++------ man/generateGDSSNPinfo.Rd | 30 ++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index db7862b6f..de70e4cb0 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -77,18 +77,19 @@ appendGDSSampleOnly <- function(gds, listSamples) { #' ## Required package #' library(gdsfmt) #' -#' ## Only execute code if withr package is available +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## The RDS file containing the filtered SNP information +#' fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") +#' +#' ## Different code depending of the withr package availability #' if (requireNamespace("withr", quietly = TRUE)) { -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") #' #' ## Temporary Reference GDS file #' file1KG <- withr::local_file("1KG_TEMP_002.gds") #' filenewGDS <- createfn.gds(file1KG) #' -#' ## The RDS file containing the filtered SNP information -#' fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") -#' #' ## Add SNV information to Reference GDS #' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, #' fileFREQ=fileFilerterSNVs, verbose=TRUE) @@ -98,6 +99,23 @@ appendGDSSampleOnly <- function(gds, listSamples) { #' #' ## Remove temporary 1KG_TEMP_002.gds file #' withr::deferred_run() +#' +#' } else { +#' +#' ## Temporary Reference GDS file +#' file1KG <- file.path("1KG_TEMP_002.gds") +#' filenewGDS <- createfn.gds(file1KG) +#' +#' ## Add SNV information to Reference GDS +#' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, +#' fileFREQ=fileFilerterSNVs, verbose=TRUE) +#' +#' ## Close GDS file (important) +#' closefn.gds(filenewGDS) +#' +#' ## Remove temporary 1KG_TEMP_002.gds file +#' unlink(file1KG) +#' #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/man/generateGDSSNPinfo.Rd b/man/generateGDSSNPinfo.Rd index d3b0829b5..6139ba8f0 100644 --- a/man/generateGDSSNPinfo.Rd +++ b/man/generateGDSSNPinfo.Rd @@ -29,18 +29,19 @@ GDS file. ## Required package library(gdsfmt) -## Only execute code if withr package is available +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +## The RDS file containing the filtered SNP information +fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") + +## Different code depending of the withr package availability if (requireNamespace("withr", quietly = TRUE)) { - ## Path to the demo pedigree file is located in this package - dataDir <- system.file("extdata", package="RAIDS") ## Temporary Reference GDS file file1KG <- withr::local_file("1KG_TEMP_002.gds") filenewGDS <- createfn.gds(file1KG) - ## The RDS file containing the filtered SNP information - fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") - ## Add SNV information to Reference GDS RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, fileFREQ=fileFilerterSNVs, verbose=TRUE) @@ -50,6 +51,23 @@ if (requireNamespace("withr", quietly = TRUE)) { ## Remove temporary 1KG_TEMP_002.gds file withr::deferred_run() + +} else { + + ## Temporary Reference GDS file + file1KG <- file.path("1KG_TEMP_002.gds") + filenewGDS <- createfn.gds(file1KG) + + ## Add SNV information to Reference GDS + RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, + fileFREQ=fileFilerterSNVs, verbose=TRUE) + + ## Close GDS file (important) + closefn.gds(filenewGDS) + + ## Remove temporary 1KG_TEMP_002.gds file + unlink(file1KG) + } } From aa0205a479d460cc95305b687f8a924383c11c7a Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 27 Jun 2023 19:16:24 -0400 Subject: [PATCH 042/385] Update generateMapSnvSel() example --- R/process1KG.R | 17 +++++++---------- man/generateMapSnvSel.Rd | 17 +++++++---------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index 631378908..0e673b1e4 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -155,13 +155,14 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' #' @examples #' +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## Demo SNV information file used as input +#' snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") +#' #' ## Different code depending of the withr package availability #' if (requireNamespace("withr", quietly = TRUE)) { -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") -#' -#' ## Demo SNV information file used as input -#' snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") #' #' ## Temporary output files #' ## The first file contains the indexes of the retained SNPs @@ -178,12 +179,8 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' #' ## Remove temporary files #' withr::deferred_run() -#' } else { -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") #' -#' ## Demo SNV information file used as input -#' snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") +#' } else { #' #' ## Temporary output files #' ## The first file contains the indexes of the retained SNPs diff --git a/man/generateMapSnvSel.Rd b/man/generateMapSnvSel.Rd index 3714fe93d..4f93537de 100644 --- a/man/generateMapSnvSel.Rd +++ b/man/generateMapSnvSel.Rd @@ -57,13 +57,14 @@ of the SAS super population.} } \examples{ +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +## Demo SNV information file used as input +snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") + ## Different code depending of the withr package availability if (requireNamespace("withr", quietly = TRUE)) { - ## Path to the demo pedigree file is located in this package - dataDir <- system.file("extdata", package="RAIDS") - - ## Demo SNV information file used as input - snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") ## Temporary output files ## The first file contains the indexes of the retained SNPs @@ -80,12 +81,8 @@ if (requireNamespace("withr", quietly = TRUE)) { ## Remove temporary files withr::deferred_run() -} else { - ## Path to the demo pedigree file is located in this package - dataDir <- system.file("extdata", package="RAIDS") - ## Demo SNV information file used as input - snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") +} else { ## Temporary output files ## The first file contains the indexes of the retained SNPs From 4d623bcc11c7fca295da3675962ff10cc4120b42 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 28 Jun 2023 13:44:37 -0400 Subject: [PATCH 043/385] Update examples in 2 functions --- R/process1KG.R | 54 ++++++++++++++++++++++++++----------- man/generatePhase1KG2GDS.Rd | 12 ++++----- man/identifyRelative.Rd | 42 ++++++++++++++++++++++------- 3 files changed, 76 insertions(+), 32 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index 0e673b1e4..e9113909d 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -406,7 +406,7 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' @examples #' #' ## Required package -#' library(withr) +#' library(gdsfmt) #' #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") @@ -421,7 +421,7 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' #' ## Temporary Reference GDS file containing 1KG information -#' fileReferenceGDS <- local_file(file.path(dataDir, "1KG_TEMP_02.gds")) +#' fileReferenceGDS <- "1KG_TEMP_02.gds" #' #' ## Create a temporary Reference GDS file containing information from 1KG #' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, @@ -429,7 +429,7 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' fileNameGDS=fileReferenceGDS, listSamples=NULL) #' #' ## Temporary Phase GDS file that will contain the 1KG Phase information -#' fileRefPhaseGDS <- local_file(file.path(dataDir, "1KG_TEMP_Phase_02.gds")) +#' fileRefPhaseGDS <- "1KG_TEMP_Phase_02.gds" #' #' ## Create Reference Phase GDS file #' gdsPhase <- createfn.gds(fileRefPhaseGDS) @@ -437,11 +437,9 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' ## Open Reference GDS file #' gdsRef <- openfn.gds(fileReferenceGDS) #' -#' \dontrun{ #' ## Fill temporary Reference Phase GDS file #' generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, #' pathGeno=dataDir, fileSNPsRDS=filterSNVFile, verbose=FALSE) -#' } #' #' ## Close 1KG Phase information file #' closefn.gds(gdsPhase) @@ -450,7 +448,9 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' closefn.gds(gdsRef) #' #' ## Remove temporary files -#' deferred_run() +#' unlink(fileReferenceGDS, force=TRUE) +#' unlink(fileRefPhaseGDS, force=TRUE) +#' #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn readmode.gdsn @@ -546,20 +546,42 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, #' ## Temporary output files #' ## The first RDS file will contain the list of unrelated patients #' ## The second RDS file will contain the kinship information between patients -#' patientTmpFile <- local_file(file.path(dataDir, -#' "unrelatedPatients_TEMP.rds")) -#' ibdTmpFile <- local_file(file.path(dataDir,"ibd_TEMP.rds")) +#' patientTmpFile <- "unrelatedPatients_TEMP.rds" +#' ibdTmpFile <- "ibd_TEMP.rds" #' -#' ## Identify unrelated patients in 1KG GDS file -#' identifyRelative(gds=tmpGDS, maf=0.05, thresh=2^(-11/2), -#' fileIBD=ibdTmpFile, filePart=patientTmpFile) +#' ## Different code depending of the withr package availability +#' if (requireNamespace("withr", quietly = TRUE)) { #' -#' ## Close 1K GDS file -#' closefn.gds(tmpGDS) +#' ## Temporary output files +#' ## The first RDS file will contain the list of unrelated patients +#' ## The second RDS file will contain the kinship information +#' ## between patients +#' patientTmpFileLocal <- withr::local_file(patientTmpFile) +#' ibdTmpFileLocal <- withr::local_file(ibdTmpFile) #' -#' ## Remove temporary files -#' deferred_run() +#' ## Identify unrelated patients in 1KG GDS file +#' identifyRelative(gds=tmpGDS, maf=0.05, thresh=2^(-11/2), +#' fileIBD=ibdTmpFileLocal, filePart=patientTmpFileLocal) #' +#' ## Close 1K GDS file +#' closefn.gds(tmpGDS) +#' +#' ## Remove temporary files +#' withr::deferred_run() +#' +#' } else { +#' +#' ## Identify unrelated patients in 1KG GDS file +#' identifyRelative(gds=tmpGDS, maf=0.05, thresh=2^(-11/2), +#' fileIBD=ibdTmpFile, filePart=patientTmpFile) +#' +#' ## Close 1K GDS file +#' closefn.gds(tmpGDS) +#' +#' ## Remove temporary files +#' unlink(patientTmpFile, force=TRUE) +#' unlink(ibdTmpFile, force=TRUE) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' diff --git a/man/generatePhase1KG2GDS.Rd b/man/generatePhase1KG2GDS.Rd index dec5438ed..942effece 100644 --- a/man/generatePhase1KG2GDS.Rd +++ b/man/generatePhase1KG2GDS.Rd @@ -45,7 +45,7 @@ GDS file and is added into a Reference Phase GDS file. An entry called \examples{ ## Required package -library(withr) +library(gdsfmt) ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") @@ -60,7 +60,7 @@ snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") ## Temporary Reference GDS file containing 1KG information -fileReferenceGDS <- local_file(file.path(dataDir, "1KG_TEMP_02.gds")) +fileReferenceGDS <- "1KG_TEMP_02.gds" ## Create a temporary Reference GDS file containing information from 1KG generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, @@ -68,7 +68,7 @@ generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, fileNameGDS=fileReferenceGDS, listSamples=NULL) ## Temporary Phase GDS file that will contain the 1KG Phase information -fileRefPhaseGDS <- local_file(file.path(dataDir, "1KG_TEMP_Phase_02.gds")) +fileRefPhaseGDS <- "1KG_TEMP_Phase_02.gds" ## Create Reference Phase GDS file gdsPhase <- createfn.gds(fileRefPhaseGDS) @@ -76,11 +76,9 @@ gdsPhase <- createfn.gds(fileRefPhaseGDS) ## Open Reference GDS file gdsRef <- openfn.gds(fileReferenceGDS) -\dontrun{ ## Fill temporary Reference Phase GDS file generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, pathGeno=dataDir, fileSNPsRDS=filterSNVFile, verbose=FALSE) -} ## Close 1KG Phase information file closefn.gds(gdsPhase) @@ -89,7 +87,9 @@ closefn.gds(gdsPhase) closefn.gds(gdsRef) ## Remove temporary files -deferred_run() +unlink(fileReferenceGDS, force=TRUE) +unlink(fileRefPhaseGDS, force=TRUE) + } \author{ diff --git a/man/identifyRelative.Rd b/man/identifyRelative.Rd index be12f2791..8bea9b944 100644 --- a/man/identifyRelative.Rd +++ b/man/identifyRelative.Rd @@ -57,20 +57,42 @@ tmpGDS <- snpgdsOpen(fileGDS) ## Temporary output files ## The first RDS file will contain the list of unrelated patients ## The second RDS file will contain the kinship information between patients -patientTmpFile <- local_file(file.path(dataDir, - "unrelatedPatients_TEMP.rds")) -ibdTmpFile <- local_file(file.path(dataDir,"ibd_TEMP.rds")) +patientTmpFile <- "unrelatedPatients_TEMP.rds" +ibdTmpFile <- "ibd_TEMP.rds" -## Identify unrelated patients in 1KG GDS file -identifyRelative(gds=tmpGDS, maf=0.05, thresh=2^(-11/2), - fileIBD=ibdTmpFile, filePart=patientTmpFile) +## Different code depending of the withr package availability +if (requireNamespace("withr", quietly = TRUE)) { -## Close 1K GDS file -closefn.gds(tmpGDS) + ## Temporary output files + ## The first RDS file will contain the list of unrelated patients + ## The second RDS file will contain the kinship information + ## between patients + patientTmpFileLocal <- withr::local_file(patientTmpFile) + ibdTmpFileLocal <- withr::local_file(ibdTmpFile) -## Remove temporary files -deferred_run() + ## Identify unrelated patients in 1KG GDS file + identifyRelative(gds=tmpGDS, maf=0.05, thresh=2^(-11/2), + fileIBD=ibdTmpFileLocal, filePart=patientTmpFileLocal) + ## Close 1K GDS file + closefn.gds(tmpGDS) + + ## Remove temporary files + withr::deferred_run() + +} else { + + ## Identify unrelated patients in 1KG GDS file + identifyRelative(gds=tmpGDS, maf=0.05, thresh=2^(-11/2), + fileIBD=ibdTmpFile, filePart=patientTmpFile) + + ## Close 1K GDS file + closefn.gds(tmpGDS) + + ## Remove temporary files + unlink(patientTmpFile, force=TRUE) + unlink(ibdTmpFile, force=TRUE) +} } \author{ From 09b1c0c5f85dd8ebffc26487934ea10cf5f9cd5f Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 28 Jun 2023 13:46:09 -0400 Subject: [PATCH 044/385] Remove withr from identifyRelative() example --- R/process1KG.R | 3 +-- man/identifyRelative.Rd | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index e9113909d..e7610290c 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -532,8 +532,7 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, #' #' @examples #' -#' ## Needed packages -#' library(withr) +#' ## Required package #' library(gdsfmt) #' #' ## Path to the demo pedigree file is located in this package diff --git a/man/identifyRelative.Rd b/man/identifyRelative.Rd index 8bea9b944..b074a31ca 100644 --- a/man/identifyRelative.Rd +++ b/man/identifyRelative.Rd @@ -43,8 +43,7 @@ between the patients. } \examples{ -## Needed packages -library(withr) +## Required package library(gdsfmt) ## Path to the demo pedigree file is located in this package From 0dba6a9e8bd38a7853d8554123a0fd8bbbf18940 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 29 Jun 2023 16:13:19 -0400 Subject: [PATCH 045/385] Update example in generatePhase1KG2GDS() function --- R/process1KG.R | 6 +++-- man/generatePhase1KG2GDS.Rd | 50 ------------------------------------- 2 files changed, 4 insertions(+), 52 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index e7610290c..e1ebc45b6 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -438,8 +438,10 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' gdsRef <- openfn.gds(fileReferenceGDS) #' #' ## Fill temporary Reference Phase GDS file -#' generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, -#' pathGeno=dataDir, fileSNPsRDS=filterSNVFile, verbose=FALSE) +#' if (FALSE) { +#' generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, +#' pathGeno=dataDir, fileSNPsRDS=filterSNVFile, verbose=FALSE)} +#' } #' #' ## Close 1KG Phase information file #' closefn.gds(gdsPhase) diff --git a/man/generatePhase1KG2GDS.Rd b/man/generatePhase1KG2GDS.Rd index 942effece..d449628f4 100644 --- a/man/generatePhase1KG2GDS.Rd +++ b/man/generatePhase1KG2GDS.Rd @@ -41,56 +41,6 @@ The function is adding the phase information into the Reference Phase GDS file. The phase information is extracted from a Reference GDS file and is added into a Reference Phase GDS file. An entry called 'phase' is added to the Reference Phase GDS file. -} -\examples{ - -## Required package -library(gdsfmt) - -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", package="RAIDS") - -## The RDS file containing the pedigree information -pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") - -## The RDS file containing the indexes of the retained SNPs -snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") - -## The RDS file containing the filtered SNP information -filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") - -## Temporary Reference GDS file containing 1KG information -fileReferenceGDS <- "1KG_TEMP_02.gds" - -## Create a temporary Reference GDS file containing information from 1KG -generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, - fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, - fileNameGDS=fileReferenceGDS, listSamples=NULL) - -## Temporary Phase GDS file that will contain the 1KG Phase information -fileRefPhaseGDS <- "1KG_TEMP_Phase_02.gds" - -## Create Reference Phase GDS file -gdsPhase <- createfn.gds(fileRefPhaseGDS) - -## Open Reference GDS file -gdsRef <- openfn.gds(fileReferenceGDS) - -## Fill temporary Reference Phase GDS file -generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, - pathGeno=dataDir, fileSNPsRDS=filterSNVFile, verbose=FALSE) - -## Close 1KG Phase information file -closefn.gds(gdsPhase) - -## Close Reference information file -closefn.gds(gdsRef) - -## Remove temporary files -unlink(fileReferenceGDS, force=TRUE) -unlink(fileRefPhaseGDS, force=TRUE) - - } \author{ Pascal Belleau, Astrid Deschênes and Alexander Krasnitz From 7b9b7b7bc8c9978937fd0824ac6edb98ff25d40b Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 29 Jun 2023 22:37:29 -0400 Subject: [PATCH 046/385] Update doc, change variable fileOUT to fileOut --- R/gdsWrapper.R | 2 +- R/process1KG.R | 6 +- R/processStudy.R | 58 +++++++++-------- R/tools.R | 35 ++++++----- man/add1KG2SampleGDS.Rd | 70 ++++++++++++--------- man/addBlockFromPlink2GDS.Rd | 2 +- man/addGDS1KGLDBlock.Rd | 2 +- man/generatePhase1KG2GDS.Rd | 54 +++++++++++++++- man/groupChrPruning.Rd | 12 ++-- man/snvListVCF.Rd | 8 +-- tests/testthat/fixtures/ex1.generic.txt.gz | Bin 0 -> 484 bytes tests/testthat/test-tools.R | 36 +++++------ vignettes/Create_1KG_GDS_File.Rmd | 10 +-- 13 files changed, 187 insertions(+), 108 deletions(-) create mode 100644 tests/testthat/fixtures/ex1.generic.txt.gz diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index de70e4cb0..94373ba6c 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -484,7 +484,7 @@ gds2tped <- function(gds, listSample, listSNP, pedOUT) { #' #' @description TODO #' -#' @param gds an object of class \code{gds} opened for the sample +#' @param gds an object of class \code{gds} opened in writing mode. #' #' @param listBlock TODO #' diff --git a/R/process1KG.R b/R/process1KG.R index e1ebc45b6..083118831 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -401,7 +401,7 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' @param verbose a \code{logicial} indicating if the function should #' print messages when running. Default: \code{FALSE}. #' -#' @return The function returns \code{0L} when succesful. +#' @return The function returns \code{0L} when successful. #' #' @examples #' @@ -440,7 +440,7 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' ## Fill temporary Reference Phase GDS file #' if (FALSE) { #' generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, -#' pathGeno=dataDir, fileSNPsRDS=filterSNVFile, verbose=FALSE)} +#' pathGeno=dataDir, fileSNPsRDS=filterSNVFile, verbose=FALSE) #' } #' #' ## Close 1KG Phase information file @@ -801,7 +801,7 @@ basePCASample <- function(gds, listSample.Ref=NULL, listSNP=NULL, np=1L) { #' @param gds an object of class #' \link[gdsfmt]{gds.class} (a GDS file), TODO #' -#' @param gdsOut an object of class \code{gds} in writing +#' @param gdsOut an object of class \code{gds} opened in writing mode. #' #' @param PATHBLOCK TODO #' diff --git a/R/processStudy.R b/R/processStudy.R index b069df4d8..1732eb4ed 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -618,37 +618,45 @@ pruningSample <- function(gdsReference, #' #' ## Copy the Profile GDS file demo that has been pruned #' ## into a test directory (deleted after the example has been run) -#' dataDirGenotyping <- file.path(system.file("extdata", package="RAIDS"), -#' "demoAddGenotype") -#' dir.create(dataDirGenotyping, showWarnings=FALSE, -#' recursive=FALSE, mode="0777") -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), -#' file.path(dataDirGenotyping, "ex1.gds")) +#' dataDirGenotypingTmp <- file.path("demoAddGenotypeTmp") #' -#' ## Open 1KG file -#' gds1KG <- snpgdsOpen(fileGDS) +#' ## Only run example if the directory containing the genotype can be created +#' if (!dir.exists(dataDirGenotypingTmp)) { +#' if (dir.create(dataDirGenotypingTmp, showWarnings=FALSE, +#' recursive=FALSE, mode="0777")) { #' -#' ## Compute the list of pruned SNVs for a specific profile 'ex1' -#' ## and save it in the Profile GDS file 'ex1.gds' -#' add1KG2SampleGDS(gdsReference=gds1KG, -#' fileProfileGDS=file.path(dataDirGenotyping, "ex1.gds"), -#' currentProfile=c("ex1"), -#' studyID=studyDF$study.id) +#' ## Copy required file +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), +#' file.path(dataDirGenotypingTmp, "ex1.gds")) #' -#' ## Close the 1KG GDS file (it is important to always close the GDS files) -#' closefn.gds(gds1KG) +#' ## Open 1KG file +#' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Check content of Profile GDS file -#' ## The 'pruned.study' entry should be present -#' content <- openfn.gds(file.path(dataDirGenotyping, "ex1.gds")) -#' content +#' ## Compute the list of pruned SNVs for a specific profile 'ex1' +#' ## and save it in the Profile GDS file 'ex1.gds' +#' add1KG2SampleGDS(gdsReference=gds1KG, +#' fileProfileGDS=file.path(dataDirGenotypingTmp, "ex1.gds"), +#' currentProfile=c("ex1"), +#' studyID=studyDF$study.id) #' -#' ## Close the Profile GDS file (it is important to always close the GDS files) -#' closefn.gds(content) +#' ## Close the 1KG GDS file (important) +#' closefn.gds(gds1KG) +#' +#' ## Check content of Profile GDS file +#' ## The 'pruned.study' entry should be present +#' content <- openfn.gds(file.path(dataDirGenotypingTmp, "ex1.gds")) +#' content +#' +#' ## Close the Profile GDS file (important) +#' closefn.gds(content) +#' +#' ## Unlink Profile GDS file (created for demo purpose) +#' unlink(file.path(dataDirGenotypingTmp, "ex1.gds"), force=TRUE) +#' unlink(dataDirGenotypingTmp, force=TRUE) +#' +#' } +#' } #' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink(file.path(dataDirGenotyping, "ex1.gds")) -#' unlink(dataDirGenotyping) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn objdesp.gdsn diff --git a/R/tools.R b/R/tools.R index 009b23641..7595d365d 100644 --- a/R/tools.R +++ b/R/tools.R @@ -9,7 +9,7 @@ #' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} #' (a GDS file), the 1KG GDS file. #' -#' @param fileOUT a \code{character} string representing the path and file +#' @param fileOut a \code{character} string representing the path and file #' name of the VCF file that will be created wit the retained SNP information. #' #' @param offset a single \code{integer} that is added to the SNP position to @@ -19,7 +19,7 @@ #' @param freqCutoff a single positive \code{numeric} specifying the cut-off to #' keep a SNP. If \code{NULL}, all SNPs are retained. Default: \code{NULL}. #' -#' @return The integer \code{0} when successful. +#' @return The integer \code{0L} when successful. #' #' @examples #' @@ -34,7 +34,7 @@ #' #' ## Create a VCF file with the SNV dataset present in the GDS file #' ## No cutoff on frequency, so all SNVs are saved -#' snvListVCF(gdsReference=fileGDS, fileOUT=vcfFile, offset=0L, freqCutoff=NULL) +#' snvListVCF(gdsReference=fileGDS, fileOut=vcfFile, offset=0L, freqCutoff=NULL) #' #' ## Close GDS file (IMPORTANT) #' closefn.gds(fileGDS) @@ -48,7 +48,7 @@ #' @importFrom S4Vectors isSingleNumber #' @encoding UTF-8 #' @export -snvListVCF <- function(gdsReference, fileOUT, offset=0L, freqCutoff=NULL) { +snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { ## Validate that gdsReference is an object of class gds.class if (!inherits(gdsReference, "gds.class")) { @@ -112,15 +112,15 @@ snvListVCF <- function(gdsReference, fileOUT, offset=0L, freqCutoff=NULL) { ## in the range (0,1)"> #CHROM POS ID REF ALT QUAL FILTER INFO - cat(paste0('##fileformat=VCFv4.3', "\n"), file = fileOUT) + cat(paste0('##fileformat=VCFv4.3', "\n"), file = fileOut) cat(paste0('##FILTER=', - "\n"), file = fileOUT, append=TRUE) + "\n"), file = fileOut, append=TRUE) cat(paste0('##INFO=', - "\n"), file = fileOUT, append=TRUE) - cat('#', file = fileOUT, append=TRUE) + "\n"), file = fileOut, append=TRUE) + cat('#', file = fileOut, append=TRUE) - write.table(df, file=fileOUT, sep="\t", append=TRUE, row.names=FALSE, + write.table(df, file=fileOut, sep="\t", append=TRUE, row.names=FALSE, col.names=TRUE, quote=FALSE) ## Successful @@ -131,13 +131,17 @@ snvListVCF <- function(gdsReference, fileOUT, offset=0L, freqCutoff=NULL) { #' #' @description TODO #' -#' @param pathPrunedGDS TODO +#' @param pathPrunedGDS a \code{character} string representing the path where +#' the pruned files for each chromosome are located. +#' The path must exists. #' #' @param filePref TODO #' -#' @param fileOUT TODO +#' @param fileOut a \code{character} string representing name of the output +#' file that will be created. THe file will contain the information for all +#' pruned chromosome. The file must have a ".rds" extension. #' -#' @return TODO a \code{vector} of \code{numeric} +#' @return The integer \code{0L} when successful. #' #' @examples #' @@ -149,7 +153,7 @@ snvListVCF <- function(gdsReference, fileOUT, offset=0L, freqCutoff=NULL) { #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @encoding UTF-8 #' @keywords internal -groupChrPruning <- function(pathPrunedGDS, filePref, fileOUT) { +groupChrPruning <- function(pathPrunedGDS, filePref, fileOut) { prunedList <- list() @@ -168,7 +172,10 @@ groupChrPruning <- function(pathPrunedGDS, filePref, fileOUT) { pruned <- do.call(c, prunedList) ## Save all the information into one file - saveRDS(pruned, fileChr <- file.path(pathPrunedGDS, fileOUT)) + saveRDS(pruned, fileChr <- file.path(pathPrunedGDS, fileOut)) + + ## Successfull + return(0L) } diff --git a/man/add1KG2SampleGDS.Rd b/man/add1KG2SampleGDS.Rd index cb66868ce..0e5bfa805 100644 --- a/man/add1KG2SampleGDS.Rd +++ b/man/add1KG2SampleGDS.Rd @@ -51,37 +51,45 @@ studyDF <- data.frame(study.id="MYDATA", ## Copy the Profile GDS file demo that has been pruned ## into a test directory (deleted after the example has been run) -dataDirGenotyping <- file.path(system.file("extdata", package="RAIDS"), - "demoAddGenotype") -dir.create(dataDirGenotyping, showWarnings=FALSE, - recursive=FALSE, mode="0777") -file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), - file.path(dataDirGenotyping, "ex1.gds")) - -## Open 1KG file -gds1KG <- snpgdsOpen(fileGDS) - -## Compute the list of pruned SNVs for a specific profile 'ex1' -## and save it in the Profile GDS file 'ex1.gds' -add1KG2SampleGDS(gdsReference=gds1KG, - fileProfileGDS=file.path(dataDirGenotyping, "ex1.gds"), - currentProfile=c("ex1"), - studyID=studyDF$study.id) - -## Close the 1KG GDS file (it is important to always close the GDS files) -closefn.gds(gds1KG) - -## Check content of Profile GDS file -## The 'pruned.study' entry should be present -content <- openfn.gds(file.path(dataDirGenotyping, "ex1.gds")) -content - -## Close the Profile GDS file (it is important to always close the GDS files) -closefn.gds(content) - -## Unlink Profile GDS file (created for demo purpose) -unlink(file.path(dataDirGenotyping, "ex1.gds")) -unlink(dataDirGenotyping) +dataDirGenotypingTmp <- file.path("demoAddGenotypeTmp") + +## Only run example if the directory containing the genotype can be created +if (!dir.exists(dataDirGenotypingTmp)) { + if (dir.create(dataDirGenotypingTmp, showWarnings=FALSE, + recursive=FALSE, mode="0777")) { + + ## Copy required file + file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), + file.path(dataDirGenotypingTmp, "ex1.gds")) + + ## Open 1KG file + gds1KG <- snpgdsOpen(fileGDS) + + ## Compute the list of pruned SNVs for a specific profile 'ex1' + ## and save it in the Profile GDS file 'ex1.gds' + add1KG2SampleGDS(gdsReference=gds1KG, + fileProfileGDS=file.path(dataDirGenotypingTmp, "ex1.gds"), + currentProfile=c("ex1"), + studyID=studyDF$study.id) + + ## Close the 1KG GDS file (important) + closefn.gds(gds1KG) + + ## Check content of Profile GDS file + ## The 'pruned.study' entry should be present + content <- openfn.gds(file.path(dataDirGenotypingTmp, "ex1.gds")) + content + + ## Close the Profile GDS file (important) + closefn.gds(content) + + ## Unlink Profile GDS file (created for demo purpose) + unlink(file.path(dataDirGenotypingTmp, "ex1.gds"), force=TRUE) + unlink(dataDirGenotypingTmp, force=TRUE) + + } +} + } \author{ diff --git a/man/addBlockFromPlink2GDS.Rd b/man/addBlockFromPlink2GDS.Rd index e922be722..e46600afb 100644 --- a/man/addBlockFromPlink2GDS.Rd +++ b/man/addBlockFromPlink2GDS.Rd @@ -19,7 +19,7 @@ addBlockFromPlink2GDS( \item{gds}{an object of class \link[gdsfmt]{gds.class} (a GDS file), TODO} -\item{gdsOut}{an object of class \code{gds} in writing} +\item{gdsOut}{an object of class \code{gds} opened in writing mode.} \item{PATHBLOCK}{TODO} diff --git a/man/addGDS1KGLDBlock.Rd b/man/addGDS1KGLDBlock.Rd index f9eff3958..0b6b90ef8 100644 --- a/man/addGDS1KGLDBlock.Rd +++ b/man/addGDS1KGLDBlock.Rd @@ -8,7 +8,7 @@ addGDS1KGLDBlock(gds, listBlock, blockName, blockDesc) } \arguments{ -\item{gds}{an object of class \code{gds} opened for the sample} +\item{gds}{an object of class \code{gds} opened in writing mode.} \item{listBlock}{TODO} diff --git a/man/generatePhase1KG2GDS.Rd b/man/generatePhase1KG2GDS.Rd index d449628f4..fc5f20961 100644 --- a/man/generatePhase1KG2GDS.Rd +++ b/man/generatePhase1KG2GDS.Rd @@ -34,13 +34,65 @@ file must exist. The file must be a RDS file.} print messages when running. Default: \code{FALSE}.} } \value{ -The function returns \code{0L} when succesful. +The function returns \code{0L} when successful. } \description{ The function is adding the phase information into the Reference Phase GDS file. The phase information is extracted from a Reference GDS file and is added into a Reference Phase GDS file. An entry called 'phase' is added to the Reference Phase GDS file. +} +\examples{ + +## Required package +library(gdsfmt) + +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +## The RDS file containing the pedigree information +pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") + +## The RDS file containing the indexes of the retained SNPs +snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") + +## The RDS file containing the filtered SNP information +filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") + +## Temporary Reference GDS file containing 1KG information +fileReferenceGDS <- "1KG_TEMP_02.gds" + +## Create a temporary Reference GDS file containing information from 1KG +generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, + fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, + fileNameGDS=fileReferenceGDS, listSamples=NULL) + +## Temporary Phase GDS file that will contain the 1KG Phase information +fileRefPhaseGDS <- "1KG_TEMP_Phase_02.gds" + +## Create Reference Phase GDS file +gdsPhase <- createfn.gds(fileRefPhaseGDS) + +## Open Reference GDS file +gdsRef <- openfn.gds(fileReferenceGDS) + +## Fill temporary Reference Phase GDS file +if (FALSE) { + generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, + pathGeno=dataDir, fileSNPsRDS=filterSNVFile, verbose=FALSE) +} + +## Close 1KG Phase information file +closefn.gds(gdsPhase) + +## Close Reference information file +closefn.gds(gdsRef) + +## Remove temporary files +unlink(fileReferenceGDS, force=TRUE) +unlink(fileRefPhaseGDS, force=TRUE) + + } \author{ Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/man/groupChrPruning.Rd b/man/groupChrPruning.Rd index 9f987e76d..c3c56cc21 100644 --- a/man/groupChrPruning.Rd +++ b/man/groupChrPruning.Rd @@ -5,17 +5,21 @@ \alias{groupChrPruning} \title{Merge the pruning files by chromosome in one file} \usage{ -groupChrPruning(pathPrunedGDS, filePref, fileOUT) +groupChrPruning(pathPrunedGDS, filePref, fileOut) } \arguments{ -\item{pathPrunedGDS}{TODO} +\item{pathPrunedGDS}{a \code{character} string representing the path where +the pruned files for each chromosome are located. +The path must exists.} \item{filePref}{TODO} -\item{fileOUT}{TODO} +\item{fileOut}{a \code{character} string representing name of the output +file that will be created. THe file will contain the information for all +pruned chromosome. The file must have a ".rds" extension.} } \value{ -TODO a \code{vector} of \code{numeric} +The integer \code{0L} when successful. } \description{ TODO diff --git a/man/snvListVCF.Rd b/man/snvListVCF.Rd index b0891e545..a46de8e93 100644 --- a/man/snvListVCF.Rd +++ b/man/snvListVCF.Rd @@ -6,13 +6,13 @@ \title{Generate a VCF with the information from the SNPs that pass a cut-off threshold} \usage{ -snvListVCF(gdsReference, fileOUT, offset = 0L, freqCutoff = NULL) +snvListVCF(gdsReference, fileOut, offset = 0L, freqCutoff = NULL) } \arguments{ \item{gdsReference}{an object of class \code{\link[gdsfmt]{gds.class}} (a GDS file), the 1KG GDS file.} -\item{fileOUT}{a \code{character} string representing the path and file +\item{fileOut}{a \code{character} string representing the path and file name of the VCF file that will be created wit the retained SNP information.} \item{offset}{a single \code{integer} that is added to the SNP position to @@ -23,7 +23,7 @@ Default: \code{0L}.} keep a SNP. If \code{NULL}, all SNPs are retained. Default: \code{NULL}.} } \value{ -The integer \code{0} when successful. +The integer \code{0L} when successful. } \description{ This function extract the SNPs that pass a frequency cut-off @@ -44,7 +44,7 @@ vcfFile <- file.path(dataDir, "Demo_TMP_01.vcf") ## Create a VCF file with the SNV dataset present in the GDS file ## No cutoff on frequency, so all SNVs are saved -snvListVCF(gdsReference=fileGDS, fileOUT=vcfFile, offset=0L, freqCutoff=NULL) +snvListVCF(gdsReference=fileGDS, fileOut=vcfFile, offset=0L, freqCutoff=NULL) ## Close GDS file (IMPORTANT) closefn.gds(fileGDS) diff --git a/tests/testthat/fixtures/ex1.generic.txt.gz b/tests/testthat/fixtures/ex1.generic.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..48192f0940e5a099580f4a9e0c9375d87f2ef22f GIT binary patch literal 484 zcmVj)c-D@d*gEC78+6LO``>(WN zVtLXT2qy5eog;YBBEb+^kiY{l*Y0z<~FQ0>YoFlAiTde%Z(&C(iL zPfO*%oG}&b*aF*tqa@F(atP-zI2SHm+76pQPwL*eHBJ?~?iLRl?JhRGU2k*Twwy!6 z4V*E1nYLC8j01M}x6=~X?qO?XbG}Q90V8#M9hiYoe_NuNLM*yp6DWmiz2-;P)11Ll_I z`+9&)B>MbP@36)km^AFlHL#9Y>b82^+INNIii%N>jG`u#Yob`oHsBlu=QiL-`o%hu a&iQdAgxm9P%Bd!owfGO&(sHs*1^@uMIr&Hc literal 0 HcmV?d00001 diff --git a/tests/testthat/test-tools.R b/tests/testthat/test-tools.R index f5a99df6d..63ffee98b 100644 --- a/tests/testthat/test-tools.R +++ b/tests/testthat/test-tools.R @@ -43,7 +43,7 @@ test_that("snvListVCF() must return error when offset is a character string", { error_message <- "The \'offset\' must be a single integer." - expect_error(snvListVCF(gdsReference=gds, fileOUT, offset="HELLO", + expect_error(snvListVCF(gdsReference=gds, fileOut, offset="HELLO", freqCutoff=NULL), error_message) closefn.gds(gds) @@ -56,11 +56,11 @@ test_that("snvListVCF() must return error when gds is a character string", { data.dir <- system.file("extdata", package="RAIDS") - fileOUT <- file.path(data.dir, "VCF_TEMP.vcf") + fileOut <- file.path(data.dir, "VCF_TEMP.vcf") error_message <- "The \'gdsReference\' must be an object of class \'gds.class\'." - expect_error(snvListVCF(gdsReference="welcome.txt", fileOUT=fileOUT, offset=0L, + expect_error(snvListVCF(gdsReference="welcome.txt", fileOut=fileOut, offset=0L, freqCutoff=NULL), error_message) }) @@ -94,11 +94,11 @@ test_that("snvListVCF() must return error when freqCutoff is a character string" gds <- snpgdsOpen(fileGDS) withr::defer(closefn.gds(gds), envir = parent.frame()) - fileOUT <- file.path(data.dir, "VCF_TEMP.vcf") + fileOut <- file.path(data.dir, "VCF_TEMP.vcf") error_message <- "The \'freqCutoff\' must be a single numeric or NULL." - expect_error(snvListVCF(gdsReference=gds, fileOUT=fileOUT, offset=0L, + expect_error(snvListVCF(gdsReference=gds, fileOut=fileOut, offset=0L, freqCutoff="BED"), error_message) }) @@ -112,16 +112,16 @@ test_that("snvListVCF() must return expected results when freqCutoff is NULL", { gds <- openfn.gds(fileGDS) withr::defer(closefn.gds(gds), envir=parent.frame()) - fileOUT <- file.path(data.dir, "VCF_TEMP_01.vcf") - withr::defer(unlink(fileOUT, force=TRUE), envir=parent.frame()) + fileOut <- file.path(data.dir, "VCF_TEMP_01.vcf") + withr::defer(unlink(fileOut, force=TRUE), envir=parent.frame()) - result1 <- suppressWarnings(snvListVCF(gdsReference=gds, fileOUT=fileOUT, offset=0L, - freqCutoff=NULL)) + result1 <- suppressWarnings(snvListVCF(gdsReference=gds, fileOut=fileOut, + offset=0L, freqCutoff=NULL)) ## Read two times the vcf file, ## First for the columns names, second for the data - tmp_vcf <- readLines(fileOUT) - tmp_vcf_data <- read.table(fileOUT, stringsAsFactors=FALSE) + tmp_vcf <- readLines(fileOut) + tmp_vcf_data <- read.table(fileOut, stringsAsFactors=FALSE) # filter for the columns names tmp_vcf <- tmp_vcf[-(grep("#CHROM", tmp_vcf)+1):-(length(tmp_vcf))] @@ -130,7 +130,7 @@ test_that("snvListVCF() must return expected results when freqCutoff is NULL", { expect_equal(result1, 0L) - expect_true(file.exists(fileOUT)) + expect_true(file.exists(fileOut)) expect_equal(nrow(tmp_vcf_data), 7) expect_equal(ncol(tmp_vcf_data), 8) }) @@ -145,16 +145,16 @@ test_that("snvListVCF() must return expected results when freqCutoff is 0.3", { gds <- openfn.gds(fileGDS) withr::defer(closefn.gds(gds), envir=parent.frame()) - fileOUT <- file.path(data.dir, "VCF_TEMP_02.vcf") - withr::defer(unlink(fileOUT, force=TRUE), envir=parent.frame()) + fileOut <- file.path(data.dir, "VCF_TEMP_02.vcf") + withr::defer(unlink(fileOut, force=TRUE), envir=parent.frame()) - result1 <- suppressWarnings(snvListVCF(gdsReference=gds, fileOUT=fileOUT, offset=0L, + result1 <- suppressWarnings(snvListVCF(gdsReference=gds, fileOut=fileOut, offset=0L, freqCutoff=0.3)) ## Read two times the vcf file, ## First for the columns names, second for the data - tmp_vcf <- readLines(fileOUT) - tmp_vcf_data <- read.table(fileOUT, stringsAsFactors=FALSE) + tmp_vcf <- readLines(fileOut) + tmp_vcf_data <- read.table(fileOut, stringsAsFactors=FALSE) # filter for the columns names tmp_vcf <- tmp_vcf[-(grep("#CHROM",tmp_vcf)+1):-(length(tmp_vcf))] @@ -163,7 +163,7 @@ test_that("snvListVCF() must return expected results when freqCutoff is 0.3", { expect_equal(result1, 0L) - expect_true(file.exists(fileOUT)) + expect_true(file.exists(fileOut)) expect_equal(nrow(tmp_vcf_data), 2) expect_equal(ncol(tmp_vcf_data), 8) }) diff --git a/vignettes/Create_1KG_GDS_File.Rmd b/vignettes/Create_1KG_GDS_File.Rmd index 9eec0c050..e2ea8e37d 100644 --- a/vignettes/Create_1KG_GDS_File.Rmd +++ b/vignettes/Create_1KG_GDS_File.Rmd @@ -447,10 +447,10 @@ library(RAIDS) gds <- snpgdsOpen(fileGDS1kg) ## The VCF file that will be created -fileOUT <- "SNPretained.VCF" +fileOut <- "SNPretained.VCF" ## Generate the VCF with the retained SNP position -snvListVCF(gdsReference=gds, fileOUT=fileOUT, offset=1, freqCutoff=NULL) +snvListVCF(gdsReference=gds, fileOut=fileOut, offset=1, freqCutoff=NULL) ## Close the 1KG GDS file closefn.gds(gds) @@ -465,12 +465,12 @@ In a terminal: ## This in not a R script ## This script is in bash -## Compress the new VCF file (fileOUT parameter) -bgzip fileOUT +## Compress the new VCF file (fileOut parameter) +bgzip fileOut ## Index the new VCF file ## HTSlib software is needed -tabix -p vcf fileOUT.gz +tabix -p vcf fileOut.gz ``` From 9ac2486d01fe39faf93da599c0401af60be36141 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 11 Jul 2023 13:46:43 -0400 Subject: [PATCH 047/385] Update version to 0.99.6 --- DESCRIPTION | 2 +- inst/NEWS.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 74d66390d..123740630 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.5 +Version: 0.99.6 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index 0fd98426a..3b3a35918 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,11 @@ +CHANGES IN VERSION 0.99.6 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o The vignette now referes to the generic formatted reference GDS rather than 1KG GDS file to showcase that the software is not dependant of the 1KG GDS file. Any refence dataset can be used as long as the dataset is formatted into a GDS file. + + CHANGES IN VERSION 0.99.5 ------------------------ From df217e97914d170a1d897e03a85f9e6028d60738 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 7 Aug 2023 21:22:35 -0400 Subject: [PATCH 048/385] Update vignette --- vignettes/MainSteps_Step1_v04.png | Bin 0 -> 48559 bytes vignettes/MainSteps_Wrapper_v04.png | Bin 0 -> 50071 bytes vignettes/MainSteps_v04.png | Bin 0 -> 45332 bytes vignettes/RAIDS.Rmd | 181 +++++++--------------------- 4 files changed, 45 insertions(+), 136 deletions(-) create mode 100644 vignettes/MainSteps_Step1_v04.png create mode 100644 vignettes/MainSteps_Wrapper_v04.png create mode 100644 vignettes/MainSteps_v04.png diff --git a/vignettes/MainSteps_Step1_v04.png b/vignettes/MainSteps_Step1_v04.png new file mode 100644 index 0000000000000000000000000000000000000000..650fa18776df511292b2d5aba210b5a537c8c731 GIT binary patch literal 48559 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%0Doh^y&CJZ> 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 H244RI)hnJ^ literal 0 HcmV?d00001 diff --git a/vignettes/MainSteps_Wrapper_v04.png b/vignettes/MainSteps_Wrapper_v04.png new file mode 100644 index 0000000000000000000000000000000000000000..ee7a8c5ab5d0322d21d6bb01deab1879313da1aa GIT binary patch literal 50071 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

(ttSdir-`)VLcy1^o>>Z|oA7edgRD)a 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 BYIy(v literal 0 HcmV?d00001 diff --git a/vignettes/MainSteps_v04.png b/vignettes/MainSteps_v04.png new file mode 100644 index 0000000000000000000000000000000000000000..1720ec1fd195f746e6a3f3728da069896e911621 GIT binary patch literal 45332 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 I=fU&;1>QuN4gdfE literal 0 HcmV?d00001 diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 504ea23d1..d465704ba 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -110,21 +110,18 @@ This is an overview of genetic ancestry inference from cancer-derived molecular data: ```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference process.", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_v03.png") +knitr::include_graphics("MainSteps_v04.png") ``` The main steps are: -1. Format reference data from the population reference dataset (optional) -2. Format cancer-derived data set starting from BAM files -3. Optimize ancestry inference parameters -4. Infer ancestry for the subjects of the external study +**Step 1.** Format reference data from the population reference dataset (optional) -These main steps are described in detail in the following. +**Step 2.1** Optimize ancestry inference parameters -You can also run the steps from Step 2 Sub-step 4 to the end, with the -default parameters, -in one command with the [wrapper](#wrapper) function. +**Step 2.2** Infer ancestry for the subjects of the external study + +These steps are described in detail in the following.

@@ -133,7 +130,7 @@ in one command with the [wrapper](#wrapper) function. ```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from the population reference dataset (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step1_v03.png") +knitr::include_graphics("MainSteps_Step1_v04.png") ``` @@ -145,8 +142,10 @@ At this step three important reference files are created: - The population reference SNV Annotation GDS file - The population reference SNV Retained VCF file -Note that these pre-processed -files are available for 1000 Genomes (1KG), in hg38, at: +The reference files associated to +the Cancer Research associated paper are available. Note that these +pre-processed files are for 1000 Genomes (1KG), in hg38. The files are +available here:/span> [https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper](https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper) @@ -166,60 +165,40 @@ vignette.
-## Step 2 - Prepare cancer-derived data for ancestry inference - -Molecular profiles in a cancer-derived data set must be formatted -following a series of sub-steps. - -```{r graphStep2, echo=FALSE, fig.align="center", fig.cap="Step 2 - Formatting the information from an external study", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step2_v03.png") -``` - -
- -These sub-steps are: - -1. Create a directory containing the 3 reference files from the population reference -2. Make a SNP pileup file for each profile -3. Create an RDS file containing information about the profiles -Note that a mapped BAM file is needed for each sample (step 2). -The reference -genome used for the mapping must be the same as the one used to generate the -population reference GDS file. - -
+## Step 2 - Wrapper function to run ancestry inference in one command -### Sub-Step 2.1 Create a directory containing the 3 required reference files - -The 3 required reference files should be stored in the same directory. In the -example below, this directory is referred to as **pathReference**. +The final step can be run with a wrapper function +that encapsulates multiple steps of the workflow. -For more information on creating your own reference files, -see the vignette -[Formatting the information from the population reference dataset (optional)](Create_1KG_GDS_file.html). +```{r graphWrapper, echo=FALSE, fig.align="center", fig.cap="Final step - The wrapper function encapsulates multiple steps of the workflow.", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_Wrapper_v04.png") +``` + +In summary, the wrapper function generates the synthetic dataset and uses it +to selected the optimal parameters before calling the genetic ancestry on +the current profiles.
-### Sub-Step 2.2 Generate a SNP pileup file (1 file per profile) - -A file containing the read counts for the reference and alternative -nucleotides at each SNP position present in the -**population reference GDS File ** must be created for each profile. -This file is refereed as a **Profile SNP pileup file**. - +The wrapper function, called _runExomeAncestry()_, requires 4 files as input: -```{r graphStep2SubStep2, echo=FALSE, fig.align="center", fig.cap="Generate a Profile SNP pileup file (1 file per profile)", out.width='100%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step2_SubStep2_SNP-Pileup_v03.png") -``` +- The **population reference GDS file** +- The **population reference SNV Annotation GDS file** +- The **Profile SNP pileup file** (one per sample present in the study) +- The **Profile PED RDS file** (one file with information for all profiles in the study) +A *data.frame* containing the general information about the study is +also required. The *data.frame* must contain those 3 columns: -The read counts can be extracted using different software such as Bioconductor -[RSamtools](https://bioconductor.org/packages/release/bioc/html/Rsamtools.html) -package [@Morgan2023] and -[snp-pileup](https://github.com/mskcc/facets/tree/master/inst/extcode), -which is associated to the facets package [@Shen2016] +- _study.id_: The study identifier (example: TCGA-BRCA). +- _study.desc_: The description of the study. +- _study.platform_: The type of sequencing (example: RNA-seq). +The required **population reference GDS file** and +**population reference SNV Annotation GDS file** should be stored in the same +directory. In the example below, this directory is referred to +as **pathReference**. The generic **Profile SNP pileup file** format is coma separated and the mandatory columns are: @@ -239,16 +218,10 @@ at position zero. Note that the name assigned to the **Profile SNP pileup file** has to correspond to the profile identifier (Name.ID) in the following analysis. For example, a SNP pileup file called "Sample.01.txt.gz" would be -associated to the "Sample.01" profile. - -
+associated to the "Sample.01" profile. -### Sub-Step 2.3 Create a Profile PED RDS file containing the information about the profiles - -An RDS file describing all the profiles to be analyzed -is required. - -The PED RDS file must contain a *data.frame* with these 5 columns: +The **Profile PED RDS file** must contain a *data.frame* describing all +the profiles to be analyzed. These 5 mandatory columns: - _Name.ID_: The unique sample identifier. The profile VCF file should be called "Name.ID.txt.gz". @@ -265,75 +238,6 @@ Alternatively, the PED information can be saved in another type of file (CVS, etc..) as long as the *data.frame* information can be regenerated in R (with _read.csv()_ or else). - -```{r pedCreation, echo=TRUE, warning=FALSE, message=FALSE} -############################################################## -## Location of the Profile PED RDS file to be created -############################################################## -dataDir <- system.file("extdata", package="RAIDS") -demoPEDFile <- file.path(dataDir, "Demo_PED.RDS") - -############################################################## -## Create a data frame with the mandatory columns -## All columns are in character string format (no factor) -############################################################## -pedDF <- data.frame(Name.ID=c("Sample_01", "Sample_02", "Sample_03"), - Case.ID=c("Patient_h11", "Patient_h12", "Patient_h18"), - Sample.Type=rep("Primary Tumor", 3), - Diagnosis=rep("Cancer", 3), - Source=rep("Databank B", 3), - stringsAsFactors=FALSE) - -############################################################## -## The row names must correspond to the name of the profiles -############################################################## -rownames(pedDF) <- pedDF$Name.ID - -############################################################## -## Save the data frame into a RDS file -############################################################## -saveRDS(object=pedDF, file=demoPEDFile) - -## Remove RDS file (created for demo purpose) -rm(demoPEDFile) -``` - -
- -## Final Step - Wrapper function to run ancestry inference in one command - -The final step can be run with a wrapper function -that encapsulates multiple steps of the workflow. - -```{r graphWrapper, echo=FALSE, fig.align="center", fig.cap="Final step - The wrapper function encapsulates multiple steps of the workflow.", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Wrapper_v03.png") -``` - -As a complement, the companion vignette -[Ancestry Inference Step by Step (optional)](Ancestry_Inference_Step_by_Step.html) -describes all steps covered by the wrapper function. - -In summary, the wrapper function generates the synthetic dataset and uses it -to selected the optimal parameters before calling the genetic ancestry on -the current profiles. - -
- -The wrapper function, called _runExomeAncestry()_, requires 4 files as input: - -- The **population reference GDS file** -- The **population reference SNV Annotation GDS file** -- The **Profile SNP pileup file** (one per sample present in the study) -- The **Profile PED RDS file** (one file with information for all profiles in the study) - -A *data.frame* containing the general information about the study is -also required. The *data.frame* must contain those 3 columns: - -- _study.id_: The study identifier (example: TCGA-BRCA). -- _study.desc_: The description of the study. -- _study.platform_: The type of sequencing (example: RNA-seq). - - ```{r runExomeAncestry, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ######################################################################### ## Load required packages @@ -365,16 +269,21 @@ fileAnnotGDS <- file.path(pathReference, "exAnnot1kg.gds") ######################################################################### ## The Sample SNP pileup files (one per sample) need -## to be located in the same directory. +## to be all located in the same directory. ######################################################################### pathGeno <- file.path(dataDir, "example", "snpPileup") ######################################################################### ## The path where the Sample GDS files (one per sample) -## will be created need to be specified. +## will be created needs to be specified. ######################################################################### pathProfileGDS <- file.path(dataDir, "example", "out.tmp") + +######################################################################### +## The path where the result files will be created needs to +## be specified +######################################################################### pathOut <- file.path(dataDir, "example", "res.out") ######################################################################### From f11e42742945e21b1b11ccc66d54b4efea4b81e2 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 8 Aug 2023 12:24:01 -0400 Subject: [PATCH 049/385] Remove old vignette illustrations --- vignettes/MainSteps_Step1_v03.png | Bin 55569 -> 0 bytes vignettes/MainSteps_Wrapper_v03.png | Bin 58841 -> 0 bytes vignettes/MainSteps_v03.png | Bin 52210 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 vignettes/MainSteps_Step1_v03.png delete mode 100644 vignettes/MainSteps_Wrapper_v03.png delete mode 100644 vignettes/MainSteps_v03.png diff --git a/vignettes/MainSteps_Step1_v03.png b/vignettes/MainSteps_Step1_v03.png deleted file mode 100644 index dbc1e24dcbe2b335d8e50e235755da0ec59d8288..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55569 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 diff --git a/vignettes/MainSteps_Wrapper_v03.png b/vignettes/MainSteps_Wrapper_v03.png deleted file mode 100644 index 3ec99f804575dc86bf092124015e13fd6d071b2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58841 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

}(4B#cHV3^+1s=igXdI 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 z�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ô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 w-!Xc^x7LZE7LR;i4{ktRtH#UyFNB$N&HU diff --git a/vignettes/MainSteps_v03.png b/vignettes/MainSteps_v03.png deleted file mode 100644 index e27983fcfee931c91577b8f56be37cb1c3caa052..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52210 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 Date: Tue, 8 Aug 2023 13:04:10 -0400 Subject: [PATCH 050/385] Adding missing illustrations --- vignettes/MainSteps_Step1_v03.png | Bin 0 -> 55570 bytes vignettes/MainSteps_v03.png | Bin 0 -> 55450 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 vignettes/MainSteps_Step1_v03.png create mode 100644 vignettes/MainSteps_v03.png diff --git a/vignettes/MainSteps_Step1_v03.png b/vignettes/MainSteps_Step1_v03.png new file mode 100644 index 0000000000000000000000000000000000000000..030ec557835b4571bcac9936d26c4520500beefc GIT binary patch literal 55570 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 literal 0 HcmV?d00001 diff --git a/vignettes/MainSteps_v03.png b/vignettes/MainSteps_v03.png new file mode 100644 index 0000000000000000000000000000000000000000..da98af2e3bf3e524b08cf579c428d857be438bdf GIT binary patch literal 55450 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 Date: Tue, 8 Aug 2023 13:32:53 -0400 Subject: [PATCH 051/385] update main steps illustration --- vignettes/MainSteps_v03.png | Bin 55450 -> 52211 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/vignettes/MainSteps_v03.png b/vignettes/MainSteps_v03.png index da98af2e3bf3e524b08cf579c428d857be438bdf..83464367ccc3b60fe8aac84f168bf81fb1961509 100644 GIT binary patch literal 52211 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 Date: Tue, 8 Aug 2023 17:04:20 -0400 Subject: [PATCH 052/385] Update examples in documentation --- R/allelicFraction.R | 98 +++++++++++++++++----------------- R/gdsWrapper.R | 47 ++++++++-------- R/process1KG.R | 6 +-- R/processStudy.R | 53 ++++++++---------- man/add1KG2SampleGDS.Rd | 53 ++++++++---------- man/estimateAllelicFraction.Rd | 98 +++++++++++++++++----------------- man/generateGDS1KG.Rd | 2 +- man/generateGDSSNPinfo.Rd | 47 ++++++++-------- man/generateMapSnvSel.Rd | 2 +- man/identifyRelative.Rd | 2 +- 10 files changed, 196 insertions(+), 212 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index 31541835b..8ae37dfa5 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -234,8 +234,8 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' #' ``` #' -#' if (requireNamespace("GenomeInfoDb", quietly = TRUE) && -#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly = TRUE)) { +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { #' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] #' } #' @@ -246,57 +246,55 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' ## Required library for GDS #' library(gdsfmt) #' -#' ## Path to the demo 1KG GDS file is located in this package +#' ## Path to the demo 1KG GDS file located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' -#' ## Copy the Profile GDS file demo that has been pruned and annotated -#' ## into a test directory (deleted after the example has been run) -#' dataDirAllelicFraction <- file.path(system.file("extdata", package="RAIDS"), -#' "demoAllelicFraction") -#' dir.create(dataDirAllelicFraction, showWarnings=FALSE, -#' recursive=FALSE, mode="0777") -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), -#' file.path(dataDirAllelicFraction, "ex1.gds")) -#' -#' ## Open the reference GDS file (demo version) -#' gds1KG <- snpgdsOpen(fileGDS) -#' -#' ## Profile GDS file for one profile -#' fileProfile <- file.path(dataDirAllelicFraction, "ex1.gds") -#' profileGDS <- openfn.gds(fileProfile, readonly=FALSE) -#' -#' ## Chromosome length information -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, -#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, -#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, -#' 156040895L, 57227415L, 16569L) -#' -#' ## A formal way to get the chormosome length information -#' ## library(GenomeInfoDb) -#' ## library(BSgenome.Hsapiens.UCSC.hg38) -#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] -#' -#' ## Estimate the allelic fraction of the pruned SNVs -#' estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, -#' currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, -#' studyType="DNA", minCov=10L, minProb=0.999, eProb=0.001, -#' cutOffLOH=-5, cutOffHomoScore=-3, wAR=9, cutOffAR=3, -#' gdsRefAnnot=NULL, blockID=NULL) -#' -#' ## The allelic fraction is saved in the 'lap' node of the Profile GDS file -#' ## The 'lap' entry should be present -#' profileGDS -#' -#' ## Close both GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) -#' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink(file.path(dataDirAllelicFraction, "ex1.gds")) -#' unlink(dataDirAllelicFraction) +#' ## Example can only be run if the current directory is in writing mode +#' if (file.access(getwd()) == 0) { +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' ## into current directory +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' "ex1.gds") +#' +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileGDS) +#' +#' ## Profile GDS file for one profile +#' fileProfile <- file.path("ex1.gds") +#' profileGDS <- openfn.gds(fileProfile, readonly=FALSE) +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, +#' 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, +#' 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, +#' 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) +#' +#' ## A formal way to get the chormosome length information +#' ## library(GenomeInfoDb) +#' ## library(BSgenome.Hsapiens.UCSC.hg38) +#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] +#' +#' ## Estimate the allelic fraction of the pruned SNVs +#' estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, +#' currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, +#' studyType="DNA", minCov=10L, minProb=0.999, eProb=0.001, +#' cutOffLOH=-5, cutOffHomoScore=-3, wAR=9, cutOffAR=3, +#' gdsRefAnnot=NULL, blockID=NULL) +#' +#' ## The allelic fraction is saved in the 'lap' node of Profile GDS file +#' ## The 'lap' entry should be present +#' profileGDS +#' +#' ## Close both GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) +#' +#' ## Unlink Profile GDS file (created for demo purpose) +#' unlink("ex1.gds", force=TRUE) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom rlang arg_match diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 94373ba6c..288d594f4 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -84,38 +84,41 @@ appendGDSSampleOnly <- function(gds, listSamples) { #' fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' #' ## Different code depending of the withr package availability -#' if (requireNamespace("withr", quietly = TRUE)) { +#' ## The current directory must be writable +#' if (file.access(getwd()) == 0) { +#' if (requireNamespace("withr", quietly=TRUE)) { #' -#' ## Temporary Reference GDS file -#' file1KG <- withr::local_file("1KG_TEMP_002.gds") -#' filenewGDS <- createfn.gds(file1KG) +#' ## Temporary Reference GDS file +#' file1KG <- withr::local_file("1KG_TEMP_002.gds") +#' filenewGDS <- createfn.gds(file1KG) #' -#' ## Add SNV information to Reference GDS -#' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, -#' fileFREQ=fileFilerterSNVs, verbose=TRUE) +#' ## Add SNV information to Reference GDS +#' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, +#' fileFREQ=fileFilerterSNVs, verbose=TRUE) #' -#' ## Close GDS file (important) -#' closefn.gds(filenewGDS) +#' ## Close GDS file (important) +#' closefn.gds(filenewGDS) #' -#' ## Remove temporary 1KG_TEMP_002.gds file -#' withr::deferred_run() +#' ## Remove temporary 1KG_TEMP_002.gds file +#' withr::deferred_run() #' -#' } else { +#' } else { #' -#' ## Temporary Reference GDS file -#' file1KG <- file.path("1KG_TEMP_002.gds") -#' filenewGDS <- createfn.gds(file1KG) +#' ## Temporary Reference GDS file +#' file1KG <- file.path("1KG_TEMP_002.gds") +#' filenewGDS <- createfn.gds(file1KG) #' -#' ## Add SNV information to Reference GDS -#' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, -#' fileFREQ=fileFilerterSNVs, verbose=TRUE) +#' ## Add SNV information to Reference GDS +#' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, +#' fileFREQ=fileFilerterSNVs, verbose=TRUE) #' -#' ## Close GDS file (important) -#' closefn.gds(filenewGDS) +#' ## Close GDS file (important) +#' closefn.gds(filenewGDS) #' -#' ## Remove temporary 1KG_TEMP_002.gds file -#' unlink(file1KG) +#' ## Remove temporary 1KG_TEMP_002.gds file +#' unlink(file1KG, force=TRUE) #' +#' } #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/R/process1KG.R b/R/process1KG.R index 083118831..f1618b4d2 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -162,7 +162,7 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") #' #' ## Different code depending of the withr package availability -#' if (requireNamespace("withr", quietly = TRUE)) { +#' if (requireNamespace("withr", quietly=TRUE)) { #' #' ## Temporary output files #' ## The first file contains the indexes of the retained SNPs @@ -305,7 +305,7 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { #' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' #' ## Different code depending of the withr package availability -#' if (requireNamespace("withr", quietly = TRUE)) { +#' if (requireNamespace("withr", quietly=TRUE)) { #' #' ## Temporary GDS file containing 1KG information #' gdsFile <- withr::local_file(file.path(dataDir, "1KG_TEMP.gds")) @@ -551,7 +551,7 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, #' ibdTmpFile <- "ibd_TEMP.rds" #' #' ## Different code depending of the withr package availability -#' if (requireNamespace("withr", quietly = TRUE)) { +#' if (requireNamespace("withr", quietly=TRUE)) { #' #' ## Temporary output files #' ## The first RDS file will contain the list of unrelated patients diff --git a/R/processStudy.R b/R/processStudy.R index 1732eb4ed..e8e838a1f 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -616,45 +616,36 @@ pruningSample <- function(gdsReference, #' study.platform="PLATFORM", #' stringsAsFactors=FALSE) #' -#' ## Copy the Profile GDS file demo that has been pruned -#' ## into a test directory (deleted after the example has been run) -#' dataDirGenotypingTmp <- file.path("demoAddGenotypeTmp") -#' #' ## Only run example if the directory containing the genotype can be created -#' if (!dir.exists(dataDirGenotypingTmp)) { -#' if (dir.create(dataDirGenotypingTmp, showWarnings=FALSE, -#' recursive=FALSE, mode="0777")) { -#' -#' ## Copy required file -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), -#' file.path(dataDirGenotypingTmp, "ex1.gds")) +#' if (file.access(getwd()) == 0) { #' -#' ## Open 1KG file -#' gds1KG <- snpgdsOpen(fileGDS) +#' ## Copy required file +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), +#' file.path(getwd(), "ex2.gds")) #' -#' ## Compute the list of pruned SNVs for a specific profile 'ex1' -#' ## and save it in the Profile GDS file 'ex1.gds' -#' add1KG2SampleGDS(gdsReference=gds1KG, -#' fileProfileGDS=file.path(dataDirGenotypingTmp, "ex1.gds"), -#' currentProfile=c("ex1"), -#' studyID=studyDF$study.id) +#' ## Open 1KG file +#' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Close the 1KG GDS file (important) -#' closefn.gds(gds1KG) +#' ## Compute the list of pruned SNVs for a specific profile 'ex1' +#' ## and save it in the Profile GDS file 'ex2.gds' +#' add1KG2SampleGDS(gdsReference=gds1KG, +#' fileProfileGDS=file.path(getwd(), "ex2.gds"), +#' currentProfile=c("ex1"), +#' studyID=studyDF$study.id) #' -#' ## Check content of Profile GDS file -#' ## The 'pruned.study' entry should be present -#' content <- openfn.gds(file.path(dataDirGenotypingTmp, "ex1.gds")) -#' content +#' ## Close the 1KG GDS file (important) +#' closefn.gds(gds1KG) #' -#' ## Close the Profile GDS file (important) -#' closefn.gds(content) +#' ## Check content of Profile GDS file +#' ## The 'pruned.study' entry should be present +#' content <- openfn.gds(file.path(getwd(), "ex2.gds")) +#' content #' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink(file.path(dataDirGenotypingTmp, "ex1.gds"), force=TRUE) -#' unlink(dataDirGenotypingTmp, force=TRUE) +#' ## Close the Profile GDS file (important) +#' closefn.gds(content) #' -#' } +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(file.path(getwd(), "ex2.gds"), force=TRUE) #' } #' #' diff --git a/man/add1KG2SampleGDS.Rd b/man/add1KG2SampleGDS.Rd index 0e5bfa805..95e34bd21 100644 --- a/man/add1KG2SampleGDS.Rd +++ b/man/add1KG2SampleGDS.Rd @@ -49,45 +49,36 @@ studyDF <- data.frame(study.id="MYDATA", study.platform="PLATFORM", stringsAsFactors=FALSE) -## Copy the Profile GDS file demo that has been pruned -## into a test directory (deleted after the example has been run) -dataDirGenotypingTmp <- file.path("demoAddGenotypeTmp") - ## Only run example if the directory containing the genotype can be created -if (!dir.exists(dataDirGenotypingTmp)) { - if (dir.create(dataDirGenotypingTmp, showWarnings=FALSE, - recursive=FALSE, mode="0777")) { - - ## Copy required file - file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), - file.path(dataDirGenotypingTmp, "ex1.gds")) +if (file.access(getwd()) == 0) { - ## Open 1KG file - gds1KG <- snpgdsOpen(fileGDS) + ## Copy required file + file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), + file.path(getwd(), "ex2.gds")) - ## Compute the list of pruned SNVs for a specific profile 'ex1' - ## and save it in the Profile GDS file 'ex1.gds' - add1KG2SampleGDS(gdsReference=gds1KG, - fileProfileGDS=file.path(dataDirGenotypingTmp, "ex1.gds"), - currentProfile=c("ex1"), - studyID=studyDF$study.id) + ## Open 1KG file + gds1KG <- snpgdsOpen(fileGDS) - ## Close the 1KG GDS file (important) - closefn.gds(gds1KG) + ## Compute the list of pruned SNVs for a specific profile 'ex1' + ## and save it in the Profile GDS file 'ex2.gds' + add1KG2SampleGDS(gdsReference=gds1KG, + fileProfileGDS=file.path(getwd(), "ex2.gds"), + currentProfile=c("ex1"), + studyID=studyDF$study.id) - ## Check content of Profile GDS file - ## The 'pruned.study' entry should be present - content <- openfn.gds(file.path(dataDirGenotypingTmp, "ex1.gds")) - content + ## Close the 1KG GDS file (important) + closefn.gds(gds1KG) - ## Close the Profile GDS file (important) - closefn.gds(content) + ## Check content of Profile GDS file + ## The 'pruned.study' entry should be present + content <- openfn.gds(file.path(getwd(), "ex2.gds")) + content - ## Unlink Profile GDS file (created for demo purpose) - unlink(file.path(dataDirGenotypingTmp, "ex1.gds"), force=TRUE) - unlink(dataDirGenotypingTmp, force=TRUE) + ## Close the Profile GDS file (important) + closefn.gds(content) - } + ## Remove Profile GDS file (created for demo purpose) + unlink(file.path(getwd(), "ex2.gds"), force=TRUE) } diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index a57935145..2f00d1a63 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -101,8 +101,8 @@ As example, for hg38 genome: ``` -if (requireNamespace("GenomeInfoDb", quietly = TRUE) && - requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly = TRUE)) { +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] } @@ -113,57 +113,55 @@ if (requireNamespace("GenomeInfoDb", quietly = TRUE) && ## Required library for GDS library(gdsfmt) -## Path to the demo 1KG GDS file is located in this package +## Path to the demo 1KG GDS file located in this package dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") -## Copy the Profile GDS file demo that has been pruned and annotated -## into a test directory (deleted after the example has been run) -dataDirAllelicFraction <- file.path(system.file("extdata", package="RAIDS"), - "demoAllelicFraction") -dir.create(dataDirAllelicFraction, showWarnings=FALSE, - recursive=FALSE, mode="0777") -file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), - file.path(dataDirAllelicFraction, "ex1.gds")) - -## Open the reference GDS file (demo version) -gds1KG <- snpgdsOpen(fileGDS) - -## Profile GDS file for one profile -fileProfile <- file.path(dataDirAllelicFraction, "ex1.gds") -profileGDS <- openfn.gds(fileProfile, readonly=FALSE) - -## Chromosome length information -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) - -## A formal way to get the chormosome length information -## library(GenomeInfoDb) -## library(BSgenome.Hsapiens.UCSC.hg38) -## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] - -## Estimate the allelic fraction of the pruned SNVs -estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, - currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, - studyType="DNA", minCov=10L, minProb=0.999, eProb=0.001, - cutOffLOH=-5, cutOffHomoScore=-3, wAR=9, cutOffAR=3, - gdsRefAnnot=NULL, blockID=NULL) - -## The allelic fraction is saved in the 'lap' node of the Profile GDS file -## The 'lap' entry should be present -profileGDS - -## Close both GDS files (important) -closefn.gds(profileGDS) -closefn.gds(gds1KG) - -## Unlink Profile GDS file (created for demo purpose) -unlink(file.path(dataDirAllelicFraction, "ex1.gds")) -unlink(dataDirAllelicFraction) +## Example can only be run if the current directory is in writing mode +if (file.access(getwd()) == 0) { + ## Copy the Profile GDS file demo that has been pruned and annotated + ## into current directory + file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), + "ex1.gds") + + ## Open the reference GDS file (demo version) + gds1KG <- snpgdsOpen(fileGDS) + + ## Profile GDS file for one profile + fileProfile <- file.path("ex1.gds") + profileGDS <- openfn.gds(fileProfile, readonly=FALSE) + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, + 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, + 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, + 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, + 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) + + ## A formal way to get the chormosome length information + ## library(GenomeInfoDb) + ## library(BSgenome.Hsapiens.UCSC.hg38) + ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] + + ## Estimate the allelic fraction of the pruned SNVs + estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, + currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, + studyType="DNA", minCov=10L, minProb=0.999, eProb=0.001, + cutOffLOH=-5, cutOffHomoScore=-3, wAR=9, cutOffAR=3, + gdsRefAnnot=NULL, blockID=NULL) + + ## The allelic fraction is saved in the 'lap' node of Profile GDS file + ## The 'lap' entry should be present + profileGDS + + ## Close both GDS files (important) + closefn.gds(profileGDS) + closefn.gds(gds1KG) + + ## Unlink Profile GDS file (created for demo purpose) + unlink("ex1.gds", force=TRUE) +} } \author{ diff --git a/man/generateGDS1KG.Rd b/man/generateGDS1KG.Rd index 3cf2275c2..8eab0e7dd 100644 --- a/man/generateGDS1KG.Rd +++ b/man/generateGDS1KG.Rd @@ -77,7 +77,7 @@ snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") ## Different code depending of the withr package availability -if (requireNamespace("withr", quietly = TRUE)) { +if (requireNamespace("withr", quietly=TRUE)) { ## Temporary GDS file containing 1KG information gdsFile <- withr::local_file(file.path(dataDir, "1KG_TEMP.gds")) diff --git a/man/generateGDSSNPinfo.Rd b/man/generateGDSSNPinfo.Rd index 6139ba8f0..c8f2e30f9 100644 --- a/man/generateGDSSNPinfo.Rd +++ b/man/generateGDSSNPinfo.Rd @@ -36,38 +36,41 @@ dataDir <- system.file("extdata", package="RAIDS") fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") ## Different code depending of the withr package availability -if (requireNamespace("withr", quietly = TRUE)) { +## The current directory must be writable +if (file.access(getwd()) == 0) { + if (requireNamespace("withr", quietly=TRUE)) { - ## Temporary Reference GDS file - file1KG <- withr::local_file("1KG_TEMP_002.gds") - filenewGDS <- createfn.gds(file1KG) + ## Temporary Reference GDS file + file1KG <- withr::local_file("1KG_TEMP_002.gds") + filenewGDS <- createfn.gds(file1KG) - ## Add SNV information to Reference GDS - RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, - fileFREQ=fileFilerterSNVs, verbose=TRUE) + ## Add SNV information to Reference GDS + RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, + fileFREQ=fileFilerterSNVs, verbose=TRUE) - ## Close GDS file (important) - closefn.gds(filenewGDS) + ## Close GDS file (important) + closefn.gds(filenewGDS) - ## Remove temporary 1KG_TEMP_002.gds file - withr::deferred_run() + ## Remove temporary 1KG_TEMP_002.gds file + withr::deferred_run() -} else { + } else { - ## Temporary Reference GDS file - file1KG <- file.path("1KG_TEMP_002.gds") - filenewGDS <- createfn.gds(file1KG) + ## Temporary Reference GDS file + file1KG <- file.path("1KG_TEMP_002.gds") + filenewGDS <- createfn.gds(file1KG) - ## Add SNV information to Reference GDS - RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, - fileFREQ=fileFilerterSNVs, verbose=TRUE) + ## Add SNV information to Reference GDS + RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, + fileFREQ=fileFilerterSNVs, verbose=TRUE) - ## Close GDS file (important) - closefn.gds(filenewGDS) + ## Close GDS file (important) + closefn.gds(filenewGDS) - ## Remove temporary 1KG_TEMP_002.gds file - unlink(file1KG) + ## Remove temporary 1KG_TEMP_002.gds file + unlink(file1KG, force=TRUE) + } } } diff --git a/man/generateMapSnvSel.Rd b/man/generateMapSnvSel.Rd index 4f93537de..7dcec6a39 100644 --- a/man/generateMapSnvSel.Rd +++ b/man/generateMapSnvSel.Rd @@ -64,7 +64,7 @@ dataDir <- system.file("extdata", package="RAIDS") snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") ## Different code depending of the withr package availability -if (requireNamespace("withr", quietly = TRUE)) { +if (requireNamespace("withr", quietly=TRUE)) { ## Temporary output files ## The first file contains the indexes of the retained SNPs diff --git a/man/identifyRelative.Rd b/man/identifyRelative.Rd index b074a31ca..cee751052 100644 --- a/man/identifyRelative.Rd +++ b/man/identifyRelative.Rd @@ -60,7 +60,7 @@ patientTmpFile <- "unrelatedPatients_TEMP.rds" ibdTmpFile <- "ibd_TEMP.rds" ## Different code depending of the withr package availability -if (requireNamespace("withr", quietly = TRUE)) { +if (requireNamespace("withr", quietly=TRUE)) { ## Temporary output files ## The first RDS file will contain the list of unrelated patients From b4ff92c65a2c5682d8683ffa405222f7f2e31804 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 8 Aug 2023 22:25:49 -0400 Subject: [PATCH 053/385] Update some examples that needs to have a file copied in the working directories --- R/allelicFraction_internal.R | 120 +++++++++++++++---------------- R/processStudy.R | 55 +++++++------- man/computeAllelicFractionDNA.Rd | 77 ++++++++++---------- man/getTableSNV.Rd | 55 +++++++------- man/pruningSample.Rd | 61 ++++++++-------- 5 files changed, 179 insertions(+), 189 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 94318035f..da4fa1766 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -62,35 +62,32 @@ #' dataDir <- system.file("extdata/tests", package="RAIDS") #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' -#' ## Copy the Profile GDS file demo that has been pruned and annotated -#' ## into a test directory (deleted after the example has been run) -#' dataDirAllelicFraction <- file.path(system.file("extdata", package="RAIDS"), -#' "demoAllelicFraction") -#' dir.create(dataDirAllelicFraction, showWarnings=FALSE, -#' recursive=FALSE, mode="0777") -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), -#' file.path(dataDirAllelicFraction, "ex1.gds")) -#' -#' ## Open the reference GDS file (demo version) -#' gds1KG <- snpgdsOpen(fileGDS) -#' -#' ## Profile GDS file for one profile -#' fileProfile <- file.path(dataDirAllelicFraction, "ex1.gds") -#' profileGDS <- openfn.gds(fileProfile) -#' -#' ## The function returns a data frame containing the SNVs information -#' result <- RAIDS:::getTableSNV(gdsReference=gds1KG, gdsSample=profileGDS, -#' currentProfile="ex1", studyID="MYDATA", minCov=10L, minProb=0.999, -#' eProb=0.001, verbose=FALSE) -#' head(result) -#' -#' ## Close both GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) -#' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink(file.path(dataDirAllelicFraction, "ex1.gds")) -#' unlink(dataDirAllelicFraction) +#' ## Example can only be run if the current directory is in writing mode +#' if (file.access(getwd()) == 0) { +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' file.path(getwd(), "ex1.gds")) +#' +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileGDS) +#' +#' ## Profile GDS file for one profile +#' fileProfile <- file.path(getwd(), "ex1.gds") +#' profileGDS <- openfn.gds(fileProfile) +#' +#' ## The function returns a data frame containing the SNVs information +#' result <- RAIDS:::getTableSNV(gdsReference=gds1KG, gdsSample=profileGDS, +#' currentProfile="ex1", studyID="MYDATA", minCov=10L, minProb=0.999, +#' eProb=0.001, verbose=FALSE) +#' head(result) +#' +#' ## Close both GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) +#' +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn @@ -518,45 +515,44 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snp.pos, chr, #' dataDir <- system.file("extdata/tests", package="RAIDS") #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' -#' ## Copy the Profile GDS file demo that has been pruned and annotated -#' ## into a test directory (deleted after the example has been run) -#' dataDirAllelicFraction <- file.path(system.file("extdata", package="RAIDS"), -#' "demoAllelicFraction") -#' dir.create(dataDirAllelicFraction, showWarnings=FALSE, -#' recursive=FALSE, mode="0777") -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), -#' file.path(dataDirAllelicFraction, "ex1.gds")) +#' ## Example can only be run if the current directory is in writing mode +#' if (file.access(getwd()) == 0) { #' -#' ## Open the reference GDS file (demo version) -#' gds1KG <- snpgdsOpen(fileGDS) +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' file.path(getwd(), "ex1.gds")) #' -#' ## Profile GDS file for one profile -#' fileProfile <- file.path(dataDirAllelicFraction, "ex1.gds") -#' profileGDS <- openfn.gds(fileProfile) +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Chromosome length information -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, -#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, -#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, -#' 156040895L, 57227415L, 16569L) +#' ## Profile GDS file for one profile +#' fileProfile <- file.path(getwd(), "ex1.gds") +#' profileGDS <- openfn.gds(fileProfile) #' -#' ## The function returns a data frame containing the allelic fraction info -#' result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, -#' gdsSample=profileGDS, -#' currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, minCov=10L, -#' minProb=0.999, eProb=0.001, cutOffLOH=-5, -#' cutOffHomoScore=-3, wAR=9L, verbose=FALSE) -#' head(result) +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, +#' 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, +#' 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, +#' 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) #' -#' ## Close both GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) +#' ## The function returns a data frame containing the allelic fraction info +#' result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, +#' gdsSample=profileGDS, +#' currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, minCov=10L, +#' minProb=0.999, eProb=0.001, cutOffLOH=-5, +#' cutOffHomoScore=-3, wAR=9L, verbose=FALSE) +#' head(result) #' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink(file.path(dataDirAllelicFraction, "ex1.gds")) -#' unlink(dataDirAllelicFraction) +#' ## Close both GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) +#' +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn diff --git a/R/processStudy.R b/R/processStudy.R index e8e838a1f..05350e140 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -421,37 +421,36 @@ appendStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' Source = rep("Databank B", 2), stringsAsFactors = FALSE) #' rownames(samplePED) <- samplePED$Name.ID #' -#' ## Copy the Profile GDS file demo that has not been pruned yet -#' ## into a test directory (deleted after the example has been run) -#' dataDirPruning <- file.path(system.file("extdata", package="RAIDS"), -#' "demoPruning") -#' dir.create(dataDirPruning, showWarnings=FALSE, -#' recursive=FALSE, mode="0777") -#' file.copy(file.path(dataDir, "ex1_demo.gds"), -#' file.path(dataDirPruning, "ex1.gds")) -#' -#' ## Open 1KG file -#' gds1KG <- snpgdsOpen(fileGDS) -#' -#' ## Compute the list of pruned SNVs for a specific profile 'ex1' -#' ## and save it in the Profile GDS file 'ex1.gds' -#' pruningSample(gdsReference=gds1KG, currentProfile=c("ex1"), -#' studyID = studyDF$study.id, pathProfileGDS=dataDirPruning) -#' -#' ## Close the 1KG GDS file (it is important to always close the GDS files) -#' closefn.gds(gds1KG) +#' ## Example can only be run if the current directory is in writing mode +#' if (file.access(getwd()) == 0) { +#' +#' ## Copy the Profile GDS file demo that has not been pruned yet +#' file.copy(file.path(dataDir, "ex1_demo.gds"), +#' file.path(getwd(), "ex1.gds")) #' -#' ## Check content of Profile GDS file -#' ## The 'pruned.study' entry should be present -#' content <- openfn.gds(file.path(dataDirPruning, "ex1.gds")) -#' content +#' ## Open 1KG file +#' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Close the Profile GDS file (it is important to always close the GDS files) -#' closefn.gds(content) +#' ## Compute the list of pruned SNVs for a specific profile 'ex1' +#' ## and save it in the Profile GDS file 'ex1.gds' +#' pruningSample(gdsReference=gds1KG, currentProfile=c("ex1"), +#' studyID = studyDF$study.id, pathProfileGDS=getwd()) #' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink(file.path(dataDirPruning, "ex1.gds")) -#' unlink(dataDirPruning) +#' ## Close the 1KG GDS file (it is important to always close the GDS files) +#' closefn.gds(gds1KG) +#' +#' ## Check content of Profile GDS file +#' ## The 'pruned.study' entry should be present +#' content <- openfn.gds(file.path(getwd(), "ex1.gds")) +#' content +#' +#' ## Close the Profile GDS file (important) +#' closefn.gds(content) +#' +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(file.path(getwd(), "ex1.gds"), force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn diff --git a/man/computeAllelicFractionDNA.Rd b/man/computeAllelicFractionDNA.Rd index 159d8830d..876fe6b6b 100644 --- a/man/computeAllelicFractionDNA.Rd +++ b/man/computeAllelicFractionDNA.Rd @@ -99,45 +99,44 @@ allelic fraction for the pruned SNV dataset specific to a DNA-seq profile dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") -## Copy the Profile GDS file demo that has been pruned and annotated -## into a test directory (deleted after the example has been run) -dataDirAllelicFraction <- file.path(system.file("extdata", package="RAIDS"), - "demoAllelicFraction") -dir.create(dataDirAllelicFraction, showWarnings=FALSE, - recursive=FALSE, mode="0777") -file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), - file.path(dataDirAllelicFraction, "ex1.gds")) - -## Open the reference GDS file (demo version) -gds1KG <- snpgdsOpen(fileGDS) - -## Profile GDS file for one profile -fileProfile <- file.path(dataDirAllelicFraction, "ex1.gds") -profileGDS <- openfn.gds(fileProfile) - -## Chromosome length information -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) - -## The function returns a data frame containing the allelic fraction info -result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, - gdsSample=profileGDS, - currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, minCov=10L, - minProb=0.999, eProb=0.001, cutOffLOH=-5, - cutOffHomoScore=-3, wAR=9L, verbose=FALSE) -head(result) - -## Close both GDS files (important) -closefn.gds(profileGDS) -closefn.gds(gds1KG) - -## Unlink Profile GDS file (created for demo purpose) -unlink(file.path(dataDirAllelicFraction, "ex1.gds")) -unlink(dataDirAllelicFraction) +## Example can only be run if the current directory is in writing mode +if (file.access(getwd()) == 0) { + + ## Copy the Profile GDS file demo that has been pruned and annotated + file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), + file.path(getwd(), "ex1.gds")) + + ## Open the reference GDS file (demo version) + gds1KG <- snpgdsOpen(fileGDS) + + ## Profile GDS file for one profile + fileProfile <- file.path(getwd(), "ex1.gds") + profileGDS <- openfn.gds(fileProfile) + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, + 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, + 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, + 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, + 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) + + ## The function returns a data frame containing the allelic fraction info + result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, + gdsSample=profileGDS, + currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, minCov=10L, + minProb=0.999, eProb=0.001, cutOffLOH=-5, + cutOffHomoScore=-3, wAR=9L, verbose=FALSE) + head(result) + + ## Close both GDS files (important) + closefn.gds(profileGDS) + closefn.gds(gds1KG) + + ## Remove Profile GDS file (created for demo purpose) + unlink(fileProfile, force=TRUE) + +} } \author{ diff --git a/man/getTableSNV.Rd b/man/getTableSNV.Rd index acf2b2165..8536cdd5f 100644 --- a/man/getTableSNV.Rd +++ b/man/getTableSNV.Rd @@ -81,35 +81,32 @@ library(gdsfmt) dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") -## Copy the Profile GDS file demo that has been pruned and annotated -## into a test directory (deleted after the example has been run) -dataDirAllelicFraction <- file.path(system.file("extdata", package="RAIDS"), - "demoAllelicFraction") -dir.create(dataDirAllelicFraction, showWarnings=FALSE, - recursive=FALSE, mode="0777") -file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), - file.path(dataDirAllelicFraction, "ex1.gds")) - -## Open the reference GDS file (demo version) -gds1KG <- snpgdsOpen(fileGDS) - -## Profile GDS file for one profile -fileProfile <- file.path(dataDirAllelicFraction, "ex1.gds") -profileGDS <- openfn.gds(fileProfile) - -## The function returns a data frame containing the SNVs information -result <- RAIDS:::getTableSNV(gdsReference=gds1KG, gdsSample=profileGDS, - currentProfile="ex1", studyID="MYDATA", minCov=10L, minProb=0.999, - eProb=0.001, verbose=FALSE) -head(result) - -## Close both GDS files (important) -closefn.gds(profileGDS) -closefn.gds(gds1KG) - -## Unlink Profile GDS file (created for demo purpose) -unlink(file.path(dataDirAllelicFraction, "ex1.gds")) -unlink(dataDirAllelicFraction) +## Example can only be run if the current directory is in writing mode +if (file.access(getwd()) == 0) { + ## Copy the Profile GDS file demo that has been pruned and annotated + file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), + file.path(getwd(), "ex1.gds")) + + ## Open the reference GDS file (demo version) + gds1KG <- snpgdsOpen(fileGDS) + + ## Profile GDS file for one profile + fileProfile <- file.path(getwd(), "ex1.gds") + profileGDS <- openfn.gds(fileProfile) + + ## The function returns a data frame containing the SNVs information + result <- RAIDS:::getTableSNV(gdsReference=gds1KG, gdsSample=profileGDS, + currentProfile="ex1", studyID="MYDATA", minCov=10L, minProb=0.999, + eProb=0.001, verbose=FALSE) + head(result) + + ## Close both GDS files (important) + closefn.gds(profileGDS) + closefn.gds(gds1KG) + + ## Remove Profile GDS file (created for demo purpose) + unlink(fileProfile, force=TRUE) +} } \author{ diff --git a/man/pruningSample.Rd b/man/pruningSample.Rd index 15c459ec8..4353ea2f0 100644 --- a/man/pruningSample.Rd +++ b/man/pruningSample.Rd @@ -131,37 +131,36 @@ samplePED <- data.frame(Name.ID = c("ex1", "ex2"), Source = rep("Databank B", 2), stringsAsFactors = FALSE) rownames(samplePED) <- samplePED$Name.ID -## Copy the Profile GDS file demo that has not been pruned yet -## into a test directory (deleted after the example has been run) -dataDirPruning <- file.path(system.file("extdata", package="RAIDS"), - "demoPruning") -dir.create(dataDirPruning, showWarnings=FALSE, - recursive=FALSE, mode="0777") -file.copy(file.path(dataDir, "ex1_demo.gds"), - file.path(dataDirPruning, "ex1.gds")) - -## Open 1KG file -gds1KG <- snpgdsOpen(fileGDS) - -## Compute the list of pruned SNVs for a specific profile 'ex1' -## and save it in the Profile GDS file 'ex1.gds' -pruningSample(gdsReference=gds1KG, currentProfile=c("ex1"), - studyID = studyDF$study.id, pathProfileGDS=dataDirPruning) - -## Close the 1KG GDS file (it is important to always close the GDS files) -closefn.gds(gds1KG) - -## Check content of Profile GDS file -## The 'pruned.study' entry should be present -content <- openfn.gds(file.path(dataDirPruning, "ex1.gds")) -content - -## Close the Profile GDS file (it is important to always close the GDS files) -closefn.gds(content) - -## Unlink Profile GDS file (created for demo purpose) -unlink(file.path(dataDirPruning, "ex1.gds")) -unlink(dataDirPruning) +## Example can only be run if the current directory is in writing mode +if (file.access(getwd()) == 0) { + + ## Copy the Profile GDS file demo that has not been pruned yet + file.copy(file.path(dataDir, "ex1_demo.gds"), + file.path(getwd(), "ex1.gds")) + + ## Open 1KG file + gds1KG <- snpgdsOpen(fileGDS) + + ## Compute the list of pruned SNVs for a specific profile 'ex1' + ## and save it in the Profile GDS file 'ex1.gds' + pruningSample(gdsReference=gds1KG, currentProfile=c("ex1"), + studyID = studyDF$study.id, pathProfileGDS=getwd()) + + ## Close the 1KG GDS file (it is important to always close the GDS files) + closefn.gds(gds1KG) + + ## Check content of Profile GDS file + ## The 'pruned.study' entry should be present + content <- openfn.gds(file.path(getwd(), "ex1.gds")) + content + + ## Close the Profile GDS file (important) + closefn.gds(content) + + ## Remove Profile GDS file (created for demo purpose) + unlink(file.path(getwd(), "ex1.gds"), force=TRUE) + +} } \author{ From 0ff89c4707eba268dd3236739a69ed13fbc88663 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 9 Aug 2023 01:06:40 -0400 Subject: [PATCH 054/385] Update example for prepSynthetic() function --- R/synthetic.R | 56 ++++++++++++++++++++++---------------------- man/prepSynthetic.Rd | 56 ++++++++++++++++++++++---------------------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/R/synthetic.R b/R/synthetic.R index c28b22a5d..48bc4e618 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -224,44 +224,44 @@ splitSelectByPop <- function(dataRef) { #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") #' -#' ## Copy the Profile GDS file demo that has been pruned and annotated -#' ## into a test directory (deleted after the example has been run) -#' dataDirAllelicFraction <- file.path(system.file("extdata", package="RAIDS"), -#' "demoAllelicFraction") -#' dir.create(dataDirAllelicFraction, showWarnings=FALSE, -#' recursive=FALSE, mode="0777") +#' ## Only run example if the directory containing the genotype can be created +#' if (file.access(getwd()) == 0) { #' -#' ## Profile GDS file -#' fileNameGDS <- file.path(dataDirAllelicFraction, "ex1.gds") +#' ## Profile GDS file +#' fileNameGDS <- file.path(getwd(), "ex1.gds") #' -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), #' fileNameGDS) #' -#' ## Information about the synthetic data set -#' syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", -#' study.desc="MYDATA synthetic data", study.platform="PLATFORM", -#' stringsAsFactors=FALSE) +#' ## Information about the synthetic data set +#' syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", +#' study.desc="MYDATA synthetic data", study.platform="PLATFORM", +#' stringsAsFactors=FALSE) #' -#' ## Add information related to the synthetic profiles into the Profile GDS -#' prepSynthetic(fileProfileGDS=fileNameGDS, -#' listSampleRef=c("HG00243", "HG00150"), profileID="ex1", -#' studyDF=syntheticStudyDF, nbSim=1L, prefix="synthetic", verbose=FALSE) +#' ## Add information related to the synthetic profiles into the Profile GDS +#' prepSynthetic(fileProfileGDS=fileNameGDS, +#' listSampleRef=c("HG00243", "HG00150"), profileID="ex1", +#' studyDF=syntheticStudyDF, nbSim=1L, prefix="synthetic", +#' verbose=FALSE) #' -#' ## Open Profile GDS file -#' profileGDS <- openfn.gds(fileNameGDS) +#' ## Open Profile GDS file +#' profileGDS <- openfn.gds(fileNameGDS) #' -#' ## The synthetic profiles should be added in the 'study.annot' entry -#' tail(read.gdsn(index.gdsn(profileGDS, "study.annot"))) +#' ## The synthetic profiles should be added in the 'study.annot' entry +#' tail(read.gdsn(index.gdsn(profileGDS, "study.annot"))) #' -#' ## The synthetic study information should be added to the 'study.list' entry -#' tail(read.gdsn(index.gdsn(profileGDS, "study.list"))) +#' ## The synthetic study information should be added to +#' ## the 'study.list' entry +#' tail(read.gdsn(index.gdsn(profileGDS, "study.list"))) #' -#' ## Close GDS file (important) -#' closefn.gds(profileGDS) +#' ## Close GDS file (important) +#' closefn.gds(profileGDS) #' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink(file.path(dataDirAllelicFraction, "ex1.gds")) -#' unlink(dataDirAllelicFraction) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileNameGDS, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn diff --git a/man/prepSynthetic.Rd b/man/prepSynthetic.Rd index 10d487c61..ba0681633 100644 --- a/man/prepSynthetic.Rd +++ b/man/prepSynthetic.Rd @@ -73,44 +73,44 @@ library(gdsfmt) ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata/tests", package="RAIDS") -## Copy the Profile GDS file demo that has been pruned and annotated -## into a test directory (deleted after the example has been run) -dataDirAllelicFraction <- file.path(system.file("extdata", package="RAIDS"), - "demoAllelicFraction") -dir.create(dataDirAllelicFraction, showWarnings=FALSE, - recursive=FALSE, mode="0777") +## Only run example if the directory containing the genotype can be created +if (file.access(getwd()) == 0) { -## Profile GDS file -fileNameGDS <- file.path(dataDirAllelicFraction, "ex1.gds") + ## Profile GDS file + fileNameGDS <- file.path(getwd(), "ex1.gds") -file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), + ## Copy the Profile GDS file demo that has been pruned and annotated + file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), fileNameGDS) -## Information about the synthetic data set -syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", - study.desc="MYDATA synthetic data", study.platform="PLATFORM", - stringsAsFactors=FALSE) + ## Information about the synthetic data set + syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", + study.desc="MYDATA synthetic data", study.platform="PLATFORM", + stringsAsFactors=FALSE) -## Add information related to the synthetic profiles into the Profile GDS -prepSynthetic(fileProfileGDS=fileNameGDS, - listSampleRef=c("HG00243", "HG00150"), profileID="ex1", - studyDF=syntheticStudyDF, nbSim=1L, prefix="synthetic", verbose=FALSE) + ## Add information related to the synthetic profiles into the Profile GDS + prepSynthetic(fileProfileGDS=fileNameGDS, + listSampleRef=c("HG00243", "HG00150"), profileID="ex1", + studyDF=syntheticStudyDF, nbSim=1L, prefix="synthetic", + verbose=FALSE) -## Open Profile GDS file -profileGDS <- openfn.gds(fileNameGDS) + ## Open Profile GDS file + profileGDS <- openfn.gds(fileNameGDS) -## The synthetic profiles should be added in the 'study.annot' entry -tail(read.gdsn(index.gdsn(profileGDS, "study.annot"))) + ## The synthetic profiles should be added in the 'study.annot' entry + tail(read.gdsn(index.gdsn(profileGDS, "study.annot"))) -## The synthetic study information should be added to the 'study.list' entry -tail(read.gdsn(index.gdsn(profileGDS, "study.list"))) + ## The synthetic study information should be added to + ## the 'study.list' entry + tail(read.gdsn(index.gdsn(profileGDS, "study.list"))) -## Close GDS file (important) -closefn.gds(profileGDS) + ## Close GDS file (important) + closefn.gds(profileGDS) -## Unlink Profile GDS file (created for demo purpose) -unlink(file.path(dataDirAllelicFraction, "ex1.gds")) -unlink(dataDirAllelicFraction) + ## Remove Profile GDS file (created for demo purpose) + unlink(fileNameGDS, force=TRUE) + +} } \author{ From 3fa09a44ad7d1fe5783dec9a455c8acbfb572d2f Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 9 Aug 2023 12:39:44 -0400 Subject: [PATCH 055/385] Update prepSynthetic() and syntheticGeno() examples --- R/synthetic.R | 80 +++++++++++++++++++++----------------------- man/prepSynthetic.Rd | 8 ++--- man/syntheticGeno.Rd | 72 +++++++++++++++++++-------------------- 3 files changed, 78 insertions(+), 82 deletions(-) diff --git a/R/synthetic.R b/R/synthetic.R index 48bc4e618..e1218d963 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -224,11 +224,11 @@ splitSelectByPop <- function(dataRef) { #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") #' -#' ## Only run example if the directory containing the genotype can be created -#' if (file.access(getwd()) == 0) { +#' ## Temporary Profile GDS file +#' fileNameGDS <- file.path(getwd(), "ex1.gds") #' -#' ## Profile GDS file -#' fileNameGDS <- file.path(getwd(), "ex1.gds") +#' ## Only run example if the directory is writable +#' if (file.access(getwd()) == 0 && !file.exists(fileNameGDS)) { #' #' ## Copy the Profile GDS file demo that has been pruned and annotated #' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), @@ -386,56 +386,54 @@ prepSynthetic <- function(fileProfileGDS, listSampleRef, #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") #' -#' ## Copy the Profile GDS file demo that has been pruned and annotated -#' ## into a test directory (deleted after the example has been run) -#' dataDirAllelicFraction <- file.path(system.file("extdata", package="RAIDS"), -#' "demoAllelicFraction") -#' dir.create(dataDirAllelicFraction, showWarnings=FALSE, -#' recursive=FALSE, mode="0777") -#' #' ## Profile GDS file -#' fileNameGDS <- file.path(dataDirAllelicFraction, "ex1.gds") +#' fileNameGDS <- file.path(getwd(), "ex1.gds") +#' +#' ## Only run example if the directory is writable +#' if (file.access(getwd()) == 0 && !file.exists(fileNameGDS)) { #' -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), #' fileNameGDS) #' -#' ## Information about the synthetic data set -#' syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", -#' study.desc="MYDATA synthetic data", study.platform="PLATFORM", -#' stringsAsFactors=FALSE) +#' ## Information about the synthetic data set +#' syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", +#' study.desc="MYDATA synthetic data", study.platform="PLATFORM", +#' stringsAsFactors=FALSE) #' -#' ## Add information related to the synthetic profiles into the Profile GDS -#' prepSynthetic(fileProfileGDS=fileNameGDS, -#' listSampleRef=c("HG00243", "HG00150"), profileID="ex1", -#' studyDF=syntheticStudyDF, nbSim=1L, prefix="synthTest", -#' verbose=FALSE) +#' ## Add information related to the synthetic profiles into the Profile GDS +#' prepSynthetic(fileProfileGDS=fileNameGDS, +#' listSampleRef=c("HG00243", "HG00150"), profileID="ex1", +#' studyDF=syntheticStudyDF, nbSim=1L, prefix="synthTest", +#' verbose=FALSE) #' -#' ## The 1KG files -#' gds1KG <- snpgdsOpen(file.path(dataDir, +#' ## The 1KG files +#' gds1KG <- snpgdsOpen(file.path(dataDir, #' "ex1_good_small_1KG_GDS.gds")) -#' gds1KGAnnot <- openfn.gds(file.path(dataDir, +#' gds1KGAnnot <- openfn.gds(file.path(dataDir, #' "ex1_good_small_1KG_Annot_GDS.gds")) #' -#' ## Generate the synthetic profiles and add them into the Profile GDS -#' syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gds1KGAnnot, -#' fileProfileGDS=fileNameGDS, profileID="ex1", -#' listSampleRef=c("HG00243", "HG00150"), nbSim=1, -#' prefix="synthTest", -#' pRecomb=0.01, minProb=0.999, seqError=0.001) +#' ## Generate the synthetic profiles and add them into the Profile GDS +#' syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gds1KGAnnot, +#' fileProfileGDS=fileNameGDS, profileID="ex1", +#' listSampleRef=c("HG00243", "HG00150"), nbSim=1, +#' prefix="synthTest", +#' pRecomb=0.01, minProb=0.999, seqError=0.001) #' -#' ## Open Profile GDS file -#' profileGDS <- openfn.gds(fileNameGDS) +#' ## Open Profile GDS file +#' profileGDS <- openfn.gds(fileNameGDS) #' -#' tail(read.gdsn(index.gdsn(profileGDS, "sample.id"))) +#' tail(read.gdsn(index.gdsn(profileGDS, "sample.id"))) #' -#' ## Close GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) -#' closefn.gds(gds1KGAnnot) +#' ## Close GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) +#' closefn.gds(gds1KGAnnot) #' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink(file.path(dataDirAllelicFraction, "ex1.gds")) -#' unlink(dataDirAllelicFraction) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileNameGDS, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn diff --git a/man/prepSynthetic.Rd b/man/prepSynthetic.Rd index ba0681633..f1623332c 100644 --- a/man/prepSynthetic.Rd +++ b/man/prepSynthetic.Rd @@ -73,11 +73,11 @@ library(gdsfmt) ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata/tests", package="RAIDS") -## Only run example if the directory containing the genotype can be created -if (file.access(getwd()) == 0) { +## Temporary Profile GDS file +fileNameGDS <- file.path(getwd(), "ex1.gds") - ## Profile GDS file - fileNameGDS <- file.path(getwd(), "ex1.gds") +## Only run example if the directory is writable +if (file.access(getwd()) == 0 && !file.exists(fileNameGDS)) { ## Copy the Profile GDS file demo that has been pruned and annotated file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), diff --git a/man/syntheticGeno.Rd b/man/syntheticGeno.Rd index d8b5b15fe..3e7a5194d 100644 --- a/man/syntheticGeno.Rd +++ b/man/syntheticGeno.Rd @@ -79,56 +79,54 @@ library(gdsfmt) ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata/tests", package="RAIDS") -## Copy the Profile GDS file demo that has been pruned and annotated -## into a test directory (deleted after the example has been run) -dataDirAllelicFraction <- file.path(system.file("extdata", package="RAIDS"), - "demoAllelicFraction") -dir.create(dataDirAllelicFraction, showWarnings=FALSE, - recursive=FALSE, mode="0777") - ## Profile GDS file -fileNameGDS <- file.path(dataDirAllelicFraction, "ex1.gds") +fileNameGDS <- file.path(getwd(), "ex1.gds") + +## Only run example if the directory is writable +if (file.access(getwd()) == 0 && !file.exists(fileNameGDS)) { -file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), + ## Copy the Profile GDS file demo that has been pruned and annotated + file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), fileNameGDS) -## Information about the synthetic data set -syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", - study.desc="MYDATA synthetic data", study.platform="PLATFORM", - stringsAsFactors=FALSE) + ## Information about the synthetic data set + syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", + study.desc="MYDATA synthetic data", study.platform="PLATFORM", + stringsAsFactors=FALSE) -## Add information related to the synthetic profiles into the Profile GDS -prepSynthetic(fileProfileGDS=fileNameGDS, - listSampleRef=c("HG00243", "HG00150"), profileID="ex1", - studyDF=syntheticStudyDF, nbSim=1L, prefix="synthTest", - verbose=FALSE) + ## Add information related to the synthetic profiles into the Profile GDS + prepSynthetic(fileProfileGDS=fileNameGDS, + listSampleRef=c("HG00243", "HG00150"), profileID="ex1", + studyDF=syntheticStudyDF, nbSim=1L, prefix="synthTest", + verbose=FALSE) -## The 1KG files -gds1KG <- snpgdsOpen(file.path(dataDir, + ## The 1KG files + gds1KG <- snpgdsOpen(file.path(dataDir, "ex1_good_small_1KG_GDS.gds")) -gds1KGAnnot <- openfn.gds(file.path(dataDir, + gds1KGAnnot <- openfn.gds(file.path(dataDir, "ex1_good_small_1KG_Annot_GDS.gds")) -## Generate the synthetic profiles and add them into the Profile GDS -syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gds1KGAnnot, - fileProfileGDS=fileNameGDS, profileID="ex1", - listSampleRef=c("HG00243", "HG00150"), nbSim=1, - prefix="synthTest", - pRecomb=0.01, minProb=0.999, seqError=0.001) + ## Generate the synthetic profiles and add them into the Profile GDS + syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gds1KGAnnot, + fileProfileGDS=fileNameGDS, profileID="ex1", + listSampleRef=c("HG00243", "HG00150"), nbSim=1, + prefix="synthTest", + pRecomb=0.01, minProb=0.999, seqError=0.001) -## Open Profile GDS file -profileGDS <- openfn.gds(fileNameGDS) + ## Open Profile GDS file + profileGDS <- openfn.gds(fileNameGDS) -tail(read.gdsn(index.gdsn(profileGDS, "sample.id"))) + tail(read.gdsn(index.gdsn(profileGDS, "sample.id"))) -## Close GDS files (important) -closefn.gds(profileGDS) -closefn.gds(gds1KG) -closefn.gds(gds1KGAnnot) + ## Close GDS files (important) + closefn.gds(profileGDS) + closefn.gds(gds1KG) + closefn.gds(gds1KGAnnot) -## Unlink Profile GDS file (created for demo purpose) -unlink(file.path(dataDirAllelicFraction, "ex1.gds")) -unlink(dataDirAllelicFraction) + ## Remove Profile GDS file (created for demo purpose) + unlink(fileNameGDS, force=TRUE) + +} } \author{ From d257cca4a51d8513fb699db983fc2b80dc9d8d10 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 9 Aug 2023 15:53:00 -0400 Subject: [PATCH 056/385] Update examples for getTableSNV() and computeAllelicFractionDNA() functions --- R/allelicFraction_internal.R | 16 ++++++++++------ man/computeAllelicFractionDNA.Rd | 8 +++++--- man/getTableSNV.Rd | 8 +++++--- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index da4fa1766..2b548dad7 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -62,8 +62,11 @@ #' dataDir <- system.file("extdata/tests", package="RAIDS") #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' +#' ## Temporary Profile GDS file for one profile +#' fileProfile <- file.path(getwd(), "ex1.gds") +#' #' ## Example can only be run if the current directory is in writing mode -#' if (file.access(getwd()) == 0) { +#' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { #' ## Copy the Profile GDS file demo that has been pruned and annotated #' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), #' file.path(getwd(), "ex1.gds")) @@ -71,8 +74,7 @@ #' ## Open the reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Profile GDS file for one profile -#' fileProfile <- file.path(getwd(), "ex1.gds") +#' ## Open Profile GDS file for one profile #' profileGDS <- openfn.gds(fileProfile) #' #' ## The function returns a data frame containing the SNVs information @@ -515,8 +517,11 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snp.pos, chr, #' dataDir <- system.file("extdata/tests", package="RAIDS") #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' +#' ## Temporary Profile GDS file for one profile +#' fileProfile <- file.path(getwd(), "ex1.gds") +#' #' ## Example can only be run if the current directory is in writing mode -#' if (file.access(getwd()) == 0) { +#' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { #' #' ## Copy the Profile GDS file demo that has been pruned and annotated #' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), @@ -525,8 +530,7 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snp.pos, chr, #' ## Open the reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Profile GDS file for one profile -#' fileProfile <- file.path(getwd(), "ex1.gds") +#' ## Open Profile GDS file for one profile #' profileGDS <- openfn.gds(fileProfile) #' #' ## Chromosome length information diff --git a/man/computeAllelicFractionDNA.Rd b/man/computeAllelicFractionDNA.Rd index 876fe6b6b..f7af4b7e6 100644 --- a/man/computeAllelicFractionDNA.Rd +++ b/man/computeAllelicFractionDNA.Rd @@ -99,8 +99,11 @@ allelic fraction for the pruned SNV dataset specific to a DNA-seq profile dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +## Temporary Profile GDS file for one profile +fileProfile <- file.path(getwd(), "ex1.gds") + ## Example can only be run if the current directory is in writing mode -if (file.access(getwd()) == 0) { +if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { ## Copy the Profile GDS file demo that has been pruned and annotated file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), @@ -109,8 +112,7 @@ if (file.access(getwd()) == 0) { ## Open the reference GDS file (demo version) gds1KG <- snpgdsOpen(fileGDS) - ## Profile GDS file for one profile - fileProfile <- file.path(getwd(), "ex1.gds") + ## Open Profile GDS file for one profile profileGDS <- openfn.gds(fileProfile) ## Chromosome length information diff --git a/man/getTableSNV.Rd b/man/getTableSNV.Rd index 8536cdd5f..797fb248d 100644 --- a/man/getTableSNV.Rd +++ b/man/getTableSNV.Rd @@ -81,8 +81,11 @@ library(gdsfmt) dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +## Temporary Profile GDS file for one profile +fileProfile <- file.path(getwd(), "ex1.gds") + ## Example can only be run if the current directory is in writing mode -if (file.access(getwd()) == 0) { +if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { ## Copy the Profile GDS file demo that has been pruned and annotated file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), file.path(getwd(), "ex1.gds")) @@ -90,8 +93,7 @@ if (file.access(getwd()) == 0) { ## Open the reference GDS file (demo version) gds1KG <- snpgdsOpen(fileGDS) - ## Profile GDS file for one profile - fileProfile <- file.path(getwd(), "ex1.gds") + ## Open Profile GDS file for one profile profileGDS <- openfn.gds(fileProfile) ## The function returns a data frame containing the SNVs information From 3848f844a01d04242fd10e9027191616de721d78 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 9 Aug 2023 15:55:33 -0400 Subject: [PATCH 057/385] Update example for estimateAllelicFraction() function --- R/allelicFraction.R | 6 ++++-- man/estimateAllelicFraction.Rd | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index 8ae37dfa5..af92ff541 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -250,8 +250,11 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' dataDir <- system.file("extdata/tests", package="RAIDS") #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' +#' ## Profile GDS file for one profile +#' fileProfile <- file.path("ex1.gds") +#' #' ## Example can only be run if the current directory is in writing mode -#' if (file.access(getwd()) == 0) { +#' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { #' ## Copy the Profile GDS file demo that has been pruned and annotated #' ## into current directory #' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), @@ -261,7 +264,6 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' gds1KG <- snpgdsOpen(fileGDS) #' #' ## Profile GDS file for one profile -#' fileProfile <- file.path("ex1.gds") #' profileGDS <- openfn.gds(fileProfile, readonly=FALSE) #' #' ## Chromosome length information diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index 2f00d1a63..91d10cee7 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -117,8 +117,11 @@ library(gdsfmt) dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +## Profile GDS file for one profile +fileProfile <- file.path("ex1.gds") + ## Example can only be run if the current directory is in writing mode -if (file.access(getwd()) == 0) { +if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { ## Copy the Profile GDS file demo that has been pruned and annotated ## into current directory file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), @@ -128,7 +131,6 @@ if (file.access(getwd()) == 0) { gds1KG <- snpgdsOpen(fileGDS) ## Profile GDS file for one profile - fileProfile <- file.path("ex1.gds") profileGDS <- openfn.gds(fileProfile, readonly=FALSE) ## Chromosome length information From 6a6484d125825c2823db407c8e8d7c1210783ddf Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 9 Aug 2023 15:58:25 -0400 Subject: [PATCH 058/385] Changed parameter of arg_match for compatibility with older R version --- R/processStudy.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/processStudy.R b/R/processStudy.R index 05350e140..4f410b5a3 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2255,7 +2255,7 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, verbose=verbose) ## Matches a character method against a table of candidate values - algorithm <- arg_match(algorithm, multiple=FALSE) + algorithm <- arg_match(algorithm) ## Merge results from PCA run on synthetic data present in RDS files KNN.list <- list() From 3e69f2d19d952bc483cb96ff38f5736efec2523c Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 9 Aug 2023 19:55:36 -0400 Subject: [PATCH 059/385] Update examples in documentation and change 1KG reference in documentation --- R/allelicFraction.R | 4 ++-- R/allelicFraction_internal.R | 16 ++++++++-------- R/gdsWrapper_internal.R | 2 +- R/processStudy.R | 31 ++++++++++++++++++------------- man/add1KG2SampleGDS.Rd | 15 +++++++++------ man/addGDSRef.Rd | 2 +- man/computeAllelicFractionDNA.Rd | 2 +- man/computeAllelicFractionRNA.Rd | 2 +- man/computeLOHBlocksDNAChr.Rd | 2 +- man/estimateAllelicFraction.Rd | 4 ++-- man/getTableSNV.Rd | 10 +++++----- man/pruningSample.Rd | 12 +++++++----- man/runExomeAncestry.Rd | 4 ++-- 13 files changed, 58 insertions(+), 48 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index af92ff541..8075a0086 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -166,7 +166,7 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' the type of study (DNA or RNA). #' #' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), the opened 1KG GDS file. +#' (a GDS file), the opened Reference GDS file. #' #' @param gdsProfile an object of class \code{\link[gdsfmt]{gds.class}} #' (a GDS file), the opened Profile GDS file. @@ -210,7 +210,7 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' Default: \code{3}. #' #' @param gdsRefAnnot an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), the1 1KG Annotation GDS file. +#' (a GDS file), the opened Reference SNV Annotation GDS file. #' This parameter is RNA specific. #' Default: \code{NULL}. #' diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 2b548dad7..cd8db002d 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -1,10 +1,10 @@ #' @title Extract the genotype information for a SNV dataset using -#' the Profile GDS file and the 1KG GDS file +#' the Profile GDS file and the Reference GDS file #' #' @description The function generates a \code{data.frame} containing the #' genotype information from a initial list of SNVs associated to a specific -#' profile. The function uses the information present in the 1KG GDS file -#' (reference) and the Profile GDS file. +#' profile. The function uses the information present in the Reference GDS file +#' and the Profile GDS file. #' #' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} (a #' GDS file), the opened 1KG GDS file. @@ -47,7 +47,7 @@ #' the normal genotype is unknown.} #' \item{pruned} { a \code{logical}} #' \item{snp.index} {a \code{vector} of \code{integer} representing the -#' position of the SNVs in the 1KG GDS file.} +#' position of the SNVs in the Reference GDS file.} #' \item{keep} {a \code{logical} } #' \item{hetero} {a \code{logical} } #' \item{homo} {a \code{logical} } @@ -69,7 +69,7 @@ #' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { #' ## Copy the Profile GDS file demo that has been pruned and annotated #' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), -#' file.path(getwd(), "ex1.gds")) +#' fileProfile) #' #' ## Open the reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileGDS) @@ -233,7 +233,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' #' @param gdsReference an object of class #' \code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, an -#' opened 1KG GDS file. +#' opened Reference GDS file. #' #' @param chrInfo a \code{vector} of \code{integer} representing the length of #' the chromosomes. As an example, the information ca be obtained from @@ -525,7 +525,7 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snp.pos, chr, #' #' ## Copy the Profile GDS file demo that has been pruned and annotated #' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), -#' file.path(getwd(), "ex1.gds")) +#' fileProfile) #' #' ## Open the reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileGDS) @@ -655,7 +655,7 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' (a GDS file), the opened Profile GDS file. #' #' @param gdsRefAnnot an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), the opeoned 1KG SNV Annotation GDS file. +#' (a GDS file), the opened Reference SNV Annotation GDS file. #' #' @param currentProfile a \code{character} string corresponding to #' the sample identifier as used in \code{\link{pruningSample}} function. diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 9ab8b5f24..ed6fd20a6 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -119,7 +119,7 @@ generateGDSRefSample <- function(gdsReference, dfPedReference, #' ## Required library #' library(gdsfmt) #' -#' ## Locate RDS with unrelated/related status for 1KG samples +#' ## Locate RDS with unrelated/related status for Reference samples #' dataDir <- system.file("extdata", package="RAIDS") #' rdsFilePath <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") #' diff --git a/R/processStudy.R b/R/processStudy.R index 05350e140..86a684672 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -421,12 +421,14 @@ appendStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' Source = rep("Databank B", 2), stringsAsFactors = FALSE) #' rownames(samplePED) <- samplePED$Name.ID #' +#' ## Temporary Profile GDS file +#' profileFile <- file.path(getwd(), "ex1.gds") +#' #' ## Example can only be run if the current directory is in writing mode -#' if (file.access(getwd()) == 0) { +#' if (file.access(getwd()) == 0 && !file.exists(profileFile)) { #' #' ## Copy the Profile GDS file demo that has not been pruned yet -#' file.copy(file.path(dataDir, "ex1_demo.gds"), -#' file.path(getwd(), "ex1.gds")) +#' file.copy(file.path(dataDir, "ex1_demo.gds"), profileFile) #' #' ## Open 1KG file #' gds1KG <- snpgdsOpen(fileGDS) @@ -441,14 +443,14 @@ appendStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' #' ## Check content of Profile GDS file #' ## The 'pruned.study' entry should be present -#' content <- openfn.gds(file.path(getwd(), "ex1.gds")) +#' content <- openfn.gds(profileFile) #' content #' #' ## Close the Profile GDS file (important) #' closefn.gds(content) #' #' ## Remove Profile GDS file (created for demo purpose) -#' unlink(file.path(getwd(), "ex1.gds"), force=TRUE) +#' unlink(profileFile, force=TRUE) #' #' } #' @@ -615,12 +617,15 @@ pruningSample <- function(gdsReference, #' study.platform="PLATFORM", #' stringsAsFactors=FALSE) #' -#' ## Only run example if the directory containing the genotype can be created -#' if (file.access(getwd()) == 0) { +#' ## Temporary Profile file +#' fileProfile <- file.path(getwd(), "ex2.gds") +#' +#' ## Only run example if the directory is writable +#' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { #' #' ## Copy required file #' file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), -#' file.path(getwd(), "ex2.gds")) +#' fileProfile) #' #' ## Open 1KG file #' gds1KG <- snpgdsOpen(fileGDS) @@ -628,7 +633,7 @@ pruningSample <- function(gdsReference, #' ## Compute the list of pruned SNVs for a specific profile 'ex1' #' ## and save it in the Profile GDS file 'ex2.gds' #' add1KG2SampleGDS(gdsReference=gds1KG, -#' fileProfileGDS=file.path(getwd(), "ex2.gds"), +#' fileProfileGDS=fileProfile, #' currentProfile=c("ex1"), #' studyID=studyDF$study.id) #' @@ -637,14 +642,14 @@ pruningSample <- function(gdsReference, #' #' ## Check content of Profile GDS file #' ## The 'pruned.study' entry should be present -#' content <- openfn.gds(file.path(getwd(), "ex2.gds")) +#' content <- openfn.gds(fileProfile) #' content #' #' ## Close the Profile GDS file (important) #' closefn.gds(content) #' #' ## Remove Profile GDS file (created for demo purpose) -#' unlink(file.path(getwd(), "ex2.gds"), force=TRUE) +#' unlink(fileProfile, force=TRUE) #' } #' #' @@ -2338,10 +2343,10 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' the directory where the output files are created. #' #' @param fileReferenceGDS a \code{character} string representing the file -#' name of the 1KG GDS file. The file must exist. +#' name of the Reference GDS file. The file must exist. #' #' @param fileReferenceAnnotGDS a \code{character} string representing the -#' file name of the 1KG GDS annotation file. The file must exist. +#' file name of the Reference GDS Annotation file. The file must exist. #' #' @param chrInfo a \code{vector} of positive \code{integer} values #' representing the length of the chromosomes. See 'details' section. diff --git a/man/add1KG2SampleGDS.Rd b/man/add1KG2SampleGDS.Rd index 95e34bd21..15d039fc8 100644 --- a/man/add1KG2SampleGDS.Rd +++ b/man/add1KG2SampleGDS.Rd @@ -49,12 +49,15 @@ studyDF <- data.frame(study.id="MYDATA", study.platform="PLATFORM", stringsAsFactors=FALSE) -## Only run example if the directory containing the genotype can be created -if (file.access(getwd()) == 0) { +## Temporary Profile file +fileProfile <- file.path(getwd(), "ex2.gds") + +## Only run example if the directory is writable +if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { ## Copy required file file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), - file.path(getwd(), "ex2.gds")) + fileProfile) ## Open 1KG file gds1KG <- snpgdsOpen(fileGDS) @@ -62,7 +65,7 @@ if (file.access(getwd()) == 0) { ## Compute the list of pruned SNVs for a specific profile 'ex1' ## and save it in the Profile GDS file 'ex2.gds' add1KG2SampleGDS(gdsReference=gds1KG, - fileProfileGDS=file.path(getwd(), "ex2.gds"), + fileProfileGDS=fileProfile, currentProfile=c("ex1"), studyID=studyDF$study.id) @@ -71,14 +74,14 @@ if (file.access(getwd()) == 0) { ## Check content of Profile GDS file ## The 'pruned.study' entry should be present - content <- openfn.gds(file.path(getwd(), "ex2.gds")) + content <- openfn.gds(fileProfile) content ## Close the Profile GDS file (important) closefn.gds(content) ## Remove Profile GDS file (created for demo purpose) - unlink(file.path(getwd(), "ex2.gds"), force=TRUE) + unlink(fileProfile, force=TRUE) } diff --git a/man/addGDSRef.Rd b/man/addGDSRef.Rd index c976e966e..974070225 100644 --- a/man/addGDSRef.Rd +++ b/man/addGDSRef.Rd @@ -33,7 +33,7 @@ that contains the information about the unrelated reference samples. ## Required library library(gdsfmt) -## Locate RDS with unrelated/related status for 1KG samples +## Locate RDS with unrelated/related status for Reference samples dataDir <- system.file("extdata", package="RAIDS") rdsFilePath <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") diff --git a/man/computeAllelicFractionDNA.Rd b/man/computeAllelicFractionDNA.Rd index f7af4b7e6..ae65fc56c 100644 --- a/man/computeAllelicFractionDNA.Rd +++ b/man/computeAllelicFractionDNA.Rd @@ -107,7 +107,7 @@ if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { ## Copy the Profile GDS file demo that has been pruned and annotated file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), - file.path(getwd(), "ex1.gds")) + fileProfile) ## Open the reference GDS file (demo version) gds1KG <- snpgdsOpen(fileGDS) diff --git a/man/computeAllelicFractionRNA.Rd b/man/computeAllelicFractionRNA.Rd index 9891a3a83..04d5c10ac 100644 --- a/man/computeAllelicFractionRNA.Rd +++ b/man/computeAllelicFractionRNA.Rd @@ -30,7 +30,7 @@ computeAllelicFractionRNA( (a GDS file), the opened Profile GDS file.} \item{gdsRefAnnot}{an object of class \code{\link[gdsfmt]{gds.class}} -(a GDS file), the opeoned 1KG SNV Annotation GDS file.} +(a GDS file), the opened Reference SNV Annotation GDS file.} \item{currentProfile}{a \code{character} string corresponding to the sample identifier as used in \code{\link{pruningSample}} function.} diff --git a/man/computeLOHBlocksDNAChr.Rd b/man/computeLOHBlocksDNAChr.Rd index 7a68e9587..32169fb10 100644 --- a/man/computeLOHBlocksDNAChr.Rd +++ b/man/computeLOHBlocksDNAChr.Rd @@ -10,7 +10,7 @@ computeLOHBlocksDNAChr(gdsReference, chrInfo, snp.pos, chr, genoN = 1e-04) \arguments{ \item{gdsReference}{an object of class \code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, an -opened 1KG GDS file.} +opened Reference GDS file.} \item{chrInfo}{a \code{vector} of \code{integer} representing the length of the chromosomes. As an example, the information ca be obtained from diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index 91d10cee7..db6888561 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -27,7 +27,7 @@ estimateAllelicFraction( } \arguments{ \item{gdsReference}{an object of class \code{\link[gdsfmt]{gds.class}} -(a GDS file), the opened 1KG GDS file.} +(a GDS file), the opened Reference GDS file.} \item{gdsProfile}{an object of class \code{\link[gdsfmt]{gds.class}} (a GDS file), the opened Profile GDS file.} @@ -71,7 +71,7 @@ log score, that the SNVs in a gene are allelic fraction different 0.5 Default: \code{3}.} \item{gdsRefAnnot}{an object of class \code{\link[gdsfmt]{gds.class}} -(a GDS file), the1 1KG Annotation GDS file. +(a GDS file), the opened Reference SNV Annotation GDS file. This parameter is RNA specific. Default: \code{NULL}.} diff --git a/man/getTableSNV.Rd b/man/getTableSNV.Rd index 797fb248d..95db95e0b 100644 --- a/man/getTableSNV.Rd +++ b/man/getTableSNV.Rd @@ -4,7 +4,7 @@ \name{getTableSNV} \alias{getTableSNV} \title{Extract the genotype information for a SNV dataset using -the Profile GDS file and the 1KG GDS file} +the Profile GDS file and the Reference GDS file} \usage{ getTableSNV( gdsReference, @@ -60,7 +60,7 @@ SNV. The possibles are: \code{0} (wild-type homozygote), \code{1} the normal genotype is unknown.} \item{pruned} { a \code{logical}} \item{snp.index} {a \code{vector} of \code{integer} representing the -position of the SNVs in the 1KG GDS file.} +position of the SNVs in the Reference GDS file.} \item{keep} {a \code{logical} } \item{hetero} {a \code{logical} } \item{homo} {a \code{logical} } @@ -69,8 +69,8 @@ position of the SNVs in the 1KG GDS file.} \description{ The function generates a \code{data.frame} containing the genotype information from a initial list of SNVs associated to a specific -profile. The function uses the information present in the 1KG GDS file -(reference) and the Profile GDS file. +profile. The function uses the information present in the Reference GDS file +and the Profile GDS file. } \examples{ @@ -88,7 +88,7 @@ fileProfile <- file.path(getwd(), "ex1.gds") if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { ## Copy the Profile GDS file demo that has been pruned and annotated file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), - file.path(getwd(), "ex1.gds")) + fileProfile) ## Open the reference GDS file (demo version) gds1KG <- snpgdsOpen(fileGDS) diff --git a/man/pruningSample.Rd b/man/pruningSample.Rd index 4353ea2f0..f193d3c1d 100644 --- a/man/pruningSample.Rd +++ b/man/pruningSample.Rd @@ -131,12 +131,14 @@ samplePED <- data.frame(Name.ID = c("ex1", "ex2"), Source = rep("Databank B", 2), stringsAsFactors = FALSE) rownames(samplePED) <- samplePED$Name.ID +## Temporary Profile GDS file +profileFile <- file.path(getwd(), "ex1.gds") + ## Example can only be run if the current directory is in writing mode -if (file.access(getwd()) == 0) { +if (file.access(getwd()) == 0 && !file.exists(profileFile)) { ## Copy the Profile GDS file demo that has not been pruned yet - file.copy(file.path(dataDir, "ex1_demo.gds"), - file.path(getwd(), "ex1.gds")) + file.copy(file.path(dataDir, "ex1_demo.gds"), profileFile) ## Open 1KG file gds1KG <- snpgdsOpen(fileGDS) @@ -151,14 +153,14 @@ if (file.access(getwd()) == 0) { ## Check content of Profile GDS file ## The 'pruned.study' entry should be present - content <- openfn.gds(file.path(getwd(), "ex1.gds")) + content <- openfn.gds(profileFile) content ## Close the Profile GDS file (important) closefn.gds(content) ## Remove Profile GDS file (created for demo purpose) - unlink(file.path(getwd(), "ex1.gds"), force=TRUE) + unlink(profileFile, force=TRUE) } diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index b45307584..42ce3e82f 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -47,10 +47,10 @@ associated SNP-pileup file called "Name.ID.txt.gz".} the directory where the output files are created.} \item{fileReferenceGDS}{a \code{character} string representing the file -name of the 1KG GDS file. The file must exist.} +name of the Reference GDS file. The file must exist.} \item{fileReferenceAnnotGDS}{a \code{character} string representing the -file name of the 1KG GDS annotation file. The file must exist.} +file name of the Reference GDS Annotation file. The file must exist.} \item{chrInfo}{a \code{vector} of positive \code{integer} values representing the length of the chromosomes. See 'details' section.} From 3d8d739d411d5dc82fa89a6acce5499b8ff1ec10 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 9 Aug 2023 21:13:38 -0400 Subject: [PATCH 060/385] Remove references to 1KG in documentation --- R/allelicFraction_internal.R | 16 +++--- R/gdsWrapper.R | 2 +- R/process1KG.R | 86 ++++++++++++++++---------------- R/process1KG_internal.R | 12 ++--- R/processStudy.R | 26 +++++----- man/addGeneBlockGDSRefAnnot.Rd | 4 +- man/addRef2GDS1KG.Rd | 13 ++--- man/computeAllelicFractionDNA.Rd | 4 +- man/computeAllelicFractionRNA.Rd | 2 +- man/computeAllelicImbDNAChr.Rd | 2 +- man/computeLOHBlocksDNAChr.Rd | 2 +- man/createStudy2GDS1KG.Rd | 10 ++-- man/generateGDS1KG.Rd | 12 ++--- man/generateMapSnvSel.Rd | 4 +- man/getGeneBlock.Rd | 2 +- man/getRef1KGPop.Rd | 8 +-- man/getTableSNV.Rd | 2 +- man/identifyRelative.Rd | 18 +++---- man/prepPed1KG.Rd | 21 ++++---- man/pruningSample.Rd | 7 +-- man/validatePrepPed1KG.Rd | 12 ++--- 21 files changed, 136 insertions(+), 129 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index cd8db002d..495e93325 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -7,7 +7,7 @@ #' and the Profile GDS file. #' #' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} (a -#' GDS file), the opened 1KG GDS file. +#' GDS file), the opened Reference GDS file. #' #' @param gdsSample an object of class \code{\link[gdsfmt]{gds.class}} #' (a GDS file), the opened Profile GDS file. @@ -258,7 +258,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' \item{pruned} {a \code{logical} indicating if the SNV is retained after #' pruning} #' \item{snp.index} {a \code{integer} representing the index position of the -#' SNV in the 1KG GDS file that contains all SNVs} +#' SNV in the Reference GDS file that contains all SNVs} #' \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} #' \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} #' \item{homo} {a \code{logical} indicating if the SNV is homozygote} @@ -446,7 +446,7 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snp.pos, chr, #' allelic fraction for the pruned SNV dataset specific to a DNA-seq profile #' #' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), the opened 1KG GDS file. +#' (a GDS file), the opened Reference GDS file. #' #' @param gdsSample an object of class \code{\link[gdsfmt]{gds.class}} #' (a GDS file), the opened Profile GDS file. @@ -499,7 +499,7 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snp.pos, chr, #' \item{pruned} {a \code{logical} indicating if the SNV is retained after #' pruning} #' \item{snp.index} {a \code{integer} representing the index position of the -#' SNV in the 1KG GDS file that contains all SNVs} +#' SNV in the Reference GDS file that contains all SNVs} #' \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} #' \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} #' \item{homo} {a \code{logical} indicating if the SNV is homozygote} @@ -569,7 +569,7 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, wAR=9L, verbose) { ## Extract the genotype information for a SNV dataset using - ## the Profile GDS file and the 1KG GDS file + ## the Profile GDS file and the Reference GDS file snp.pos <- getTableSNV(gdsReference=gdsReference, gdsSample=gdsSample, currentProfile=currentProfile, studyID=studyID, minCov=minCov, minProb=minProb, eProb=eProb, verbose=verbose) @@ -649,7 +649,7 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' TODO #' #' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), the opened 1KG GDS file. +#' (a GDS file), the opened Reference GDS file. #' #' @param gdsSample an object of class \code{\link[gdsfmt]{gds.class}} #' (a GDS file), the opened Profile GDS file. @@ -712,7 +712,7 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, cutOffAR=3, verbose) { ## Extract the genotype information for a SNV dataset using - ## the GDS Sample file and the 1KG GDS file + ## the GDS Sample file and the Reference GDS file snp.pos <- getTableSNV(gdsReference, gdsSample, currentProfile, studyID, minCov, minProb, eProb) # Keep only SNV in GDS ref because to reduce SNV artefact from RNA @@ -796,7 +796,7 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, #' \item{pruned} {a \code{logical} indicating if the SNV is retained after #' pruning} #' \item{snp.index} {a \code{integer} representing the index position of the -#' SNV in the 1KG GDS file that contains all SNVs} +#' SNV in the Reference GDS file that contains all SNVs} #' \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} #' \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} #' \item{homo} {a \code{logical} indicating if the SNV is homozygote} diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 288d594f4..d462603e5 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -611,7 +611,7 @@ addUpdateSegment <- function(gdsProfile, snp.seg) { #' @description TODO #' #' @param gdsRefAnnot an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), the opened 1KG SNV Annotation GDS file. RNA specific +#' (a GDS file), the opened Reference SNV Annotation GDS file. RNA specific #' Default: \code{NULL}. #' #' @param snp.index TODO diff --git a/R/process1KG.R b/R/process1KG.R index f1618b4d2..f4b4b9d86 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -1,6 +1,6 @@ -#' @title Prepare the pedigree file using pedigree information from 1KG +#' @title Prepare the pedigree file using pedigree information from Reference #' -#' @description Using the pedigree file from 1KG, this function extracts +#' @description Using the pedigree file from Reference, this function extracts #' needed information and formats it into a \code{data.frame} so in can #' be used in following steps of the ancestry inference process. The #' function also requires that the genotyping files associated to each @@ -8,22 +8,23 @@ #' #' @param filePed a \code{character} string representing the path and #' file name of the pedigree file (PED file) that contains the information -#' related to the profiles present in the 1KG GDS file. The PED file must +#' related to the profiles present in the Reference GDS file. The PED file must #' exist. #' #' @param pathGeno a \code{character} string representing the path where -#' the 1KG genotyping files for each profile are located. Only the profiles -#' with associated genotyping files are retained in the creation of the final -#' \code{data.frame}. The name of the genotyping files must correspond to -#' the individual identification (Individual.ID) in the pedigree file -#' (PED file). +#' the Reference genotyping files for each profile are located. Only the +#' profiles with associated genotyping files are retained in the creation of +#' the final \code{data.frame}. The name of the genotyping files must +#' correspond to the individual identification (Individual.ID) in the +#' pedigree file (PED file). #' Default: \code{"./data/sampleGeno"}. #' #' @param batch a\code{integer} that uniquely identifies the source of the -#' pedigree information. The 1KG is usually \code{0L}. Default: \code{0L}. +#' pedigree information. The Reference is usually \code{0L}. +#' Default: \code{0L}. #' #' @return a \code{data.frame} containing the needed pedigree information -#' from 1KG. The \code{data.frame} contains those columns: +#' from Reference. The \code{data.frame} contains those columns: #' \itemize{ #' \item{sample.id}{a \code{character} string representing the profile unique #' ID.} @@ -59,7 +60,7 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), ## Validate parameters validatePrepPed1KG(filePed=filePed, pathGeno=pathGeno, batch=batch) - ## Read the pedigree file from 1KG + ## Read the pedigree file from Reference ped1KG <- read.delim(filePed) ## Create a data.frame containing the needed information @@ -117,8 +118,8 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' for the frequency in at least one super population. Default: \code{0.01}. #' #' @param fileSNV a \code{character} string representing the path and -#' file name of the bulk SNP information file from 1KG. The file must be in -#' text format. The file must exist. +#' file name of the bulk SNP information file from Reference. The file must +#' be in text format. The file must exist. #' #' @param fileSNPsRDS a \code{character} string representing the path and #' file name of the RDS file that will contain the indexes of the retained @@ -243,12 +244,12 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { } -#' @title Generate the GDS file that will contain the information from 1KG -#' data set (reference data set) +#' @title Generate the GDS file that will contain the information from +#' Reference data set (reference data set) #' #' @description This function generates the GDS file that will contain the -#' information from 1KG. The function also add the samples information, the -#' SNP information and the genotyping information into the GDS file. +#' information from Reference. The function also add the samples information, +#' the SNP information and the genotyping information into the GDS file. #' #' @param pathGeno a \code{character} string representing the path where #' the 1K genotyping files for each sample are located. The name of the @@ -307,7 +308,7 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { #' ## Different code depending of the withr package availability #' if (requireNamespace("withr", quietly=TRUE)) { #' -#' ## Temporary GDS file containing 1KG information +#' ## Temporary GDS file containing Reference information #' gdsFile <- withr::local_file(file.path(dataDir, "1KG_TEMP.gds")) #' #' ## Create a temporary GDS file containing information from 1KG @@ -320,7 +321,7 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { #' #' } else { #' -#' ## Temporary GDS file containing 1KG information +#' ## Temporary GDS file containing Reference information #' gdsFile <- file.path(dataDir, "1KG_TEMP.gds") #' #' ## Create a temporary GDS file containing information from 1KG @@ -499,16 +500,16 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, return(0L) } -#' @title Identify genetically unrelated patients in GDS 1KG file +#' @title Identify genetically unrelated patients in GDS Reference file #' #' @description The function identify patients that are genetically related in -#' the 1KG file. It generates a first RDS file with the list of unrelated +#' the Reference file. It generates a first RDS file with the list of unrelated #' patient. It also generates a second RDS file with the kinship coefficient #' between the patients. #' #' @param gds an object of class #' \code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, the -#' 1KG GDS file. +#' Reference GDS file. #' #' @param maf a single \code{numeric} representing the threshold for the minor #' allele frequency. Only the SNPs with ">= maf" will be used. @@ -525,7 +526,7 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, #' #' @param filePart a \code{character} string representing the path and file #' name of the RDS file that will be created. The RDS file will contain the -#' information about the 1KG patients that are unrelated. The file will +#' information about the Reference patients that are unrelated. The file will #' contains two lists: the \code{list} of related samples, called \code{rels} #' and the list of unrelated samples, called \code{unrels}. #' The extension of the file must be '.rds'. @@ -540,7 +541,7 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' -#' ## Open existing 1K GDS file +#' ## Open existing demo Reference GDS file #' fileGDS <- file.path(dataDir, "1KG_Demo.gds") #' tmpGDS <- snpgdsOpen(fileGDS) #' @@ -560,11 +561,11 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, #' patientTmpFileLocal <- withr::local_file(patientTmpFile) #' ibdTmpFileLocal <- withr::local_file(ibdTmpFile) #' -#' ## Identify unrelated patients in 1KG GDS file +#' ## Identify unrelated patients in demo Reference GDS file #' identifyRelative(gds=tmpGDS, maf=0.05, thresh=2^(-11/2), #' fileIBD=ibdTmpFileLocal, filePart=patientTmpFileLocal) #' -#' ## Close 1K GDS file +#' ## Close demo Reference GDS file #' closefn.gds(tmpGDS) #' #' ## Remove temporary files @@ -572,11 +573,11 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, #' #' } else { #' -#' ## Identify unrelated patients in 1KG GDS file +#' ## Identify unrelated patients in demo Reference GDS file #' identifyRelative(gds=tmpGDS, maf=0.05, thresh=2^(-11/2), #' fileIBD=ibdTmpFile, filePart=patientTmpFile) #' -#' ## Close 1K GDS file +#' ## Close demo Reference GDS file #' closefn.gds(tmpGDS) #' #' ## Remove temporary files @@ -624,24 +625,25 @@ identifyRelative <- function(gds, maf=0.05, thresh=2^(-11/2), } -#' @title Add the information about the unrelated patients to the 1KG GDS file +#' @title Add the information about the unrelated patients to the Reference +#' GDS file #' #' @description This function adds the information about the unrelated patients -#' to the 1KG GDS file. More specifically, it creates the field +#' to the Reference GDS file. More specifically, it creates the field #' \code{sample.ref} which as the value \code{1} when the sample #' is unrelated and the value \code{0} otherwise. #' The \code{sample.ref} is filled based on the information present in the #' input RDS file. #' #' @param fileNameGDS a \code{character} string representing the path and file -#' name of the GDS file that contains the 1KG information. The 1KG GDS file -#' must contain the SNP information, the genotyping information and -#' the pedigree information from 1000 Genomes. +#' name of the GDS file that contains the Reference information. The +#' Reference GDS file must contain the SNP information, the genotyping +#' information and the pedigree information from Reference dataset. #' The extension of the file must be '.gds'. #' #' @param filePart a \code{character} string representing the path and file #' name of the RDS file that contains the -#' information about the 1KG patients that are unrelated. +#' information about the Reference patients that are unrelated. #' The extension of the file must be '.rds'. The file must exists. #' #' @return The integer \code{0L} when successful. @@ -880,16 +882,16 @@ addBlockFromPlink2GDS <- function(gds, gdsOut, PATHBLOCK, #' for the reference profiles (real ancestry assignation) #' #' @description The function extract the specified column for the 'sample.ref' -#' node present in the 1KG GDS file. The column must be present in the +#' node present in the Reference GDS file. The column must be present in the #' \code{data.frame} saved in the 'sample.ref' node. Only the information for #' the reference profiles is returned. The values #' represent the known ancestry assignation. #' #' @param gdsReference an object of class -#' \link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file. +#' \link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file. #' #' @param popName a \code{character} string representing the name of the column -#' that will be fetched in the \code{data.frame} present in the 1KG GDS +#' that will be fetched in the \code{data.frame} present in the Reference GDS #' "sample.ref" node. The column must be present in the \code{data.frame}. #' Default: \code{"superPop"}. #' @@ -903,7 +905,7 @@ addBlockFromPlink2GDS <- function(gds, gdsOut, PATHBLOCK, #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' -#' ## Open existing 1K GDS file with "sample.ref" node +#' ## Open existing demo 1K GDS file with "sample.ref" node #' nameFileGDS <- file.path(dataDir, "1KG_Demo_with_sampleREF.gds") #' fileGDS <- snpgdsOpen(nameFileGDS) #' @@ -952,9 +954,9 @@ getRef1KGPop <- function(gdsReference, popName="superPop") { #' @description TODO #' #' @param gdsReference an object of class -#' \link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file. +#' \link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file. #' -#' @param file.gdsRefAnnot the filename corresponding the 1KG SNV +#' @param file.gdsRefAnnot the filename corresponding the Reference SNV #' Annotation GDS file. The function will #' open it in write mode and close it after. The file must exist. #' @@ -1002,7 +1004,7 @@ addGeneBlockGDSRefAnnot <- function(gdsReference, file.gdsRefAnnot, ## Generate two indexes based on gene annotation for gdsAnnot1KG block dfGeneBlock <- generateGeneBlock(gdsReference, winSize, EnsDb) - ## Opne GDS 1KG Annotation file in writting mode + ## Open GDS Reference Annotation file in writting mode gdsRefAnnot <- openfn.gds(file.gdsRefAnnot, readonly=FALSE) blockName <- paste0("Gene.", suffixe.blockName) @@ -1013,7 +1015,7 @@ addGeneBlockGDSRefAnnot <- function(gdsReference, file.gdsRefAnnot, blockDesc <- paste0("List of blocks of split by genes ", suffixe.blockName) addGDS1KGLDBlock(gdsRefAnnot, dfGeneBlock$GeneS, blockName, blockDesc) - ## Close GDS 1KG annotation file + ## Close GDS Reference annotation file closefn.gds(gdsRefAnnot) ## Success diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index 0d98476b2..190a70ded 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -415,14 +415,14 @@ generateGeneBlock <- function(gdsReference, winSize=10000, EnsDb) { #' exist. #' #' @param pathGeno a \code{character} string representing the path where -#' the 1KG genotyping files for each profile are located. Only the profiles -#' with associated genotyping files are retained in the creation of the final -#' \code{data.frame}. The name of the genotyping files must correspond to -#' the individual identification (Individual.ID) in the pedigree file -#' (PED file). +#' the Reference genotyping files for each profile are located. Only the +#' profiles with associated genotyping files are retained in the creation of +#' the final \code{data.frame}. The name of the genotyping files must +#' correspond to the individual identification (Individual.ID) in the +#' pedigree file (PED file). #' #' @param batch a\code{integer} that uniquely identifies the source of the -#' pedigree information. The 1KG is usually \code{0L}. +#' pedigree information. The Reference is usually \code{0L}. #' #' @return The function returns \code{0L} when successful. #' diff --git a/R/processStudy.R b/R/processStudy.R index 347aa7b87..9a19ac873 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2,10 +2,10 @@ #' using the information from a RDS Sample description file and the 1KG #' GDS file #' -#' @description The function uses the information for the 1KG GDS file and the -#' RDS Sample Description file to create the Profile GDS file. One Profile GDS -#' file is created per profile. One Profile GDS file will be created for each -#' entry present in the \code{listProfiles} parameter. +#' @description The function uses the information for the Reference GDS file +#' and the RDS Sample Description file to create the Profile GDS file. One +#' Profile GDS file is created per profile. One Profile GDS file will be +#' created for each entry present in the \code{listProfiles} parameter. #' #' @param pathGeno a \code{character} string representing the path to the #' directory containing the VCF output of SNP-pileup for each sample. The @@ -31,7 +31,7 @@ #' can be defined. #' #' @param fileNameGDS a \code{character} string representing the file name of -#' the 1KG GDS file. The file must exist. +#' the Reference GDS file. The file must exist. #' #' @param batch a single positive \code{integer} representing the current #' identifier for the batch. Beware, this field is not stored anymore. @@ -148,7 +148,7 @@ createStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), genoSource <- arg_match(genoSource) - ## Read the 1KG GDS file + ## Read the Reference GDS file gdsReference <- snpgdsOpen(filename=fileNameGDS) ## Extract the chromosome and position information for all SNPs in 1KG GDS @@ -281,10 +281,11 @@ appendStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), ## Open the RDS Sample information file pedStudy <- readRDS(file=filePedRDS) - ## Read the 1KG GDS file + ## Read the Reference GDS file gdsReference <- snpgdsOpen(filename=fileNameGDS) - ## Extract the chromosome and position information for all SNPs in 1KG GDS + ## Extract the chromosome and position information for all SNPs + ## in Reference GDS ## Create a data.frame containing the information snpCHR <- index.gdsn(node=gdsReference, "snp.chromosome") snpPOS <- index.gdsn(node=gdsReference, "snp.position") @@ -307,7 +308,7 @@ appendStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), message("Genotype DONE ", Sys.time()) } - ## Close 1KG GDS file + ## Close Reference GDS file closefn.gds(gdsReference) ## Return successful code @@ -316,7 +317,8 @@ appendStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' @title Compute the list of pruned SNVs for a specific profile using the -#' information from the 1KG GDS file and a linkage disequilibrium analysis +#' information from the Reference GDS file and a linkage disequilibrium +#' analysis #' #' @description This function computes the list of pruned SNVs for a #' specific profile. When @@ -400,7 +402,7 @@ appendStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' ## Required library for GDS #' library(gdsfmt) #' -#' ## Path to the demo 1KG GDS file is located in this package +#' ## Path to the demo Reference GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' @@ -438,7 +440,7 @@ appendStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' pruningSample(gdsReference=gds1KG, currentProfile=c("ex1"), #' studyID = studyDF$study.id, pathProfileGDS=getwd()) #' -#' ## Close the 1KG GDS file (it is important to always close the GDS files) +#' ## Close the Reference GDS file (important) #' closefn.gds(gds1KG) #' #' ## Check content of Profile GDS file diff --git a/man/addGeneBlockGDSRefAnnot.Rd b/man/addGeneBlockGDSRefAnnot.Rd index b5113fc4e..5728790a2 100644 --- a/man/addGeneBlockGDSRefAnnot.Rd +++ b/man/addGeneBlockGDSRefAnnot.Rd @@ -17,9 +17,9 @@ addGeneBlockGDSRefAnnot( } \arguments{ \item{gdsReference}{an object of class -\link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file.} +\link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file.} -\item{file.gdsRefAnnot}{the filename corresponding the 1KG SNV +\item{file.gdsRefAnnot}{the filename corresponding the Reference SNV Annotation GDS file. The function will open it in write mode and close it after. The file must exist.} diff --git a/man/addRef2GDS1KG.Rd b/man/addRef2GDS1KG.Rd index 0199031e3..ede83943c 100644 --- a/man/addRef2GDS1KG.Rd +++ b/man/addRef2GDS1KG.Rd @@ -3,20 +3,21 @@ \encoding{UTF-8} \name{addRef2GDS1KG} \alias{addRef2GDS1KG} -\title{Add the information about the unrelated patients to the 1KG GDS file} +\title{Add the information about the unrelated patients to the Reference +GDS file} \usage{ addRef2GDS1KG(fileNameGDS, filePart) } \arguments{ \item{fileNameGDS}{a \code{character} string representing the path and file -name of the GDS file that contains the 1KG information. The 1KG GDS file -must contain the SNP information, the genotyping information and -the pedigree information from 1000 Genomes. +name of the GDS file that contains the Reference information. The +Reference GDS file must contain the SNP information, the genotyping +information and the pedigree information from Reference dataset. The extension of the file must be '.gds'.} \item{filePart}{a \code{character} string representing the path and file name of the RDS file that contains the -information about the 1KG patients that are unrelated. +information about the Reference patients that are unrelated. The extension of the file must be '.rds'. The file must exists.} } \value{ @@ -24,7 +25,7 @@ The integer \code{0L} when successful. } \description{ This function adds the information about the unrelated patients -to the 1KG GDS file. More specifically, it creates the field +to the Reference GDS file. More specifically, it creates the field \code{sample.ref} which as the value \code{1} when the sample is unrelated and the value \code{0} otherwise. The \code{sample.ref} is filled based on the information present in the diff --git a/man/computeAllelicFractionDNA.Rd b/man/computeAllelicFractionDNA.Rd index ae65fc56c..fd683cc5b 100644 --- a/man/computeAllelicFractionDNA.Rd +++ b/man/computeAllelicFractionDNA.Rd @@ -23,7 +23,7 @@ computeAllelicFractionDNA( } \arguments{ \item{gdsReference}{an object of class \code{\link[gdsfmt]{gds.class}} -(a GDS file), the opened 1KG GDS file.} +(a GDS file), the opened Reference GDS file.} \item{gdsSample}{an object of class \code{\link[gdsfmt]{gds.class}} (a GDS file), the opened Profile GDS file.} @@ -77,7 +77,7 @@ contains those columns: \item{pruned} {a \code{logical} indicating if the SNV is retained after pruning} \item{snp.index} {a \code{integer} representing the index position of the -SNV in the 1KG GDS file that contains all SNVs} +SNV in the Reference GDS file that contains all SNVs} \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} \item{homo} {a \code{logical} indicating if the SNV is homozygote} diff --git a/man/computeAllelicFractionRNA.Rd b/man/computeAllelicFractionRNA.Rd index 04d5c10ac..edb3127bd 100644 --- a/man/computeAllelicFractionRNA.Rd +++ b/man/computeAllelicFractionRNA.Rd @@ -24,7 +24,7 @@ computeAllelicFractionRNA( } \arguments{ \item{gdsReference}{an object of class \code{\link[gdsfmt]{gds.class}} -(a GDS file), the opened 1KG GDS file.} +(a GDS file), the opened Reference GDS file.} \item{gdsSample}{an object of class \code{\link[gdsfmt]{gds.class}} (a GDS file), the opened Profile GDS file.} diff --git a/man/computeAllelicImbDNAChr.Rd b/man/computeAllelicImbDNAChr.Rd index 1d16ed967..004bd05de 100644 --- a/man/computeAllelicImbDNAChr.Rd +++ b/man/computeAllelicImbDNAChr.Rd @@ -27,7 +27,7 @@ the normal genotype is unknown.} \item{pruned} {a \code{logical} indicating if the SNV is retained after pruning} \item{snp.index} {a \code{integer} representing the index position of the -SNV in the 1KG GDS file that contains all SNVs} +SNV in the Reference GDS file that contains all SNVs} \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} \item{homo} {a \code{logical} indicating if the SNV is homozygote} diff --git a/man/computeLOHBlocksDNAChr.Rd b/man/computeLOHBlocksDNAChr.Rd index 32169fb10..8334e9ba3 100644 --- a/man/computeLOHBlocksDNAChr.Rd +++ b/man/computeLOHBlocksDNAChr.Rd @@ -35,7 +35,7 @@ the normal genotype is unknown.} \item{pruned} {a \code{logical} indicating if the SNV is retained after pruning} \item{snp.index} {a \code{integer} representing the index position of the -SNV in the 1KG GDS file that contains all SNVs} +SNV in the Reference GDS file that contains all SNVs} \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} \item{homo} {a \code{logical} indicating if the SNV is homozygote} diff --git a/man/createStudy2GDS1KG.Rd b/man/createStudy2GDS1KG.Rd index dcc460070..a75744a92 100644 --- a/man/createStudy2GDS1KG.Rd +++ b/man/createStudy2GDS1KG.Rd @@ -45,7 +45,7 @@ must contain the information for all the samples passed in the can be defined.} \item{fileNameGDS}{a \code{character} string representing the file name of -the 1KG GDS file. The file must exist.} +the Reference GDS file. The file must exist.} \item{batch}{a single positive \code{integer} representing the current identifier for the batch. Beware, this field is not stored anymore. @@ -83,10 +83,10 @@ printed. Default: \code{FALSE}.} The function returns \code{0L} when successful. } \description{ -The function uses the information for the 1KG GDS file and the -RDS Sample Description file to create the Profile GDS file. One Profile GDS -file is created per profile. One Profile GDS file will be created for each -entry present in the \code{listProfiles} parameter. +The function uses the information for the Reference GDS file +and the RDS Sample Description file to create the Profile GDS file. One +Profile GDS file is created per profile. One Profile GDS file will be +created for each entry present in the \code{listProfiles} parameter. } \examples{ diff --git a/man/generateGDS1KG.Rd b/man/generateGDS1KG.Rd index 8eab0e7dd..2382905cc 100644 --- a/man/generateGDS1KG.Rd +++ b/man/generateGDS1KG.Rd @@ -3,8 +3,8 @@ \encoding{UTF-8} \name{generateGDS1KG} \alias{generateGDS1KG} -\title{Generate the GDS file that will contain the information from 1KG -data set (reference data set)} +\title{Generate the GDS file that will contain the information from +Reference data set (reference data set)} \usage{ generateGDS1KG( pathGeno = file.path("data", "sampleGeno"), @@ -54,8 +54,8 @@ The integer \code{0L} when successful. } \description{ This function generates the GDS file that will contain the -information from 1KG. The function also add the samples information, the -SNP information and the genotyping information into the GDS file. +information from Reference. The function also add the samples information, +the SNP information and the genotyping information into the GDS file. } \details{ More information about GDS file format can be found at the Bioconductor @@ -79,7 +79,7 @@ filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") ## Different code depending of the withr package availability if (requireNamespace("withr", quietly=TRUE)) { - ## Temporary GDS file containing 1KG information + ## Temporary GDS file containing Reference information gdsFile <- withr::local_file(file.path(dataDir, "1KG_TEMP.gds")) ## Create a temporary GDS file containing information from 1KG @@ -92,7 +92,7 @@ if (requireNamespace("withr", quietly=TRUE)) { } else { - ## Temporary GDS file containing 1KG information + ## Temporary GDS file containing Reference information gdsFile <- file.path(dataDir, "1KG_TEMP.gds") ## Create a temporary GDS file containing information from 1KG diff --git a/man/generateMapSnvSel.Rd b/man/generateMapSnvSel.Rd index 7dcec6a39..97eb1bf66 100644 --- a/man/generateMapSnvSel.Rd +++ b/man/generateMapSnvSel.Rd @@ -12,8 +12,8 @@ generateMapSnvSel(cutOff = 0.01, fileSNV, fileSNPsRDS, fileFREQ) for the frequency in at least one super population. Default: \code{0.01}.} \item{fileSNV}{a \code{character} string representing the path and -file name of the bulk SNP information file from 1KG. The file must be in -text format. The file must exist.} +file name of the bulk SNP information file from Reference. The file must +be in text format. The file must exist.} \item{fileSNPsRDS}{a \code{character} string representing the path and file name of the RDS file that will contain the indexes of the retained diff --git a/man/getGeneBlock.Rd b/man/getGeneBlock.Rd index 4e682eef6..710d4a519 100644 --- a/man/getGeneBlock.Rd +++ b/man/getGeneBlock.Rd @@ -9,7 +9,7 @@ getGeneBlock(gdsRefAnnot, snp.index, blockID) } \arguments{ \item{gdsRefAnnot}{an object of class \code{\link[gdsfmt]{gds.class}} -(a GDS file), the opened 1KG SNV Annotation GDS file. RNA specific +(a GDS file), the opened Reference SNV Annotation GDS file. RNA specific Default: \code{NULL}.} \item{snp.index}{TODO} diff --git a/man/getRef1KGPop.Rd b/man/getRef1KGPop.Rd index 13972760c..3ba200dad 100644 --- a/man/getRef1KGPop.Rd +++ b/man/getRef1KGPop.Rd @@ -10,10 +10,10 @@ getRef1KGPop(gdsReference, popName = "superPop") } \arguments{ \item{gdsReference}{an object of class -\link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file.} +\link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file.} \item{popName}{a \code{character} string representing the name of the column -that will be fetched in the \code{data.frame} present in the 1KG GDS +that will be fetched in the \code{data.frame} present in the Reference GDS "sample.ref" node. The column must be present in the \code{data.frame}. Default: \code{"superPop"}.} } @@ -25,7 +25,7 @@ identifiers are used as names for the \code{vector}. } \description{ The function extract the specified column for the 'sample.ref' -node present in the 1KG GDS file. The column must be present in the +node present in the Reference GDS file. The column must be present in the \code{data.frame} saved in the 'sample.ref' node. Only the information for the reference profiles is returned. The values represent the known ancestry assignation. @@ -35,7 +35,7 @@ represent the known ancestry assignation. ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") -## Open existing 1K GDS file with "sample.ref" node +## Open existing demo 1K GDS file with "sample.ref" node nameFileGDS <- file.path(dataDir, "1KG_Demo_with_sampleREF.gds") fileGDS <- snpgdsOpen(nameFileGDS) diff --git a/man/getTableSNV.Rd b/man/getTableSNV.Rd index 95db95e0b..477984c90 100644 --- a/man/getTableSNV.Rd +++ b/man/getTableSNV.Rd @@ -19,7 +19,7 @@ getTableSNV( } \arguments{ \item{gdsReference}{an object of class \code{\link[gdsfmt]{gds.class}} (a -GDS file), the opened 1KG GDS file.} +GDS file), the opened Reference GDS file.} \item{gdsSample}{an object of class \code{\link[gdsfmt]{gds.class}} (a GDS file), the opened Profile GDS file.} diff --git a/man/identifyRelative.Rd b/man/identifyRelative.Rd index cee751052..9c80a293c 100644 --- a/man/identifyRelative.Rd +++ b/man/identifyRelative.Rd @@ -3,14 +3,14 @@ \encoding{UTF-8} \name{identifyRelative} \alias{identifyRelative} -\title{Identify genetically unrelated patients in GDS 1KG file} +\title{Identify genetically unrelated patients in GDS Reference file} \usage{ identifyRelative(gds, maf = 0.05, thresh = 2^(-11/2), fileIBD, filePart) } \arguments{ \item{gds}{an object of class \code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, the -1KG GDS file.} +Reference GDS file.} \item{maf}{a single \code{numeric} representing the threshold for the minor allele frequency. Only the SNPs with ">= maf" will be used. @@ -27,7 +27,7 @@ The extension of the file must be '.rds'.} \item{filePart}{a \code{character} string representing the path and file name of the RDS file that will be created. The RDS file will contain the -information about the 1KG patients that are unrelated. The file will +information about the Reference patients that are unrelated. The file will contains two lists: the \code{list} of related samples, called \code{rels} and the list of unrelated samples, called \code{unrels}. The extension of the file must be '.rds'.} @@ -37,7 +37,7 @@ The extension of the file must be '.rds'.} } \description{ The function identify patients that are genetically related in -the 1KG file. It generates a first RDS file with the list of unrelated +the Reference file. It generates a first RDS file with the list of unrelated patient. It also generates a second RDS file with the kinship coefficient between the patients. } @@ -49,7 +49,7 @@ library(gdsfmt) ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") -## Open existing 1K GDS file +## Open existing demo Reference GDS file fileGDS <- file.path(dataDir, "1KG_Demo.gds") tmpGDS <- snpgdsOpen(fileGDS) @@ -69,11 +69,11 @@ if (requireNamespace("withr", quietly=TRUE)) { patientTmpFileLocal <- withr::local_file(patientTmpFile) ibdTmpFileLocal <- withr::local_file(ibdTmpFile) - ## Identify unrelated patients in 1KG GDS file + ## Identify unrelated patients in demo Reference GDS file identifyRelative(gds=tmpGDS, maf=0.05, thresh=2^(-11/2), fileIBD=ibdTmpFileLocal, filePart=patientTmpFileLocal) - ## Close 1K GDS file + ## Close demo Reference GDS file closefn.gds(tmpGDS) ## Remove temporary files @@ -81,11 +81,11 @@ if (requireNamespace("withr", quietly=TRUE)) { } else { - ## Identify unrelated patients in 1KG GDS file + ## Identify unrelated patients in demo Reference GDS file identifyRelative(gds=tmpGDS, maf=0.05, thresh=2^(-11/2), fileIBD=ibdTmpFile, filePart=patientTmpFile) - ## Close 1K GDS file + ## Close demo Reference GDS file closefn.gds(tmpGDS) ## Remove temporary files diff --git a/man/prepPed1KG.Rd b/man/prepPed1KG.Rd index d467cccd6..a409d4cd7 100644 --- a/man/prepPed1KG.Rd +++ b/man/prepPed1KG.Rd @@ -3,30 +3,31 @@ \encoding{UTF-8} \name{prepPed1KG} \alias{prepPed1KG} -\title{Prepare the pedigree file using pedigree information from 1KG} +\title{Prepare the pedigree file using pedigree information from Reference} \usage{ prepPed1KG(filePed, pathGeno = file.path("data", "sampleGeno"), batch = 0L) } \arguments{ \item{filePed}{a \code{character} string representing the path and file name of the pedigree file (PED file) that contains the information -related to the profiles present in the 1KG GDS file. The PED file must +related to the profiles present in the Reference GDS file. The PED file must exist.} \item{pathGeno}{a \code{character} string representing the path where -the 1KG genotyping files for each profile are located. Only the profiles -with associated genotyping files are retained in the creation of the final -\code{data.frame}. The name of the genotyping files must correspond to -the individual identification (Individual.ID) in the pedigree file -(PED file). +the Reference genotyping files for each profile are located. Only the +profiles with associated genotyping files are retained in the creation of +the final \code{data.frame}. The name of the genotyping files must +correspond to the individual identification (Individual.ID) in the +pedigree file (PED file). Default: \code{"./data/sampleGeno"}.} \item{batch}{a\code{integer} that uniquely identifies the source of the -pedigree information. The 1KG is usually \code{0L}. Default: \code{0L}.} +pedigree information. The Reference is usually \code{0L}. +Default: \code{0L}.} } \value{ a \code{data.frame} containing the needed pedigree information -from 1KG. The \code{data.frame} contains those columns: +from Reference. The \code{data.frame} contains those columns: \itemize{ \item{sample.id}{a \code{character} string representing the profile unique ID.} @@ -40,7 +41,7 @@ ancestry of the profile.} } } \description{ -Using the pedigree file from 1KG, this function extracts +Using the pedigree file from Reference, this function extracts needed information and formats it into a \code{data.frame} so in can be used in following steps of the ancestry inference process. The function also requires that the genotyping files associated to each diff --git a/man/pruningSample.Rd b/man/pruningSample.Rd index f193d3c1d..191730234 100644 --- a/man/pruningSample.Rd +++ b/man/pruningSample.Rd @@ -4,7 +4,8 @@ \name{pruningSample} \alias{pruningSample} \title{Compute the list of pruned SNVs for a specific profile using the -information from the 1KG GDS file and a linkage disequilibrium analysis} +information from the Reference GDS file and a linkage disequilibrium +analysis} \usage{ pruningSample( gdsReference, @@ -110,7 +111,7 @@ function can be specified by the user. ## Required library for GDS library(gdsfmt) -## Path to the demo 1KG GDS file is located in this package +## Path to the demo Reference GDS file is located in this package dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") @@ -148,7 +149,7 @@ if (file.access(getwd()) == 0 && !file.exists(profileFile)) { pruningSample(gdsReference=gds1KG, currentProfile=c("ex1"), studyID = studyDF$study.id, pathProfileGDS=getwd()) - ## Close the 1KG GDS file (it is important to always close the GDS files) + ## Close the Reference GDS file (important) closefn.gds(gds1KG) ## Check content of Profile GDS file diff --git a/man/validatePrepPed1KG.Rd b/man/validatePrepPed1KG.Rd index e07dd8e27..142ffd7e8 100644 --- a/man/validatePrepPed1KG.Rd +++ b/man/validatePrepPed1KG.Rd @@ -14,14 +14,14 @@ related to the profiles present in the 1KG GDS file. The PED file must exist.} \item{pathGeno}{a \code{character} string representing the path where -the 1KG genotyping files for each profile are located. Only the profiles -with associated genotyping files are retained in the creation of the final -\code{data.frame}. The name of the genotyping files must correspond to -the individual identification (Individual.ID) in the pedigree file -(PED file).} +the Reference genotyping files for each profile are located. Only the +profiles with associated genotyping files are retained in the creation of +the final \code{data.frame}. The name of the genotyping files must +correspond to the individual identification (Individual.ID) in the +pedigree file (PED file).} \item{batch}{a\code{integer} that uniquely identifies the source of the -pedigree information. The 1KG is usually \code{0L}.} +pedigree information. The Reference is usually \code{0L}.} } \value{ The function returns \code{0L} when successful. From e850d8300595df606d65f6670f94a166272ecc2b Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 9 Aug 2023 22:51:20 -0400 Subject: [PATCH 061/385] Update examples in function documentation --- R/allelicFraction.R | 4 +- R/allelicFraction_internal.R | 8 +-- R/process1KG.R | 99 +++++++++++++++++++--------------- man/computeLOHBlocksDNAChr.Rd | 6 +-- man/estimateAllelicFraction.Rd | 4 +- man/generateGDS1KG.Rd | 43 ++++++++------- man/generatePhase1KG2GDS.Rd | 52 ++++++++++-------- man/getTableSNV.Rd | 2 + 8 files changed, 124 insertions(+), 94 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index 8075a0086..93c091f25 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -255,8 +255,9 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' #' ## Example can only be run if the current directory is in writing mode #' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { +#' #' ## Copy the Profile GDS file demo that has been pruned and annotated -#' ## into current directory +#' ## into current directory #' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), #' "ex1.gds") #' @@ -296,6 +297,7 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' #' ## Unlink Profile GDS file (created for demo purpose) #' unlink("ex1.gds", force=TRUE) +#' #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 495e93325..823c94424 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -67,6 +67,7 @@ #' #' ## Example can only be run if the current directory is in writing mode #' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { +#' #' ## Copy the Profile GDS file demo that has been pruned and annotated #' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), #' fileProfile) @@ -89,6 +90,7 @@ #' #' ## Remove Profile GDS file (created for demo purpose) #' unlink(fileProfile, force=TRUE) +#' #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz @@ -298,11 +300,11 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' ## Required library for GDS #' library(gdsfmt) #' -#' ## Path to the demo 1KG GDS file is located in this package +#' ## Path to the demo Reference GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' -#' ## Open the reference GDS file (demo version) +#' ## Open the Reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileGDS) #' #' ## Chromosome length information for hg38 @@ -334,7 +336,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' chrInfo=chrInfo, snp.pos=snpInfo, chr=1L, genoN=0.0001) #' head(result) #' -#' ## Close GDS file (important) +#' ## Close Reference GDS file (important) #' closefn.gds(gds1KG) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/R/process1KG.R b/R/process1KG.R index f4b4b9d86..29020a3a9 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -72,8 +72,8 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), stringsAsFactors=FALSE) ## Create a list with all populations associated to each super-population - ## TODO The population versus super.population is hard-coded - ## TODO change to parameters + ## NOTE The population versus super.population is hard-coded + ## NOTE change to parameters listSuperPop1000G <- list() listSuperPop1000G[['EAS']] <- c("CHB", "JPT", "CHS", "CDX", "KHV") listSuperPop1000G[['EUR']] <- c("CEU", "TSI", "FIN", "GBR", "IBS") @@ -305,33 +305,38 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { #' ## The RDS file containing the filtered SNP information #' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' -#' ## Different code depending of the withr package availability -#' if (requireNamespace("withr", quietly=TRUE)) { +#' ## Temporary Reference GDS file +#' tempRefGDS <- file.path(getwd(), "1KG_TEMP.gds") #' -#' ## Temporary GDS file containing Reference information -#' gdsFile <- withr::local_file(file.path(dataDir, "1KG_TEMP.gds")) +#' ## Only run example if the directory is writable +#' if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { #' -#' ## Create a temporary GDS file containing information from 1KG -#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, -#' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, -#' fileNameGDS=gdsFile, listSamples=NULL) +#' ## Different code depending of the withr package availability +#' if (requireNamespace("withr", quietly=TRUE)) { #' -#' ## Remove temporary files -#' withr::deferred_run() +#' ## Temporary Reference GDS file +#' gdsFile <- withr::local_file(tempRefGDS) #' -#' } else { +#' ## Create a temporary Reference GDS file containing +#' ## information from reference file +#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +#' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, +#' fileNameGDS=gdsFile, listSamples=NULL) #' -#' ## Temporary GDS file containing Reference information -#' gdsFile <- file.path(dataDir, "1KG_TEMP.gds") +#' ## Remove temporary files +#' withr::deferred_run() #' -#' ## Create a temporary GDS file containing information from 1KG -#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, -#' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, -#' fileNameGDS=gdsFile, listSamples=NULL) +#' } else { #' -#' ## Remove temporary files -#' unlink(gdsFile) +#' ## Create a temporary Reference GDS file +#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +#' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, +#' fileNameGDS=tempRefGDS, listSamples=NULL) +#' +#' ## Remove temporary files +#' unlink(tempRefGDS, force=TRUE) #' +#' } #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz @@ -421,39 +426,45 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' ## The RDS file containing the filtered SNP information #' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' -#' ## Temporary Reference GDS file containing 1KG information +#' ## Temporary Reference GDS file containing reference information #' fileReferenceGDS <- "1KG_TEMP_02.gds" #' -#' ## Create a temporary Reference GDS file containing information from 1KG -#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, -#' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, -#' fileNameGDS=fileReferenceGDS, listSamples=NULL) +#' ## Only run example if the directory is writable +#' if (file.access(getwd()) == 0 && !file.exists(fileReferenceGDS)) { +#' +#' ## Create a temporary Reference GDS file containing information from 1KG +#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +#' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, +#' fileNameGDS=fileReferenceGDS, listSamples=NULL) #' -#' ## Temporary Phase GDS file that will contain the 1KG Phase information -#' fileRefPhaseGDS <- "1KG_TEMP_Phase_02.gds" +#' ## Temporary Phase GDS file that will contain the 1KG Phase information +#' fileRefPhaseGDS <- "1KG_TEMP_Phase_02.gds" #' -#' ## Create Reference Phase GDS file -#' gdsPhase <- createfn.gds(fileRefPhaseGDS) +#' ## Create Reference Phase GDS file +#' gdsPhase <- createfn.gds(fileRefPhaseGDS) #' -#' ## Open Reference GDS file -#' gdsRef <- openfn.gds(fileReferenceGDS) +#' ## Open Reference GDS file +#' gdsRef <- openfn.gds(fileReferenceGDS) #' -#' ## Fill temporary Reference Phase GDS file -#' if (FALSE) { -#' generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, -#' pathGeno=dataDir, fileSNPsRDS=filterSNVFile, verbose=FALSE) -#' } +#' ## Fill temporary Reference Phase GDS file +#' if (FALSE) { +#' generatePhase1KG2GDS(gdsReference=gdsRef, +#' gdsReferencePhase=gdsPhase, +#' pathGeno=dataDir, fileSNPsRDS=filterSNVFile, +#' verbose=FALSE) +#' } #' -#' ## Close 1KG Phase information file -#' closefn.gds(gdsPhase) +#' ## Close Reference Phase information file +#' closefn.gds(gdsPhase) #' -#' ## Close Reference information file -#' closefn.gds(gdsRef) +#' ## Close Reference information file +#' closefn.gds(gdsRef) #' -#' ## Remove temporary files -#' unlink(fileReferenceGDS, force=TRUE) -#' unlink(fileRefPhaseGDS, force=TRUE) +#' ## Remove temporary files +#' unlink(fileReferenceGDS, force=TRUE) +#' unlink(fileRefPhaseGDS, force=TRUE) #' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn readmode.gdsn diff --git a/man/computeLOHBlocksDNAChr.Rd b/man/computeLOHBlocksDNAChr.Rd index 8334e9ba3..20e6908bd 100644 --- a/man/computeLOHBlocksDNAChr.Rd +++ b/man/computeLOHBlocksDNAChr.Rd @@ -80,11 +80,11 @@ chromosome using the homozygote SNVs present on the chromosome. ## Required library for GDS library(gdsfmt) -## Path to the demo 1KG GDS file is located in this package +## Path to the demo Reference GDS file is located in this package dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") -## Open the reference GDS file (demo version) +## Open the Reference GDS file (demo version) gds1KG <- snpgdsOpen(fileGDS) ## Chromosome length information for hg38 @@ -116,7 +116,7 @@ result <- RAIDS:::computeLOHBlocksDNAChr(gdsReference=gds1KG, chrInfo=chrInfo, snp.pos=snpInfo, chr=1L, genoN=0.0001) head(result) -## Close GDS file (important) +## Close Reference GDS file (important) closefn.gds(gds1KG) } diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index db6888561..c5cc5d5cf 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -122,8 +122,9 @@ fileProfile <- file.path("ex1.gds") ## Example can only be run if the current directory is in writing mode if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { + ## Copy the Profile GDS file demo that has been pruned and annotated - ## into current directory + ## into current directory file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), "ex1.gds") @@ -163,6 +164,7 @@ if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { ## Unlink Profile GDS file (created for demo purpose) unlink("ex1.gds", force=TRUE) + } } diff --git a/man/generateGDS1KG.Rd b/man/generateGDS1KG.Rd index 2382905cc..c79a1a221 100644 --- a/man/generateGDS1KG.Rd +++ b/man/generateGDS1KG.Rd @@ -76,33 +76,38 @@ snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") ## The RDS file containing the filtered SNP information filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") -## Different code depending of the withr package availability -if (requireNamespace("withr", quietly=TRUE)) { +## Temporary Reference GDS file +tempRefGDS <- file.path(getwd(), "1KG_TEMP.gds") - ## Temporary GDS file containing Reference information - gdsFile <- withr::local_file(file.path(dataDir, "1KG_TEMP.gds")) +## Only run example if the directory is writable +if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { - ## Create a temporary GDS file containing information from 1KG - generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, - fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, - fileNameGDS=gdsFile, listSamples=NULL) + ## Different code depending of the withr package availability + if (requireNamespace("withr", quietly=TRUE)) { - ## Remove temporary files - withr::deferred_run() + ## Temporary Reference GDS file + gdsFile <- withr::local_file(tempRefGDS) -} else { + ## Create a temporary Reference GDS file containing + ## information from reference file + generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, + fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, + fileNameGDS=gdsFile, listSamples=NULL) - ## Temporary GDS file containing Reference information - gdsFile <- file.path(dataDir, "1KG_TEMP.gds") + ## Remove temporary files + withr::deferred_run() - ## Create a temporary GDS file containing information from 1KG - generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, - fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, - fileNameGDS=gdsFile, listSamples=NULL) + } else { - ## Remove temporary files - unlink(gdsFile) + ## Create a temporary Reference GDS file + generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, + fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, + fileNameGDS=tempRefGDS, listSamples=NULL) + ## Remove temporary files + unlink(tempRefGDS, force=TRUE) + + } } } diff --git a/man/generatePhase1KG2GDS.Rd b/man/generatePhase1KG2GDS.Rd index fc5f20961..b6f0b5783 100644 --- a/man/generatePhase1KG2GDS.Rd +++ b/man/generatePhase1KG2GDS.Rd @@ -59,39 +59,45 @@ snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") ## The RDS file containing the filtered SNP information filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") -## Temporary Reference GDS file containing 1KG information +## Temporary Reference GDS file containing reference information fileReferenceGDS <- "1KG_TEMP_02.gds" -## Create a temporary Reference GDS file containing information from 1KG -generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, - fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, - fileNameGDS=fileReferenceGDS, listSamples=NULL) +## Only run example if the directory is writable +if (file.access(getwd()) == 0 && !file.exists(fileReferenceGDS)) { -## Temporary Phase GDS file that will contain the 1KG Phase information -fileRefPhaseGDS <- "1KG_TEMP_Phase_02.gds" + ## Create a temporary Reference GDS file containing information from 1KG + generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, + fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, + fileNameGDS=fileReferenceGDS, listSamples=NULL) -## Create Reference Phase GDS file -gdsPhase <- createfn.gds(fileRefPhaseGDS) + ## Temporary Phase GDS file that will contain the 1KG Phase information + fileRefPhaseGDS <- "1KG_TEMP_Phase_02.gds" -## Open Reference GDS file -gdsRef <- openfn.gds(fileReferenceGDS) + ## Create Reference Phase GDS file + gdsPhase <- createfn.gds(fileRefPhaseGDS) -## Fill temporary Reference Phase GDS file -if (FALSE) { - generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, - pathGeno=dataDir, fileSNPsRDS=filterSNVFile, verbose=FALSE) -} + ## Open Reference GDS file + gdsRef <- openfn.gds(fileReferenceGDS) + + ## Fill temporary Reference Phase GDS file + if (FALSE) { + generatePhase1KG2GDS(gdsReference=gdsRef, + gdsReferencePhase=gdsPhase, + pathGeno=dataDir, fileSNPsRDS=filterSNVFile, + verbose=FALSE) + } -## Close 1KG Phase information file -closefn.gds(gdsPhase) + ## Close Reference Phase information file + closefn.gds(gdsPhase) -## Close Reference information file -closefn.gds(gdsRef) + ## Close Reference information file + closefn.gds(gdsRef) -## Remove temporary files -unlink(fileReferenceGDS, force=TRUE) -unlink(fileRefPhaseGDS, force=TRUE) + ## Remove temporary files + unlink(fileReferenceGDS, force=TRUE) + unlink(fileRefPhaseGDS, force=TRUE) +} } \author{ diff --git a/man/getTableSNV.Rd b/man/getTableSNV.Rd index 477984c90..723225449 100644 --- a/man/getTableSNV.Rd +++ b/man/getTableSNV.Rd @@ -86,6 +86,7 @@ fileProfile <- file.path(getwd(), "ex1.gds") ## Example can only be run if the current directory is in writing mode if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { + ## Copy the Profile GDS file demo that has been pruned and annotated file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), fileProfile) @@ -108,6 +109,7 @@ if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { ## Remove Profile GDS file (created for demo purpose) unlink(fileProfile, force=TRUE) + } } From 913b09a969a3fb2cd2bc9358b10ad4b095530ead Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 10 Aug 2023 11:15:37 -0400 Subject: [PATCH 062/385] Update example for estimateAllelicFration() function --- R/allelicFraction.R | 6 +++--- man/estimateAllelicFraction.Rd | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index 93c091f25..29f84cb2c 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -259,7 +259,7 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' ## Copy the Profile GDS file demo that has been pruned and annotated #' ## into current directory #' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), -#' "ex1.gds") +#' fileProfile) #' #' ## Open the reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileGDS) @@ -295,8 +295,8 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { #' closefn.gds(profileGDS) #' closefn.gds(gds1KG) #' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink("ex1.gds", force=TRUE) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) #' #' } #' diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index c5cc5d5cf..8bf9207b6 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -126,7 +126,7 @@ if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { ## Copy the Profile GDS file demo that has been pruned and annotated ## into current directory file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), - "ex1.gds") + fileProfile) ## Open the reference GDS file (demo version) gds1KG <- snpgdsOpen(fileGDS) @@ -162,8 +162,8 @@ if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { closefn.gds(profileGDS) closefn.gds(gds1KG) - ## Unlink Profile GDS file (created for demo purpose) - unlink("ex1.gds", force=TRUE) + ## Remove Profile GDS file (created for demo purpose) + unlink(fileProfile, force=TRUE) } From 4e2ac2057ce30b3f33a20b7f711a35a3ede75b54 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 10 Aug 2023 12:20:42 -0400 Subject: [PATCH 063/385] Update vignette; the files are created in the current directory only if the directory is in writable mode --- vignettes/RAIDS.Rmd | 135 +++++++++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 65 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index d465704ba..bac17094e 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -24,6 +24,7 @@ BiocStyle::markdown() suppressPackageStartupMessages({ library(knitr) library(RAIDS) + library(gdsfmt) }) set.seed(121444) @@ -145,7 +146,7 @@ At this step three important reference files are created: The reference files associated to the Cancer Research associated paper are available. Note that these pre-processed files are for 1000 Genomes (1KG), in hg38. The files are -available here:/span> +available here: [https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper](https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper) @@ -239,69 +240,56 @@ file (CVS, etc..) as long as the *data.frame* information can be regenerated in R (with _read.csv()_ or else). ```{r runExomeAncestry, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -######################################################################### +############################################################################# ## Load required packages -######################################################################### +############################################################################# library(RAIDS) library(gdsfmt) ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata", package="RAIDS") -######################################################################### +############################################################################# ## The path and file name for the PED RDS file ## will the information about the analyzed samples -######################################################################### +############################################################################# filePED <- file.path(dataDir, "example", "pedEx.rds") ped <- readRDS(filePED) head(ped) -######################################################################### +############################################################################# ## The population reference GDS file and SNV Annotation GDS file ## need to be located in the same directory. ## Note that the population reference GDS file used for this example is a ## simplified version and CANNOT be used for any real analysis -######################################################################### +############################################################################# pathReference <- file.path(dataDir, "example", "gdsRef") fileGDS <- file.path(pathReference, "ex1kg.gds") fileAnnotGDS <- file.path(pathReference, "exAnnot1kg.gds") -######################################################################### -## The Sample SNP pileup files (one per sample) need -## to be all located in the same directory. -######################################################################### -pathGeno <- file.path(dataDir, "example", "snpPileup") - -######################################################################### -## The path where the Sample GDS files (one per sample) -## will be created needs to be specified. -######################################################################### -pathProfileGDS <- file.path(dataDir, "example", "out.tmp") - - -######################################################################### -## The path where the result files will be created needs to -## be specified -######################################################################### -pathOut <- file.path(dataDir, "example", "res.out") - -######################################################################### +############################################################################# ## A data frame containing general information about the study ## is also required. The data frame must have ## those 3 columns: "study.id", "study.desc", "study.platform" -######################################################################### +############################################################################# studyDF <- data.frame(study.id="MYDATA", study.desc="Description", study.platform="PLATFORM", stringsAsFactors=FALSE) -######################################################################### +############################################################################# +## The Sample SNP pileup files (one per sample) need +## to be all located in the same directory. +############################################################################# +pathGeno <- file.path(dataDir, "example", "snpPileup") + +############################################################################# ## Fix RNG seed to ensure reproducible results -######################################################################### +############################################################################# set.seed(3043) -######################################################################### +############################################################################# ## Select the profiles from the population reference GDS file for ## the synthetic data. ## Here we select 2 profiles from the simplified 1KG GDS for each @@ -310,7 +298,7 @@ set.seed(3043) ## subcontinental-level but it is too big for the example. ## The 1KG files in this example only have 6 profiles for each ## subcontinental-level (for demo purpose only). -######################################################################### +############################################################################# gds1KG <- snpgdsOpen(fileGDS) dataRef <- select1KGPop(gds1KG, nbProfiles=2L) closefn.gds(gds1KG) @@ -323,23 +311,37 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) -## A formal way to get the chormosome length information for hg38 -## library(GenomeInfoDb) -## library(BSgenome.Hsapiens.UCSC.hg38) -## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] - - -######################################################################### -## The wrapper function generates the synthetic dataset and uses it -## to selected the optimal parameters before calling the genetic -## ancestry on the current profiles. -## All important information, for each step, are saved in -## multiple output files. -## The 'genoSource' parameter has 2 options depending on how the -## SNP pileup files have been generated: -## "snp-pileup" (snp-pileup software) or "generic" (other software) -######################################################################### -runExomeAncestry(pedStudy=ped, studyDF=studyDF, +############################################################################# +## The path where the Sample GDS files (one per sample) +## will be created needs to be specified. +############################################################################# +pathProfileGDS <- file.path(getwd(), "example", "out.tmp") + +############################################################################# +## The path where the result files will be created needs to +## be specified +############################################################################# +pathOut <- file.path(getwd(), "example", "res.out") + +print(file.access(getwd()) == 0 && !dir.exists(file.path(getwd(), "example"))) +## Example can only be run if the current directory is in writing mode +if (file.access(getwd()) == 0 && !dir.exists(file.path(getwd(), "example"))) { + + dir.create(file.path(getwd(), "example")) + dir.create(pathProfileGDS) + dir.create(pathOut) + + ######################################################################### + ## The wrapper function generates the synthetic dataset and uses it + ## to selected the optimal parameters before calling the genetic + ## ancestry on the current profiles. + ## All important information, for each step, are saved in + ## multiple output files. + ## The 'genoSource' parameter has 2 options depending on how the + ## SNP pileup files have been generated: + ## "snp-pileup" (snp-pileup software) or "generic" (other software) + ######################################################################### + runExomeAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, @@ -348,21 +350,24 @@ runExomeAncestry(pedStudy=ped, studyDF=studyDF, chrInfo=chrInfo, syntheticRefDF=dataRef, genoSource="snp-pileup") -list.files(pathOut) -list.files(file.path(pathOut, ped$Name.ID[1])) - -######################################################################### -## The file containing the ancestry inference (SuperPop column) and -## optimal number of PCA component (D column) -## optimal number of neighbours (K column) -######################################################################### -resAncestry <- read.csv(file.path(pathOut, + list.files(pathOut) + list.files(file.path(pathOut, ped$Name.ID[1])) + + ######################################################################### + ## The file containing the ancestry inference (SuperPop column) and + ## optimal number of PCA component (D column) + ## optimal number of neighbours (K column) + ######################################################################### + resAncestry <- read.csv(file.path(pathOut, paste0(ped$Name.ID[1], ".Ancestry.csv"))) -resAncestry + resAncestry + + ## Remove temporary files created for this demo + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + unlink(file.path(getwd(), "example"), force=TRUE) +} -## Remove temporary files created for this demo -unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -unlink(pathOut, recursive=TRUE, force=TRUE) ```
@@ -371,9 +376,9 @@ unlink(pathOut, recursive=TRUE, force=TRUE) The *runExomeAncestry()* function generates 3 types of files in the *pathOut* directory. -* The ancestry inference CSV file (".Ancestry.csv" file) -* The inference information RDS file (".infoCall.rds" file) -* The parameter information RDS files from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory) +* The ancestry inference CSV file (**".Ancestry.csv"** file) +* The inference information RDS file (**".infoCall.rds"** file) +* The parameter information RDS files from the synthetic inference (**"KNN.synt.*.rds"** files in a sub-directory) In addition, a sub-directory (named using the *profile ID*) is also created. From a24d536559b27d2193037e79f820d6cc0deceba5 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 10 Aug 2023 12:27:11 -0400 Subject: [PATCH 064/385] Remove print() in vignette --- vignettes/RAIDS.Rmd | 1 - 1 file changed, 1 deletion(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index bac17094e..3056d187e 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -323,7 +323,6 @@ pathProfileGDS <- file.path(getwd(), "example", "out.tmp") ############################################################################# pathOut <- file.path(getwd(), "example", "res.out") -print(file.access(getwd()) == 0 && !dir.exists(file.path(getwd(), "example"))) ## Example can only be run if the current directory is in writing mode if (file.access(getwd()) == 0 && !dir.exists(file.path(getwd(), "example"))) { From ed9c6f733b73bce84ba8610a46881be77f48acf6 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 10 Aug 2023 13:28:23 -0400 Subject: [PATCH 065/385] Update for loop in estimateAllelicFraction() function --- R/allelicFraction.R | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index 29f84cb2c..24078192c 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -336,14 +336,25 @@ estimateAllelicFraction <- function(gdsReference, gdsProfile, cutOffLOH=cutOffLOH, cutOffAR=cutOffAR, verbose=verbose) } + ## FOR_LOOP modification to be validated by Pascal + ## Remove commented code and this text after validation + + ## Calculate the cumulative sum for each chromosome + cumSumResult <- lapply(unique(snp.pos$snp.chr), function(i) { + snpChr <- snp.pos[snp.pos$snp.chr == i, ] + tmp <- c(0, abs(snpChr[2:nrow(snpChr), "lap"] - + snpChr[seq_len(nrow(snpChr)- 1), "lap"]) > 1e-3) + return(cumsum(tmp)) + }) + + # Find segment with same lap snp.pos$seg <- rep(0, nrow(snp.pos)) k <- 1 - # Find segment with same lap - for(chr in seq_len(22)) { - snpChr <- snp.pos[snp.pos$snp.chr == chr, ] - tmp <- c(0, abs(snpChr[2:nrow(snpChr), "lap"] - - snpChr[seq_len(nrow(snpChr)- 1), "lap"]) > 1e-3) - snp.pos$seg[snp.pos$snp.chr == chr] <- cumsum(tmp) + k + for(chr in unique(snp.pos$snp.chr)) { + ##snpChr <- snp.pos[snp.pos$snp.chr == chr, ] + ##tmp <- c(0, abs(snpChr[2:nrow(snpChr), "lap"] - + ## snpChr[seq_len(nrow(snpChr)- 1), "lap"]) > 1e-3) + snp.pos$seg[snp.pos$snp.chr == chr] <- cumSumResult[[chr]] + k k <- max(snp.pos$seg[snp.pos$snp.chr == chr]) + 1 } From 73ad45992693a55f98c8431ce8e9c88532c1f80c Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 10 Aug 2023 17:16:04 -0400 Subject: [PATCH 066/385] Removing for loop from syntheticGeno() and adding unit test --- R/synthetic.R | 39 +++++++++++++---- tests/testthat/test-synthetic.R | 75 ++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 9 deletions(-) diff --git a/R/synthetic.R b/R/synthetic.R index e1218d963..3e9c880b2 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -600,24 +600,47 @@ syntheticGeno <- function(gdsReference, gdsRefAnnot, fileProfileGDS, profileID, rownames(blockZone) <- listB - # We have to manage multipple simulation which mean - # different number of zone for the different simulation + + ## FOR_LOOP modification to be validated by Pascal + ## Remove commented code and this text after validation + + # We have to manage multiple simulation which means + # different number of zone for the different simulations LAPparent <- matrix(nrow = nbSNV, ncol = nbSim) - for(i in seq_len(nbSim)){ + # for(i in seq_len(nbSim)){ + # # list of zone with the same phase relatively to 1KG + # listZone <- unique(blockZone[,i]) + # + # ## matrix if the lap is the first entry in the phase or + # ## the second for each zone + # lapPos <- matrix(sample(x=c(0,1), size=1 *(length(listZone)), + # replace=TRUE), ncol=1) + # + # rownames(lapPos) <- listZone + # + # LAPparent[, i] <- + # lapPos[as.character(blockZone[as.character(blockDF[, + # curSP]),i]),] + # } + + + # We have to manage multiple simulations which means + # different number of zones for the different simulations + lapValues <- vapply(seq_len(nbSim), function(i) { # list of zone with the same phase relatively to 1KG listZone <- unique(blockZone[,i]) ## matrix if the lap is the first entry in the phase or ## the second for each zone lapPos <- matrix(sample(x=c(0,1), size=1 *(length(listZone)), - replace=TRUE), ncol=1) + replace=TRUE), ncol=1) rownames(lapPos) <- listZone - LAPparent[, i] <- - lapPos[as.character(blockZone[as.character(blockDF[, - curSP]),i]),] - } + return(lapPos[as.character(blockZone[as.character(blockDF[, + curSP]),i]),]) + }, double(nbSNV)) + LAPparent[, seq_len(nbSim)] <- lapValues phaseVal <- read.gdsn(index.gdsn(gdsRefAnnot, "phase"), start=c(1,listPosRef.1kg[r]), count=c(-1,1))[list1KG] diff --git a/tests/testthat/test-synthetic.R b/tests/testthat/test-synthetic.R index 9d9136727..fe657f13c 100644 --- a/tests/testthat/test-synthetic.R +++ b/tests/testthat/test-synthetic.R @@ -361,7 +361,7 @@ test_that(paste0("syntheticGeno() must return error when minProb is a ", }) -test_that(paste0("syntheticGeno() must return error expected results"), { +test_that(paste0("syntheticGeno() must return expected results"), { set.seed(121) @@ -415,6 +415,79 @@ test_that(paste0("syntheticGeno() must return error expected results"), { rep(0, 27))) }) + + +test_that(paste0("syntheticGeno() must return expected results when nbSim=3"), { + + set.seed(121) + + dataDirSample <- test_path("fixtures/sampleGDSforEstimAlleFraction") + file.copy(file.path(dataDirSample, "ex1_demoForEstimAllFrac.gds"), + file.path(dataDirSample, "ex1.gds")) + withr::defer((unlink(file.path(dataDirSample, "ex1.gds"))), + envir=parent.frame()) + + dataDirRef <- test_path("fixtures") + + ## Open 1KG Annotation GDS file + fileRefAnnot <- file.path(dataDirRef, "ex1_good_small_1KG_Annot_GDS.gds") + gdsRefAnnot <- openfn.gds(fileRefAnnot) + withr::defer((closefn.gds(gdsRefAnnot)), envir=parent.frame()) + + ## Open 1KG GDS file + gds1KG <- snpgdsOpen(file.path(dataDirRef, "ex1_good_small_1KG_GDS.gds")) + withr::defer((closefn.gds(gds1KG)), envir=parent.frame()) + + synthStudyDF <- data.frame(study.id="MYDATA.Synthetic", + study.desc="MYDATA synthetic data", + study.platform="PLATFORM", + stringsAsFactors=FALSE) + + result1 <- prepSynthetic(fileProfileGDS=file.path(dataDirSample, "ex1.gds"), + listSampleRef=c("HG00243", "HG00149"), profileID="ex1", + studyDF=synthStudyDF, nbSim=3L, prefix="test2", verbose=FALSE) + + result2 <- syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gdsRefAnnot, + fileProfileGDS=file.path(dataDirSample, "ex1.gds"), profileID="ex1", + listSampleRef=c("HG00243", "HG00149"), nbSim=3, prefix="test2", + pRecomb=0.01, minProb=0.999, seqError=0.001) + + expect_equal(result2, 0L) + + profileGDS <- openfn.gds(file.path(dataDirSample, "ex1.gds")) + withr::defer((closefn.gds(profileGDS)), envir=parent.frame()) + + sampleList <- read.gdsn(index.gdsn(profileGDS, "sample.id")) + + expect_equal(sampleList[158:163], + c("test2.ex1.HG00243.1", "test2.ex1.HG00243.2", "test2.ex1.HG00243.3", + "test2.ex1.HG00149.1", "test2.ex1.HG00149.2", "test2.ex1.HG00149.3")) + + genotype <- read.gdsn(index.gdsn(profileGDS, "genotype")) + + expect_equal(genotype[,158], c(rep(0, 16), 2, 0, 0, 1, rep(0, 13), 2, + rep(0, 27))) + + expect_equal(genotype[,159], c(rep(0, 16), 2, 0, 0, 1, rep(0, 13), + 2, rep(0, 16), 3, rep(0, 9), 3)) + + expect_equal(genotype[,160], c(rep(0, 8), 3, 0, 3, rep(0, 5), 2, 0, 0, 1, + 3, rep(0, 12), 2, rep(0, 27))) + + expect_equal(genotype[,161], c(3, rep(0, 6), 3, 0, 2, rep(0, 5), 1, 2, + rep(0, 13), 1, 0, 0, 2, + rep(0, 13), 1, rep(0, 13))) + + expect_equal(genotype[,162], c(rep(0, 8), 3, 2, rep(0, 5), 1, 2, + rep(0, 13), 1, 0, 0, 2, + rep(0, 4), 3, rep(0, 8), 1, rep(0, 13))) + + expect_equal(genotype[,163], c(rep(0, 9), 2, rep(0, 5), 1, 2, + rep(0, 13), 1, + rep(0, 2), 2, rep(0, 13), 1, rep(0, 13))) +}) + + ############################################################################# ### Tests prepSynthetic() results ############################################################################# From a02c31cb480e2f0591a44a5e1045ea1b44ddc5ac Mon Sep 17 00:00:00 2001 From: belleau Date: Thu, 10 Aug 2023 17:48:52 -0400 Subject: [PATCH 067/385] Vectorize a loop in computeAllelicFractionRNA --- R/allelicFraction_internal.R | 91 ++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 25 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index da4fa1766..4548df9ad 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -729,40 +729,81 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, snp.pos$freq <- read.gdsn(index.gdsn(gdsReference, "snp.AF"))[snp.pos$snp.index] # for each chromosome - listBlock <- list() - for(chr in unique(snp.pos$snp.chr)) { - - if (verbose) { - message("chr ", chr) - message("Step 1 ", Sys.time()) - } - - #listHetero <- dfHetero[dfHetero$snp.chr == chr, "snp.pos"] - listChr <- which(snp.pos$snp.chr == chr) - # snp.pos.chr <- snp.pos[listChr,] - - blockAF <- tableBlockAF(snp.pos=snp.pos[listChr,]) - # LOH - blockAF$aRF[blockAF$lRhomo <= cutOffLOH] <- 0 - blockAF$aRF[blockAF$lR >= cutOffAR] <- blockAF$aFraction[blockAF$lR - >= cutOffAR] - blockAF$aRF[blockAF$lR < cutOffAR & blockAF$nbHetero > 1] <- 0.5 - - listBlock[[chr]] <- blockAF + # listBlock <- list() + + ## FOR_LOOP modification to be validated by Pascal + ## Remove commented code and this text after validation + listBlock <- lapply(unique(snp.pos$snp.chr), FUN = function(x, snp.pos, verbose){ + if (verbose) { + message("chr ", x) + message("Step 1 ", Sys.time()) + } + listChr <- which(snp.pos$snp.chr == x) + blockAF <- tableBlockAF(snp.pos=snp.pos[listChr,]) + blockAF$aRF[blockAF$lRhomo <= cutOffLOH] <- 0 + blockAF$aRF[blockAF$lR >= cutOffAR] <- blockAF$aFraction[blockAF$lR + >= cutOffAR] + blockAF$aRF[blockAF$lR < cutOffAR & blockAF$nbHetero > 1] <- 0.5 - if (verbose) { - message("Step 1 done ", Sys.time()) - } - } + #listBlock[[x]] <- blockAF + if (verbose) { + message("Step 1 done ", Sys.time()) + } + return(blockAF) + }, snp.pos=snp.pos, + verbose=verbose) blockAF <- do.call(rbind, listBlock) listMissing <- which(abs(blockAF$aRF + 1) < 1e-6) + blockAF[listMissing, "aRF"] <- sample(blockAF$aRF[-1*listMissing], - length(listMissing), replace=TRUE) + length(listMissing), replace=TRUE) + for(b in seq_len(nrow(blockAF))) { snp.pos$lap[snp.pos$block.id == blockAF$block[b]] <- blockAF$aRF[b] } + # listMissing <- which(abs(blockAF$aRF + 1) < 1e-6) + # blockAF[listMissing, "aRF"] <- sample(blockAF$aRF[-1*listMissing], + # length(listMissing), replace=TRUE) + + # listBlock <- list() + # print(system.time(for(chr in unique(snp.pos$snp.chr)) { + # + # if (verbose) { + # message("chr ", chr) + # message("Step 1 ", Sys.time()) + # } + # + # #listHetero <- dfHetero[dfHetero$snp.chr == chr, "snp.pos"] + # listChr <- which(snp.pos$snp.chr == chr) + # # snp.pos.chr <- snp.pos[listChr,] + # + # blockAF <- tableBlockAF(snp.pos=snp.pos[listChr,]) + # # LOH + # blockAF$aRF[blockAF$lRhomo <= cutOffLOH] <- 0 + # blockAF$aRF[blockAF$lR >= cutOffAR] <- blockAF$aFraction[blockAF$lR + # >= cutOffAR] + # blockAF$aRF[blockAF$lR < cutOffAR & blockAF$nbHetero > 1] <- 0.5 + # + # listBlock[[chr]] <- blockAF + # + # if (verbose) { + # message("Step 1 done ", Sys.time()) + # } + # })) + # + # blockAF1 <- do.call(rbind, listBlock) + # + # listMissing <- which(abs(blockAF1$aRF + 1) < 1e-6) + # set.seed(654) + # blockAF1[listMissing, "aRF"] <- sample(blockAF1$aRF[-1*listMissing], + # length(listMissing), replace=TRUE) + # + # + # for(b in seq_len(nrow(blockAF1))) { + # snp.pos$lap[snp.pos$block.id == blockAF1$block[b]] <- blockAF1$aRF[b] + # } return(snp.pos) } From e4c7a0ddeb4d893c8982e4ce7819ca4afdb7d9d5 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 10 Aug 2023 22:59:39 -0400 Subject: [PATCH 068/385] Remove loop in select1KGPop() function --- R/synthetic.R | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/R/synthetic.R b/R/synthetic.R index 3e9c880b2..5fec8f602 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -77,20 +77,33 @@ select1KGPop <- function(gdsReference, nbProfiles) { "sample.annot"))[listKeep,] sample.id <- read.gdsn(index.gdsn(gdsReference, "sample.id"))[listKeep] listPop <- unique(sample.annot$pop.group) - listSel <- list() + + ## FOR_LOOP modification to be validated by Pascal + ## Remove commented code and this text after validation ## For each subcontinental population, randomly select a fixed number of ## samples - for(i in seq_len(length(listPop))) { - listGroup <- which(sample.annot$pop.group == listPop[i]) - tmp <- sample(listGroup, min(nbProfiles, length(listGroup))) - listSel[[i]] <- data.frame(sample.id=sample.id[tmp], - pop.group=sample.annot$pop.group[tmp], - superPop=sample.annot$superPop[tmp], - stringsAsFactors=FALSE) - } + # listSel <- list() + # for(i in seq_len(length(listPop))) { + # listGroup <- which(sample.annot$pop.group == listPop[i]) + # tmp <- sample(listGroup, min(nbProfiles, length(listGroup))) + # listSel[[i]] <- data.frame(sample.id=sample.id[tmp], + # pop.group=sample.annot$pop.group[tmp], + # superPop=sample.annot$superPop[tmp], + # stringsAsFactors=FALSE) + # } - df <- do.call(rbind, listSel) + ## For each subcontinental population, randomly select a fixed number of + ## samples + dfAll <- lapply(seq_len(length(listPop)), function(i) { + listGroup <- which(sample.annot$pop.group == listPop[i]) + tmp <- sample(listGroup, min(nbProfiles, length(listGroup))) + return(data.frame(sample.id=sample.id[tmp], + pop.group=sample.annot$pop.group[tmp], + superPop=sample.annot$superPop[tmp], + stringsAsFactors=FALSE)) }) + + df <- do.call(rbind, dfAll) return(df) } From 0fd2dedbf377f8c2f16c75314c00752bc0f0dc30 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 11 Aug 2023 13:59:36 -0400 Subject: [PATCH 069/385] Add missing library to addUpdateSegment() example --- R/gdsWrapper.R | 4 +++- man/addUpdateSegment.Rd | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index d462603e5..9b570b0b0 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -479,7 +479,6 @@ gds2tped <- function(gds, listSample, listSNP, pedOUT) { write.table(tped, pedOUT, quote=FALSE, sep="\t", row.names=FALSE, col.names=FALSE) - } @@ -565,6 +564,9 @@ addGDS1KGLDBlock <- function(gds, listBlock, blockName, blockDesc) { #' #' @examples #' +#' ## Required library +#' library(gdsfmt) +#' #' ## Create a temporary GDS file in an test directory #' dataDir <- system.file("extdata/tests", package="RAIDS") #' gdsFilePath <- file.path(dataDir, "GDS_TEMP.gds") diff --git a/man/addUpdateSegment.Rd b/man/addUpdateSegment.Rd index 4839a1f8b..718c0249d 100644 --- a/man/addUpdateSegment.Rd +++ b/man/addUpdateSegment.Rd @@ -28,6 +28,9 @@ already exists, the previous information is erased. } \examples{ +## Required library +library(gdsfmt) + ## Create a temporary GDS file in an test directory dataDir <- system.file("extdata/tests", package="RAIDS") gdsFilePath <- file.path(dataDir, "GDS_TEMP.gds") From fbff9bd04b62d63f95c815265f5397bdffde1790 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 11 Aug 2023 14:17:47 -0400 Subject: [PATCH 070/385] Vectorize a loop in tableBlockAF and update doc --- R/allelicFraction_internal.R | 269 ++++++++++++++++++++++++++--------- man/tableBlockAF.Rd | 27 +++- 2 files changed, 221 insertions(+), 75 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index feab7b92e..143974593 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -580,6 +580,10 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, snp.pos$LOH <- rep(0, nrow(snp.pos)) snp.pos$imbAR <- rep(-1, nrow(snp.pos)) + lapply(unique(snp.pos$snp.chr), FUN=function(x, snp.pos){ + + }) + homoBlock <- list() for(chr in unique(snp.pos$snp.chr)) { @@ -1209,16 +1213,35 @@ calcAFMLRNA <- function(snp.pos.Hetero) { } -#' @title TODO +#' @title TOREVIEW Compile the info about the allelic fraction for each bloc. In the case of RNA-seq +#' the blaocks are gene #' -#' @description TODO +#' @description TOREVIEW For each block evaluate score about lost of heterizygocity and allelic fration #' #' @param snp.pos For a specific chromosome a \code{data.frame} with lap for #' the SNV dataset with #' coverage > \code{minCov}. #' -#' @return TODO a \code{data.frame} with the information related to allelic -#' fraction for each block gene +#' @return TOREVIEW resBlock a \code{data.frame} containing only heterozygote SNVs. The +#' \code{data.frame} contain those columns: +#' \itemize{ +#' \item{block} {a single \code{integer} id of the block.} +#' \item{aRF} {a single \code{numeric} allelic fraction final not compute +#' here -1 for all entries.} +#' \item{aFraction} {a single \code{integer} allelic fraction possible if not LOH.} +#' \item{lR} {a single \code{integer} representing the coverage for +#' the alternative allele.} +#' \item{nPhase} {a single \code{integer} number of SNV phase.} +#' \item{sumAlleleLow} {a single \code{integer} TODO.} +#' \item{sumAlleleHigh} {a single \code{integer} TODO.} +#' \item{lH} {a single \code{numeric} for the homozygotes log10 of the product +#' frequencies of the allele not found in the profile (not a probability).} +#' \item{lM} {a single \code{numeric} log10 product frequency allele in population.} +#' \item{lRhomo} {a single \code{numeric} score lH - lM.} +#' #' \item{nbHomo} {a single \code{integer} score lH - lM.} +#' #' \item{nbKeep} {a single \code{integer} score lH - lM.} +#' #' \item{nbHetero} {a single \code{integer} score lH - lM.} +#' } #' #' @examples #' @@ -1233,92 +1256,196 @@ tableBlockAF <- function(snp.pos) { listBlocks <- unique(snp.pos$block.id) - resBlock <- data.frame(block = listBlocks, - aRF = rep(-1, length(listBlocks)), - aFraction = rep(-1, length(listBlocks)), - lR = rep(-1, length(listBlocks)), - nPhase = rep(-1, length(listBlocks)), - sumAlleleLow = rep(-1, length(listBlocks)), - sumAlleleHigh = rep(-1, length(listBlocks)), - lH = rep(-1, length(listBlocks)), - lM = rep(-1, length(listBlocks)), - lRhomo = rep(1, length(listBlocks))) + # resBlock <- data.frame(block = listBlocks, + # aRF = rep(-1, length(listBlocks)), + # aFraction = rep(-1, length(listBlocks)), + # lR = rep(-1, length(listBlocks)), + # nPhase = rep(-1, length(listBlocks)), + # sumAlleleLow = rep(-1, length(listBlocks)), + # sumAlleleHigh = rep(-1, length(listBlocks)), + # lH = rep(-1, length(listBlocks)), + # lM = rep(-1, length(listBlocks)), + # lRhomo = rep(1, length(listBlocks))) + ## FOR_LOOP modification to be validated by Pascal + ## Remove commented code and this text after validation + resBlock <- data.frame(block = listBlocks) + + # Number of homozygote by block tmp <- aggregate(snp.pos[, c( "homo"), drop = FALSE], by = list(block=snp.pos$block.id) ,sum) row.names(tmp) <- as.character(tmp[,1]) resBlock$nbHomo <- tmp[as.character(listBlocks),2] + # Number of snv keep by block tmp <- aggregate(snp.pos[, c( "keep"), drop = FALSE], by = list(block=snp.pos$block.id) ,sum) row.names(tmp) <- as.character(tmp[,1]) resBlock$nbKeep <- tmp[as.character(listBlocks),2] + # Number of heterozygote by block tmp <- aggregate(snp.pos[, c( "hetero"), drop = FALSE], by = list(block=snp.pos$block.id) ,sum) row.names(tmp) <- as.character(tmp[,1]) resBlock$nbHetero <- tmp[as.character(listBlocks),2] - for (i in seq_len(length(listBlocks))) { - # start with LOH - - lH <- 1 - lM <- 1 - if (resBlock[i, "nbKeep"] > 0 & - (resBlock[i, "nbKeep"] == resBlock[i, "nbHomo"] | - (resBlock[i, "nbHomo"] > 0 & resBlock[i, "nbHetero"] == 1)) ) { - - # Check if 1 hetero with allelic fraction (<=0.05) - # it is considered as all homozygote - flag <- TRUE - if (resBlock[i, "nbHetero"] == 1) { - tmp <- min(snp.pos[snp.pos$block.id == resBlock$block[i] & - snp.pos$hetero, c("cnt.ref" , "cnt.alt")])/ - sum(snp.pos[snp.pos$block.id == resBlock$block[i] & - snp.pos$hetero, c("cnt.ref" , "cnt.alt")]) - flag <- ifelse(tmp > 0.05, FALSE,TRUE) - } - if(flag){ - listRef <- which(snp.pos$block.id == resBlock$block[i] & - snp.pos$homo & - snp.pos$cnt.ref > snp.pos$cnt.alt) - listAlt <- which(snp.pos$block.id == resBlock$block[i] & - snp.pos$homo & - snp.pos$cnt.ref < snp.pos$cnt.alt) - tmp <- snp.pos$freq[listRef] - tmp[which(tmp < 0.01)] <- 0.01 - lH <- ifelse(length(listRef) > 0, sum(log10(1-tmp)*2), 0) - - tmp <- snp.pos$freq[listAlt] - tmp[which(tmp < 0.01)] <- 0.01 - lH <- lH + ifelse(length(listAlt) > 0, sum(log10(tmp)*2), 0) - - lM <- sum(log10(apply(snp.pos[which(snp.pos$block.id == - resBlock$block[i] & snp.pos$homo), - "freq", drop=FALSE], 1, - FUN = function(x) { - return(max(x^2, 2*(x * (1-x)), (1-x)^2)) - }))) - resBlock$sumAlleleLow[i] <- 0 - resBlock$sumAlleleHigh[i] <- sum(snp.pos[listRef, "cnt.ref"]) + - sum(snp.pos[listAlt, "cnt.alt"]) - } - } + resBlock <- apply(resBlock, 1, FUN=function(x,snp.pos){ + resBlock <- data.frame(block = x[1], + nbHomo = x[2], + nbKeep = x[3], + nbHetero = x[4], + aRF = -1, + aFraction = -1, + lR = -1, + nPhase = -1, + sumAlleleLow = -1, + sumAlleleHigh = -1, + lH = -1, + lM = -1, + lRhomo = 1) + + lH <- 1 + lM <- 1 + if (resBlock[1, "nbKeep"] > 0 & + (resBlock[1, "nbKeep"] == resBlock[1, "nbHomo"] | + (resBlock[1, "nbHomo"] > 0 & resBlock[1, "nbHetero"] == 1)) ) { + + # Check if 1 hetero with allelic fraction (<=0.05) + # it is considered as all homozygote + flag <- TRUE + if (resBlock[1, "nbHetero"] == 1) { + tmp <- min(snp.pos[snp.pos$block.id == resBlock$block[1] & + snp.pos$hetero, c("cnt.ref" , "cnt.alt")])/ + sum(snp.pos[snp.pos$block.id == resBlock$block[1] & + snp.pos$hetero, c("cnt.ref" , "cnt.alt")]) + # flag is true if allelic fraction <= 0.05 + flag <- ifelse(tmp > 0.05, FALSE,TRUE) + } - resBlock[i, c("lH", "lM", "lRhomo")] <- c(lH, lM, lH - lM) + if(flag){ + # List homozygote ref + listRef <- which(snp.pos$block.id == resBlock$block[1] & + snp.pos$homo & + snp.pos$cnt.ref > snp.pos$cnt.alt) + # list homozygote alt + listAlt <- which(snp.pos$block.id == resBlock$block[1] & + snp.pos$homo & + snp.pos$cnt.ref < snp.pos$cnt.alt) + # freq of the Ref allele in population of listRef + tmp <- snp.pos$freq[listRef] + # min freq is 0.01 + tmp[which(tmp < 0.01)] <- 0.01 + # log10 of the product of the frequency of the alternative allele in pop for listRef + lH <- ifelse(length(listRef) > 0, sum(log10(1-tmp)*2), 0) + # freq of the Ref allele in population of listAlt + tmp <- snp.pos$freq[listAlt] + tmp[which(tmp < 0.01)] <- 0.01 + # log10 of the product of the frequency of the alternative allele in pop for listRef + # plus log10 of the product of the frequency of the reference allele in pop for listAlt + lH <- lH + ifelse(length(listAlt) > 0, sum(log10(tmp)*2), 0) + + lM <- sum(log10(apply(snp.pos[which(snp.pos$block.id == + resBlock$block[1] & snp.pos$homo), + "freq", drop=FALSE], 1, + FUN = function(x) { + return(max(x^2, 2*(x * (1-x)), (1-x)^2)) + }))) + resBlock$sumAlleleLow[1] <- 0 + resBlock$sumAlleleHigh[1] <- sum(snp.pos[listRef, "cnt.ref"]) + + sum(snp.pos[listAlt, "cnt.alt"]) + } + } + # compute the score of the homozygote on the block + # if heterozygote present lH = lM = 1 and lRhomo = 0 + resBlock[1, c("lH", "lM", "lRhomo")] <- c(lH, lM, lH - lM) - # get hetero and compute AF - if (resBlock[i, "nbKeep"] > 0 & resBlock[i, "nbHetero"] > 1) { + # get hetero and compute AF nbHetero > 1 + if (resBlock[1, "nbKeep"] > 0 & resBlock[1, "nbHetero"] > 1) { - resML <- calcAFMLRNA(snp.pos[which(snp.pos$block.id == - resBlock$block[i] & snp.pos$hetero),]) + resML <- calcAFMLRNA(snp.pos[which(snp.pos$block.id == + resBlock$block[1] & snp.pos$hetero),]) - resBlock$aFraction[i] <- resML$aFraction - resBlock$lR[i] <- resML$lR - resBlock$nPhase[i] <- resML$nPhase - resBlock$sumAlleleLow[i] <- resML$sumAlleleLow - resBlock$sumAlleleHigh[i] <- resML$sumAlleleHigh - } - } + resBlock$aFraction[1] <- resML$aFraction + resBlock$lR[1] <- resML$lR + resBlock$nPhase[1] <- resML$nPhase + resBlock$sumAlleleLow[1] <- resML$sumAlleleLow + resBlock$sumAlleleHigh[1] <- resML$sumAlleleHigh + } + return(resBlock) + }, snp.pos=snp.pos) + resBlock <- do.call(rbind, resBlock) + # for (i in seq_len(length(listBlocks))) { + # # start with LOH + # + # lH <- 1 + # lM <- 1 + # # if at least 1 homozygote variants and no more than 1 hetrozygote + # # to check for LOH + # if (resBlock[i, "nbKeep"] > 0 & + # (resBlock[i, "nbKeep"] == resBlock[i, "nbHomo"] | + # (resBlock[i, "nbHomo"] > 0 & resBlock[i, "nbHetero"] == 1)) ) { + # + # # Check if 1 hetero with allelic fraction (<=0.05) + # # it is considered as all homozygote + # flag <- TRUE + # if (resBlock[i, "nbHetero"] == 1) { + # tmp <- min(snp.pos[snp.pos$block.id == resBlock$block[i] & + # snp.pos$hetero, c("cnt.ref" , "cnt.alt")])/ + # sum(snp.pos[snp.pos$block.id == resBlock$block[i] & + # snp.pos$hetero, c("cnt.ref" , "cnt.alt")]) + # # flag is true if allelic fraction <= 0.05 + # flag <- ifelse(tmp > 0.05, FALSE,TRUE) + # } + # + # if(flag){ + # # List homozygote ref + # listRef <- which(snp.pos$block.id == resBlock$block[i] & + # snp.pos$homo & + # snp.pos$cnt.ref > snp.pos$cnt.alt) + # # list homozygote alt + # listAlt <- which(snp.pos$block.id == resBlock$block[i] & + # snp.pos$homo & + # snp.pos$cnt.ref < snp.pos$cnt.alt) + # # freq of the Ref allele in population of listRef + # tmp <- snp.pos$freq[listRef] + # # min freq is 0.01 + # tmp[which(tmp < 0.01)] <- 0.01 + # # log10 of the product of the frequency of the alternative allele in pop for listRef + # lH <- ifelse(length(listRef) > 0, sum(log10(1-tmp)*2), 0) + # # freq of the Ref allele in population of listAlt + # tmp <- snp.pos$freq[listAlt] + # tmp[which(tmp < 0.01)] <- 0.01 + # # log10 of the product of the frequency of the alternative allele in pop for listRef + # # plus log10 of the product of the frequency of the reference allele in pop for listAlt + # lH <- lH + ifelse(length(listAlt) > 0, sum(log10(tmp)*2), 0) + # + # lM <- sum(log10(apply(snp.pos[which(snp.pos$block.id == + # resBlock$block[i] & snp.pos$homo), + # "freq", drop=FALSE], 1, + # FUN = function(x) { + # return(max(x^2, 2*(x * (1-x)), (1-x)^2)) + # }))) + # resBlock$sumAlleleLow[i] <- 0 + # resBlock$sumAlleleHigh[i] <- sum(snp.pos[listRef, "cnt.ref"]) + + # sum(snp.pos[listAlt, "cnt.alt"]) + # } + # } + # # compute the score of the homozygote on the block + # # if heterozygote present lH = lM = 1 and lRhomo = 0 + # resBlock[i, c("lH", "lM", "lRhomo")] <- c(lH, lM, lH - lM) + # + # # get hetero and compute AF nbHetero > 1 + # if (resBlock[i, "nbKeep"] > 0 & resBlock[i, "nbHetero"] > 1) { + # + # resML <- calcAFMLRNA(snp.pos[which(snp.pos$block.id == + # resBlock$block[i] & snp.pos$hetero),]) + # + # resBlock$aFraction[i] <- resML$aFraction + # resBlock$lR[i] <- resML$lR + # resBlock$nPhase[i] <- resML$nPhase + # resBlock$sumAlleleLow[i] <- resML$sumAlleleLow + # resBlock$sumAlleleHigh[i] <- resML$sumAlleleHigh + # } + # } return(resBlock) } diff --git a/man/tableBlockAF.Rd b/man/tableBlockAF.Rd index b2a321c73..c763940d5 100644 --- a/man/tableBlockAF.Rd +++ b/man/tableBlockAF.Rd @@ -3,7 +3,8 @@ \encoding{UTF-8} \name{tableBlockAF} \alias{tableBlockAF} -\title{TODO} +\title{TOREVIEW Compile the info about the allelic fraction for each bloc. In the case of RNA-seq +the blaocks are gene} \usage{ tableBlockAF(snp.pos) } @@ -13,11 +14,29 @@ the SNV dataset with coverage > \code{minCov}.} } \value{ -TODO a \code{data.frame} with the information related to allelic -fraction for each block gene +TOREVIEW resBlock a \code{data.frame} containing only heterozygote SNVs. The +\code{data.frame} contain those columns: +\itemize{ +\item{block} {a single \code{integer} id of the block.} +\item{aRF} {a single \code{numeric} allelic fraction final not compute +here -1 for all entries.} +\item{aFraction} {a single \code{integer} allelic fraction possible if not LOH.} +\item{lR} {a single \code{integer} representing the coverage for +the alternative allele.} +\item{nPhase} {a single \code{integer} number of SNV phase.} +\item{sumAlleleLow} {a single \code{integer} TODO.} +\item{sumAlleleHigh} {a single \code{integer} TODO.} +\item{lH} {a single \code{numeric} for the homozygotes log10 of the product +frequencies of the allele not found in the profile (not a probability).} +\item{lM} {a single \code{numeric} log10 product frequency allele in population.} +\item{lRhomo} {a single \code{numeric} score lH - lM.} +#' \item{nbHomo} {a single \code{integer} score lH - lM.} +#' \item{nbKeep} {a single \code{integer} score lH - lM.} +#' \item{nbHetero} {a single \code{integer} score lH - lM.} +} } \description{ -TODO +TOREVIEW For each block evaluate score about lost of heterizygocity and allelic fration } \examples{ From f6a636814ead2aba213b69974e8e525aad95b45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Fri, 11 Aug 2023 16:24:56 -0400 Subject: [PATCH 071/385] Update check-bioc.yaml --- .github/workflows/check-bioc.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index 2be10d9be..c62f31a34 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -51,8 +51,8 @@ jobs: fail-fast: false matrix: config: - - { os: ubuntu-latest, r: '4.2.2', bioc: '3.16', cont: "bioconductor/bioconductor_docker:RELEASE_3_16", rspm: "https://packagemanager.posit.co" } - ## - { os: ubuntu-latest, r: '4.3', bioc: '3.17', cont: "bioconductor/bioconductor_docker:RELEASE_3_17", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + ## - { os: ubuntu-latest, r: '4.2.2', bioc: '3.16', cont: "bioconductor/bioconductor_docker:RELEASE_3_16", rspm: "https://packagemanager.posit.co" } + - { os: ubuntu-latest, r: '4.3', bioc: '3.17', cont: "bioconductor/bioconductor_docker:RELEASE_3_17", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - { os: macOS-latest, r: '4.2.2', bioc: '3.16'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} env: From 70ce17e12f183a3003ec796359234b860c9e8eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Fri, 11 Aug 2023 17:06:32 -0400 Subject: [PATCH 072/385] Update check-bioc.yaml --- .github/workflows/check-bioc.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index c62f31a34..69b85aa46 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -53,7 +53,8 @@ jobs: config: ## - { os: ubuntu-latest, r: '4.2.2', bioc: '3.16', cont: "bioconductor/bioconductor_docker:RELEASE_3_16", rspm: "https://packagemanager.posit.co" } - { os: ubuntu-latest, r: '4.3', bioc: '3.17', cont: "bioconductor/bioconductor_docker:RELEASE_3_17", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - - { os: macOS-latest, r: '4.2.2', bioc: '3.16'} + ## - { os: macOS-latest, r: '4.2.2', bioc: '3.16'} + - { os: macOS-latest, r: '4.3', bioc: '3.17'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true From 040f95dafdf51f5736425a4c6b1b3c9b44c925b3 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 11 Aug 2023 17:48:58 -0400 Subject: [PATCH 073/385] Change getGeneBlock() to getBlockIDs() and add unit test --- R/allelicFraction_internal.R | 4 +- R/gdsWrapper.R | 40 ------------- R/gdsWrapper_internal.R | 69 +++++++++++++++++++++- R/process1KG.R | 2 +- R/processStudy.R | 7 ++- man/generateGDS1KGgenotypeFromSNPPileup.Rd | 4 +- man/getBlockIDs.Rd | 59 ++++++++++++++++++ man/getGeneBlock.Rd | 37 ------------ tests/testthat/test-gdsWrapper_internal.R | 26 ++++++++ 9 files changed, 162 insertions(+), 86 deletions(-) create mode 100644 man/getBlockIDs.Rd delete mode 100644 man/getGeneBlock.Rd diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index feab7b92e..96cdb6d7c 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -721,8 +721,8 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, snp.pos <- snp.pos[which(snp.pos$snp.index > 0),] # Get the block structure base on genes from gdsRefAnnot - snp.pos$block.id <- getGeneBlock(gdsRefAnnot=gdsRefAnnot, - snp.index=snp.pos$snp.index, blockID=blockID) + snp.pos$block.id <- getBlockIDs(gdsRefAnnot=gdsRefAnnot, + snpIndex=snp.pos$snp.index, blockTypeID=blockID) snp.pos$phase <- rep(3, nrow(snp.pos)) if ("phase" %in% ls.gdsn(node=gdsSample)) { diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 9b570b0b0..3b5e00f3d 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -608,44 +608,4 @@ addUpdateSegment <- function(gdsProfile, snp.seg) { } -#' @title Get the block number for each SNV in snp.index -#' -#' @description TODO -#' -#' @param gdsRefAnnot an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), the opened Reference SNV Annotation GDS file. RNA specific -#' Default: \code{NULL}. -#' -#' @param snp.index TODO -#' -#' @param blockID a \code{character} string corresponding to the block -#' identifier in \code{gdsRefAnnot}. RNA specific -#' Default: \code{NULL} -#' -#' @return TODO a \code{vector} of \code{numeric} corresponding to the -#' block identifier -#' -#' @examples -#' -#' # TODO -#' gds <- "Demo GDS TODO" -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt index.gdsn read.gdsn -#' @encoding UTF-8 -#' @keywords internal -getGeneBlock <- function(gdsRefAnnot, snp.index, blockID) { - - block.annot <- read.gdsn(index.gdsn(gdsRefAnnot, "block.annot")) - pos <- which(block.annot$block.id == blockID) - - if(length(pos) != 1) { - stop("Try to get Gene.Block with blockID problematic ", blockID) - } - - b <- read.gdsn(index.gdsn(gdsRefAnnot, "block"), start=c(1,pos), - count = c(-1,1))[snp.index] - - return(b) -} diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index ed6fd20a6..b87aa407e 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -276,8 +276,8 @@ appendGDSgenotypeMat <- function(gds, matG) { #' @param dfPedProfile a \code{data.frame} with the information about #' the sample(s). #' Those are mandatory columns: "Name.ID", -#' "Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in -#' \code{character} strings. The \code{data.frame} +#' "Case.ID", "Sample.Type", "Diagnosis" and "Source". All columns must be in +#' \code{character} strings format. The \code{data.frame} #' must contain the information for all the samples passed in the #' \code{listSamples} parameter. #' @@ -1111,3 +1111,68 @@ addUpdateLap <- function(gdsProfile, snpLap) { return(0L) } + + +#' @title Extract the block identifiers for a list of SNVs +#' +#' @description The function uses the GDS Reference Annotation file to extract +#' the unique block identifiers for a list of SNVs. The block type that is +#' going to be used to extract the information has to be provided by the +#' user. +#' +#' @param gdsRefAnnot an object of class \code{\link[gdsfmt]{gds.class}} +#' (a GDS file), the opened Reference SNV Annotation GDS file. +#' +#' @param snpIndex a \code{vectcor} of \code{integer} representing the +#' indexes of the SNVs of interest. +#' +#' @param blockTypeID a \code{character} string corresponding to the block +#' type used to extract the block identifiers. The block type must be +#' present in the GDS Reference Annotation file. +#' +#' @return a \code{vector} of \code{numeric} corresponding to the +#' block identifiers for the SNVs of interest. +#' +#' @examples +#' +#' # Required library +#' library(gdsfmt) +#' +#' ## Path to the demo 1KG Annotation GDS file located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +#' +#' gdsRefAnnotation <- openfn.gds(fileAnnotGDS) +#' +#' ## The indexes for the SNVs of interest +#' snpIndex <- c(1,3,5,6,9) +#' +#' ## Extract the block identifiers for the SNVs represented by their indexes +#' ## for the block created using the genes from Hsapiens Ensembl v86 +#' RAIDS:::getBlockIDs(gdsRefAnnot=gdsRefAnnotation, snpIndex=snpIndex, +#' blockTypeID="GeneS.Ensembl.Hsapiens.v86") +#' +#' closefn.gds(gdsRefAnnotation) +#' +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt index.gdsn read.gdsn +#' @encoding UTF-8 +#' @keywords internal +getBlockIDs <- function(gdsRefAnnot, snpIndex, blockTypeID) { + + block.annot <- read.gdsn(index.gdsn(gdsRefAnnot, "block.annot")) + pos <- which(block.annot$block.id == blockTypeID) + + if(length(pos) != 1) { + stop("The following block type is not found in the ", + "GDS Annotation file: \'", blockTypeID, "\'") + } + + b <- read.gdsn(index.gdsn(gdsRefAnnot, "block"), start=c(1, pos), + count = c(-1, 1))[snpIndex] + + return(b) +} diff --git a/R/process1KG.R b/R/process1KG.R index 29020a3a9..24106f558 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -864,7 +864,7 @@ addBlockFromPlink2GDS <- function(gds, gdsOut, PATHBLOCK, listChr <- seq_len(22) listBlock <- list() for(chr in listChr) { - if(verbose) { message("chr", chr, " ",Sys.time()) } + if(verbose) { message("chr", chr, " ", Sys.time()) } snp.keep <- snp.position[snp.chromosome == chr] diff --git a/R/processStudy.R b/R/processStudy.R index 9a19ac873..b7f541efa 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -783,6 +783,9 @@ addPhase1KG2SampleGDSFromFile <- function(gdsReference, pathProfileGDS, listGDSSample <- dir(pathProfileGDS, pattern = ".+.gds") + ## Each index is very big and there is a lot of overlapping between + ## the samples + ## The for loop limits the memory usage indexAll <- NULL for(fileProfileGDS in listGDSSample) { gdsSample <- openfn.gds(filename=file.path(pathProfileGDS, @@ -2517,9 +2520,9 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, studyDF=studyDF, pathProfileGDS=pathProfileGDS, genoSource=genoSource, verbose=verbose) - ## Open the 1KG GDS file (demo version) + ## Open the Reference GDS file gds1KG <- snpgdsOpen(fileReferenceGDS) - ## Open the 1KG GDS file and 1KG SNV Annotation file + ## Open the Reference GDS file and 1KG SNV Annotation file gdsAnnot1KG <- openfn.gds(fileReferenceAnnotGDS) listProfileRef <- syntheticRefDF$sample.id diff --git a/man/generateGDS1KGgenotypeFromSNPPileup.Rd b/man/generateGDS1KGgenotypeFromSNPPileup.Rd index e553576be..7d1abec74 100644 --- a/man/generateGDS1KGgenotypeFromSNPPileup.Rd +++ b/man/generateGDS1KGgenotypeFromSNPPileup.Rd @@ -53,8 +53,8 @@ representing the sequencing error rate. Default: \code{0.001}.} \item{dfPedProfile}{a \code{data.frame} with the information about the sample(s). Those are mandatory columns: "Name.ID", -"Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in -\code{character} strings. The \code{data.frame} +"Case.ID", "Sample.Type", "Diagnosis" and "Source". All columns must be in +\code{character} strings format. The \code{data.frame} must contain the information for all the samples passed in the \code{listSamples} parameter.} diff --git a/man/getBlockIDs.Rd b/man/getBlockIDs.Rd new file mode 100644 index 000000000..5ab78bb23 --- /dev/null +++ b/man/getBlockIDs.Rd @@ -0,0 +1,59 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gdsWrapper_internal.R +\encoding{UTF-8} +\name{getBlockIDs} +\alias{getBlockIDs} +\title{Extract the block identifiers for a list of SNVs} +\usage{ +getBlockIDs(gdsRefAnnot, snpIndex, blockTypeID) +} +\arguments{ +\item{gdsRefAnnot}{an object of class \code{\link[gdsfmt]{gds.class}} +(a GDS file), the opened Reference SNV Annotation GDS file.} + +\item{snpIndex}{a \code{vectcor} of \code{integer} representing the +indexes of the SNVs of interest.} + +\item{blockTypeID}{a \code{character} string corresponding to the block +type used to extract the block identifiers. The block type must be +present in the GDS Reference Annotation file.} +} +\value{ +a \code{vector} of \code{numeric} corresponding to the +block identifiers for the SNVs of interest. +} +\description{ +The function uses the GDS Reference Annotation file to extract +the unique block identifiers for a list of SNVs. The block type that is +going to be used to extract the information has to be provided by the +user. +} +\examples{ + +# Required library +library(gdsfmt) + +## Path to the demo 1KG Annotation GDS file located in this package +dataDir <- system.file("extdata", package="RAIDS") + +path1KG <- file.path(dataDir, "example", "gdsRef") +fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") + +gdsRefAnnotation <- openfn.gds(fileAnnotGDS) + +## The indexes for the SNVs of interest +snpIndex <- c(1,3,5,6,9) + +## Extract the block identifiers for the SNVs represented by their indexes +## for the block created using the genes from Hsapiens Ensembl v86 +RAIDS:::getBlockIDs(gdsRefAnnot=gdsRefAnnotation, snpIndex=snpIndex, + blockTypeID="GeneS.Ensembl.Hsapiens.v86") + +closefn.gds(gdsRefAnnotation) + + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} diff --git a/man/getGeneBlock.Rd b/man/getGeneBlock.Rd deleted file mode 100644 index 710d4a519..000000000 --- a/man/getGeneBlock.Rd +++ /dev/null @@ -1,37 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gdsWrapper.R -\encoding{UTF-8} -\name{getGeneBlock} -\alias{getGeneBlock} -\title{Get the block number for each SNV in snp.index} -\usage{ -getGeneBlock(gdsRefAnnot, snp.index, blockID) -} -\arguments{ -\item{gdsRefAnnot}{an object of class \code{\link[gdsfmt]{gds.class}} -(a GDS file), the opened Reference SNV Annotation GDS file. RNA specific -Default: \code{NULL}.} - -\item{snp.index}{TODO} - -\item{blockID}{a \code{character} string corresponding to the block -identifier in \code{gdsRefAnnot}. RNA specific -Default: \code{NULL}} -} -\value{ -TODO a \code{vector} of \code{numeric} corresponding to the -block identifier -} -\description{ -TODO -} -\examples{ - -# TODO -gds <- "Demo GDS TODO" - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{internal} diff --git a/tests/testthat/test-gdsWrapper_internal.R b/tests/testthat/test-gdsWrapper_internal.R index e76a03d2a..87f963b48 100644 --- a/tests/testthat/test-gdsWrapper_internal.R +++ b/tests/testthat/test-gdsWrapper_internal.R @@ -494,3 +494,29 @@ test_that("addUpdateLap() must copy the expected entry in \"lap\" node of the GD expect_equal(results, lap) }) + +context("getBlockIDs() results") + + +test_that("getBlockIDs() must return the expected result", { + + ## Create a temporary GDS file in an test directory + dataDir <- system.file("extdata/example/gdsRef", package="RAIDS") + fileGDS <- file.path(dataDir, "exAnnot1kg.gds") + + annotFile <- openfn.gds(fileGDS) + defer(closefn.gds(annotFile), envir=parent.frame()) + + ## Vector of segment identifiers + indexes <- c(1, 3, 6, 8, 9) + + ## Block identifiers for the selected SNVs + result <- RAIDS:::getBlockIDs(gdsRefAnnot=annotFile, snpIndex=indexes, + blockTypeID="GeneS.Ensembl.Hsapiens.v86") + + expected <- rep(943, 5) + + expect_equal(result, expected) +}) + + From 0295cde4e5ee78ef3ca1875c5ad686e5e73776df Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 11 Aug 2023 19:18:46 -0400 Subject: [PATCH 074/385] Add unit test for getBlockIDs() --- tests/testthat/test-gdsWrapper_internal.R | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/testthat/test-gdsWrapper_internal.R b/tests/testthat/test-gdsWrapper_internal.R index 87f963b48..58152d806 100644 --- a/tests/testthat/test-gdsWrapper_internal.R +++ b/tests/testthat/test-gdsWrapper_internal.R @@ -520,3 +520,23 @@ test_that("getBlockIDs() must return the expected result", { }) +test_that("getBlockIDs() must return expected error", { + + ## Create a temporary GDS file in an test directory + dataDir <- system.file("extdata/example/gdsRef", package="RAIDS") + fileGDS <- file.path(dataDir, "exAnnot1kg.gds") + + annotFile <- openfn.gds(fileGDS) + defer(closefn.gds(annotFile), envir=parent.frame()) + + ## Vector of segment identifiers + indexes <- c(1, 3, 6, 8, 9) + + error_message <- paste0("The following block type is not found in the ", + "GDS Annotation file: \'InformationTremblay\'") + + expect_error(RAIDS:::getBlockIDs(gdsRefAnnot=annotFile, snpIndex=indexes, + blockTypeID="InformationTremblay"), + error_message, fixed=TRUE) +}) + From 851a4988e3b7e30e3bbfed2d958d291fb35fef9f Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sat, 12 Aug 2023 16:20:33 -0400 Subject: [PATCH 075/385] Change examples to be run only when directory is writable for 2 functions --- R/gdsWrapper_internal.R | 68 ++++++++++++++++++++++----------------- man/addGDSStudyPruning.Rd | 31 ++++++++++-------- man/addUpdateLap.Rd | 37 ++++++++++++--------- 3 files changed, 78 insertions(+), 58 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index b87aa407e..e9b1df8a6 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -1007,25 +1007,30 @@ appendGDSRefSample <- function(gdsReference, dfPedReference, batch=1, #' #' ## Create a temporary GDS file in an test directory #' dataDir <- system.file("extdata/tests", package="RAIDS") -#' gdsFilePath <- file.path(dataDir, "GDS_TEMP_1.gds") +#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_1.gds") #' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' ## Only run if directory is in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { #' -#' ## Vector of low allelic fraction -#' study <- c("s19222", 's19588', 's19988', 's20588', 's23598') +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) #' -#' ## Add segments to the GDS file -#' RAIDS:::addGDSStudyPruning(gdsProfile=tmpGDS, pruned=study) +#' ## Vector of low allelic fraction +#' study <- c("s19222", 's19588', 's19988', 's20588', 's23598') #' -#' ## Read lap information from GDS file -#' read.gdsn(index.gdsn(node=tmpGDS, path="pruned.study")) +#' ## Add segments to the GDS file +#' RAIDS:::addGDSStudyPruning(gdsProfile=tmpGDS, pruned=study) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Read lap information from GDS file +#' read.gdsn(index.gdsn(node=tmpGDS, path="pruned.study")) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) +#' +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn index.gdsn delete.gdsn sync.gds ls.gdsn @@ -1075,29 +1080,34 @@ addGDSStudyPruning <- function(gdsProfile, pruned) { #' #' ## Create a temporary GDS file in an test directory #' dataDir <- system.file("extdata/tests", package="RAIDS") -#' gdsFilePath <- file.path(dataDir, "GDS_TEMP.gds") +#' gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") #' -#' ## Create and open the GDS file -#' gdsFile <- createfn.gds(filename=gdsFilePath) +#' ## Only run if directory is in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { #' -#' ## Create a "lap" node -#' add.gdsn(node=gdsFile, name="lap", val=rep(10L, 12)) -#' sync.gds(gdsFile) +#' ## Create and open the GDS file +#' gdsFile <- createfn.gds(filename=gdsFilePath) #' -#' ## Vector of low allelic fraction -#' lap <- c(0.1, 0.23, 0.34, 0.00, 0.12, 0.11, 0.33, 0.55) +#' ## Create a "lap" node +#' add.gdsn(node=gdsFile, name="lap", val=rep(10L, 12)) +#' sync.gds(gdsFile) #' -#' ## Add segments to the GDS file -#' RAIDS:::addUpdateLap(gdsProfile=gdsFile, snpLap=lap) +#' ## Vector of low allelic fraction +#' lap <- c(0.1, 0.23, 0.34, 0.00, 0.12, 0.11, 0.33, 0.55) #' -#' ## Read lap information from GDS file -#' read.gdsn(index.gdsn(node=gdsFile, path="lap")) +#' ## Add segments to the GDS file +#' RAIDS:::addUpdateLap(gdsProfile=gdsFile, snpLap=lap) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=gdsFile) +#' ## Read lap information from GDS file +#' read.gdsn(index.gdsn(node=gdsFile, path="lap")) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Close GDS file +#' closefn.gds(gdsfile=gdsFile) +#' +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn index.gdsn delete.gdsn sync.gds ls.gdsn diff --git a/man/addGDSStudyPruning.Rd b/man/addGDSStudyPruning.Rd index 4f33484aa..23086dbc4 100644 --- a/man/addGDSStudyPruning.Rd +++ b/man/addGDSStudyPruning.Rd @@ -31,25 +31,30 @@ library(gdsfmt) ## Create a temporary GDS file in an test directory dataDir <- system.file("extdata/tests", package="RAIDS") -gdsFilePath <- file.path(dataDir, "GDS_TEMP_1.gds") +gdsFilePath <- file.path(getwd(), "GDS_TEMP_1.gds") -## Create and open the GDS file -tmpGDS <- createfn.gds(filename=gdsFilePath) +## Only run if directory is in writing mode +if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -## Vector of low allelic fraction -study <- c("s19222", 's19588', 's19988', 's20588', 's23598') + ## Create and open the GDS file + tmpGDS <- createfn.gds(filename=gdsFilePath) -## Add segments to the GDS file -RAIDS:::addGDSStudyPruning(gdsProfile=tmpGDS, pruned=study) + ## Vector of low allelic fraction + study <- c("s19222", 's19588', 's19988', 's20588', 's23598') -## Read lap information from GDS file -read.gdsn(index.gdsn(node=tmpGDS, path="pruned.study")) + ## Add segments to the GDS file + RAIDS:::addGDSStudyPruning(gdsProfile=tmpGDS, pruned=study) -## Close GDS file -closefn.gds(gdsfile=tmpGDS) + ## Read lap information from GDS file + read.gdsn(index.gdsn(node=tmpGDS, path="pruned.study")) -## Delete the temporary GDS file -unlink(x=gdsFilePath, force=TRUE) + ## Close GDS file + closefn.gds(gdsfile=tmpGDS) + + ## Delete the temporary GDS file + unlink(x=gdsFilePath, force=TRUE) + +} } \author{ diff --git a/man/addUpdateLap.Rd b/man/addUpdateLap.Rd index 180523cc4..f2fb828b7 100644 --- a/man/addUpdateLap.Rd +++ b/man/addUpdateLap.Rd @@ -35,29 +35,34 @@ library(gdsfmt) ## Create a temporary GDS file in an test directory dataDir <- system.file("extdata/tests", package="RAIDS") -gdsFilePath <- file.path(dataDir, "GDS_TEMP.gds") +gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") -## Create and open the GDS file -gdsFile <- createfn.gds(filename=gdsFilePath) +## Only run if directory is in writing mode +if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -## Create a "lap" node -add.gdsn(node=gdsFile, name="lap", val=rep(10L, 12)) -sync.gds(gdsFile) + ## Create and open the GDS file + gdsFile <- createfn.gds(filename=gdsFilePath) -## Vector of low allelic fraction -lap <- c(0.1, 0.23, 0.34, 0.00, 0.12, 0.11, 0.33, 0.55) + ## Create a "lap" node + add.gdsn(node=gdsFile, name="lap", val=rep(10L, 12)) + sync.gds(gdsFile) -## Add segments to the GDS file -RAIDS:::addUpdateLap(gdsProfile=gdsFile, snpLap=lap) + ## Vector of low allelic fraction + lap <- c(0.1, 0.23, 0.34, 0.00, 0.12, 0.11, 0.33, 0.55) -## Read lap information from GDS file -read.gdsn(index.gdsn(node=gdsFile, path="lap")) + ## Add segments to the GDS file + RAIDS:::addUpdateLap(gdsProfile=gdsFile, snpLap=lap) -## Close GDS file -closefn.gds(gdsfile=gdsFile) + ## Read lap information from GDS file + read.gdsn(index.gdsn(node=gdsFile, path="lap")) -## Delete the temporary GDS file -unlink(x=gdsFilePath, force=TRUE) + ## Close GDS file + closefn.gds(gdsfile=gdsFile) + + ## Delete the temporary GDS file + unlink(x=gdsFilePath, force=TRUE) + +} } \author{ From 83423941c2dd9307e40a7c016cd9e9d63c1b16b5 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 13 Aug 2023 17:01:09 -0400 Subject: [PATCH 076/385] Update doc for groupChrPruning() function --- R/tools.R | 10 ++++++---- man/groupChrPruning.Rd | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/R/tools.R b/R/tools.R index 7595d365d..26b5fd652 100644 --- a/R/tools.R +++ b/R/tools.R @@ -127,7 +127,7 @@ snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { return(0L) } -#' @title Merge the pruning files by chromosome in one file +#' @title Merge the pruning files by chromosome in one RDS file #' #' @description TODO #' @@ -135,11 +135,13 @@ snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { #' the pruned files for each chromosome are located. #' The path must exists. #' -#' @param filePref TODO +#' @param filePref a \code{character} string representing the prefix used for +#' the pruned files for each chromosome. The prefix represent the complete +#' string that is before the chromosome number in the file names. #' #' @param fileOut a \code{character} string representing name of the output -#' file that will be created. THe file will contain the information for all -#' pruned chromosome. The file must have a ".rds" extension. +#' file that will be created. The file will contain the information for all +#' pruned chromosomes. The file must have a ".rds" extension. #' #' @return The integer \code{0L} when successful. #' diff --git a/man/groupChrPruning.Rd b/man/groupChrPruning.Rd index c3c56cc21..473313ac0 100644 --- a/man/groupChrPruning.Rd +++ b/man/groupChrPruning.Rd @@ -3,7 +3,7 @@ \encoding{UTF-8} \name{groupChrPruning} \alias{groupChrPruning} -\title{Merge the pruning files by chromosome in one file} +\title{Merge the pruning files by chromosome in one RDS file} \usage{ groupChrPruning(pathPrunedGDS, filePref, fileOut) } @@ -12,11 +12,13 @@ groupChrPruning(pathPrunedGDS, filePref, fileOut) the pruned files for each chromosome are located. The path must exists.} -\item{filePref}{TODO} +\item{filePref}{a \code{character} string representing the prefix used for +the pruned files for each chromosome. The prefix represent the complete +string that is before the chromosome number in the file names.} \item{fileOut}{a \code{character} string representing name of the output -file that will be created. THe file will contain the information for all -pruned chromosome. The file must have a ".rds" extension.} +file that will be created. The file will contain the information for all +pruned chromosomes. The file must have a ".rds" extension.} } \value{ The integer \code{0L} when successful. From 6958ca7c06ea70cef596c79b5356c896c83ea4ac Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 13 Aug 2023 17:02:32 -0400 Subject: [PATCH 077/385] Update doc for groupChrPruning() function --- R/tools.R | 5 ++++- man/groupChrPruning.Rd | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/R/tools.R b/R/tools.R index 26b5fd652..4fe868faa 100644 --- a/R/tools.R +++ b/R/tools.R @@ -129,7 +129,10 @@ snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { #' @title Merge the pruning files by chromosome in one RDS file #' -#' @description TODO +#' @description The function reads the information from all chromosomes. The +#' information is scattered in different files (one file per chromosome). +#' Once all information is loaded, the function merges +#' the information and saves it into a RDS file. #' #' @param pathPrunedGDS a \code{character} string representing the path where #' the pruned files for each chromosome are located. diff --git a/man/groupChrPruning.Rd b/man/groupChrPruning.Rd index 473313ac0..d87abd2ee 100644 --- a/man/groupChrPruning.Rd +++ b/man/groupChrPruning.Rd @@ -24,7 +24,10 @@ pruned chromosomes. The file must have a ".rds" extension.} The integer \code{0L} when successful. } \description{ -TODO +The function reads the information from all chromosomes. The +information is scattered in different files (one file per chromosome). +Once all information is loaded, the function merges +the information and saves it into a RDS file. } \examples{ From 7b9d4130ee52bfd515c627d287dcbb1ff38ba187 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 13 Aug 2023 23:11:45 -0400 Subject: [PATCH 078/385] Change documentation for few functions in gdsWrapper_internal.R --- R/gdsWrapper_internal.R | 210 +++++++++++---------- man/addGDSStudyPruning.Rd | 1 - man/addStudyGDSSample.Rd | 58 +++--- man/addUpdateLap.Rd | 1 - man/appendGDSRefSample.Rd | 102 +++++----- man/generateGDS1KGgenotypeFromSNPPileup.Rd | 56 +++--- 6 files changed, 232 insertions(+), 196 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index e9b1df8a6..239301883 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -308,48 +308,58 @@ appendGDSgenotypeMat <- function(gds, matG) { #' #' @examples #' -#' ## Path to the files in this package -#' dataDir <- system.file("extdata/tests", package="RAIDS") +#' ## Current directory +#' dataDir <- file.path(getwd()) +#' +#' ## Run only if directory in writing mode +#' if (file.access(dataDir) == 0) { #' -#' ## The data.frame containing the information about the study -#' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" -#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) -#' studyDF <- data.frame(study.id = "MYDATA", +#' ## Copy required file into current directory +#' file.copy(from=file.path(system.file("extdata/tests", package="RAIDS"), +#' "ex1.txt.gz"), to=dataDir) +#' +#' ## The data.frame containing the information about the study +#' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" +#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) +#' studyDF <- data.frame(study.id = "MYDATA", #' study.desc = "Description", #' study.platform = "PLATFORM", #' stringsAsFactors = FALSE) #' -#' ## The data.frame containing the information about the samples -#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) -#' samplePED <- data.frame(Name.ID=c("ex1", "ex2"), +#' ## The data.frame containing the information about the samples +#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) +#' samplePED <- data.frame(Name.ID=c("ex1", "ex2"), #' Case.ID=c("Patient_h11", "Patient_h12"), #' Diagnosis=rep("Cancer", 2), #' Sample.Type=rep("Primary Tumor", 2), #' Source=rep("Databank B", 2), stringsAsFactors=FALSE) -#' rownames(samplePED) <- samplePED$Name.ID +#' rownames(samplePED) <- samplePED$Name.ID #' -#' ## List of SNV positions -#' listPositions <- data.frame(snp.chromosome=c(rep(1, 10)), -#' snp.position=c(3467333, 3467428, 3469375, 3469387, 3469502, 3469527, -#' 3469737, 3471497, 3471565, 3471618)) +#' ## List of SNV positions +#' listPositions <- data.frame(snp.chromosome=c(rep(1, 10)), +#' snp.position=c(3467333, 3467428, 3469375, 3469387, 3469502, 3469527, +#' 3469737, 3471497, 3471565, 3471618)) #' -#' ## Append genotype information to the Profile GDS file -#' result <- RAIDS:::generateGDS1KGgenotypeFromSNPPileup(pathGeno=dataDir, +#' ## Append genotype information to the Profile GDS file +#' result <- RAIDS:::generateGDS1KGgenotypeFromSNPPileup(pathGeno=dataDir, #' listSamples=c("ex1"), listPos=listPositions, #' offset=-1, minCov=10, minProb=0.999, seqError=0.001, #' dfPedProfile=samplePED, batch=1, studyDF=studyDF, #' pathProfileGDS=dataDir, genoSource="snp-pileup", #' verbose=FALSE) #' -#' ## The function returns OL when successful -#' result +#' ## The function returns OL when successful +#' result +#' +#' ## The Profile GDS file 'ex1.gds' has been created in the +#' ## specified directory +#' list.files(dataDir) #' -#' ## The Profile GDS file 'ex1.gds' has been created in the -#' ## specified directory -#' list.files(dataDir) +#' ## Unlink Profile GDS file (created for demo purpose) +#' unlink(file.path(dataDir, "ex1.gds")) +#' unlink(file.path(dataDir, "ex1.txt.gz")) #' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink(file.path(dataDir, "ex1.gds")) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn write.gdsn openfn.gds @@ -575,41 +585,45 @@ generateGDS1KGgenotypeFromSNPPileup <- function(pathGeno, #' library(gdsfmt) #' #' ## Create a temporary GDS file in an test directory -#' dataDir <- system.file("extdata/tests", package="RAIDS") -#' gdsFilePath <- file.path(dataDir, "GDS_TEMP_11.gds") +#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") #' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' ## Run only if directory in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { #' -#' ## Create a PED data frame with sample information -#' ped1KG <- data.frame(Name.ID=c("1KG_sample_01", "1KG_sample_02"), -#' Case.ID=c("1KG_sample_01", "1KG_sample_02"), -#' Sample.Type=rep("Reference", 2), Diagnosis=rep("Reference", 2), -#' Source=rep("IGSR", 2), stringsAsFactors=FALSE) -#' -#' ## Create a Study data frame with information about the study -#' ## All samples are associated to the same study -#' studyInfo <- data.frame(study.id="Ref.1KG", -#' study.desc="Unrelated samples from 1000 Genomes", -#' study.platform="GRCh38 1000 genotypes", -#' stringsAsFactors=FALSE) +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) #' -#' ## Add the sample information to the GDS Sample file -#' ## The information for all samples is added (listSamples=NULL) -#' RAIDS:::addStudyGDSSample(gdsProfile=tmpGDS, pedProfile=ped1KG, batch=1, -#' listSamples=NULL, studyDF=studyInfo, verbose=FALSE) +#' ## Create a PED data frame with sample information +#' ped1KG <- data.frame(Name.ID=c("1KG_sample_01", "1KG_sample_02"), +#' Case.ID=c("1KG_sample_01", "1KG_sample_02"), +#' Sample.Type=rep("Reference", 2), Diagnosis=rep("Reference", 2), +#' Source=rep("IGSR", 2), stringsAsFactors=FALSE) #' -#' ## Read study information from GDS Sample file -#' read.gdsn(index.gdsn(node=tmpGDS, path="study.list")) +#' ## Create a Study data frame with information about the study +#' ## All samples are associated to the same study +#' studyInfo <- data.frame(study.id="Ref.1KG", +#' study.desc="Unrelated samples from 1000 Genomes", +#' study.platform="GRCh38 1000 genotypes", +#' stringsAsFactors=FALSE) #' -#' ## Read sample information from GDS Sample file -#' read.gdsn(index.gdsn(node=tmpGDS, path="study.annot")) +#' ## Add the sample information to the GDS Sample file +#' ## The information for all samples is added (listSamples=NULL) +#' RAIDS:::addStudyGDSSample(gdsProfile=tmpGDS, pedProfile=ped1KG, batch=1, +#' listSamples=NULL, studyDF=studyInfo, verbose=FALSE) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Read study information from GDS Sample file +#' read.gdsn(index.gdsn(node=tmpGDS, path="study.list")) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Read sample information from GDS Sample file +#' read.gdsn(index.gdsn(node=tmpGDS, path="study.annot")) +#' +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) +#' +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn append.gdsn @@ -894,54 +908,60 @@ runLDPruning <- function(gds, method, #' library(gdsfmt) #' #' ## Create a temporary GDS file in an test directory -#' dataDir <- system.file("extdata/tests", package="RAIDS") -#' gdsFilePath <- file.path(dataDir, "GDS_TEMP_03.gds") -#' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) -#' -#' ## Create "sample.id" node (the node must be present) -#' add.gdsn(node=tmpGDS, name="sample.id", val=c("sample_01", -#' "sample_02")) +#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_03.gds") #' -#' ## Create "sample.annot" node (the node must be present) -#' add.gdsn(node=tmpGDS, name="sample.annot", val=data.frame( -#' Name.ID=c("sample_01", "sample_02"), -#' sex=c(1,1), # 1:Male 2: Female -#' pop.group=c("ACB", "ACB"), -#' superPop=c("AFR", "AFR"), -#' batch=c(1, 1), -#' stringsAsFactors=FALSE)) -#' -#' sync.gds(gdsfile=tmpGDS) -#' -#' ## Create a data.frame with information about samples -#' sample_info <- data.frame(Name.ID=c("sample_04", "sample_05", "sample_06"), -#' sex=c(1,2,1), # 1:Male 2: Female -#' pop.group=c("ACB", "ACB", "ACB"), -#' superPop=c("AFR", "AFR", "AFR"), -#' stringsAsFactors=FALSE) -#' -#' ## The row names must be the sample identifiers -#' rownames(sample_info) <- sample_info$Name.ID -#' -#' ## Add information about 2 samples to the GDS file -#' RAIDS:::appendGDSRefSample(gdsReference=tmpGDS, dfPedReference=sample_info, -#' batch=2, listSamples=c("sample_04", "sample_06"), verbose=FALSE) +#' ## Only run if directory is in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { #' -#' ## Read sample identifier list -#' ## Only "sample_04" and "sample_06" should have been added -#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' +#' ## Create "sample.id" node (the node must be present) +#' add.gdsn(node=tmpGDS, name="sample.id", val=c("sample_01", +#' "sample_02")) +#' +#' ## Create "sample.annot" node (the node must be present) +#' add.gdsn(node=tmpGDS, name="sample.annot", val=data.frame( +#' Name.ID=c("sample_01", "sample_02"), +#' sex=c(1,1), # 1:Male 2: Female +#' pop.group=c("ACB", "ACB"), +#' superPop=c("AFR", "AFR"), +#' batch=c(1, 1), +#' stringsAsFactors=FALSE)) +#' +#' sync.gds(gdsfile=tmpGDS) +#' +#' ## Create a data.frame with information about samples +#' sample_info <- data.frame(Name.ID=c("sample_04", "sample_05", +#' "sample_06"), +#' sex=c(1,2,1), # 1:Male 2: Female +#' pop.group=c("ACB", "ACB", "ACB"), +#' superPop=c("AFR", "AFR", "AFR"), +#' stringsAsFactors=FALSE) +#' +#' ## The row names must be the sample identifiers +#' rownames(sample_info) <- sample_info$Name.ID +#' +#' ## Add information about 2 samples to the GDS file +#' RAIDS:::appendGDSRefSample(gdsReference=tmpGDS, +#' dfPedReference=sample_info, +#' batch=2, listSamples=c("sample_04", "sample_06"), verbose=FALSE) +#' +#' ## Read sample identifier list +#' ## Only "sample_04" and "sample_06" should have been added +#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) +#' +#' ## Read sample information from GDS file +#' ## Only "sample_04" and "sample_06" should have been added +#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) #' -#' ## Read sample information from GDS file -#' ## Only "sample_04" and "sample_06" should have been added -#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn append.gdsn @@ -1006,7 +1026,6 @@ appendGDSRefSample <- function(gdsReference, dfPedReference, batch=1, #' library(gdsfmt) #' #' ## Create a temporary GDS file in an test directory -#' dataDir <- system.file("extdata/tests", package="RAIDS") #' gdsFilePath <- file.path(getwd(), "GDS_TEMP_1.gds") #' #' ## Only run if directory is in writing mode @@ -1079,7 +1098,6 @@ addGDSStudyPruning <- function(gdsProfile, pruned) { #' library(gdsfmt) #' #' ## Create a temporary GDS file in an test directory -#' dataDir <- system.file("extdata/tests", package="RAIDS") #' gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") #' #' ## Only run if directory is in writing mode diff --git a/man/addGDSStudyPruning.Rd b/man/addGDSStudyPruning.Rd index 23086dbc4..28a560e3b 100644 --- a/man/addGDSStudyPruning.Rd +++ b/man/addGDSStudyPruning.Rd @@ -30,7 +30,6 @@ deleted and a new entry is created. library(gdsfmt) ## Create a temporary GDS file in an test directory -dataDir <- system.file("extdata/tests", package="RAIDS") gdsFilePath <- file.path(getwd(), "GDS_TEMP_1.gds") ## Only run if directory is in writing mode diff --git a/man/addStudyGDSSample.Rd b/man/addStudyGDSSample.Rd index cd55bcd99..75cb73164 100644 --- a/man/addStudyGDSSample.Rd +++ b/man/addStudyGDSSample.Rd @@ -55,41 +55,45 @@ created and then, the information is added. library(gdsfmt) ## Create a temporary GDS file in an test directory -dataDir <- system.file("extdata/tests", package="RAIDS") -gdsFilePath <- file.path(dataDir, "GDS_TEMP_11.gds") +gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") -## Create and open the GDS file -tmpGDS <- createfn.gds(filename=gdsFilePath) +## Run only if directory in writing mode +if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -## Create a PED data frame with sample information -ped1KG <- data.frame(Name.ID=c("1KG_sample_01", "1KG_sample_02"), - Case.ID=c("1KG_sample_01", "1KG_sample_02"), - Sample.Type=rep("Reference", 2), Diagnosis=rep("Reference", 2), - Source=rep("IGSR", 2), stringsAsFactors=FALSE) + ## Create and open the GDS file + tmpGDS <- createfn.gds(filename=gdsFilePath) -## Create a Study data frame with information about the study -## All samples are associated to the same study -studyInfo <- data.frame(study.id="Ref.1KG", - study.desc="Unrelated samples from 1000 Genomes", - study.platform="GRCh38 1000 genotypes", - stringsAsFactors=FALSE) + ## Create a PED data frame with sample information + ped1KG <- data.frame(Name.ID=c("1KG_sample_01", "1KG_sample_02"), + Case.ID=c("1KG_sample_01", "1KG_sample_02"), + Sample.Type=rep("Reference", 2), Diagnosis=rep("Reference", 2), + Source=rep("IGSR", 2), stringsAsFactors=FALSE) -## Add the sample information to the GDS Sample file -## The information for all samples is added (listSamples=NULL) -RAIDS:::addStudyGDSSample(gdsProfile=tmpGDS, pedProfile=ped1KG, batch=1, - listSamples=NULL, studyDF=studyInfo, verbose=FALSE) + ## Create a Study data frame with information about the study + ## All samples are associated to the same study + studyInfo <- data.frame(study.id="Ref.1KG", + study.desc="Unrelated samples from 1000 Genomes", + study.platform="GRCh38 1000 genotypes", + stringsAsFactors=FALSE) -## Read study information from GDS Sample file -read.gdsn(index.gdsn(node=tmpGDS, path="study.list")) + ## Add the sample information to the GDS Sample file + ## The information for all samples is added (listSamples=NULL) + RAIDS:::addStudyGDSSample(gdsProfile=tmpGDS, pedProfile=ped1KG, batch=1, + listSamples=NULL, studyDF=studyInfo, verbose=FALSE) -## Read sample information from GDS Sample file -read.gdsn(index.gdsn(node=tmpGDS, path="study.annot")) + ## Read study information from GDS Sample file + read.gdsn(index.gdsn(node=tmpGDS, path="study.list")) -## Close GDS file -closefn.gds(gdsfile=tmpGDS) + ## Read sample information from GDS Sample file + read.gdsn(index.gdsn(node=tmpGDS, path="study.annot")) -## Delete the temporary GDS file -unlink(x=gdsFilePath, force=TRUE) + ## Close GDS file + closefn.gds(gdsfile=tmpGDS) + + ## Delete the temporary GDS file + unlink(x=gdsFilePath, force=TRUE) + +} } \author{ diff --git a/man/addUpdateLap.Rd b/man/addUpdateLap.Rd index f2fb828b7..c487c8027 100644 --- a/man/addUpdateLap.Rd +++ b/man/addUpdateLap.Rd @@ -34,7 +34,6 @@ already be present in the GDS file. library(gdsfmt) ## Create a temporary GDS file in an test directory -dataDir <- system.file("extdata/tests", package="RAIDS") gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") ## Only run if directory is in writing mode diff --git a/man/appendGDSRefSample.Rd b/man/appendGDSRefSample.Rd index c0f67a718..78144dfa4 100644 --- a/man/appendGDSRefSample.Rd +++ b/man/appendGDSRefSample.Rd @@ -49,54 +49,60 @@ addStudyGDSSample() must be used. library(gdsfmt) ## Create a temporary GDS file in an test directory -dataDir <- system.file("extdata/tests", package="RAIDS") -gdsFilePath <- file.path(dataDir, "GDS_TEMP_03.gds") - -## Create and open the GDS file -tmpGDS <- createfn.gds(filename=gdsFilePath) - -## Create "sample.id" node (the node must be present) -add.gdsn(node=tmpGDS, name="sample.id", val=c("sample_01", - "sample_02")) - -## Create "sample.annot" node (the node must be present) -add.gdsn(node=tmpGDS, name="sample.annot", val=data.frame( - Name.ID=c("sample_01", "sample_02"), - sex=c(1,1), # 1:Male 2: Female - pop.group=c("ACB", "ACB"), - superPop=c("AFR", "AFR"), - batch=c(1, 1), - stringsAsFactors=FALSE)) - -sync.gds(gdsfile=tmpGDS) - -## Create a data.frame with information about samples -sample_info <- data.frame(Name.ID=c("sample_04", "sample_05", "sample_06"), - sex=c(1,2,1), # 1:Male 2: Female - pop.group=c("ACB", "ACB", "ACB"), - superPop=c("AFR", "AFR", "AFR"), - stringsAsFactors=FALSE) - -## The row names must be the sample identifiers -rownames(sample_info) <- sample_info$Name.ID - -## Add information about 2 samples to the GDS file -RAIDS:::appendGDSRefSample(gdsReference=tmpGDS, dfPedReference=sample_info, - batch=2, listSamples=c("sample_04", "sample_06"), verbose=FALSE) - -## Read sample identifier list -## Only "sample_04" and "sample_06" should have been added -read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) - -## Read sample information from GDS file -## Only "sample_04" and "sample_06" should have been added -read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) - -## Close GDS file -closefn.gds(gdsfile=tmpGDS) - -## Delete the temporary GDS file -unlink(x=gdsFilePath, force=TRUE) +gdsFilePath <- file.path(getwd(), "GDS_TEMP_03.gds") + +## Only run if directory is in writing mode +if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { + + ## Create and open the GDS file + tmpGDS <- createfn.gds(filename=gdsFilePath) + + ## Create "sample.id" node (the node must be present) + add.gdsn(node=tmpGDS, name="sample.id", val=c("sample_01", + "sample_02")) + + ## Create "sample.annot" node (the node must be present) + add.gdsn(node=tmpGDS, name="sample.annot", val=data.frame( + Name.ID=c("sample_01", "sample_02"), + sex=c(1,1), # 1:Male 2: Female + pop.group=c("ACB", "ACB"), + superPop=c("AFR", "AFR"), + batch=c(1, 1), + stringsAsFactors=FALSE)) + + sync.gds(gdsfile=tmpGDS) + + ## Create a data.frame with information about samples + sample_info <- data.frame(Name.ID=c("sample_04", "sample_05", + "sample_06"), + sex=c(1,2,1), # 1:Male 2: Female + pop.group=c("ACB", "ACB", "ACB"), + superPop=c("AFR", "AFR", "AFR"), + stringsAsFactors=FALSE) + + ## The row names must be the sample identifiers + rownames(sample_info) <- sample_info$Name.ID + + ## Add information about 2 samples to the GDS file + RAIDS:::appendGDSRefSample(gdsReference=tmpGDS, + dfPedReference=sample_info, + batch=2, listSamples=c("sample_04", "sample_06"), verbose=FALSE) + + ## Read sample identifier list + ## Only "sample_04" and "sample_06" should have been added + read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) + + ## Read sample information from GDS file + ## Only "sample_04" and "sample_06" should have been added + read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) + + ## Close GDS file + closefn.gds(gdsfile=tmpGDS) + + ## Delete the temporary GDS file + unlink(x=gdsFilePath, force=TRUE) + +} } \author{ diff --git a/man/generateGDS1KGgenotypeFromSNPPileup.Rd b/man/generateGDS1KGgenotypeFromSNPPileup.Rd index 7d1abec74..f5c2ebe67 100644 --- a/man/generateGDS1KGgenotypeFromSNPPileup.Rd +++ b/man/generateGDS1KGgenotypeFromSNPPileup.Rd @@ -91,48 +91,58 @@ from a SNV file as generated by SNP-pileup or other tools. } \examples{ -## Path to the files in this package -dataDir <- system.file("extdata/tests", package="RAIDS") +## Current directory +dataDir <- file.path(getwd()) -## The data.frame containing the information about the study -## The 3 mandatory columns: "study.id", "study.desc", "study.platform" -## The entries should be strings, not factors (stringsAsFactors=FALSE) -studyDF <- data.frame(study.id = "MYDATA", +## Run only if directory in writing mode +if (file.access(dataDir) == 0) { + + ## Copy required file into current directory + file.copy(from=file.path(system.file("extdata/tests", package="RAIDS"), + "ex1.txt.gz"), to=dataDir) + + ## The data.frame containing the information about the study + ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" + ## The entries should be strings, not factors (stringsAsFactors=FALSE) + studyDF <- data.frame(study.id = "MYDATA", study.desc = "Description", study.platform = "PLATFORM", stringsAsFactors = FALSE) -## The data.frame containing the information about the samples -## The entries should be strings, not factors (stringsAsFactors=FALSE) -samplePED <- data.frame(Name.ID=c("ex1", "ex2"), + ## The data.frame containing the information about the samples + ## The entries should be strings, not factors (stringsAsFactors=FALSE) + samplePED <- data.frame(Name.ID=c("ex1", "ex2"), Case.ID=c("Patient_h11", "Patient_h12"), Diagnosis=rep("Cancer", 2), Sample.Type=rep("Primary Tumor", 2), Source=rep("Databank B", 2), stringsAsFactors=FALSE) -rownames(samplePED) <- samplePED$Name.ID + rownames(samplePED) <- samplePED$Name.ID -## List of SNV positions -listPositions <- data.frame(snp.chromosome=c(rep(1, 10)), - snp.position=c(3467333, 3467428, 3469375, 3469387, 3469502, 3469527, - 3469737, 3471497, 3471565, 3471618)) + ## List of SNV positions + listPositions <- data.frame(snp.chromosome=c(rep(1, 10)), + snp.position=c(3467333, 3467428, 3469375, 3469387, 3469502, 3469527, + 3469737, 3471497, 3471565, 3471618)) -## Append genotype information to the Profile GDS file -result <- RAIDS:::generateGDS1KGgenotypeFromSNPPileup(pathGeno=dataDir, + ## Append genotype information to the Profile GDS file + result <- RAIDS:::generateGDS1KGgenotypeFromSNPPileup(pathGeno=dataDir, listSamples=c("ex1"), listPos=listPositions, offset=-1, minCov=10, minProb=0.999, seqError=0.001, dfPedProfile=samplePED, batch=1, studyDF=studyDF, pathProfileGDS=dataDir, genoSource="snp-pileup", verbose=FALSE) -## The function returns OL when successful -result + ## The function returns OL when successful + result -## The Profile GDS file 'ex1.gds' has been created in the -## specified directory -list.files(dataDir) + ## The Profile GDS file 'ex1.gds' has been created in the + ## specified directory + list.files(dataDir) -## Unlink Profile GDS file (created for demo purpose) -unlink(file.path(dataDir, "ex1.gds")) + ## Unlink Profile GDS file (created for demo purpose) + unlink(file.path(dataDir, "ex1.gds")) + unlink(file.path(dataDir, "ex1.txt.gz")) + +} } \author{ From db706a48dd673d3e5451d81f3ed5de29ab39b6ec Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 00:51:38 -0400 Subject: [PATCH 079/385] Remove TODO to Note in the MD documents --- doc/README_1KG_GDS.md | 2 +- doc/README_StudyInit.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/README_1KG_GDS.md b/doc/README_1KG_GDS.md index 26e7deb85..0b5999f0e 100644 --- a/doc/README_1KG_GDS.md +++ b/doc/README_1KG_GDS.md @@ -79,7 +79,7 @@ In R: ## Split the VCF by sample -TODO +NOTE: Should be implemented ## Generate the base GDS file with 1KG diff --git a/doc/README_StudyInit.md b/doc/README_StudyInit.md index a9d3eb4ce..5fb7b77fd 100644 --- a/doc/README_StudyInit.md +++ b/doc/README_StudyInit.md @@ -53,7 +53,7 @@ The output from snp-pileup should be Name.ID.txt -TODO change the path to something generic +NOTE: change the path to something generic You add the genotype call from the SNP-pileup to the gds 1KG and create a GDS file for each sample. @@ -149,7 +149,7 @@ in the pruning process to the gds Sample |--+ pruned.study { Str8 237908, 2.2M } -TODO +NOTE Add genotype only for the snp selected in pruning to gdsSample library(RAIDS) From c0dcb333adff37ce6e45edd3466fb98a1eec2a4f Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 01:17:10 -0400 Subject: [PATCH 080/385] Update vignette --- vignettes/Create_Reference_GDS_File.Rmd | 76 +++++++++++++++++++++++++ vignettes/RAIDS.Rmd | 12 ++-- 2 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 vignettes/Create_Reference_GDS_File.Rmd diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd new file mode 100644 index 000000000..6544e5a10 --- /dev/null +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -0,0 +1,76 @@ +--- +title: "Population reference dataset GDS files (optional)" +author: Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +output: + BiocStyle::html_document: + number_sections: yes + toc: true + pkgdown: + number_sections: yes + as_is: true +urlcolor: darkred +linkcolor: darkred +bibliography: aicsBiblio.bibtex +vignette: > + %\VignetteIndexEntry{Population reference dataset GDS files (optional)} + %\VignettePackage{RAIDS} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r style, echo=FALSE, results='hide', warning=FALSE, message=FALSE} +BiocStyle::markdown() + +suppressPackageStartupMessages({ + library(knitr) + library(RAIDS) +}) + +set.seed(121444) +``` + +
+**Package**: `r Rpackage("RAIDS")`
+**Authors**: `r packageDescription("RAIDS")[["Author"]]`
+**Version**: `r packageDescription("RAIDS")$Version`
+**Compiled date**: `r Sys.Date()`
+**License**: `r packageDescription("RAIDS")[["License"]]`
+ + +
+
+ + + + +This section explains in further details the format of the population reference +GDS files that are needed to run the ancestry inference tool. + +- Remove related samples + + +# Pre-processed files, from 1000 Genomes in hg38, are available + +Pre-processed files used in the RAIDS associated publication, are +available at this address: + + +[https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper](https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper) + +Beware that some of those files are voluminous. + +
+
+ +# Session info + +Here is the output of `sessionInfo()` on the system on which this document was +compiled: + +```{r sessionInfo, echo=FALSE} +sessionInfo() +``` + +
+
+ diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 3056d187e..c180011b3 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -122,7 +122,8 @@ The main steps are: **Step 2.2** Infer ancestry for the subjects of the external study -These steps are described in detail in the following. +These steps are described in detail in the following. Steps 2.1 and 2.2 can be +run together using one wrapper function.

@@ -143,6 +144,10 @@ At this step three important reference files are created: - The population reference SNV Annotation GDS file - The population reference SNV Retained VCF file + +The format of those files are described the [Population reference dataset GDS files (optional)](Create_Reference_GDS_file.html) +vignette. + The reference files associated to the Cancer Research associated paper are available. Note that these pre-processed files are for 1000 Genomes (1KG), in hg38. The files are @@ -161,13 +166,10 @@ hg38 [@Lowy-Gallego2019a]. This section can be skipped if you choose to use the pre-processed files. -The execution of this step is explained in the [Formatting the information from the population reference dataset (optional)](Create_1KG_GDS_file.html) -vignette. -
-## Step 2 - Wrapper function to run ancestry inference in one command +## Step 2 - Wrapper function to run ancestry inference on DNA data in one command The final step can be run with a wrapper function that encapsulates multiple steps of the workflow. From 0fdab8b8e150ebc398120be140465658d86d696a Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 09:51:52 -0400 Subject: [PATCH 081/385] Change examples for addGDSRef() and generateGDSRefSample() to validate that the directory is in writable mode --- R/gdsWrapper_internal.R | 92 ++++++++++++++++++++----------------- man/addGDSRef.Rd | 36 ++++++++------- man/generateGDSRefSample.Rd | 56 +++++++++++----------- 3 files changed, 100 insertions(+), 84 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 239301883..8245155c5 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -31,40 +31,44 @@ #' ## Required library #' library(gdsfmt) #' -#' ## Create a temporary GDS file in an test directory -#' dataDir <- system.file("extdata/tests", package="RAIDS") -#' gdsFilePath <- file.path(dataDir, "GDS_TEMP_10.gds") +#' ## Temporary GDS file in urrent directory +#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_10.gds") #' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' ## Run only if directory in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { #' -#' ## Create "sample.annot" node (the node must be present) -#' pedInformation <- data.frame(sample.id=c("sample_01", "sample_02"), -#' Name.ID=c("sample_01", "sample_02"), -#' sex=c(1,1), # 1:Male 2: Female -#' pop.group=c("ACB", "ACB"), -#' superPop=c("AFR", "AFR"), -#' batch=c(1, 1), -#' stringsAsFactors=FALSE) +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) #' -#' ## The row names must be the sample identifiers -#' rownames(pedInformation) <- pedInformation$Name.ID +#' ## Create "sample.annot" node (the node must be present) +#' pedInformation <- data.frame(sample.id=c("sample_01", "sample_02"), +#' Name.ID=c("sample_01", "sample_02"), +#' sex=c(1,1), # 1:Male 2: Female +#' pop.group=c("ACB", "ACB"), +#' superPop=c("AFR", "AFR"), +#' batch=c(1, 1), +#' stringsAsFactors=FALSE) #' -#' ## Add information about 2 samples to the GDS file -#' RAIDS:::generateGDSRefSample(gdsReference=tmpGDS, -#' dfPedReference=pedInformation, listSamples=NULL) +#' ## The row names must be the sample identifiers +#' rownames(pedInformation) <- pedInformation$Name.ID #' -#' ## Read sample identifier list -#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) +#' ## Add information about 2 samples to the GDS file +#' RAIDS:::generateGDSRefSample(gdsReference=tmpGDS, +#' dfPedReference=pedInformation, listSamples=NULL) #' -#' ## Read sample information from GDS file -#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) +#' ## Read sample identifier list +#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Read sample information from GDS file +#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) +#' +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn @@ -123,28 +127,32 @@ generateGDSRefSample <- function(gdsReference, dfPedReference, #' dataDir <- system.file("extdata", package="RAIDS") #' rdsFilePath <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") #' -#' ## Create a temporary GDS file in an test directory -#' dataDir <- system.file("extdata/tests", package="RAIDS") -#' gdsFilePath <- file.path(dataDir, "GDS_TEMP_11.gds") #' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") +#' +#' ## Run only if directory in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +#' +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) # -#' ## Create "sample.id" node (the node must be present) -#' sampleIDs <- c("HG00104", "HG00109", "HG00110") -#' add.gdsn(node=tmpGDS, name="sample.id", val=sampleIDs) +#' ## Create "sample.id" node (the node must be present) +#' sampleIDs <- c("HG00104", "HG00109", "HG00110") +#' add.gdsn(node=tmpGDS, name="sample.id", val=sampleIDs) #' -#' ## Create "sample.ref" node in GDS file using RDS information -#' RAIDS:::addGDSRef(gdsReference=tmpGDS, filePart=rdsFilePath) +#' ## Create "sample.ref" node in GDS file using RDS information +#' RAIDS:::addGDSRef(gdsReference=tmpGDS, filePart=rdsFilePath) #' -#' ## Read sample reference data.frame -#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.ref")) +#' ## Read sample reference data.frame +#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.ref")) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn diff --git a/man/addGDSRef.Rd b/man/addGDSRef.Rd index 974070225..752a4ad3e 100644 --- a/man/addGDSRef.Rd +++ b/man/addGDSRef.Rd @@ -37,27 +37,31 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") rdsFilePath <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") -## Create a temporary GDS file in an test directory -dataDir <- system.file("extdata/tests", package="RAIDS") -gdsFilePath <- file.path(dataDir, "GDS_TEMP_11.gds") -## Create and open the GDS file -tmpGDS <- createfn.gds(filename=gdsFilePath) -## Create "sample.id" node (the node must be present) -sampleIDs <- c("HG00104", "HG00109", "HG00110") -add.gdsn(node=tmpGDS, name="sample.id", val=sampleIDs) +gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") -## Create "sample.ref" node in GDS file using RDS information -RAIDS:::addGDSRef(gdsReference=tmpGDS, filePart=rdsFilePath) +## Run only if directory in writing mode +if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -## Read sample reference data.frame -read.gdsn(index.gdsn(node=tmpGDS, path="sample.ref")) + ## Create and open the GDS file + tmpGDS <- createfn.gds(filename=gdsFilePath) + ## Create "sample.id" node (the node must be present) + sampleIDs <- c("HG00104", "HG00109", "HG00110") + add.gdsn(node=tmpGDS, name="sample.id", val=sampleIDs) -## Close GDS file -closefn.gds(gdsfile=tmpGDS) + ## Create "sample.ref" node in GDS file using RDS information + RAIDS:::addGDSRef(gdsReference=tmpGDS, filePart=rdsFilePath) -## Delete the temporary GDS file -unlink(x=gdsFilePath, force=TRUE) + ## Read sample reference data.frame + read.gdsn(index.gdsn(node=tmpGDS, path="sample.ref")) + + ## Close GDS file + closefn.gds(gdsfile=tmpGDS) + + ## Delete the temporary GDS file + unlink(x=gdsFilePath, force=TRUE) + + } } \author{ diff --git a/man/generateGDSRefSample.Rd b/man/generateGDSRefSample.Rd index a9a7d6290..0a696f1bf 100644 --- a/man/generateGDSRefSample.Rd +++ b/man/generateGDSRefSample.Rd @@ -41,40 +41,44 @@ the \code{data.frame} passed to the function. The nodes "sample.id" and ## Required library library(gdsfmt) -## Create a temporary GDS file in an test directory -dataDir <- system.file("extdata/tests", package="RAIDS") -gdsFilePath <- file.path(dataDir, "GDS_TEMP_10.gds") +## Temporary GDS file in urrent directory +gdsFilePath <- file.path(getwd(), "GDS_TEMP_10.gds") -## Create and open the GDS file -tmpGDS <- createfn.gds(filename=gdsFilePath) +## Run only if directory in writing mode +if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -## Create "sample.annot" node (the node must be present) -pedInformation <- data.frame(sample.id=c("sample_01", "sample_02"), - Name.ID=c("sample_01", "sample_02"), - sex=c(1,1), # 1:Male 2: Female - pop.group=c("ACB", "ACB"), - superPop=c("AFR", "AFR"), - batch=c(1, 1), - stringsAsFactors=FALSE) + ## Create and open the GDS file + tmpGDS <- createfn.gds(filename=gdsFilePath) -## The row names must be the sample identifiers -rownames(pedInformation) <- pedInformation$Name.ID + ## Create "sample.annot" node (the node must be present) + pedInformation <- data.frame(sample.id=c("sample_01", "sample_02"), + Name.ID=c("sample_01", "sample_02"), + sex=c(1,1), # 1:Male 2: Female + pop.group=c("ACB", "ACB"), + superPop=c("AFR", "AFR"), + batch=c(1, 1), + stringsAsFactors=FALSE) -## Add information about 2 samples to the GDS file -RAIDS:::generateGDSRefSample(gdsReference=tmpGDS, - dfPedReference=pedInformation, listSamples=NULL) + ## The row names must be the sample identifiers + rownames(pedInformation) <- pedInformation$Name.ID -## Read sample identifier list -read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) + ## Add information about 2 samples to the GDS file + RAIDS:::generateGDSRefSample(gdsReference=tmpGDS, + dfPedReference=pedInformation, listSamples=NULL) -## Read sample information from GDS file -read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) + ## Read sample identifier list + read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) -## Close GDS file -closefn.gds(gdsfile=tmpGDS) + ## Read sample information from GDS file + read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) -## Delete the temporary GDS file -unlink(x=gdsFilePath, force=TRUE) + ## Close GDS file + closefn.gds(gdsfile=tmpGDS) + + ## Delete the temporary GDS file + unlink(x=gdsFilePath, force=TRUE) + +} } \author{ From 1434071b3ae54eefa96362bb32b8fabfdd150efa Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 10:34:56 -0400 Subject: [PATCH 082/385] Update documentation for some functions; adding validation that the directory is in writable mode and that the current directory is used to create the temporary files --- R/gdsWrapper_internal.R | 55 +++++++++++++++++++++---------------- man/addGDSRef.Rd | 2 +- man/addStudyGDSSample.Rd | 2 +- man/appendGDSgenotypeMat.Rd | 46 +++++++++++++++++-------------- man/runLDPruning.Rd | 3 ++ 5 files changed, 61 insertions(+), 47 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 8245155c5..976c0a970 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -127,7 +127,7 @@ generateGDSRefSample <- function(gdsReference, dfPedReference, #' dataDir <- system.file("extdata", package="RAIDS") #' rdsFilePath <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") #' -#' +#' ## Temporary GDS file #' gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") #' #' ## Run only if directory in writing mode @@ -203,35 +203,39 @@ addGDSRef <- function(gdsReference, filePart) { #' ## Required library #' library(gdsfmt) #' -#' ## Create a temporary GDS file in an test directory -#' dataDir <- system.file("extdata/tests", package="RAIDS") -#' gdsFilePath <- file.path(dataDir, "GDS_TEMP_06.gds") +#' ## Create a temporary GDS file +#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_06.gds") #' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' ## Run only if directory in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { #' -#' ## Create a "genotype" node with initial matrix -#' genoInitial <- matrix(rep(0L, 10), nrow=2) +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) #' -#' add.gdsn(node=tmpGDS, name="genotype", val=genoInitial) -#' sync.gds(tmpGDS) +#' ## Create a "genotype" node with initial matrix +#' genoInitial <- matrix(rep(0L, 10), nrow=2) #' -#' ## New genotype information to be added -#' newGenotype <- matrix(rep(1L, 6), nrow=2) +#' add.gdsn(node=tmpGDS, name="genotype", val=genoInitial) +#' sync.gds(tmpGDS) #' -#' ## Add segments to the GDS file -#' RAIDS:::appendGDSgenotypeMat(gds=tmpGDS, matG=newGenotype) +#' ## New genotype information to be added +#' newGenotype <- matrix(rep(1L, 6), nrow=2) #' -#' ## Read genotype information from GDS file -#' ## The return matrix should be a combination of both initial matrix -#' ## and new matrix (column binded) -#' read.gdsn(index.gdsn(node=tmpGDS, path="genotype")) +#' ## Add segments to the GDS file +#' RAIDS:::appendGDSgenotypeMat(gds=tmpGDS, matG=newGenotype) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Read genotype information from GDS file +#' ## The return matrix should be a combination of both initial matrix +#' ## and new matrix (column binded) +#' read.gdsn(index.gdsn(node=tmpGDS, path="genotype")) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) +#' +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn @@ -592,7 +596,7 @@ generateGDS1KGgenotypeFromSNPPileup <- function(pathGeno, #' ## Required library #' library(gdsfmt) #' -#' ## Create a temporary GDS file in an test directory +#' ## Create a temporary GDS file in an current directory #' gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") #' #' ## Run only if directory in writing mode @@ -844,6 +848,9 @@ runIBDKING <- function(gds, profileID=NULL, snpID=NULL, maf=0.05, verbose) { #' #' @examples #' +#' ## Required +#' library(SNPRelate) +#' #' ## Open an example dataset (HapMap) #' genoFile <- snpgdsOpen(snpgdsExampleFileName()) #' @@ -1105,7 +1112,7 @@ addGDSStudyPruning <- function(gdsProfile, pruned) { #' ## Required library #' library(gdsfmt) #' -#' ## Create a temporary GDS file in an test directory +#' ## Create a temporary GDS file #' gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") #' #' ## Only run if directory is in writing mode diff --git a/man/addGDSRef.Rd b/man/addGDSRef.Rd index 752a4ad3e..e242e7b49 100644 --- a/man/addGDSRef.Rd +++ b/man/addGDSRef.Rd @@ -37,7 +37,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") rdsFilePath <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") - +## Temporary GDS file gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") ## Run only if directory in writing mode diff --git a/man/addStudyGDSSample.Rd b/man/addStudyGDSSample.Rd index 75cb73164..69a27c4ff 100644 --- a/man/addStudyGDSSample.Rd +++ b/man/addStudyGDSSample.Rd @@ -54,7 +54,7 @@ created and then, the information is added. ## Required library library(gdsfmt) -## Create a temporary GDS file in an test directory +## Create a temporary GDS file in an current directory gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") ## Run only if directory in writing mode diff --git a/man/appendGDSgenotypeMat.Rd b/man/appendGDSgenotypeMat.Rd index 6e82542fb..bb0265e6f 100644 --- a/man/appendGDSgenotypeMat.Rd +++ b/man/appendGDSgenotypeMat.Rd @@ -36,35 +36,39 @@ correspond to the number of rows of the matrix present in the ## Required library library(gdsfmt) -## Create a temporary GDS file in an test directory -dataDir <- system.file("extdata/tests", package="RAIDS") -gdsFilePath <- file.path(dataDir, "GDS_TEMP_06.gds") +## Create a temporary GDS file +gdsFilePath <- file.path(getwd(), "GDS_TEMP_06.gds") -## Create and open the GDS file -tmpGDS <- createfn.gds(filename=gdsFilePath) +## Run only if directory in writing mode +if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -## Create a "genotype" node with initial matrix -genoInitial <- matrix(rep(0L, 10), nrow=2) + ## Create and open the GDS file + tmpGDS <- createfn.gds(filename=gdsFilePath) -add.gdsn(node=tmpGDS, name="genotype", val=genoInitial) -sync.gds(tmpGDS) + ## Create a "genotype" node with initial matrix + genoInitial <- matrix(rep(0L, 10), nrow=2) -## New genotype information to be added -newGenotype <- matrix(rep(1L, 6), nrow=2) + add.gdsn(node=tmpGDS, name="genotype", val=genoInitial) + sync.gds(tmpGDS) -## Add segments to the GDS file -RAIDS:::appendGDSgenotypeMat(gds=tmpGDS, matG=newGenotype) + ## New genotype information to be added + newGenotype <- matrix(rep(1L, 6), nrow=2) -## Read genotype information from GDS file -## The return matrix should be a combination of both initial matrix -## and new matrix (column binded) -read.gdsn(index.gdsn(node=tmpGDS, path="genotype")) + ## Add segments to the GDS file + RAIDS:::appendGDSgenotypeMat(gds=tmpGDS, matG=newGenotype) -## Close GDS file -closefn.gds(gdsfile=tmpGDS) + ## Read genotype information from GDS file + ## The return matrix should be a combination of both initial matrix + ## and new matrix (column binded) + read.gdsn(index.gdsn(node=tmpGDS, path="genotype")) -## Delete the temporary GDS file -unlink(x=gdsFilePath, force=TRUE) + ## Close GDS file + closefn.gds(gdsfile=tmpGDS) + + ## Delete the temporary GDS file + unlink(x=gdsFilePath, force=TRUE) + +} } \author{ diff --git a/man/runLDPruning.Rd b/man/runLDPruning.Rd index e9c8d438c..e75f60ebd 100644 --- a/man/runLDPruning.Rd +++ b/man/runLDPruning.Rd @@ -66,6 +66,9 @@ SNPRelate package (https://bioconductor.org/packages/SNPRelate/). } \examples{ +## Required +library(SNPRelate) + ## Open an example dataset (HapMap) genoFile <- snpgdsOpen(snpgdsExampleFileName()) From 63493c7c56275321b4651565eacc45facbec4e48 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 11:22:33 -0400 Subject: [PATCH 083/385] Correct example for addUpdateSegment() function --- R/gdsWrapper.R | 46 ++++++++++++++++++++++++----------------- man/addGDS1KGLDBlock.Rd | 4 ++++ man/addUpdateLap.Rd | 2 +- man/addUpdateSegment.Rd | 38 +++++++++++++++++++--------------- 4 files changed, 53 insertions(+), 37 deletions(-) diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 3b5e00f3d..3490f9732 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -498,6 +498,10 @@ gds2tped <- function(gds, listSample, listSNP, pedOUT) { #' #' @examples #' +#' +#' ## Required library +#' library(gdsfmt) +#' #' # TODO #' gds <- "Demo GDS TODO" #' @@ -555,7 +559,7 @@ addGDS1KGLDBlock <- function(gds, listBlock, blockName, blockDesc) { #' @param gdsProfile an object of class \code{\link[gdsfmt]{gds.class}} #' (a GDS file), a GDS Sample file. #' -#' @param snp.seg a \code{vector} of \code{integer} representing the segment +#' @param snpSeg a \code{vector} of \code{integer} representing the segment #' identifiers associated to each SNV selected for the specific sample. The #' length of the \code{vector} should correspond to the number of SNVs #' present in the "snp.id" entry of the GDS sample file. @@ -567,38 +571,42 @@ addGDS1KGLDBlock <- function(gds, listBlock, blockName, blockDesc) { #' ## Required library #' library(gdsfmt) #' -#' ## Create a temporary GDS file in an test directory -#' dataDir <- system.file("extdata/tests", package="RAIDS") -#' gdsFilePath <- file.path(dataDir, "GDS_TEMP.gds") +#' ## Temporary GDS file +#' gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") #' -#' ## Create and open the GDS file -#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) +#' ## Only run if directory is in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { #' -#' ## Vector of segment identifiers -#' segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L) +#' ## Create and open the GDS file +#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) #' -#' ## Add segments to the GDS file -#' RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snp.seg=segments) +#' ## Vector of segment identifiers +#' segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L) #' -#' ## Read segments information from GDS file -#' read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) +#' ## Add segments to the GDS file +#' RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=GDS_file_tmp) +#' ## Read segments information from GDS file +#' read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Close GDS file +#' closefn.gds(gdsfile=GDS_file_tmp) +#' +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn index.gdsn delete.gdsn sync.gds ls.gdsn #' @encoding UTF-8 #' @keywords internal -addUpdateSegment <- function(gdsProfile, snp.seg) { +addUpdateSegment <- function(gdsProfile, snpSeg) { if("segment" %in% ls.gdsn(gdsProfile)) { - snpLap <- write.gdsn(index.gdsn(gdsProfile, "segment"), snp.seg) + snpLap <- write.gdsn(index.gdsn(gdsProfile, "segment"), snpSeg) } else{ - snpLap <- add.gdsn(gdsProfile, "segment", snp.seg, storage="uint32") + snpLap <- add.gdsn(gdsProfile, "segment", snpSeg, storage="uint32") } sync.gds(gdsProfile) diff --git a/man/addGDS1KGLDBlock.Rd b/man/addGDS1KGLDBlock.Rd index 0b6b90ef8..bf069ba42 100644 --- a/man/addGDS1KGLDBlock.Rd +++ b/man/addGDS1KGLDBlock.Rd @@ -24,6 +24,10 @@ TODO } \examples{ + +## Required library +library(gdsfmt) + # TODO gds <- "Demo GDS TODO" diff --git a/man/addUpdateLap.Rd b/man/addUpdateLap.Rd index c487c8027..470818371 100644 --- a/man/addUpdateLap.Rd +++ b/man/addUpdateLap.Rd @@ -33,7 +33,7 @@ already be present in the GDS file. ## Required library library(gdsfmt) -## Create a temporary GDS file in an test directory +## Create a temporary GDS file gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") ## Only run if directory is in writing mode diff --git a/man/addUpdateSegment.Rd b/man/addUpdateSegment.Rd index 718c0249d..0069d4377 100644 --- a/man/addUpdateSegment.Rd +++ b/man/addUpdateSegment.Rd @@ -6,13 +6,13 @@ \title{Add information related to segments associated to the SNV dataset for a specific sample into a GDS file} \usage{ -addUpdateSegment(gdsProfile, snp.seg) +addUpdateSegment(gdsProfile, snpSeg) } \arguments{ \item{gdsProfile}{an object of class \code{\link[gdsfmt]{gds.class}} (a GDS file), a GDS Sample file.} -\item{snp.seg}{a \code{vector} of \code{integer} representing the segment +\item{snpSeg}{a \code{vector} of \code{integer} representing the segment identifiers associated to each SNV selected for the specific sample. The length of the \code{vector} should correspond to the number of SNVs present in the "snp.id" entry of the GDS sample file.} @@ -31,27 +31,31 @@ already exists, the previous information is erased. ## Required library library(gdsfmt) -## Create a temporary GDS file in an test directory -dataDir <- system.file("extdata/tests", package="RAIDS") -gdsFilePath <- file.path(dataDir, "GDS_TEMP.gds") +## Temporary GDS file +gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") -## Create and open the GDS file -GDS_file_tmp <- createfn.gds(filename=gdsFilePath) +## Only run if directory is in writing mode +if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -## Vector of segment identifiers -segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L) + ## Create and open the GDS file + GDS_file_tmp <- createfn.gds(filename=gdsFilePath) -## Add segments to the GDS file -RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snp.seg=segments) + ## Vector of segment identifiers + segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L) -## Read segments information from GDS file -read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) + ## Add segments to the GDS file + RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) -## Close GDS file -closefn.gds(gdsfile=GDS_file_tmp) + ## Read segments information from GDS file + read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) -## Delete the temporary GDS file -unlink(x=gdsFilePath, force=TRUE) + ## Close GDS file + closefn.gds(gdsfile=GDS_file_tmp) + + ## Delete the temporary GDS file + unlink(x=gdsFilePath, force=TRUE) + +} } \author{ From 77b97373d54afe484e847496eb6d2ab6bd1bdc37 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 14:18:01 -0400 Subject: [PATCH 084/385] Correct tests for addUpdateSegment() function --- tests/testthat/test-gdsWrapper.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-gdsWrapper.R b/tests/testthat/test-gdsWrapper.R index 358fc69ec..20baa4b86 100644 --- a/tests/testthat/test-gdsWrapper.R +++ b/tests/testthat/test-gdsWrapper.R @@ -43,7 +43,7 @@ test_that("addUpdateSegment() must copy the expected entry in \"segment\" node o segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L) ## Add segments to the GDS file - RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snp.seg=segments) + RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) ## Read segments information from GDS file results <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) @@ -71,10 +71,10 @@ test_that("addUpdateSegment() must copy the expected entry in \"segment\" node o segments2 <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L, 5L, 5L, 5L, 5L) ## Add segments to the GDS file - RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snp.seg=segments) + RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) ## Update segments to the GDS file - RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snp.seg=segments2) + RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments2) ## Read segments information from GDS file results <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) From b28ef748ff50813fc7a4952c5f8522a833e77209 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 17:01:05 -0400 Subject: [PATCH 085/385] Update vignette --- vignettes/Create_Reference_GDS_File.Rmd | 59 +++++++++++++++++++++++-- vignettes/RAIDS.Rmd | 2 +- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 6544e5a10..9cfed8f5c 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -1,5 +1,5 @@ --- -title: "Population reference dataset GDS files (optional)" +title: "Population reference dataset GDS files" author: Pascal Belleau, Astrid Deschênes and Alexander Krasnitz output: BiocStyle::html_document: @@ -12,7 +12,7 @@ urlcolor: darkred linkcolor: darkred bibliography: aicsBiblio.bibtex vignette: > - %\VignetteIndexEntry{Population reference dataset GDS files (optional)} + %\VignetteIndexEntry{Population reference dataset GDS files} %\VignettePackage{RAIDS} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} @@ -24,6 +24,8 @@ BiocStyle::markdown() suppressPackageStartupMessages({ library(knitr) library(RAIDS) + library(SNPRelate) + library(gdsfmt) }) set.seed(121444) @@ -46,7 +48,58 @@ set.seed(121444) This section explains in further details the format of the population reference GDS files that are needed to run the ancestry inference tool. -- Remove related samples +Three different files are generated from the reference dataset: + +- The population reference GDS File +- The population reference SNV Annotation GDS file +- The population reference SNV Retained VCF file + + +# Population Reference GDS File + + +All related samples must be removed. + +```{r runRefGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +############################################################################# +## Load required packages +############################################################################# +library(RAIDS) +library(SNPRelate) + +pathReference <- system.file("extdata/example/", package="RAIDS") + +fileReferenceGDS <- file.path(pathReference, "gdsRef", "ex1kg.gds") + +gdsRef <- snpgdsOpen(fileReferenceGDS) + +## Show the file format +print(gdsRef) + +closefn.gds(gdsRef) +``` + +# Population Reference Annotation GDS file + + +```{r runRefAnnotGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +############################################################################# +## Load required packages +############################################################################# +library(RAIDS) +library(SNPRelate) + +pathReference <- system.file("extdata/example/", package="RAIDS") + +fileReferenceAnnotGDS <- file.path(pathReference, "gdsRef", "exAnnot1kg.gds") + +gdsRefAnnot <- openfn.gds(fileReferenceAnnotGDS) + +## Show the file format +print(gdsRefAnnot) + +closefn.gds(gdsRefAnnot) +``` # Pre-processed files, from 1000 Genomes in hg38, are available diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index c180011b3..5cf9365d4 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -145,7 +145,7 @@ At this step three important reference files are created: - The population reference SNV Retained VCF file -The format of those files are described the [Population reference dataset GDS files (optional)](Create_Reference_GDS_file.html) +The format of those files are described the [Population reference dataset GDS files](Create_Reference_GDS_file.html) vignette. The reference files associated to From a8082b3506a44fb2fe200f83e73584d2784cf5ae Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 17:01:05 -0400 Subject: [PATCH 086/385] Update vignettes --- vignettes/Create_Reference_GDS_File.Rmd | 59 +++++++++++++++++++++++-- vignettes/RAIDS.Rmd | 2 +- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 6544e5a10..9cfed8f5c 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -1,5 +1,5 @@ --- -title: "Population reference dataset GDS files (optional)" +title: "Population reference dataset GDS files" author: Pascal Belleau, Astrid Deschênes and Alexander Krasnitz output: BiocStyle::html_document: @@ -12,7 +12,7 @@ urlcolor: darkred linkcolor: darkred bibliography: aicsBiblio.bibtex vignette: > - %\VignetteIndexEntry{Population reference dataset GDS files (optional)} + %\VignetteIndexEntry{Population reference dataset GDS files} %\VignettePackage{RAIDS} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} @@ -24,6 +24,8 @@ BiocStyle::markdown() suppressPackageStartupMessages({ library(knitr) library(RAIDS) + library(SNPRelate) + library(gdsfmt) }) set.seed(121444) @@ -46,7 +48,58 @@ set.seed(121444) This section explains in further details the format of the population reference GDS files that are needed to run the ancestry inference tool. -- Remove related samples +Three different files are generated from the reference dataset: + +- The population reference GDS File +- The population reference SNV Annotation GDS file +- The population reference SNV Retained VCF file + + +# Population Reference GDS File + + +All related samples must be removed. + +```{r runRefGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +############################################################################# +## Load required packages +############################################################################# +library(RAIDS) +library(SNPRelate) + +pathReference <- system.file("extdata/example/", package="RAIDS") + +fileReferenceGDS <- file.path(pathReference, "gdsRef", "ex1kg.gds") + +gdsRef <- snpgdsOpen(fileReferenceGDS) + +## Show the file format +print(gdsRef) + +closefn.gds(gdsRef) +``` + +# Population Reference Annotation GDS file + + +```{r runRefAnnotGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +############################################################################# +## Load required packages +############################################################################# +library(RAIDS) +library(SNPRelate) + +pathReference <- system.file("extdata/example/", package="RAIDS") + +fileReferenceAnnotGDS <- file.path(pathReference, "gdsRef", "exAnnot1kg.gds") + +gdsRefAnnot <- openfn.gds(fileReferenceAnnotGDS) + +## Show the file format +print(gdsRefAnnot) + +closefn.gds(gdsRefAnnot) +``` # Pre-processed files, from 1000 Genomes in hg38, are available diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index c180011b3..5cf9365d4 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -145,7 +145,7 @@ At this step three important reference files are created: - The population reference SNV Retained VCF file -The format of those files are described the [Population reference dataset GDS files (optional)](Create_Reference_GDS_file.html) +The format of those files are described the [Population reference dataset GDS files](Create_Reference_GDS_file.html) vignette. The reference files associated to From 4cf4bc51ecaf9d2dbbd9ba8411c245412904fa92 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 18:07:44 -0400 Subject: [PATCH 087/385] Add unit tests and modify examples for some functions --- R/gdsWrapper.R | 209 +++++++--------------- R/gdsWrapper_internal.R | 134 +++++++++++++- man/addGDS1KGLDBlock.Rd | 56 +++++- man/addUpdateSegment.Rd | 2 +- man/appendGDSSampleOnly.Rd | 46 ++--- man/generateGDSRefSample.Rd | 2 +- man/generateGDSSNPinfo.Rd | 8 +- man/generateGDSgenotype.Rd | 3 +- tests/testthat/test-gdsWrapper.R | 157 ++++++---------- tests/testthat/test-gdsWrapper_internal.R | 106 +++++++++++ 10 files changed, 441 insertions(+), 282 deletions(-) diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 3490f9732..233c06db0 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -1,61 +1,3 @@ -#' @title Append sample names into a GDS file -#' -#' @description This function append the sample identifiers into the -#' "samples.id" node of a GDS file. -#' -#' @param gds an object of class -#' \link[gdsfmt]{gds.class} (a GDS file), the opened GDS file. -#' -#' @param listSample a \code{vector} of \code{character} string representing -#' the sample identifiers to be added to GDS file. -#' -#' -#' @return The integer \code{0L} when successful. -#' -#' @examples -#' -#' ## Create a temporary GDS file in an test directory -#' dataDir <- system.file("extdata/tests", package="RAIDS") -#' gdsFilePath <- file.path(dataDir, "GDS_TEMP_04.gds") -#' -#' ## Create and open the GDS file -#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) -#' -#' ## Create "sample.id" node (the node must be present) -#' add.gdsn(node=GDS_file_tmp, name="sample.id", val=c("sample_01", -#' "sample_02")) -#' -#' sync.gds(gdsfile=GDS_file_tmp) -#' -#' ## Add information about 2 samples to the GDS file -#' RAIDS:::appendGDSSampleOnly(gds=GDS_file_tmp, -#' listSamples=c("sample_03", "sample_04")) -#' -#' ## Read sample identifier list -#' ## Only "sample_03" and "sample_04" should have been added -#' read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.id")) -#' -#' ## Close GDS file -#' closefn.gds(gdsfile=GDS_file_tmp) -#' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) -#' -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt index.gdsn append.gdsn -#' @encoding UTF-8 -#' @keywords internal -appendGDSSampleOnly <- function(gds, listSamples) { - - sampleGDS <- index.gdsn(gds, "sample.id") - - append.gdsn(sampleGDS, val=listSamples, check=TRUE) - - return(0L) -} - - #' @title Add information related to SNVs into a Reference GDS file #' #' @description the function adds the SNV information into a Reference @@ -64,7 +6,7 @@ appendGDSSampleOnly <- function(gds, listSamples) { #' @param gdsReference an object of class #' \link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file. #' -#' @param fileFREQ a \code{character} string representing the path and file +#' @param fileFreq a \code{character} string representing the path and file #' name of the RDS file with the filtered SNP information. #' #' @param verbose a \code{logical} indicating if messages should be printed @@ -94,7 +36,7 @@ appendGDSSampleOnly <- function(gds, listSamples) { #' #' ## Add SNV information to Reference GDS #' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, -#' fileFREQ=fileFilerterSNVs, verbose=TRUE) +#' fileFreq=fileFilerterSNVs, verbose=TRUE) #' #' ## Close GDS file (important) #' closefn.gds(filenewGDS) @@ -110,7 +52,7 @@ appendGDSSampleOnly <- function(gds, listSamples) { #' #' ## Add SNV information to Reference GDS #' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, -#' fileFREQ=fileFilerterSNVs, verbose=TRUE) +#' fileFreq=fileFilerterSNVs, verbose=TRUE) #' #' ## Close GDS file (important) #' closefn.gds(filenewGDS) @@ -125,9 +67,9 @@ appendGDSSampleOnly <- function(gds, listSamples) { #' @importFrom gdsfmt add.gdsn #' @encoding UTF-8 #' @keywords internal -generateGDSSNPinfo <- function(gdsReference, fileFREQ, verbose) { +generateGDSSNPinfo <- function(gdsReference, fileFreq, verbose) { - mapSNVSel <- readRDS(file=fileFREQ) + mapSNVSel <- readRDS(file=fileFreq) if(verbose) { message("Read mapSNVSel DONE ", Sys.time()) } @@ -172,7 +114,8 @@ generateGDSSNPinfo <- function(gdsReference, fileFREQ, verbose) { } -#' @title Add information related to profile genotype into a Reference GDS file +#' @title Add information related to profile genotypes into a Reference +#' GDS file #' #' @description This function adds the genotype fields with the associated #' information into the Reference GDS file for the selected profiles. @@ -482,17 +425,27 @@ gds2tped <- function(gds, listSample, listSNP, pedOUT) { } -#' @title TODO +#' @title Add block information in a Population Reference GDS Annotation file #' -#' @description TODO +#' @description This function appends the information for one specific type +#' of blocks into a Population Reference GDS Annotation file. More +#' specifically, the node 'block.annot' is created if it does not exists. This +#' node contains a \code{data.frame} which will be append the description of +#' the current block. The node 'block' is also created if it does not exists. +#' This node is a \code{matrix} that will contain all the entries for the +#' current block. All the values for a specific block type are contained in a +#' single column that corresponds to the row number in the 'block.annot' node. #' #' @param gds an object of class \code{gds} opened in writing mode. #' -#' @param listBlock TODO +#' @param listBlock a \code{array} of \code{integer} representing all the +#' entries for the current block. #' -#' @param blockName TODO +#' @param blockName a \code{character} string representing the unique +#' block name. #' -#' @param blockDesc TODO +#' @param blockDesc a \code{character} string representing the description of +#' the current block. #' #' @return The integer \code{0L} when successful. #' @@ -502,8 +455,40 @@ gds2tped <- function(gds, listSample, listSNP, pedOUT) { #' ## Required library #' library(gdsfmt) #' -#' # TODO -#' gds <- "Demo GDS TODO" +#' ## Temporary GDS Annotation file in current directory +#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_Annot_14.gds") +#' +#' ## Run only if directory in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +#' +#' ## Create and open the GDS file +#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) +#' +#' ## One block +#' blockType <- "EAS.0.05.500k" +#' +#' ## The description of the block +#' blockDescription <- "EAS population blocks based on 500k windows" +#' +#' ## The values for each entry related to the block (integers) +#' blockEntries <- c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3) +#' +#' RAIDS:::addGDS1KGLDBlock(gds=GDS_file_tmp, listBlock=blockEntries, +#' blockName=blockType, blockDesc=blockDescription) +#' +#' ## Read 'block.annot' node +#' read.gdsn(index.gdsn(GDS_file_tmp, "block.annot")) +#' +#' ## Read 'block' node +#' read.gdsn(index.gdsn(GDS_file_tmp, "block")) +#' +#' ## Close GDS file +#' closefn.gds(gdsfile=GDS_file_tmp) +#' +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn index.gdsn ls.gdsn compression.gdsn @@ -517,28 +502,33 @@ addGDS1KGLDBlock <- function(gds, listBlock, blockName, blockDesc) { stringsAsFactors=FALSE) if(! ("block.annot" %in% ls.gdsn(gds))) { + ## Create 'block.annot' node when not existing var.block.annot <- add.gdsn(gds, "block.annot", block.annot) }else { + ## Append content to 'block.annot' node when existing curAnnot <- index.gdsn(gds, "block.annot/block.id") - append.gdsn(curAnnot,block.annot$block.id) + append.gdsn(curAnnot, block.annot$block.id) curAnnot <- index.gdsn(gds, "block.annot/block.desc") append.gdsn(curAnnot, block.annot$block.desc) } var.block <- NULL - if(! ("block" %in% ls.gdsn(gds))){ - var.block <- add.gdsn(gds, "block", + if(!("block" %in% ls.gdsn(gds))) { + ## Create 'block' node that will contain a matrix of integers + ## stored in compressed mode + var.block <- add.gdsn(node=gds, name="block", valdim=c(length(listBlock), 1), listBlock, storage="int32", - compress = "LZ4_RA") + compress="LZ4_RA") readmode.gdsn(var.block) - }else { + } else { if(is.null(var.block)) { var.block <- index.gdsn(gds, "block") var.block <- compression.gdsn(var.block, "") } append.gdsn(var.block, listBlock) + ## Compressed data using LZ4_RA method var.block <- compression.gdsn(var.block, "LZ4_RA") } @@ -548,72 +538,5 @@ addGDS1KGLDBlock <- function(gds, listBlock, blockName, blockDesc) { } -#' @title Add information related to segments associated to the SNV -#' dataset for a specific sample into a GDS file -#' -#' @description The function adds the information related to segments -#' associated to the SNV dataset for a specific sample into a -#' GDS file, more specifically, in the "segment" node. If the "segment" node -#' already exists, the previous information is erased. -#' -#' @param gdsProfile an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), a GDS Sample file. -#' -#' @param snpSeg a \code{vector} of \code{integer} representing the segment -#' identifiers associated to each SNV selected for the specific sample. The -#' length of the \code{vector} should correspond to the number of SNVs -#' present in the "snp.id" entry of the GDS sample file. -#' -#' @return The integer \code{0L} when successful. -#' -#' @examples -#' -#' ## Required library -#' library(gdsfmt) -#' -#' ## Temporary GDS file -#' gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") -#' -#' ## Only run if directory is in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -#' -#' ## Create and open the GDS file -#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) -#' -#' ## Vector of segment identifiers -#' segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L) -#' -#' ## Add segments to the GDS file -#' RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) -#' -#' ## Read segments information from GDS file -#' read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) -#' -#' ## Close GDS file -#' closefn.gds(gdsfile=GDS_file_tmp) -#' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) -#' -#' } -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt add.gdsn index.gdsn delete.gdsn sync.gds ls.gdsn -#' @encoding UTF-8 -#' @keywords internal -addUpdateSegment <- function(gdsProfile, snpSeg) { - - if("segment" %in% ls.gdsn(gdsProfile)) { - snpLap <- write.gdsn(index.gdsn(gdsProfile, "segment"), snpSeg) - } else{ - snpLap <- add.gdsn(gdsProfile, "segment", snpSeg, storage="uint32") - } - - sync.gds(gdsProfile) - - ## Successful - return(0L) -} - diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 976c0a970..b51b8eda5 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -31,7 +31,7 @@ #' ## Required library #' library(gdsfmt) #' -#' ## Temporary GDS file in urrent directory +#' ## Temporary GDS file in current directory #' gdsFilePath <- file.path(getwd(), "GDS_TEMP_10.gds") #' #' ## Run only if directory in writing mode @@ -1219,3 +1219,135 @@ getBlockIDs <- function(gdsRefAnnot, snpIndex, blockTypeID) { return(b) } + + +#' @title Add information related to segments associated to the SNV +#' dataset for a specific sample into a GDS file +#' +#' @description The function adds the information related to segments +#' associated to the SNV dataset for a specific sample into a +#' GDS file, more specifically, in the "segment" node. If the "segment" node +#' already exists, the previous information is erased. +#' +#' @param gdsProfile an object of class \code{\link[gdsfmt]{gds.class}} +#' (a GDS file), a GDS Sample file. +#' +#' @param snpSeg a \code{vector} of \code{integer} representing the segment +#' identifiers associated to each SNV selected for the specific sample. The +#' length of the \code{vector} should correspond to the number of SNVs +#' present in the "snp.id" entry of the GDS sample file. +#' +#' @return The integer \code{0L} when successful. +#' +#' @examples +#' +#' ## Required library +#' library(gdsfmt) +#' +#' ## Temporary GDS file +#' gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") +#' +#' ## Only run if directory is in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +#' +#' ## Create and open the GDS file +#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) +#' +#' ## Vector of segment identifiers +#' segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L) +#' +#' ## Add segments to the GDS file +#' RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) +#' +#' ## Read segments information from GDS file +#' read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) +#' +#' ## Close GDS file +#' closefn.gds(gdsfile=GDS_file_tmp) +#' +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) +#' +#' } +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt add.gdsn index.gdsn delete.gdsn sync.gds ls.gdsn +#' @encoding UTF-8 +#' @keywords internal +addUpdateSegment <- function(gdsProfile, snpSeg) { + + if("segment" %in% ls.gdsn(gdsProfile)) { + snpLap <- write.gdsn(index.gdsn(gdsProfile, "segment"), snpSeg) + } else{ + snpLap <- add.gdsn(gdsProfile, "segment", snpSeg, storage="uint32") + } + + sync.gds(gdsProfile) + + ## Successful + return(0L) +} + + +#' @title Append sample names into a GDS file +#' +#' @description This function append the sample identifiers into the +#' "samples.id" node of a GDS file. +#' +#' @param gds an object of class +#' \link[gdsfmt]{gds.class} (a GDS file), the opened GDS file. +#' +#' @param listSample a \code{vector} of \code{character} string representing +#' the sample identifiers to be added to GDS file. +#' +#' +#' @return The integer \code{0L} when successful. +#' +#' @examples +#' +#' ## Required library +#' library(gdsfmt) +#' +#' ## Temporary GDS file in current directory +#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_04.gds") +#' +#' ## Run only if directory in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +#' +#' ## Create and open the GDS file +#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) +#' +#' ## Create "sample.id" node (the node must be present) +#' add.gdsn(node=GDS_file_tmp, name="sample.id", val=c("sample_01", +#' "sample_02")) +#' +#' sync.gds(gdsfile=GDS_file_tmp) +#' +#' ## Add information about 2 samples to the GDS file +#' RAIDS:::appendGDSSampleOnly(gds=GDS_file_tmp, +#' listSamples=c("sample_03", "sample_04")) +#' +#' ## Read sample identifier list +#' ## Only "sample_03" and "sample_04" should have been added +#' read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.id")) +#' +#' ## Close GDS file +#' closefn.gds(gdsfile=GDS_file_tmp) +#' +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) +#' +#' } +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt index.gdsn append.gdsn +#' @encoding UTF-8 +#' @keywords internal +appendGDSSampleOnly <- function(gds, listSamples) { + + sampleGDS <- index.gdsn(gds, "sample.id") + + append.gdsn(sampleGDS, val=listSamples, check=TRUE) + + return(0L) +} diff --git a/man/addGDS1KGLDBlock.Rd b/man/addGDS1KGLDBlock.Rd index bf069ba42..adb3f0bab 100644 --- a/man/addGDS1KGLDBlock.Rd +++ b/man/addGDS1KGLDBlock.Rd @@ -3,24 +3,34 @@ \encoding{UTF-8} \name{addGDS1KGLDBlock} \alias{addGDS1KGLDBlock} -\title{TODO} +\title{Add block information in a Population Reference GDS Annotation file} \usage{ addGDS1KGLDBlock(gds, listBlock, blockName, blockDesc) } \arguments{ \item{gds}{an object of class \code{gds} opened in writing mode.} -\item{listBlock}{TODO} +\item{listBlock}{a \code{array} of \code{integer} representing all the +entries for the current block.} -\item{blockName}{TODO} +\item{blockName}{a \code{character} string representing the unique +block name.} -\item{blockDesc}{TODO} +\item{blockDesc}{a \code{character} string representing the description of +the current block.} } \value{ The integer \code{0L} when successful. } \description{ -TODO +This function appends the information for one specific type +of blocks into a Population Reference GDS Annotation file. More +specifically, the node 'block.annot' is created if it does not exists. This +node contains a \code{data.frame} which will be append the description of +the current block. The node 'block' is also created if it does not exists. +This node is a \code{matrix} that will contain all the entries for the +current block. All the values for a specific block type are contained in a +single column that corresponds to the row number in the 'block.annot' node. } \examples{ @@ -28,8 +38,40 @@ TODO ## Required library library(gdsfmt) -# TODO -gds <- "Demo GDS TODO" +## Temporary GDS Annotation file in current directory +gdsFilePath <- file.path(getwd(), "GDS_TEMP_Annot_14.gds") + +## Run only if directory in writing mode +if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { + + ## Create and open the GDS file + GDS_file_tmp <- createfn.gds(filename=gdsFilePath) + + ## One block + blockType <- "EAS.0.05.500k" + + ## The description of the block + blockDescription <- "EAS population blocks based on 500k windows" + + ## The values for each entry related to the block (integers) + blockEntries <- c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3) + + RAIDS:::addGDS1KGLDBlock(gds=GDS_file_tmp, listBlock=blockEntries, + blockName=blockType, blockDesc=blockDescription) + + ## Read 'block.annot' node + read.gdsn(index.gdsn(GDS_file_tmp, "block.annot")) + + ## Read 'block' node + read.gdsn(index.gdsn(GDS_file_tmp, "block")) + + ## Close GDS file + closefn.gds(gdsfile=GDS_file_tmp) + + ## Delete the temporary GDS file + unlink(x=gdsFilePath, force=TRUE) + +} } \author{ diff --git a/man/addUpdateSegment.Rd b/man/addUpdateSegment.Rd index 0069d4377..35df8d3ed 100644 --- a/man/addUpdateSegment.Rd +++ b/man/addUpdateSegment.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gdsWrapper.R +% Please edit documentation in R/gdsWrapper_internal.R \encoding{UTF-8} \name{addUpdateSegment} \alias{addUpdateSegment} diff --git a/man/appendGDSSampleOnly.Rd b/man/appendGDSSampleOnly.Rd index 0df21ce48..6b2c0cdf2 100644 --- a/man/appendGDSSampleOnly.Rd +++ b/man/appendGDSSampleOnly.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gdsWrapper.R +% Please edit documentation in R/gdsWrapper_internal.R \encoding{UTF-8} \name{appendGDSSampleOnly} \alias{appendGDSSampleOnly} @@ -23,33 +23,39 @@ This function append the sample identifiers into the } \examples{ -## Create a temporary GDS file in an test directory -dataDir <- system.file("extdata/tests", package="RAIDS") -gdsFilePath <- file.path(dataDir, "GDS_TEMP_04.gds") +## Required library +library(gdsfmt) -## Create and open the GDS file -GDS_file_tmp <- createfn.gds(filename=gdsFilePath) +## Temporary GDS file in current directory +gdsFilePath <- file.path(getwd(), "GDS_TEMP_04.gds") -## Create "sample.id" node (the node must be present) -add.gdsn(node=GDS_file_tmp, name="sample.id", val=c("sample_01", - "sample_02")) +## Run only if directory in writing mode +if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -sync.gds(gdsfile=GDS_file_tmp) + ## Create and open the GDS file + GDS_file_tmp <- createfn.gds(filename=gdsFilePath) -## Add information about 2 samples to the GDS file -RAIDS:::appendGDSSampleOnly(gds=GDS_file_tmp, - listSamples=c("sample_03", "sample_04")) + ## Create "sample.id" node (the node must be present) + add.gdsn(node=GDS_file_tmp, name="sample.id", val=c("sample_01", + "sample_02")) -## Read sample identifier list -## Only "sample_03" and "sample_04" should have been added -read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.id")) + sync.gds(gdsfile=GDS_file_tmp) -## Close GDS file -closefn.gds(gdsfile=GDS_file_tmp) + ## Add information about 2 samples to the GDS file + RAIDS:::appendGDSSampleOnly(gds=GDS_file_tmp, + listSamples=c("sample_03", "sample_04")) -## Delete the temporary GDS file -unlink(x=gdsFilePath, force=TRUE) + ## Read sample identifier list + ## Only "sample_03" and "sample_04" should have been added + read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.id")) + ## Close GDS file + closefn.gds(gdsfile=GDS_file_tmp) + + ## Delete the temporary GDS file + unlink(x=gdsFilePath, force=TRUE) + +} } \author{ diff --git a/man/generateGDSRefSample.Rd b/man/generateGDSRefSample.Rd index 0a696f1bf..1560c3737 100644 --- a/man/generateGDSRefSample.Rd +++ b/man/generateGDSRefSample.Rd @@ -41,7 +41,7 @@ the \code{data.frame} passed to the function. The nodes "sample.id" and ## Required library library(gdsfmt) -## Temporary GDS file in urrent directory +## Temporary GDS file in current directory gdsFilePath <- file.path(getwd(), "GDS_TEMP_10.gds") ## Run only if directory in writing mode diff --git a/man/generateGDSSNPinfo.Rd b/man/generateGDSSNPinfo.Rd index c8f2e30f9..e41fad72f 100644 --- a/man/generateGDSSNPinfo.Rd +++ b/man/generateGDSSNPinfo.Rd @@ -5,13 +5,13 @@ \alias{generateGDSSNPinfo} \title{Add information related to SNVs into a Reference GDS file} \usage{ -generateGDSSNPinfo(gdsReference, fileFREQ, verbose) +generateGDSSNPinfo(gdsReference, fileFreq, verbose) } \arguments{ \item{gdsReference}{an object of class \link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file.} -\item{fileFREQ}{a \code{character} string representing the path and file +\item{fileFreq}{a \code{character} string representing the path and file name of the RDS file with the filtered SNP information.} \item{verbose}{a \code{logical} indicating if messages should be printed @@ -46,7 +46,7 @@ if (file.access(getwd()) == 0) { ## Add SNV information to Reference GDS RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, - fileFREQ=fileFilerterSNVs, verbose=TRUE) + fileFreq=fileFilerterSNVs, verbose=TRUE) ## Close GDS file (important) closefn.gds(filenewGDS) @@ -62,7 +62,7 @@ if (file.access(getwd()) == 0) { ## Add SNV information to Reference GDS RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, - fileFREQ=fileFilerterSNVs, verbose=TRUE) + fileFreq=fileFilerterSNVs, verbose=TRUE) ## Close GDS file (important) closefn.gds(filenewGDS) diff --git a/man/generateGDSgenotype.Rd b/man/generateGDSgenotype.Rd index 10d8006e1..950fe7336 100644 --- a/man/generateGDSgenotype.Rd +++ b/man/generateGDSgenotype.Rd @@ -3,7 +3,8 @@ \encoding{UTF-8} \name{generateGDSgenotype} \alias{generateGDSgenotype} -\title{Add information related to profile genotype into a Reference GDS file} +\title{Add information related to profile genotypes into a Reference +GDS file} \usage{ generateGDSgenotype(gds, pathGeno, fileSNPsRDS, listSamples, verbose) } diff --git a/tests/testthat/test-gdsWrapper.R b/tests/testthat/test-gdsWrapper.R index 20baa4b86..f3b120968 100644 --- a/tests/testthat/test-gdsWrapper.R +++ b/tests/testthat/test-gdsWrapper.R @@ -23,110 +23,6 @@ local_GDS_file <- function(path) { } -############################################################################# -### Tests addUpdateSegment() results -############################################################################# - -context("addUpdateSegment() results") - - -test_that("addUpdateSegment() must copy the expected entry in \"segment\" node of the GDS file", { - - ## Create a temporary GDS file in an test directory - dataDir <- system.file("extdata/tests", package="RAIDS") - fileGDS <- file.path(dataDir, "GDS_TEMP_01.gds") - - ## Create and open a temporary GDS file - GDS_file_tmp <- local_GDS_file(fileGDS) - - ## Vector of segment identifiers - segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L) - - ## Add segments to the GDS file - RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) - - ## Read segments information from GDS file - results <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) - - ## Close GDS file - ## The file will automatically be deleted - closefn.gds(gdsfile=GDS_file_tmp) - - expect_equal(results, segments) -}) - - -test_that("addUpdateSegment() must copy the expected entry in \"segment\" node of the GDS file", { - - ## Create a temporary GDS file in an test directory - dataDir <- system.file("extdata/tests", package="RAIDS") - fileGDS <- file.path(dataDir, "GDS_TEMP_02.gds") - - ## Create and open a temporary GDS file - GDS_file_tmp <- local_GDS_file(fileGDS) - - ## Vector of segment identifiers - segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L) - ## Vector of segment identifiers - segments2 <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L, 5L, 5L, 5L, 5L) - - ## Add segments to the GDS file - RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) - - ## Update segments to the GDS file - RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments2) - - ## Read segments information from GDS file - results <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) - - ## Close GDS file - ## The file will automatically be deleted - closefn.gds(gdsfile=GDS_file_tmp) - - expect_equal(results, segments2) -}) - - -############################################################################# -### Tests appendGDSSampleOnly() results -############################################################################# - -context("appendGDSSampleOnly() results") - - -test_that("appendGDSSampleOnly() must copy the expected entry in \"sample.id\" node of the GDS file", { - - ## Create a temporary GDS file in an test directory - dataDir <- system.file("extdata/tests", package="RAIDS") - fileGDS <- file.path(dataDir, "GDS_TEMP_04.gds") - - ## Create and open a temporary GDS file - GDS_file_tmp <- local_GDS_file(fileGDS) - - ## Create sample.id field - add.gdsn(node=GDS_file_tmp, name="sample.id", val=c("sample_01", - "sample_02")) - sync.gds(gdsfile=GDS_file_tmp) - - ## Vector of SNV names - samples <- c('sample_05', 'sample_08', 'sample_11') - - ## Add name of samples to the GDS file - RAIDS:::appendGDSSampleOnly(gds=GDS_file_tmp, listSamples=samples) - - ## Read segments information from GDS file - results <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.id")) - - ## Close GDS file - ## The file will automatically be deleted - closefn.gds(gdsfile=GDS_file_tmp) - - expected <- c("sample_01", "sample_02", samples) - - expect_equal(results, expected) -}) - - ############################################################################# ### Tests appendGDSgenotypeMat() results ############################################################################# @@ -264,3 +160,56 @@ test_that("addGDSRef() must return expected result", { }) +############################################################################# +### Tests addGDS1KGLDBlock() results +############################################################################# + +context("addGDS1KGLDBlock() results") + + +test_that("addGDS1KGLDBlock() must return expected result", { + + ## Create and open a temporary GDS Annotation file + GDS_path <- test_path("fixtures", "GDS_addGDS1KGLDBlock_Temp_01.gds") + GDS_file_tmp <- createfn.gds(filename=GDS_path) + defer(unlink(x=GDS_path, force=TRUE), envir=parent.frame()) + + blockType <- "EAS.0.05.500k" + blockDescription <- "EAS population blocks based on 500k windows" + + entries <- c(1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5) + + ## Add block to the GDS file + results1 <- RAIDS:::addGDS1KGLDBlock(gds=GDS_file_tmp, listBlock=entries, + blockName=blockType, blockDesc=blockDescription) + + + blockType2 <- "AFR.0.05.500k" + blockDescription2 <- "AFR population blocks based on 500k windows" + + entries2 <- c(1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5) + + ## Add block to the GDS file + results2 <- RAIDS:::addGDS1KGLDBlock(gds=GDS_file_tmp, listBlock=entries2, + blockName=blockType2, blockDesc=blockDescription2) + + + ## Read block.annot from GDS file + results3 <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="block.annot")) + + ## Read block.annot from GDS file + results4 <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="block")) + + ## Close GDS file + ## The file will automatically be deleted + closefn.gds(gdsfile=GDS_file_tmp) + + expect_equal(results1, 0L) + expect_equal(results2, 0L) + expect_equal(results3, data.frame(block.id=c(blockType, blockType2), + block.desc=c(blockDescription, blockDescription2), + stringsAsFactors=FALSE)) + + expect_equal(results4, matrix(data=c(entries, entries2), ncol=2, + byrow=FALSE)) +}) diff --git a/tests/testthat/test-gdsWrapper_internal.R b/tests/testthat/test-gdsWrapper_internal.R index 58152d806..a8c0d5f98 100644 --- a/tests/testthat/test-gdsWrapper_internal.R +++ b/tests/testthat/test-gdsWrapper_internal.R @@ -540,3 +540,109 @@ test_that("getBlockIDs() must return expected error", { error_message, fixed=TRUE) }) + +############################################################################# +### Tests addUpdateSegment() results +############################################################################# + +context("addUpdateSegment() results") + + +test_that("addUpdateSegment() must copy the expected entry in \"segment\" node of the GDS file", { + + ## Create a temporary GDS file in an test directory + dataDir <- system.file("extdata/tests", package="RAIDS") + fileGDS <- file.path(dataDir, "GDS_TEMP_01.gds") + + ## Create and open a temporary GDS file + GDS_file_tmp <- local_GDS_file(fileGDS) + + ## Vector of segment identifiers + segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L) + + ## Add segments to the GDS file + RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) + + ## Read segments information from GDS file + results <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) + + ## Close GDS file + ## The file will automatically be deleted + closefn.gds(gdsfile=GDS_file_tmp) + + expect_equal(results, segments) +}) + + +test_that("addUpdateSegment() must copy the expected entry in \"segment\" node of the GDS file", { + + ## Create a temporary GDS file in an test directory + dataDir <- system.file("extdata/tests", package="RAIDS") + fileGDS <- file.path(dataDir, "GDS_TEMP_02.gds") + + ## Create and open a temporary GDS file + GDS_file_tmp <- local_GDS_file(fileGDS) + + ## Vector of segment identifiers + segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L) + ## Vector of segment identifiers + segments2 <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L, 5L, 5L, 5L, 5L) + + ## Add segments to the GDS file + RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) + + ## Update segments to the GDS file + RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments2) + + ## Read segments information from GDS file + results <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) + + ## Close GDS file + ## The file will automatically be deleted + closefn.gds(gdsfile=GDS_file_tmp) + + expect_equal(results, segments2) +}) + + +############################################################################# +### Tests appendGDSSampleOnly() results +############################################################################# + +context("appendGDSSampleOnly() results") + + +test_that("appendGDSSampleOnly() must copy the expected entry in \"sample.id\" node of the GDS file", { + + ## Create a temporary GDS file in an test directory + dataDir <- system.file("extdata/tests", package="RAIDS") + fileGDS <- file.path(dataDir, "GDS_TEMP_04.gds") + + ## Create and open a temporary GDS file + GDS_file_tmp <- local_GDS_file(fileGDS) + + ## Create sample.id field + add.gdsn(node=GDS_file_tmp, name="sample.id", val=c("sample_01", + "sample_02")) + sync.gds(gdsfile=GDS_file_tmp) + + ## Vector of SNV names + samples <- c('sample_05', 'sample_08', 'sample_11') + + ## Add name of samples to the GDS file + RAIDS:::appendGDSSampleOnly(gds=GDS_file_tmp, listSamples=samples) + + ## Read segments information from GDS file + results <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.id")) + + ## Close GDS file + ## The file will automatically be deleted + closefn.gds(gdsfile=GDS_file_tmp) + + expected <- c("sample_01", "sample_02", samples) + + expect_equal(results, expected) +}) + + + From c7302825f9b4006b88c99b5527c37df1638fde71 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 18:39:39 -0400 Subject: [PATCH 088/385] Arg name modification in generateGDSSNPinfo() --- R/process1KG.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/process1KG.R b/R/process1KG.R index 24106f558..e78e06a21 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -369,7 +369,7 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), dfPedReference=ped1KG, listSamples=listSamples) if(verbose) { message("Sample info DONE ", Sys.time()) } - generateGDSSNPinfo(gdsReference=newGDS, fileFREQ=fileSNVSelected, + generateGDSSNPinfo(gdsReference=newGDS, fileFreq=fileSNVSelected, verbose=verbose) if(verbose) { message("SNP info DONE ", Sys.time()) } From 6bb1aa7e4d7ef02373cab28754ea0ed79a7677de Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 19:00:19 -0400 Subject: [PATCH 089/385] Update tableBlockAF() doc --- R/allelicFraction_internal.R | 144 +++++++++++++++++++---------------- R/gdsWrapper.R | 24 +++--- man/tableBlockAF.Rd | 34 ++++++--- 3 files changed, 114 insertions(+), 88 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 95c9d253d..d42fa6d8d 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -1213,34 +1213,44 @@ calcAFMLRNA <- function(snp.pos.Hetero) { } -#' @title TOREVIEW Compile the info about the allelic fraction for each bloc. In the case of RNA-seq -#' the blaocks are gene +#' @title TOREVIEW Compile the information about the allelic fraction +#' for each bloc. #' -#' @description TOREVIEW For each block evaluate score about lost of heterizygocity and allelic fration +#' @description TOREVIEW For each block, the function evaluates a score +#' about lost of heterizygocity and allelic fration. +#' In the case of RNA-seq the blocks are genes. #' #' @param snp.pos For a specific chromosome a \code{data.frame} with lap for #' the SNV dataset with #' coverage > \code{minCov}. #' -#' @return TOREVIEW resBlock a \code{data.frame} containing only heterozygote SNVs. The +#' @return TOREVIEW resBlock a \code{data.frame} containing only heterozygote +#' SNV information. The #' \code{data.frame} contain those columns: #' \itemize{ -#' \item{block} {a single \code{integer} id of the block.} -#' \item{aRF} {a single \code{numeric} allelic fraction final not compute +#' \item{block} {a single \code{integer} representing the unique identifier +#' of the block.} +#' \item{aRF} {a single \code{numeric} representing the final allelic fraction not compute #' here -1 for all entries.} -#' \item{aFraction} {a single \code{integer} allelic fraction possible if not LOH.} +#' \item{aFraction} {a single \code{integer} representing the possible allelic +#' fraction in absence of LOH.} #' \item{lR} {a single \code{integer} representing the coverage for #' the alternative allele.} -#' \item{nPhase} {a single \code{integer} number of SNV phase.} +#' \item{nPhase} {a single \code{integer} representin the number of SNV +#' phases.} #' \item{sumAlleleLow} {a single \code{integer} TODO.} #' \item{sumAlleleHigh} {a single \code{integer} TODO.} #' \item{lH} {a single \code{numeric} for the homozygotes log10 of the product #' frequencies of the allele not found in the profile (not a probability).} -#' \item{lM} {a single \code{numeric} log10 product frequency allele in population.} +#' \item{lM} {a single \code{numeric} log10 product frequency allele +#' in population.} #' \item{lRhomo} {a single \code{numeric} score lH - lM.} -#' #' \item{nbHomo} {a single \code{integer} score lH - lM.} -#' #' \item{nbKeep} {a single \code{integer} score lH - lM.} -#' #' \item{nbHetero} {a single \code{integer} score lH - lM.} +#' \item{nbHomo} {a single \code{integer} representing the number of +#' homozygote SNVs per block.} +#' \item{nbKeep} {a single \code{integer} representing the number of +#' SNVs retained per block.} +#' \item{nbHetero} {a single \code{integer} representing the number of +#' heterozygote SNVs per block.} #' } #' #' @examples @@ -1269,59 +1279,60 @@ tableBlockAF <- function(snp.pos) { ## FOR_LOOP modification to be validated by Pascal ## Remove commented code and this text after validation - resBlock <- data.frame(block = listBlocks) - - # Number of homozygote by block - tmp <- aggregate(snp.pos[, c( "homo"), drop = FALSE], - by = list(block=snp.pos$block.id) ,sum) - row.names(tmp) <- as.character(tmp[,1]) - resBlock$nbHomo <- tmp[as.character(listBlocks),2] - # Number of snv keep by block - tmp <- aggregate(snp.pos[, c( "keep"), drop = FALSE], - by = list(block=snp.pos$block.id) ,sum) - row.names(tmp) <- as.character(tmp[,1]) - resBlock$nbKeep <- tmp[as.character(listBlocks),2] - - # Number of heterozygote by block - tmp <- aggregate(snp.pos[, c( "hetero"), drop = FALSE], - by = list(block=snp.pos$block.id) ,sum) - row.names(tmp) <- as.character(tmp[,1]) - resBlock$nbHetero <- tmp[as.character(listBlocks),2] - - resBlock <- apply(resBlock, 1, FUN=function(x,snp.pos){ - resBlock <- data.frame(block = x[1], - nbHomo = x[2], - nbKeep = x[3], - nbHetero = x[4], - aRF = -1, - aFraction = -1, - lR = -1, - nPhase = -1, - sumAlleleLow = -1, - sumAlleleHigh = -1, - lH = -1, - lM = -1, - lRhomo = 1) + resBlock <- data.frame(block=listBlocks) + + # Number of homozygotes per block + tmp <- aggregate(snp.pos[, c( "homo"), drop=FALSE], + by = list(block=snp.pos$block.id), sum) + row.names(tmp) <- as.character(tmp[, 1]) + resBlock$nbHomo <- tmp[as.character(listBlocks), 2] + + # Number of SNVs keep per block + tmp <- aggregate(snp.pos[, c( "keep"), drop=FALSE], + by = list(block=snp.pos$block.id), sum) + row.names(tmp) <- as.character(tmp[, 1]) + resBlock$nbKeep <- tmp[as.character(listBlocks), 2] + + # Number of heterozygotes per block + tmp <- aggregate(snp.pos[, c( "hetero"), drop=FALSE], + by = list(block=snp.pos$block.id), sum) + row.names(tmp) <- as.character(tmp[, 1]) + resBlock$nbHetero <- tmp[as.character(listBlocks), 2] + + resBlock <- apply(resBlock, 1, FUN=function(x, snp.pos) { + resBlock <- data.frame(block=x[1], + nbHomo=x[2], + nbKeep=x[3], + nbHetero=x[4], + aRF=-1, + aFraction=-1, + lR=-1, + nPhase=-1, + sumAlleleLow=-1, + sumAlleleHigh=-1, + lH=-1, + lM=-1, + lRhomo=1) lH <- 1 lM <- 1 if (resBlock[1, "nbKeep"] > 0 & (resBlock[1, "nbKeep"] == resBlock[1, "nbHomo"] | - (resBlock[1, "nbHomo"] > 0 & resBlock[1, "nbHetero"] == 1)) ) { + (resBlock[1, "nbHomo"] > 0 & resBlock[1, "nbHetero"] == 1))) { # Check if 1 hetero with allelic fraction (<=0.05) # it is considered as all homozygote flag <- TRUE if (resBlock[1, "nbHetero"] == 1) { tmp <- min(snp.pos[snp.pos$block.id == resBlock$block[1] & - snp.pos$hetero, c("cnt.ref" , "cnt.alt")])/ + snp.pos$hetero, c("cnt.ref" , "cnt.alt")])/ sum(snp.pos[snp.pos$block.id == resBlock$block[1] & - snp.pos$hetero, c("cnt.ref" , "cnt.alt")]) + snp.pos$hetero, c("cnt.ref" , "cnt.alt")]) # flag is true if allelic fraction <= 0.05 - flag <- ifelse(tmp > 0.05, FALSE,TRUE) + flag <- ifelse(tmp > 0.05, FALSE, TRUE) } - if(flag){ + if(flag) { # List homozygote ref listRef <- which(snp.pos$block.id == resBlock$block[1] & snp.pos$homo & @@ -1332,37 +1343,42 @@ tableBlockAF <- function(snp.pos) { snp.pos$cnt.ref < snp.pos$cnt.alt) # freq of the Ref allele in population of listRef tmp <- snp.pos$freq[listRef] - # min freq is 0.01 + ## min freq is 0.01 tmp[which(tmp < 0.01)] <- 0.01 - # log10 of the product of the frequency of the alternative allele in pop for listRef + ## log10 of the product of the frequency of the alternative + ## allele in pop for listRef lH <- ifelse(length(listRef) > 0, sum(log10(1-tmp)*2), 0) - # freq of the Ref allele in population of listAlt + ## freq of the Ref allele in population of listAlt tmp <- snp.pos$freq[listAlt] tmp[which(tmp < 0.01)] <- 0.01 - # log10 of the product of the frequency of the alternative allele in pop for listRef - # plus log10 of the product of the frequency of the reference allele in pop for listAlt - lH <- lH + ifelse(length(listAlt) > 0, sum(log10(tmp)*2), 0) + ## log10 of the product of the frequency of the + ## alternative allele in pop for listRef + ## plus log10 of the product of the frequency of + ##the reference allele in pop for listAlt + lH <- lH + ifelse(length(listAlt) > 0, + sum(log10(tmp)*2), 0) lM <- sum(log10(apply(snp.pos[which(snp.pos$block.id == - resBlock$block[1] & snp.pos$homo), + resBlock$block[1] & snp.pos$homo), "freq", drop=FALSE], 1, - FUN = function(x) { - return(max(x^2, 2*(x * (1-x)), (1-x)^2)) + FUN=function(x) { + return(max(x^2, 2*(x * (1-x)), (1-x)^2)) }))) resBlock$sumAlleleLow[1] <- 0 resBlock$sumAlleleHigh[1] <- sum(snp.pos[listRef, "cnt.ref"]) + sum(snp.pos[listAlt, "cnt.alt"]) } } - # compute the score of the homozygote on the block - # if heterozygote present lH = lM = 1 and lRhomo = 0 - resBlock[1, c("lH", "lM", "lRhomo")] <- c(lH, lM, lH - lM) - # get hetero and compute AF nbHetero > 1 + ## compute the score of the homozygote on the block + ## if heterozygote present lH = lM = 1 and lRhomo = 0 + resBlock[1, c("lH", "lM", "lRhomo")] <- c(lH, lM, lH-lM) + + ## get hetero and compute AF nbHetero > 1 if (resBlock[1, "nbKeep"] > 0 & resBlock[1, "nbHetero"] > 1) { resML <- calcAFMLRNA(snp.pos[which(snp.pos$block.id == - resBlock$block[1] & snp.pos$hetero),]) + resBlock$block[1] & snp.pos$hetero),]) resBlock$aFraction[1] <- resML$aFraction resBlock$lR[1] <- resML$lR diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 233c06db0..8d3cd66a7 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -497,39 +497,39 @@ gds2tped <- function(gds, listSample, listSNP, pedOUT) { #' @keywords internal addGDS1KGLDBlock <- function(gds, listBlock, blockName, blockDesc) { - block.annot <- data.frame(block.id=blockName, + blockAnnot <- data.frame(block.id=blockName, block.desc=blockDesc, stringsAsFactors=FALSE) if(! ("block.annot" %in% ls.gdsn(gds))) { ## Create 'block.annot' node when not existing - var.block.annot <- add.gdsn(gds, "block.annot", block.annot) + varBlockAnnot <- add.gdsn(gds, "block.annot", blockAnnot) }else { ## Append content to 'block.annot' node when existing curAnnot <- index.gdsn(gds, "block.annot/block.id") - append.gdsn(curAnnot, block.annot$block.id) + append.gdsn(curAnnot, blockAnnot$block.id) curAnnot <- index.gdsn(gds, "block.annot/block.desc") - append.gdsn(curAnnot, block.annot$block.desc) + append.gdsn(curAnnot, blockAnnot$block.desc) } - var.block <- NULL + varBlock <- NULL if(!("block" %in% ls.gdsn(gds))) { ## Create 'block' node that will contain a matrix of integers ## stored in compressed mode - var.block <- add.gdsn(node=gds, name="block", + varBlock <- add.gdsn(node=gds, name="block", valdim=c(length(listBlock), 1), listBlock, storage="int32", compress="LZ4_RA") - readmode.gdsn(var.block) + readmode.gdsn(varBlock) } else { - if(is.null(var.block)) { - var.block <- index.gdsn(gds, "block") - var.block <- compression.gdsn(var.block, "") + if(is.null(varBlock)) { + varBlock <- index.gdsn(gds, "block") + varBlock <- compression.gdsn(varBlock, "") } - append.gdsn(var.block, listBlock) + append.gdsn(varBlock, listBlock) ## Compressed data using LZ4_RA method - var.block <- compression.gdsn(var.block, "LZ4_RA") + varBlock <- compression.gdsn(varBlock, "LZ4_RA") } sync.gds(gds) diff --git a/man/tableBlockAF.Rd b/man/tableBlockAF.Rd index c763940d5..c7074a140 100644 --- a/man/tableBlockAF.Rd +++ b/man/tableBlockAF.Rd @@ -3,8 +3,8 @@ \encoding{UTF-8} \name{tableBlockAF} \alias{tableBlockAF} -\title{TOREVIEW Compile the info about the allelic fraction for each bloc. In the case of RNA-seq -the blaocks are gene} +\title{TOREVIEW Compile the information about the allelic fraction +for each bloc.} \usage{ tableBlockAF(snp.pos) } @@ -14,29 +14,39 @@ the SNV dataset with coverage > \code{minCov}.} } \value{ -TOREVIEW resBlock a \code{data.frame} containing only heterozygote SNVs. The +TOREVIEW resBlock a \code{data.frame} containing only heterozygote +SNV information. The \code{data.frame} contain those columns: \itemize{ -\item{block} {a single \code{integer} id of the block.} -\item{aRF} {a single \code{numeric} allelic fraction final not compute +\item{block} {a single \code{integer} representing the unique identifier +of the block.} +\item{aRF} {a single \code{numeric} representing the final allelic fraction not compute here -1 for all entries.} -\item{aFraction} {a single \code{integer} allelic fraction possible if not LOH.} +\item{aFraction} {a single \code{integer} representing the possible allelic +fraction in absence of LOH.} \item{lR} {a single \code{integer} representing the coverage for the alternative allele.} -\item{nPhase} {a single \code{integer} number of SNV phase.} +\item{nPhase} {a single \code{integer} representin the number of SNV +phases.} \item{sumAlleleLow} {a single \code{integer} TODO.} \item{sumAlleleHigh} {a single \code{integer} TODO.} \item{lH} {a single \code{numeric} for the homozygotes log10 of the product frequencies of the allele not found in the profile (not a probability).} -\item{lM} {a single \code{numeric} log10 product frequency allele in population.} +\item{lM} {a single \code{numeric} log10 product frequency allele +in population.} \item{lRhomo} {a single \code{numeric} score lH - lM.} -#' \item{nbHomo} {a single \code{integer} score lH - lM.} -#' \item{nbKeep} {a single \code{integer} score lH - lM.} -#' \item{nbHetero} {a single \code{integer} score lH - lM.} +\item{nbHomo} {a single \code{integer} representing the number of +homozygote SNVs per block.} +\item{nbKeep} {a single \code{integer} representing the number of +SNVs retained per block.} +\item{nbHetero} {a single \code{integer} representing the number of +heterozygote SNVs per block.} } } \description{ -TOREVIEW For each block evaluate score about lost of heterizygocity and allelic fration +TOREVIEW For each block, the function evaluates a score +about lost of heterizygocity and allelic fration. +In the case of RNA-seq the blocks are genes. } \examples{ From 85836e98da12c02ac7ed687c5c0585b310fc45b3 Mon Sep 17 00:00:00 2001 From: belleau Date: Mon, 14 Aug 2023 20:22:55 -0400 Subject: [PATCH 090/385] Add wrapper runWrapperAncestry and runProfileAncestry. Change snp.pos for snpPos --- NAMESPACE | 1 + R/allelicFraction.R | 44 +- R/allelicFraction_internal.R | 283 +++++---- R/processStudy.R | 306 ++++++---- R/processStudy_internal.R | 547 ++++++++++++++++++ man/calcAFMLRNA.Rd | 4 +- man/computeAlleleFraction.Rd | 10 +- man/computeAllelicImbDNAChr.Rd | 8 +- man/computeLOHBlocksDNAChr.Rd | 6 +- man/getTableSNV.Rd | 2 +- man/runProfileAncestry.Rd | 120 ++++ man/runRNAAncestry.Rd | 204 +++++++ man/runWrapperAncestry.Rd | 211 +++++++ man/tableBlockAF.Rd | 4 +- tests/testthat/test-allelicFraction.R | 6 +- .../testthat/test-allelicFraction_internal.R | 2 +- 16 files changed, 1474 insertions(+), 284 deletions(-) create mode 100644 man/runProfileAncestry.Rd create mode 100644 man/runRNAAncestry.Rd create mode 100644 man/runWrapperAncestry.Rd diff --git a/NAMESPACE b/NAMESPACE index 3d762a809..0ab3f8b45 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -30,6 +30,7 @@ export(prepSynthetic) export(projectSample2PCA) export(pruningSample) export(runExomeAncestry) +export(runRNAAncestry) export(select1KGPop) export(snvListVCF) export(splitSelectByPop) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index 24078192c..fee41b4ef 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -2,7 +2,7 @@ #' #' @description TODO #' -#' @param snp.pos a \code{data.frame} containing the genotype information for +#' @param snpPos a \code{data.frame} containing the genotype information for #' a SNV dataset. TODO #' #' @param w a single positive \code{numeric} representing the size of the @@ -14,9 +14,9 @@ #' @return a \code{matrix} of \code{numeric} with 3 columns where each #' row represent a segment #' of imbalanced SNVs. The first column represents the position, in -#' \code{snp.pos}, of the first +#' \code{snpPos}, of the first #' SNV in the segment. The second column represents the position, in the -#' \code{snp.pos}, of the last SNV in the segment. The third column represents +#' \code{snpPos}, of the last SNV in the segment. The third column represents #' the lower allelic frequency of the segment and is \code{NA} when the value #' cannot be calculated. The value \code{NULL} is #' returned when none of the SNVs @@ -40,7 +40,7 @@ #' stringAsFactor=FALSE) #' #' ## The function returns NULL when there is not imbalanced SNVs -#' RAIDS:::computeAlleleFraction(snp.pos=snpInfo, w=10, cutOff=-3) +#' RAIDS:::computeAlleleFraction(snpPos=snpInfo, w=10, cutOff=-3) #' #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz @@ -48,11 +48,11 @@ #' @importFrom S4Vectors isSingleNumber #' @encoding UTF-8 #' @keywords internal -computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { +computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { listBlockAR <- list() j <- 1 - tmp <- as.integer(snp.pos$imbAR == 1) + tmp <- as.integer(snpPos$imbAR == 1) z <- cbind(c(tmp[1], tmp[-1] - tmp[seq_len(length(tmp) -1)]), c(tmp[-1] - tmp[seq_len(length(tmp) -1)], tmp[length(tmp)] * -1)) @@ -60,16 +60,16 @@ computeAlleleFraction <- function(snp.pos, w=10, cutOff=-3) { ## There must be at least one segment with imbalanced SNVs to go one if(length(which(z[,1] == 1)) > 0) { ## Find segmentsof imbalanced SNVs - segImb <- data.frame(start=seq_len(nrow(snp.pos))[which(z[,1] > 0)], - end=seq_len(nrow(snp.pos))[which(z[,2] < 0)]) + segImb <- data.frame(start=seq_len(nrow(snpPos))[which(z[,1] > 0)], + end=seq_len(nrow(snpPos))[which(z[,2] < 0)]) for(i in seq_len(nrow(segImb))) { # index of the segment listSeg <- (segImb$start[i]):(segImb$end[i]) # index hetero segment - listHetero <- listSeg[snp.pos[listSeg,"hetero"] == TRUE] + listHetero <- listSeg[snpPos[listSeg,"hetero"] == TRUE] # SNP hetero for the segment - snp.hetero <- snp.pos[listHetero,] + snp.hetero <- snpPos[listHetero,] if(nrow(snp.hetero) >= 2 * w) { lapCur <- median(apply(snp.hetero[seq_len(w), @@ -319,17 +319,17 @@ estimateAllelicFraction <- function(gdsReference, gdsProfile, ## Set study type studyType <- arg_match(studyType) - snp.pos <- NULL + snpPos <- NULL ## The type of study affects the allelic fraction estimation if(studyType == "DNA") { - snp.pos <- computeAllelicFractionDNA(gdsReference=gdsReference, + snpPos <- computeAllelicFractionDNA(gdsReference=gdsReference, gdsSample=gdsProfile, currentProfile=currentProfile, studyID=studyID, chrInfo=chrInfo, minCov=minCov, minProb=minProb, eProb=eProb, cutOffLOH=cutOffLOH, cutOffHomoScore=cutOffHomoScore, wAR=wAR, verbose=verbose) } else if(studyType == "RNA") { - snp.pos <- computeAllelicFractionRNA(gdsReference=gdsReference, + snpPos <- computeAllelicFractionRNA(gdsReference=gdsReference, gdsSample=gdsProfile, gdsRefAnnot=gdsRefAnnot, currentProfile=currentProfile, studyID=studyID, blockID=blockID, chrInfo=chrInfo, minCov=minCov, minProb=minProb, eProb=eProb, @@ -340,29 +340,29 @@ estimateAllelicFraction <- function(gdsReference, gdsProfile, ## Remove commented code and this text after validation ## Calculate the cumulative sum for each chromosome - cumSumResult <- lapply(unique(snp.pos$snp.chr), function(i) { - snpChr <- snp.pos[snp.pos$snp.chr == i, ] + cumSumResult <- lapply(unique(snpPos$snp.chr), function(i) { + snpChr <- snpPos[snpPos$snp.chr == i, ] tmp <- c(0, abs(snpChr[2:nrow(snpChr), "lap"] - snpChr[seq_len(nrow(snpChr)- 1), "lap"]) > 1e-3) return(cumsum(tmp)) }) # Find segment with same lap - snp.pos$seg <- rep(0, nrow(snp.pos)) + snpPos$seg <- rep(0, nrow(snpPos)) k <- 1 - for(chr in unique(snp.pos$snp.chr)) { - ##snpChr <- snp.pos[snp.pos$snp.chr == chr, ] + for(chr in unique(snpPos$snp.chr)) { + ##snpChr <- snpPos[snpPos$snp.chr == chr, ] ##tmp <- c(0, abs(snpChr[2:nrow(snpChr), "lap"] - ## snpChr[seq_len(nrow(snpChr)- 1), "lap"]) > 1e-3) - snp.pos$seg[snp.pos$snp.chr == chr] <- cumSumResult[[chr]] + k - k <- max(snp.pos$seg[snp.pos$snp.chr == chr]) + 1 + snpPos$seg[snpPos$snp.chr == chr] <- cumSumResult[[chr]] + k + k <- max(snpPos$seg[snpPos$snp.chr == chr]) + 1 } ## Save information into the "lap" node in the Profile GDS file ## Save information into the "segment" node in the Profile GDS file ## Suppose we keep only the pruned SNVs - addUpdateLap(gdsProfile, snp.pos$lap[which(snp.pos$pruned == TRUE)]) - addUpdateSegment(gdsProfile, snp.pos$seg[which(snp.pos$pruned == TRUE)]) + addUpdateLap(gdsProfile, snpPos$lap[which(snpPos$pruned == TRUE)]) + addUpdateSegment(gdsProfile, snpPos$seg[which(snpPos$pruned == TRUE)]) return(0L) } diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 143974593..6198e1245 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -39,7 +39,7 @@ #' the reference allele.} #' \item{cnt.alt} {a single \code{integer} representing the coverage for #' the alternative allele.} -#' \item{snp.pos} {a single \code{integer} representing the SNV position.} +#' \item{snpPos} {a single \code{integer} representing the SNV position.} #' \item{snp.chr} {a single \code{integer} representing the SNV chromosome.} #' \item{normal.geno} {a single \code{numeric} indicating the genotype of the #' SNV. The possibles are: \code{0} (wild-type homozygote), \code{1} @@ -116,7 +116,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, listKeep <- cnt.total@i[which(cnt.total@x >= minCov)] + 1 ## Create the data.frame with the required information - snp.pos <- data.frame(cnt.tot=cnt.total[listKeep], + snpPos <- data.frame(cnt.tot=cnt.total[listKeep], cnt.ref=read.gdsn(index.gdsn(gdsSample, "Ref.count"), start=c(1, posCur), count=c(-1, 1))[listKeep], cnt.alt=read.gdsn(index.gdsn(gdsSample, "Alt.count"), @@ -132,7 +132,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, snp.pruned <- read.gdsn(index.gdsn(node=gdsSample, "snp.index")) listKeepPruned <- which(listKeep %in% snp.pruned) - snp.pos$pruned[listKeepPruned] <- TRUE + snpPos$pruned[listKeepPruned] <- TRUE rm(cnt.total, snp.pruned, listKeepPruned) @@ -147,7 +147,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, cnt.total <- read.gdsn(index.gdsn(gdsSample, "Total.count.o")) listKeep.o <- which(cnt.total >= minCov) - snp.pos.o <- data.frame(cnt.tot=cnt.total[listKeep.o], + snpPosO <- data.frame(cnt.tot=cnt.total[listKeep.o], cnt.ref=read.gdsn(index.gdsn(gdsSample, "Ref.count.o"))[listKeep.o], cnt.alt=read.gdsn(index.gdsn(gdsSample, "Alt.count.o"))[listKeep.o], snp.pos=read.gdsn(index.gdsn(gdsReference, @@ -157,36 +157,36 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, normal.geno=read.gdsn(index.gdsn(gdsSample, "normal.geno"))[listKeep.o], pruned=rep(0, length(listKeep)), snp.index=rep(0, length(listKeep.o)), stringsAsFactors=FALSE) - listChr <- unique(snp.pos.o$snp.chr) + listChr <- unique(snpPosO$snp.chr) listUnion <- list() - # if snp.pos.o intersect snp.pos and normal.geno != 3 (we know - # the genotype of normal) change in snp.pos normal.geno - z <- cbind(c(snp.pos.o$snp.chr, snp.pos$snp.chr, snp.pos.o$snp.chr), - c(snp.pos.o$snp.pos, snp.pos$snp.pos, snp.pos.o$snp.pos), - c(seq_len(nrow(snp.pos.o)), 0, -1*seq_len(nrow(snp.pos.o))), - c(rep(0, nrow(snp.pos.o)), seq_len(nrow(snp.pos)), - rep(0, nrow(snp.pos.o)))) + # if snpPosO intersect snpPos and normal.geno != 3 (we know + # the genotype of normal) change in snpPos normal.geno + z <- cbind(c(snpPosO$snp.chr, snpPos$snp.chr, snpPosO$snp.chr), + c(snpPosO$snp.pos, snpPos$snp.pos, snpPosO$snp.pos), + c(seq_len(nrow(snpPosO)), 0, -1*seq_len(nrow(snpPosO))), + c(rep(0, nrow(snpPosO)), seq_len(nrow(snpPos)), + rep(0, nrow(snpPosO)))) z <- z[order(z[,1], z[,2], z[,3]), ] vCum <- cumsum(z[,3]) - snp.pos[z[ vCum < 0 & z[,3] == 0, 4], "normal.geno"] <- - snp.pos.o[vCum[vCum < 0 & z[, 3] == 0], "normal.geno"] + snpPos[z[ vCum < 0 & z[,3] == 0, 4], "normal.geno"] <- + snpPosO[vCum[vCum < 0 & z[, 3] == 0], "normal.geno"] rm(z) - # Keep the snp.pos.o not in snp.pos - z <- cbind(c(snp.pos$snp.chr, snp.pos.o$snp.chr, snp.pos$snp.chr), - c(snp.pos$snp.pos, snp.pos.o$snp.pos, snp.pos$snp.pos), - c(seq_len(nrow(snp.pos)), 0, -1*seq_len(nrow(snp.pos))), - c(rep(0, nrow(snp.pos)), seq_len(nrow(snp.pos.o)), - rep(0, nrow(snp.pos)))) + # Keep the snpPosO not in snpPos + z <- cbind(c(snpPos$snp.chr, snpPosO$snp.chr, snpPos$snp.chr), + c(snpPos$snp.pos, snpPosO$snp.pos, snpPos$snp.pos), + c(seq_len(nrow(snpPos)), 0, -1*seq_len(nrow(snpPos))), + c(rep(0, nrow(snpPos)), seq_len(nrow(snpPosO)), + rep(0, nrow(snpPos)))) z <- z[order(z[,1], z[,2], z[,3]), ] - # merge snp.pos with snp.pos.o - snp.pos <- rbind(snp.pos, - snp.pos.o[z[cumsum(z[,3] == 0 & z[,3] == 0),4],]) + # merge snpPos with snpPosO + snpPos <- rbind(snpPos, + snpPosO[z[cumsum(z[,3] == 0 & z[,3] == 0),4],]) } - listCnt <- unique(snp.pos$cnt.tot) + listCnt <- unique(snpPos$cnt.tot) listCnt <- listCnt[order(listCnt)] cutOffA <- data.frame(count=unlist(vapply(listCnt, @@ -199,32 +199,32 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, FUN.VALUE = numeric(1), minProb=minProb, eProb=eProb))) row.names(cutOffA) <- as.character(listCnt) - snp.pos$keep <- rowSums(snp.pos[, c("cnt.ref", "cnt.alt")]) >= - snp.pos$cnt.tot - cutOffA[as.character(snp.pos$cnt.tot), "count"] + snpPos$keep <- rowSums(snpPos[, c("cnt.ref", "cnt.alt")]) >= + snpPos$cnt.tot - cutOffA[as.character(snpPos$cnt.tot), "count"] - snp.pos$hetero <- snp.pos$keep == TRUE & - rowSums(snp.pos[, c("cnt.ref", "cnt.alt")] >= - cutOffA[as.character(snp.pos$cnt.tot), "allele"]) == 2 + snpPos$hetero <- snpPos$keep == TRUE & + rowSums(snpPos[, c("cnt.ref", "cnt.alt")] >= + cutOffA[as.character(snpPos$cnt.tot), "allele"]) == 2 # We set to homo if 2th allele can be explain by error # can switch low allelic fraction to LOH which is less a problem # then reduce the allelic ratio by seq error - snp.pos$homo <- snp.pos$keep == TRUE & - rowSums(snp.pos[, c("cnt.ref", "cnt.alt")] >= - cutOffA[as.character(snp.pos$cnt.tot), "allele"]) == 1 + snpPos$homo <- snpPos$keep == TRUE & + rowSums(snpPos[, c("cnt.ref", "cnt.alt")] >= + cutOffA[as.character(snpPos$cnt.tot), "allele"]) == 1 ## If we know the normal is hetero then we call hetero ## if the cnt.alt and cnt.ref > 0 - listHeteroN <- which(snp.pos$homo == TRUE & - rowSums(snp.pos[, c("cnt.ref", "cnt.alt")] > 0) == 2 & - snp.pos$normal.geno == 1) + listHeteroN <- which(snpPos$homo == TRUE & + rowSums(snpPos[, c("cnt.ref", "cnt.alt")] > 0) == 2 & + snpPos$normal.geno == 1) if (length(listHeteroN) > 0) { - snp.pos$hetero[listHeteroN] <- TRUE - snp.pos$homo <- FALSE + snpPos$hetero[listHeteroN] <- TRUE + snpPos$homo <- FALSE } - return(snp.pos) + return(snpPos) } @@ -241,7 +241,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' the chromosomes. As an example, the information ca be obtained from #' package 'BSgenome.Hsapiens.UCSC.hg38'. #' -#' @param snp.pos a \code{data.frame} containing the SNV information for the +#' @param snpPos a \code{data.frame} containing the SNV information for the #' chromosome specified by the \code{chr} argument. The \code{data.frame} must #' contain: #' \itemize{ @@ -333,7 +333,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' ## The function returns a data frame containing the information about the #' ## LOH regions in the specified chromosome #' result <- RAIDS:::computeLOHBlocksDNAChr(gdsReference=gds1KG, -#' chrInfo=chrInfo, snp.pos=snpInfo, chr=1L, genoN=0.0001) +#' chrInfo=chrInfo, snpPos=snpInfo, chr=1L, genoN=0.0001) #' head(result) #' #' ## Close Reference GDS file (important) @@ -345,24 +345,24 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' @importFrom S4Vectors isSingleNumber #' @encoding UTF-8 #' @keywords internal -computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snp.pos, chr, +computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, genoN=0.0001) { genoN1 <- 1 - 2 * genoN chrEnd <- chrInfo[chr] - listHetero <- snp.pos[snp.pos$hetero == TRUE, "snp.pos"] + listHetero <- snpPos[snpPos$hetero == TRUE, "snp.pos"] homoBlock <- data.frame(chr=rep(chr, length(listHetero) + 1), start=c(1, listHetero + 1), end=c(listHetero, chrEnd)) z <- cbind(c(homoBlock$start, homoBlock$end, - snp.pos$snp.pos[which(snp.pos$homo == TRUE)]), + snpPos$snp.pos[which(snpPos$homo == TRUE)]), c(seq_len(length(homoBlock$start)), -1*seq_len(length(homoBlock$start)), - rep(0, length(which(snp.pos$homo == TRUE)))), + rep(0, length(which(snpPos$homo == TRUE)))), c(rep(0, length(homoBlock$start)), rep(0, length(homoBlock$start)), - seq_len(length(which(snp.pos$homo == TRUE))))) + seq_len(length(which(snpPos$homo == TRUE))))) z <- z[order(z[, 1]), ] @@ -385,7 +385,7 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snp.pos, chr, for (i in seq_len(nrow(homoBlock))) { blcCur <- blcSNV[blcSNV$block == i, ] - snvH <- snp.pos[blcCur$snv, ] + snvH <- snpPos[blcCur$snv, ] lH1 <- 0 lM1 <- 0 logLHR <- 0 @@ -572,32 +572,29 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, ## Extract the genotype information for a SNV dataset using ## the Profile GDS file and the Reference GDS file - snp.pos <- getTableSNV(gdsReference=gdsReference, gdsSample=gdsSample, + snpPos <- getTableSNV(gdsReference=gdsReference, gdsSample=gdsSample, currentProfile=currentProfile, studyID=studyID, minCov=minCov, minProb=minProb, eProb=eProb, verbose=verbose) - snp.pos$lap <- rep(-1, nrow(snp.pos)) - snp.pos$LOH <- rep(0, nrow(snp.pos)) - snp.pos$imbAR <- rep(-1, nrow(snp.pos)) - - lapply(unique(snp.pos$snp.chr), FUN=function(x, snp.pos){ + snpPos$lap <- rep(-1, nrow(snpPos)) + snpPos$LOH <- rep(0, nrow(snpPos)) + snpPos$imbAR <- rep(-1, nrow(snpPos)) - }) homoBlock <- list() - for(chr in unique(snp.pos$snp.chr)) { + for(chr in unique(snpPos$snp.chr)) { if (verbose) { message("chr ", chr) message("Step 1 ", Sys.time()) } - listChr <- which(snp.pos$snp.chr == chr) + listChr <- which(snpPos$snp.chr == chr) ## Identify LOH regions homoBlock[[chr]] <- computeLOHBlocksDNAChr(gdsReference=gdsReference, - chrInfo=chrInfo, snp.pos=snp.pos[listChr,], chr=chr) + chrInfo=chrInfo, snpPos=snpPos[listChr,], chr=chr) if (verbose) { message("Step 2 ", Sys.time()) } @@ -605,7 +602,7 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, cutOffLOH & homoBlock[[chr]]$homoScore <= cutOffHomoScore) z <- cbind(c(homoBlock[[chr]]$start, homoBlock[[chr]]$end, - snp.pos[listChr, "snp.pos"]), + snpPos[listChr, "snp.pos"]), c(rep(0, 2* nrow(homoBlock[[chr]])), rep(1, length(listChr))), c(homoBlock[[chr]]$LOH, -1 * homoBlock[[chr]]$LOH, @@ -615,35 +612,35 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, z <- z[order(z[,1], z[,2]), ] pos <- z[cumsum(z[,3]) > 0 & z[,4] > 0, 4] - snp.pos[listChr[pos], "lap"] <- 0 - snp.pos[listChr[pos], "LOH"] <- 1 + snpPos[listChr[pos], "lap"] <- 0 + snpPos[listChr[pos], "LOH"] <- 1 if (verbose) { message("Step 3 ", Sys.time()) } ## Identify imbalanced SNVs in specified chromosome - snp.pos[listChr, "imbAR"] <- - computeAllelicImbDNAChr(snp.pos=snp.pos[listChr, ], chr=chr, + snpPos[listChr, "imbAR"] <- + computeAllelicImbDNAChr(snpPos=snpPos[listChr, ], chr=chr, wAR=10, cutOffEmptyBox=-3) if (verbose) { message("Step 4 ", Sys.time()) } ## Compute allelic fraction for SNVs in specified chromosome - blockAF <- computeAlleleFraction(snp.pos=snp.pos[listChr, ], + blockAF <- computeAlleleFraction(snpPos=snpPos[listChr, ], w=10, cutOff=-3) if (verbose) { message("Step 5 ", Sys.time()) } if(! is.null(blockAF)) { for(i in seq_len(nrow(blockAF))) { - snp.pos[listChr[blockAF[i, 1]:blockAF[i, 2]], "lap"] <- + snpPos[listChr[blockAF[i, 1]:blockAF[i, 2]], "lap"] <- blockAF[i, 3] } } } - snp.pos[which(snp.pos[, "lap"] == -1), "lap"] <- 0.5 + snpPos[which(snpPos[, "lap"] == -1), "lap"] <- 0.5 - return(snp.pos) + return(snpPos) } @@ -719,37 +716,37 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, ## Extract the genotype information for a SNV dataset using ## the GDS Sample file and the Reference GDS file - snp.pos <- getTableSNV(gdsReference, gdsSample, currentProfile, studyID, + snpPos <- getTableSNV(gdsReference, gdsSample, currentProfile, studyID, minCov, minProb, eProb) # Keep only SNV in GDS ref because to reduce SNV artefact from RNA - snp.pos <- snp.pos[which(snp.pos$snp.index > 0),] + snpPos <- snpPos[which(snpPos$snp.index > 0),] # Get the block structure base on genes from gdsRefAnnot - snp.pos$block.id <- getGeneBlock(gdsRefAnnot=gdsRefAnnot, - snp.index=snp.pos$snp.index, blockID=blockID) + snpPos$block.id <- getGeneBlock(gdsRefAnnot=gdsRefAnnot, + snp.index=snpPos$snp.index, blockID=blockID) - snp.pos$phase <- rep(3, nrow(snp.pos)) + snpPos$phase <- rep(3, nrow(snpPos)) if ("phase" %in% ls.gdsn(node=gdsSample)) { - snp.pos$phase <- read.gdsn(index.gdsn(gdsSample, - "phase"))[snp.pos$snp.index] + snpPos$phase <- read.gdsn(index.gdsn(gdsSample, + "phase"))[snpPos$snp.index] } - snp.pos$lap <- rep(-1, nrow(snp.pos)) - snp.pos$LOH <- rep(0, nrow(snp.pos)) - snp.pos$imbAR <- rep(-1, nrow(snp.pos)) - snp.pos$freq <- read.gdsn(index.gdsn(gdsReference, - "snp.AF"))[snp.pos$snp.index] + snpPos$lap <- rep(-1, nrow(snpPos)) + snpPos$LOH <- rep(0, nrow(snpPos)) + snpPos$imbAR <- rep(-1, nrow(snpPos)) + snpPos$freq <- read.gdsn(index.gdsn(gdsReference, + "snp.AF"))[snpPos$snp.index] # for each chromosome # listBlock <- list() ## FOR_LOOP modification to be validated by Pascal ## Remove commented code and this text after validation - listBlock <- lapply(unique(snp.pos$snp.chr), FUN = function(x, snp.pos, verbose){ + listBlock <- lapply(unique(snpPos$snp.chr), FUN = function(x, snpPos, verbose){ if (verbose) { message("chr ", x) message("Step 1 ", Sys.time()) } - listChr <- which(snp.pos$snp.chr == x) - blockAF <- tableBlockAF(snp.pos=snp.pos[listChr,]) + listChr <- which(snpPos$snp.chr == x) + blockAF <- tableBlockAF(snpPos=snpPos[listChr,]) blockAF$aRF[blockAF$lRhomo <= cutOffLOH] <- 0 blockAF$aRF[blockAF$lR >= cutOffAR] <- blockAF$aFraction[blockAF$lR >= cutOffAR] @@ -761,7 +758,7 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, message("Step 1 done ", Sys.time()) } return(blockAF) - }, snp.pos=snp.pos, + }, snpPos=snpPos, verbose=verbose) blockAF <- do.call(rbind, listBlock) listMissing <- which(abs(blockAF$aRF + 1) < 1e-6) @@ -771,7 +768,7 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, for(b in seq_len(nrow(blockAF))) { - snp.pos$lap[snp.pos$block.id == blockAF$block[b]] <- blockAF$aRF[b] + snpPos$lap[snpPos$block.id == blockAF$block[b]] <- blockAF$aRF[b] } # listMissing <- which(abs(blockAF$aRF + 1) < 1e-6) # blockAF[listMissing, "aRF"] <- sample(blockAF$aRF[-1*listMissing], @@ -815,7 +812,7 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, # snp.pos$lap[snp.pos$block.id == blockAF1$block[b]] <- blockAF1$aRF[b] # } - return(snp.pos) + return(snpPos) } @@ -824,7 +821,7 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, #' @description The function verifies, for each SNV present in the data frame, #' if the SNV is in an imbalance region. #' -#' @param snp.pos a \code{data.frame} containing the SNV information for the +#' @param snpPos a \code{data.frame} containing the SNV information for the #' chromosome specified by the \code{chr} argument. The \code{data.frame} must #' contain: #' \itemize{ @@ -865,7 +862,7 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, #' imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; 1=tested #' positive for imbalance in at least 1 window). The vector as an entry for #' each SNV present in the -#' input \code{snp.pos}. +#' input \code{snpPos}. #' #' @examples #' @@ -905,7 +902,7 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, #' #' ## The function returns a data frame containing the information about the #' ## LOH regions in the specified chromosome -#' result <- RAIDS:::computeAllelicImbDNAChr(snp.pos=snpInfo, chr=1, wAR=10, +#' result <- RAIDS:::computeAllelicImbDNAChr(snpPos=snpInfo, chr=1, wAR=10, #' cutOffEmptyBox=-3) #' head(result) #' @@ -917,37 +914,37 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, #' @importFrom S4Vectors isSingleNumber #' @encoding UTF-8 #' @keywords internal -computeAllelicImbDNAChr <- function(snp.pos, chr, wAR=10, cutOffEmptyBox=-3) { +computeAllelicImbDNAChr <- function(snpPos, chr, wAR=10, cutOffEmptyBox=-3) { # We use wAR - 1 because # process the window ex: 1 to 1+wAR wAR <- wAR - 1 listHetero <- NULL - if(length(which(snp.pos$normal.geno != 3) > 0)) { - listHetero <- which(snp.pos$keep == TRUE & snp.pos$normal.geno == 1) + if(length(which(snpPos$normal.geno != 3) > 0)) { + listHetero <- which(snpPos$keep == TRUE & snpPos$normal.geno == 1) } else{ - listHetero <- which(snp.pos$hetero == TRUE) + listHetero <- which(snpPos$hetero == TRUE) } - heteroSNV <- snp.pos[listHetero, ] + heteroSNV <- snpPos[listHetero, ] if(nrow(heteroSNV) > wAR) { for(i in seq_len(nrow(heteroSNV)-wAR)) { - if(sum(snp.pos[listHetero[i]:listHetero[(i+wAR-1)], "LOH"]) == 0 ) { + if(sum(snpPos[listHetero[i]:listHetero[(i+wAR-1)], "LOH"]) == 0 ) { ## Check for imbalance regions for heterozygote SNVs cur <- testEmptyBox(heteroSNV[i:(i+wAR), c ("cnt.alt", "cnt.ref")], cutOffEmptyBox) if(cur$pCut == 1) { # Set all snv from tmpA (include homozygotes) # in the window to 1 - snp.pos[listHetero[i]:listHetero[(i+wAR)], "imbAR"] <- 1 + snpPos[listHetero[i]:listHetero[(i+wAR)], "imbAR"] <- 1 } } } } - snp.pos$imbAR[which(snp.pos$LOH == 1)] <- 0 + snpPos$imbAR[which(snpPos$LOH == 1)] <- 0 - return(snp.pos$imbAR) + return(snpPos$imbAR) } @@ -1144,7 +1141,7 @@ testEmptyBox <- function(matCov, pCutOff=-3) { #' #' @description TODO #' -#' @param snp.pos.Hetero For a specific gene (block) a \code{data.frame} with +#' @param snpPosHetero For a specific gene (block) a \code{data.frame} with #' lap for the SNV heterozygote dataset with #' coverage > \code{minCov}. The \code{data.frame} must contain those columns: #' 'phase', 'cnt.ref', 'cnt.alt'. TODO @@ -1163,25 +1160,25 @@ testEmptyBox <- function(matCov, pCutOff=-3) { #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @encoding UTF-8 #' @keywords internal -calcAFMLRNA <- function(snp.pos.Hetero) { +calcAFMLRNA <- function(snpPosHetero) { - listPhase <- which(snp.pos.Hetero$phase < 2) - m <- data.frame(aL=rep(0, nrow(snp.pos.Hetero)), - aH=rep(0, nrow(snp.pos.Hetero))) + listPhase <- which(snpPosHetero$phase < 2) + m <- data.frame(aL=rep(0, nrow(snpPosHetero)), + aH=rep(0, nrow(snpPosHetero))) if (length(listPhase) > 0) { mPhase <- data.frame(a1=rep(0, length(listPhase)), a2=rep(0, length(listPhase))) - if(length(which(snp.pos.Hetero$phase == 0)) > 0){ - mPhase[which(snp.pos.Hetero$phase == 0), "a1"] <- - snp.pos.Hetero[which(snp.pos.Hetero$phase == 0),"cnt.ref"] - mPhase[which(snp.pos.Hetero$phase == 0), "a2"] <- - snp.pos.Hetero[which(snp.pos.Hetero$phase == 0),"cnt.alt"] + if(length(which(snpPosHetero$phase == 0)) > 0){ + mPhase[which(snpPosHetero$phase == 0), "a1"] <- + snpPosHetero[which(snpPosHetero$phase == 0),"cnt.ref"] + mPhase[which(snpPosHetero$phase == 0), "a2"] <- + snpPosHetero[which(snpPosHetero$phase == 0),"cnt.alt"] } - if(length(which(snp.pos.Hetero$phase == 1)) > 0){ - mPhase[which(snp.pos.Hetero$phase == 1), "a2"] <- - snp.pos.Hetero[which(snp.pos.Hetero$phase == 1),"cnt.ref"] - mPhase[which(snp.pos.Hetero$phase == 1), "a1"] <- - snp.pos.Hetero[which(snp.pos.Hetero$phase == 1),"cnt.alt"] + if(length(which(snpPosHetero$phase == 1)) > 0){ + mPhase[which(snpPosHetero$phase == 1), "a2"] <- + snpPosHetero[which(snpPosHetero$phase == 1),"cnt.ref"] + mPhase[which(snpPosHetero$phase == 1), "a1"] <- + snpPosHetero[which(snpPosHetero$phase == 1),"cnt.alt"] } m1 <- sum(mPhase[,"a1"]) @@ -1191,17 +1188,17 @@ calcAFMLRNA <- function(snp.pos.Hetero) { m[listPhase, "aH"] <- mPhase[, (minPhase+1)%%2] } - listUnphase <- which(snp.pos.Hetero$phase > 1) + listUnphase <- which(snpPosHetero$phase > 1) if(length(listUnphase) > 0){ - minUnphase <- apply(snp.pos.Hetero[,c("cnt.ref", "cnt.alt")], 1, + minUnphase <- apply(snpPosHetero[,c("cnt.ref", "cnt.alt")], 1, FUN=min) - maxUnphase <- apply(snp.pos.Hetero[,c("cnt.ref", "cnt.alt")], 1, + maxUnphase <- apply(snpPosHetero[,c("cnt.ref", "cnt.alt")], 1, FUN=max) m[listUnphase, "aL"] <- minUnphase m[listUnphase, "aH"] <- maxUnphase } - d <- sum(rowSums(snp.pos.Hetero[,c("cnt.ref", "cnt.alt")])) + d <- sum(rowSums(snpPosHetero[,c("cnt.ref", "cnt.alt")])) aF <- sum(m[,"aL"]) / d lM <- log10(aF) * sum(m[,"aL"]) + log10(1- aF) * sum(m[,"aH"]) @@ -1218,7 +1215,7 @@ calcAFMLRNA <- function(snp.pos.Hetero) { #' #' @description TOREVIEW For each block evaluate score about lost of heterizygocity and allelic fration #' -#' @param snp.pos For a specific chromosome a \code{data.frame} with lap for +#' @param snpPos For a specific chromosome a \code{data.frame} with lap for #' the SNV dataset with #' coverage > \code{minCov}. #' @@ -1252,9 +1249,9 @@ calcAFMLRNA <- function(snp.pos.Hetero) { #' @importFrom S4Vectors aggregate #' @encoding UTF-8 #' @keywords internal -tableBlockAF <- function(snp.pos) { +tableBlockAF <- function(snpPos) { - listBlocks <- unique(snp.pos$block.id) + listBlocks <- unique(snpPos$block.id) # resBlock <- data.frame(block = listBlocks, # aRF = rep(-1, length(listBlocks)), @@ -1272,23 +1269,23 @@ tableBlockAF <- function(snp.pos) { resBlock <- data.frame(block = listBlocks) # Number of homozygote by block - tmp <- aggregate(snp.pos[, c( "homo"), drop = FALSE], - by = list(block=snp.pos$block.id) ,sum) + tmp <- aggregate(snpPos[, c( "homo"), drop = FALSE], + by = list(block=snpPos$block.id) ,sum) row.names(tmp) <- as.character(tmp[,1]) resBlock$nbHomo <- tmp[as.character(listBlocks),2] # Number of snv keep by block - tmp <- aggregate(snp.pos[, c( "keep"), drop = FALSE], - by = list(block=snp.pos$block.id) ,sum) + tmp <- aggregate(snpPos[, c( "keep"), drop = FALSE], + by = list(block=snpPos$block.id) ,sum) row.names(tmp) <- as.character(tmp[,1]) resBlock$nbKeep <- tmp[as.character(listBlocks),2] # Number of heterozygote by block - tmp <- aggregate(snp.pos[, c( "hetero"), drop = FALSE], - by = list(block=snp.pos$block.id) ,sum) + tmp <- aggregate(snpPos[, c( "hetero"), drop = FALSE], + by = list(block=snpPos$block.id) ,sum) row.names(tmp) <- as.character(tmp[,1]) resBlock$nbHetero <- tmp[as.character(listBlocks),2] - resBlock <- apply(resBlock, 1, FUN=function(x,snp.pos){ + resBlock <- apply(resBlock, 1, FUN=function(x,snpPos){ resBlock <- data.frame(block = x[1], nbHomo = x[2], nbKeep = x[3], @@ -1313,45 +1310,45 @@ tableBlockAF <- function(snp.pos) { # it is considered as all homozygote flag <- TRUE if (resBlock[1, "nbHetero"] == 1) { - tmp <- min(snp.pos[snp.pos$block.id == resBlock$block[1] & - snp.pos$hetero, c("cnt.ref" , "cnt.alt")])/ - sum(snp.pos[snp.pos$block.id == resBlock$block[1] & - snp.pos$hetero, c("cnt.ref" , "cnt.alt")]) + tmp <- min(snpPos[snpPos$block.id == resBlock$block[1] & + snpPos$hetero, c("cnt.ref" , "cnt.alt")])/ + sum(snpPos[snpPos$block.id == resBlock$block[1] & + snpPos$hetero, c("cnt.ref" , "cnt.alt")]) # flag is true if allelic fraction <= 0.05 flag <- ifelse(tmp > 0.05, FALSE,TRUE) } if(flag){ # List homozygote ref - listRef <- which(snp.pos$block.id == resBlock$block[1] & - snp.pos$homo & - snp.pos$cnt.ref > snp.pos$cnt.alt) + listRef <- which(snpPos$block.id == resBlock$block[1] & + snpPos$homo & + snpPos$cnt.ref > snpPos$cnt.alt) # list homozygote alt - listAlt <- which(snp.pos$block.id == resBlock$block[1] & - snp.pos$homo & - snp.pos$cnt.ref < snp.pos$cnt.alt) + listAlt <- which(snpPos$block.id == resBlock$block[1] & + snpPos$homo & + snpPos$cnt.ref < snpPos$cnt.alt) # freq of the Ref allele in population of listRef - tmp <- snp.pos$freq[listRef] + tmp <- snpPos$freq[listRef] # min freq is 0.01 tmp[which(tmp < 0.01)] <- 0.01 # log10 of the product of the frequency of the alternative allele in pop for listRef lH <- ifelse(length(listRef) > 0, sum(log10(1-tmp)*2), 0) # freq of the Ref allele in population of listAlt - tmp <- snp.pos$freq[listAlt] + tmp <- snpPos$freq[listAlt] tmp[which(tmp < 0.01)] <- 0.01 # log10 of the product of the frequency of the alternative allele in pop for listRef # plus log10 of the product of the frequency of the reference allele in pop for listAlt lH <- lH + ifelse(length(listAlt) > 0, sum(log10(tmp)*2), 0) - lM <- sum(log10(apply(snp.pos[which(snp.pos$block.id == - resBlock$block[1] & snp.pos$homo), + lM <- sum(log10(apply(snpPos[which(snpPos$block.id == + resBlock$block[1] & snpPos$homo), "freq", drop=FALSE], 1, FUN = function(x) { return(max(x^2, 2*(x * (1-x)), (1-x)^2)) }))) resBlock$sumAlleleLow[1] <- 0 - resBlock$sumAlleleHigh[1] <- sum(snp.pos[listRef, "cnt.ref"]) + - sum(snp.pos[listAlt, "cnt.alt"]) + resBlock$sumAlleleHigh[1] <- sum(snpPos[listRef, "cnt.ref"]) + + sum(snpPos[listAlt, "cnt.alt"]) } } # compute the score of the homozygote on the block @@ -1361,8 +1358,8 @@ tableBlockAF <- function(snp.pos) { # get hetero and compute AF nbHetero > 1 if (resBlock[1, "nbKeep"] > 0 & resBlock[1, "nbHetero"] > 1) { - resML <- calcAFMLRNA(snp.pos[which(snp.pos$block.id == - resBlock$block[1] & snp.pos$hetero),]) + resML <- calcAFMLRNA(snpPos[which(snpPos$block.id == + resBlock$block[1] & snpPos$hetero),]) resBlock$aFraction[1] <- resML$aFraction resBlock$lR[1] <- resML$lR @@ -1371,7 +1368,7 @@ tableBlockAF <- function(snp.pos) { resBlock$sumAlleleHigh[1] <- resML$sumAlleleHigh } return(resBlock) - }, snp.pos=snp.pos) + }, snpPos=snpPos) resBlock <- do.call(rbind, resBlock) # for (i in seq_len(length(listBlocks))) { # # start with LOH diff --git a/R/processStudy.R b/R/processStudy.R index 9a19ac873..4dd8f01bf 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2510,110 +2510,220 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, genoSource <- arg_match(genoSource) - listProfiles <- pedStudy[, "Name.ID"] + r <- runWrapperAncestry(pedStudy, studyDF, pathProfileGDS, + pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource, studyType="DNA", verbose) - createStudy2GDS1KG(pathGeno=pathGeno, pedStudy=pedStudy, - fileNameGDS=fileReferenceGDS, listProfiles=listProfiles, - studyDF=studyDF, pathProfileGDS=pathProfileGDS, genoSource=genoSource, - verbose=verbose) - - ## Open the 1KG GDS file (demo version) - gds1KG <- snpgdsOpen(fileReferenceGDS) - ## Open the 1KG GDS file and 1KG SNV Annotation file - gdsAnnot1KG <- openfn.gds(fileReferenceAnnotGDS) - - listProfileRef <- syntheticRefDF$sample.id - studyDF.syn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), - study.desc=paste0(studyDF$study.id, " synthetic data"), - study.platform=studyDF$study.platform, stringsAsFactors=FALSE) - - for(i in seq_len(length(listProfiles))) { - pruningSample(gdsReference=gds1KG, currentProfile=listProfiles[i], - studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS) - file.GDSProfile <- file.path(pathProfileGDS, - paste0(listProfiles[i], ".gds")) - add1KG2SampleGDS(gdsReference=gds1KG, fileProfileGDS=file.GDSProfile, - currentProfile=listProfiles[i], - studyID=studyDF$study.id) - addStudy1Kg(gds1KG, file.GDSProfile) - - gdsProfile <- openfn.gds(file.GDSProfile, readonly=FALSE) - - estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=gdsProfile, - currentProfile=listProfiles[i], studyID=studyDF$study.id, - chrInfo=chrInfo, verbose=verbose) - closefn.gds(gdsProfile) - - ## Add information related to the synthetic profiles in Profile GDS file - prepSynthetic(fileProfileGDS=file.GDSProfile, - listSampleRef=listProfileRef, profileID=listProfiles[i], - studyDF=studyDF.syn, prefix="1", verbose=verbose) - - resG <- syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gdsAnnot1KG, - fileProfileGDS=file.GDSProfile, profileID=listProfiles[i], - listSampleRef=listProfileRef, prefix="1") - - if(! file.exists(pathOut)) { - dir.create(pathOut) - } - spRef <- getRef1KGPop(gds1KG, "superPop") - sampleRM <- splitSelectByPop(syntheticRefDF) - - pathOutProfile <- file.path(pathOut, listProfiles[i]) - if(! file.exists(pathOutProfile)) { - dir.create(pathOutProfile) - } - - ## Open the Profile GDS file - gdsProfile <- snpgdsOpen(file.GDSProfile) - - ## This variable will contain the results from the PCA analyses - ## For each row of the sampleRM matrix - for(j in seq_len(nrow(sampleRM))) { - ## Run a PCA analysis using 1 synthetic profile from each - ## sub-continental ancestry - ## The synthetic profiles are projected on the 1KG PCA space - ## (the reference samples used to generate the synthetic profiles - ## are removed from this PCA) - ## The K-nearest neighbor analysis is done using - ## a range of K and D values - synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, - sampleRM=sampleRM[j,], studyIDSyn=studyDF.syn$study.id, - np=1L, spRef=spRef, eigenCount=15L, verbose=FALSE) - - ## Results are saved - saveRDS(synthKNN$matKNN, file.path(pathOutProfile, - paste0("KNN.synt.", listProfiles[i], ".", j, ".rds"))) - } - - ## Directory where the KNN results have been saved - pathKNN <- file.path(pathOut, listProfiles[i]) - listFilesName <- dir(file.path(pathKNN), ".rds") - ## List of the KNN result files from PCA on synthetic data - listFiles <- file.path(file.path(pathKNN) , listFilesName) - - resCall <- computeAncestryFromSyntheticFile(gdsReference=gds1KG, - gdsProfile=gdsProfile, listFiles=listFiles, - currentProfile=listProfiles[i], spRef=spRef, - studyIDSyn=studyDF.syn$study.id, np=1L) + ## Successful + return(r) +} - saveRDS(resCall, file.path(pathOut, - paste0(listProfiles[i], ".infoCall", ".rds"))) +#' @title Run most steps leading to the ancestry inference call on a specific +#' profile +#' +#' @description This function runs most steps leading to the ancestry inference +#' call on a specific profile. First, the function creates the Profile GDS file +#' for the specific profile using the information from a RDS Sample +#' description file and the 1KG reference GDS file. +#' +#' @param pedStudy a \code{data.frame} with those mandatory columns: "Name.ID", +#' "Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +#' \code{character} strings (no factor). The \code{data.frame} +#' must contain the information for all the samples passed in the +#' \code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +#' can be defined. +#' +#' @param studyDF a \code{data.frame} containing the information about the +#' study associated to the analysed sample(s). The \code{data.frame} must have +#' those 3 columns: "study.id", "study.desc", "study.platform". All columns +#' must be in \code{character} strings (no factor). +#' +#' @param pathProfileGDS a \code{character} string representing the path to +#' the directory where the GDS Profile files will be created. +#' Default: \code{NULL}. +#' +#' @param pathGeno a \code{character} string representing the path to the +#' directory containing the VCF output of SNP-pileup for each sample. The +#' SNP-pileup files must be compressed (gz files) and have the name identifiers +#' of the samples. A sample with "Name.ID" identifier would have an +#' associated SNP-pileup file called "Name.ID.txt.gz". +#' +#' @param pathOut a \code{character} string representing the path to +#' the directory where the output files are created. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Reference GDS file. The file must exist. +#' +#' @param fileReferenceAnnotGDS a \code{character} string representing the +#' file name of the Reference GDS Annotation file. The file must exist. +#' +#' @param chrInfo a \code{vector} of positive \code{integer} values +#' representing the length of the chromosomes. See 'details' section. +#' +#' @param syntheticRefDF a \code{data.frame} containing a subset of +#' reference profiles for each sub-population present in the Reference GDS +#' file. The \code{data.frame} must have those columns: +#' \itemize{ +#' \item{sample.id} { a \code{character} string representing the sample +#' identifier. } +#' \item{pop.group} { a \code{character} string representing the +#' subcontinental population assigned to the sample. } +#' \item{superPop} { a \code{character} string representing the +#' super-population assigned to the sample. } +#' } +#' +#' @param genoSource a \code{stirng} with two possible values: +#' snp-pileup and generic. It specify if the genotype files +#' are generate by snp-pileup(Facets) or generic format csv +#' with the column at least the columns: +#' Chromosome,Position,Ref,Alt,Count,File1R,File1A +#' where Count is the deep at the position, +#' FileR is the deep of the reference allele, and +#' File1A is the deep of the specific alternative allele +#' +#' @param verbose a \code{logical} indicating if messages should be printed +#' to show how the different steps in the function. Default: \code{FALSE}. +#' +#' @return The integer \code{0L} when successful. See details section for +#' more information about the generated output files. +#' +#' @details +#' +#' The runExomeAncestry() function generates 3 types of files +#' in the OUTPUT directory. +#' \itemize{ +#' \item{Ancestry Inference}{The ancestry inference CSV file +#' (".Ancestry.csv" file)} +#' \item{Inference Informaton}{The inference information RDS file +#' (".infoCall.rds" file)} +#' \item{Synthetic Information}{The parameter information RDS files +#' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +#' } +#' +#' In addition, a sub-directory (named using the profile ID) is +#' also created. +#' +#' @references +#' +#' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +#' Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +#' of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +#' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +#' +#' @examples +#' +#' ## Required library for GDS +#' library(gdsfmt) +#' +#' ## Path to the demo 1KG GDS file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ################################################################# +#' ## The path and file name for the PED RDS file +#' ## will the information about the analyzed samples +#' ################################################################# +#' filePED <- file.path(dataDir, "example", "pedEx.rds") +#' ped <- readRDS(filePED) +#' head(ped) +#' +#' ################################################################# +#' ## The 1KG GDS file and the 1KG SNV Annotation GDS file +#' ## need to be located in the same directory +#' ## Note that the 1KG GDS file used for this example is a +#' ## simplified version and CANNOT be used for any real analysis +#' ################################################################# +#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' +#' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") +#' fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +#' +#' ################################################################# +#' ## The Sample SNP pileup files (one per sample) need +#' ## to be located in the same directory. +#' ################################################################# +#' pathGeno <- file.path(dataDir, "example", "snpPileup") +#' +#' ################################################################# +#' ## The path where the Profile GDS Files (one per sample) +#' ## will be created need to be specified. +#' ################################################################# +#' pathProfileGDS <- file.path(dataDir, "example", "out.tmp") +#' +#' pathOut <- file.path(dataDir, "example", "res.out") +#' +#' ################################################################# +#' ## A data frame containing general information about the study +#' ## is also required. The data frame must have +#' ## those 3 columns: "studyID", "study.desc", "study.platform" +#' ################################################################# +#' studyDF <- data.frame(study.id="MYDATA", +#' study.desc="Description", +#' study.platform="PLATFORM", +#' stringsAsFactors=FALSE) +#' +#' #################################################################### +#' ## Fix seed to ensure reproducible results +#' #################################################################### +#' set.seed(3043) +#' +#' gds1KG <- snpgdsOpen(fileReferenceGDS) +#' dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +#' closefn.gds(gds1KG) +#' +#' ## Chromosome length information for hg38 +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, +#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, +#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, +#' 156040895L, 57227415L, 16569L) +#' +#' ## A formal way to get the chromosome length information for hg38 +#' ## library(GenomeInfoDb) +#' ## library(BSgenome.Hsapiens.UCSC.hg38) +#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] +#' +#' \dontrun{ +#' runExomeAncestry(pedStudy=ped, studyDF=studyDF, +#' pathProfileGDS=pathProfileGDS, +#' pathGeno=pathGeno, +#' pathOut=pathOut, +#' fileReferenceGDS=fileReferenceGDS, +#' fileReferenceAnnotGDS=fileAnnotGDS, +#' chrInfo=chrInfo, +#' syntheticRefDF=dataRef, +#' genoSource="snp-pileup") +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' } +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom utils write.csv +#' @importFrom rlang arg_match +#' @encoding UTF-8 +#' @export +runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, + pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic"), verbose=FALSE) { - write.csv(x=resCall$Ancestry, file=file.path(pathOut, - paste0(listProfiles[i], ".Ancestry",".csv")), quote=FALSE, - row.names=FALSE) + ## Validate parameters + validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, + syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) - ## Close Profile GDS file (important) - closefn.gds(gdsProfile) - } + genoSource <- arg_match(genoSource) - ## Close all GDS files - closefn.gds(gds1KG) - closefn.gds(gdsAnnot1KG) + r <- runWrapperAncestry(pedStudy, studyDF, pathProfileGDS, + pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource, studyType="RNA", verbose) ## Successful - return(0L) + return(r) } - diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 32dbfbecf..7070bedc5 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2019,3 +2019,550 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, return(res) } +#' @title TOREVIEW Run most steps leading to the ancestry inference call on a specific +#' profile +#' +#' @description This function runs most steps leading to the ancestry inference +#' call on a specific profile. First, the function creates the Profile GDS file +#' for the specific profile using the information from a RDS Sample +#' description file and the 1KG reference GDS file. +#' +#' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} +#' (a GDS file), the opened Reference GDS file. +#' +#' @param gdsRefAnnot an object of class \code{\link[gdsfmt]{gds.class}} +#' (a GDS file), the opened Reference SNV Annotation GDS file. +#' This parameter is RNA specific. +#' +#' @param studyDF a \code{data.frame} containing the information about the +#' study associated to the analysed sample(s). The \code{data.frame} must have +#' those 3 columns: "study.id", "study.desc", "study.platform". All columns +#' must be in \code{character} strings (no factor). +#' +#' @param currentProfile a \code{character} string representing the profile +#' identifier. +#' +#' @param pathProfileGDS a \code{character} string representing the path to +#' the directory where the GDS Profile files will be created. +#' Default: \code{NULL}. +#' +#' @param pathOut a \code{character} string representing the path to +#' the directory where the output files are created. +#' +#' @param chrInfo a \code{vector} of positive \code{integer} values +#' representing the length of the chromosomes. See 'details' section. +#' +#' @param syntheticRefDF a \code{data.frame} containing a subset of +#' reference profiles for each sub-population present in the Reference GDS +#' file. The \code{data.frame} must have those columns: +#' \itemize{ +#' \item{sample.id} { a \code{character} string representing the sample +#' identifier. } +#' \item{pop.group} { a \code{character} string representing the +#' subcontinental population assigned to the sample. } +#' \item{superPop} { a \code{character} string representing the +#' super-population assigned to the sample. } +#' } +#' +#' @param studyDFSyn a \code{data.frame} containing the information about the +#' synthetic data to the analysed sample(s). The \code{data.frame} must have +#' those 3 columns: "study.id", "study.desc", "study.platform". All columns +#' must be in \code{character} strings (no factor). +#' +#' @param listProfileRef a \code{vector} of \code{character} string +#' representing the +#' identifiers of the selected 1KG profiles that will be used as reference to +#' generate the synthetic profiles. +#' +#' @param studyType a \code{character} string representing the type of study. +#' The possible choices are: "DNA" and "RNA". The type of study affects the +#' way the estimation of the allelic fraction is done. Default: \code{"DNA"}. +#' +#' @param verbose a \code{logical} indicating if messages should be printed +#' to show how the different steps in the function. Default: \code{FALSE}. +#' +#' @return The integer \code{0L} when successful. See details section for +#' more information about the generated output files. +#' +#' @details +#' +#' The runWrapperAncestry() function generates 3 types of files +#' in the OUTPUT directory. +#' \itemize{ +#' \item{Ancestry Inference}{The ancestry inference CSV file +#' (".Ancestry.csv" file)} +#' \item{Inference Informaton}{The inference information RDS file +#' (".infoCall.rds" file)} +#' \item{Synthetic Information}{The parameter information RDS files +#' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +#' } +#' +#' In addition, a sub-directory (named using the profile ID) is +#' also created. +#' +#' @references +#' +#' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +#' Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +#' of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +#' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +#' +#' @examples +#' +#' ## Required library for GDS +#' library(gdsfmt) +#' # TODO +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom utils write.csv +#' @importFrom rlang arg_match +#' @encoding UTF-8 +#' @keywords @internal +runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfile, pathProfileGDS, + pathOut, chrInfo, syntheticRefDF, studyDFSyn, listProfileRef, + studyType=c("DNA", "RNA"), verbose=FALSE) { + + ## Validate parameters TODO + # validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, + # pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, + # fileReferenceGDS=fileReferenceGDS, + # fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, + # syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) + + studyType <- arg_match(studyType) + + pruningSample(gdsReference=gdsReference, currentProfile=currentProfile, + studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS) + fileGDSProfile <- file.path(pathProfileGDS, + paste0(currentProfile, ".gds")) + add1KG2SampleGDS(gdsReference=gdsReference, fileProfileGDS=fileGDSProfile, + currentProfile=currentProfile, + studyID=studyDF$study.id) + addStudy1Kg(gdsReference, fileGDSProfile) + + gdsProfile <- openfn.gds(fileGDSProfile, readonly=FALSE) + + estimateAllelicFraction(gdsReference=gdsReference, gdsProfile=gdsProfile, + currentProfile=currentProfile, studyID=studyDF$study.id, + chrInfo=chrInfo, studyType=studyType, gdsRefAnnot=gdsRefAnnot, verbose=verbose) + closefn.gds(gdsProfile) + + ## Add information related to the synthetic profiles in Profile GDS file + prepSynthetic(fileProfileGDS=fileGDSProfile, + listSampleRef=listProfileRef, profileID=currentProfile, + studyDF=studyDFSyn, prefix="1", verbose=verbose) + + resG <- syntheticGeno(gdsReference=gdsReference, gdsRefAnnot=gdsRefAnnot, + fileProfileGDS=fileGDSProfile, profileID=currentProfile, + listSampleRef=listProfileRef, prefix="1") + + if(! file.exists(pathOut)) { + dir.create(pathOut) + } + spRef <- getRef1KGPop(gdsReference, "superPop") + sampleRM <- splitSelectByPop(syntheticRefDF) + + pathOutProfile <- file.path(pathOut, currentProfile) + if(! file.exists(pathOutProfile)) { + dir.create(pathOutProfile) + } + + ## Open the Profile GDS file + gdsProfile <- snpgdsOpen(fileGDSProfile) + + ## FOR_LOOP modification to be validated by Pascal + ## Remove commented code and this text after validation + + ## This variable will contain the results from the PCA analyses + ## For each row of the sampleRM matrix + apply(t(t(seq_len(nrow(sampleRM)))), 1, FUN=function(x, sampleRM, gdsProfile, + studyDFSyn, spRef, + pathOutProfile, + currentProfile){ + synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, + sampleRM=sampleRM[x,], + studyIDSyn=studyDFSyn$study.id, + np=1L, spRef=spRef, + eigenCount=15L, + verbose=verbose) + + ## Results are saved + saveRDS(synthKNN$matKNN, file.path(pathOutProfile, + paste0("KNN.synt.", currentProfile, ".", x, ".rds"))) + return(NULL) + }, sampleRM=sampleRM, gdsProfile=gdsProfile, + studyDFSyn=studyDFSyn, spRef=spRef, pathOutProfile=pathOutProfile, + currentProfile=currentProfile) + + # for(j in seq_len(nrow(sampleRM))) { + # ## Run a PCA analysis using 1 synthetic profile from each + # ## sub-continental ancestry + # ## The synthetic profiles are projected on the 1KG PCA space + # ## (the reference samples used to generate the synthetic profiles + # ## are removed from this PCA) + # ## The K-nearest neighbor analysis is done using + # ## a range of K and D values + # synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, + # sampleRM=sampleRM[j,], studyIDSyn=studyDFSyn$study.id, + # np=1L, spRef=spRef, eigenCount=15L, verbose=FALSE) + # + # ## Results are saved + # saveRDS(synthKNN$matKNN, file.path(pathOutProfile, + # paste0("KNN.synt.", currentProfile, ".", j, ".rds"))) + # } + + ## Directory where the KNN results have been saved + pathKNN <- file.path(pathOut, currentProfile) + listFilesName <- dir(file.path(pathKNN), ".rds") + ## List of the KNN result files from PCA on synthetic data + listFiles <- file.path(file.path(pathKNN) , listFilesName) + + resCall <- computeAncestryFromSyntheticFile(gdsReference=gdsReference, + gdsProfile=gdsProfile, listFiles=listFiles, + currentProfile=currentProfile, spRef=spRef, + studyIDSyn=studyDFSyn$study.id, np=1L) + + saveRDS(resCall, file.path(pathOut, + paste0(currentProfile, ".infoCall", ".rds"))) + + write.csv(x=resCall$Ancestry, file=file.path(pathOut, + paste0(currentProfile, ".Ancestry",".csv")), quote=FALSE, + row.names=FALSE) + + ## Close Profile GDS file (important) + closefn.gds(gdsProfile) + + return(0L) +} + + +#' @title TOREVIEW Run most steps leading to the ancestry inference call on a specific +#' profile +#' +#' @description This function runs most steps leading to the ancestry inference +#' call on a specific profile. First, the function creates the Profile GDS file +#' for the specific profile using the information from a RDS Sample +#' description file and the 1KG reference GDS file. +#' +#' @param pedStudy a \code{data.frame} with those mandatory columns: "Name.ID", +#' "Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +#' \code{character} strings (no factor). The \code{data.frame} +#' must contain the information for all the samples passed in the +#' \code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +#' can be defined. +#' +#' @param studyDF a \code{data.frame} containing the information about the +#' study associated to the analysed sample(s). The \code{data.frame} must have +#' those 3 columns: "study.id", "study.desc", "study.platform". All columns +#' must be in \code{character} strings (no factor). +#' +#' @param pathProfileGDS a \code{character} string representing the path to +#' the directory where the GDS Profile files will be created. +#' Default: \code{NULL}. +#' +#' @param pathGeno a \code{character} string representing the path to the +#' directory containing the VCF output of SNP-pileup for each sample. The +#' SNP-pileup files must be compressed (gz files) and have the name identifiers +#' of the samples. A sample with "Name.ID" identifier would have an +#' associated SNP-pileup file called "Name.ID.txt.gz". +#' +#' @param pathOut a \code{character} string representing the path to +#' the directory where the output files are created. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Reference GDS file. The file must exist. +#' +#' @param fileReferenceAnnotGDS a \code{character} string representing the +#' file name of the Reference GDS Annotation file. The file must exist. +#' +#' @param chrInfo a \code{vector} of positive \code{integer} values +#' representing the length of the chromosomes. See 'details' section. +#' +#' @param syntheticRefDF a \code{data.frame} containing a subset of +#' reference profiles for each sub-population present in the Reference GDS +#' file. The \code{data.frame} must have those columns: +#' \itemize{ +#' \item{sample.id} { a \code{character} string representing the sample +#' identifier. } +#' \item{pop.group} { a \code{character} string representing the +#' subcontinental population assigned to the sample. } +#' \item{superPop} { a \code{character} string representing the +#' super-population assigned to the sample. } +#' } +#' +#' @param studyType a \code{character} string representing the type of study. +#' The possible choices are: "DNA" and "RNA". The type of study affects the +#' way the estimation of the allelic fraction is done. Default: \code{"DNA"}. +#' +#' @param genoSource a \code{stirng} with two possible values: +#' snp-pileup and generic. It specify if the genotype files +#' are generate by snp-pileup(Facets) or generic format csv +#' with the column at least the columns: +#' Chromosome,Position,Ref,Alt,Count,File1R,File1A +#' where Count is the deep at the position, +#' FileR is the deep of the reference allele, and +#' File1A is the deep of the specific alternative allele +#' +#' @param verbose a \code{logical} indicating if messages should be printed +#' to show how the different steps in the function. Default: \code{FALSE}. +#' +#' @return The integer \code{0L} when successful. See details section for +#' more information about the generated output files. +#' +#' @details +#' +#' The runWrapperAncestry() function generates 3 types of files +#' in the OUTPUT directory. +#' \itemize{ +#' \item{Ancestry Inference}{The ancestry inference CSV file +#' (".Ancestry.csv" file)} +#' \item{Inference Informaton}{The inference information RDS file +#' (".infoCall.rds" file)} +#' \item{Synthetic Information}{The parameter information RDS files +#' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +#' } +#' +#' In addition, a sub-directory (named using the profile ID) is +#' also created. +#' +#' @references +#' +#' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +#' Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +#' of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +#' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +#' +#' @examples +#' +#' ## Required library for GDS +#' library(gdsfmt) +#' +#' ## Path to the demo 1KG GDS file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ################################################################# +#' ## The path and file name for the PED RDS file +#' ## will the information about the analyzed samples +#' ################################################################# +#' filePED <- file.path(dataDir, "example", "pedEx.rds") +#' ped <- readRDS(filePED) +#' head(ped) +#' +#' ################################################################# +#' ## The 1KG GDS file and the 1KG SNV Annotation GDS file +#' ## need to be located in the same directory +#' ## Note that the 1KG GDS file used for this example is a +#' ## simplified version and CANNOT be used for any real analysis +#' ################################################################# +#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' +#' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") +#' fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +#' +#' ################################################################# +#' ## The Sample SNP pileup files (one per sample) need +#' ## to be located in the same directory. +#' ################################################################# +#' pathGeno <- file.path(dataDir, "example", "snpPileup") +#' +#' ################################################################# +#' ## The path where the Profile GDS Files (one per sample) +#' ## will be created need to be specified. +#' ################################################################# +#' pathProfileGDS <- file.path(dataDir, "example", "out.tmp") +#' +#' pathOut <- file.path(dataDir, "example", "res.out") +#' +#' ################################################################# +#' ## A data frame containing general information about the study +#' ## is also required. The data frame must have +#' ## those 3 columns: "studyID", "study.desc", "study.platform" +#' ################################################################# +#' studyDF <- data.frame(study.id="MYDATA", +#' study.desc="Description", +#' study.platform="PLATFORM", +#' stringsAsFactors=FALSE) +#' +#' #################################################################### +#' ## Fix seed to ensure reproducible results +#' #################################################################### +#' set.seed(3043) +#' +#' gds1KG <- snpgdsOpen(fileReferenceGDS) +#' dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +#' closefn.gds(gds1KG) +#' +#' ## Chromosome length information for hg38 +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, +#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, +#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, +#' 156040895L, 57227415L, 16569L) +#' +#' ## A formal way to get the chromosome length information for hg38 +#' ## library(GenomeInfoDb) +#' ## library(BSgenome.Hsapiens.UCSC.hg38) +#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] +#' +#' \dontrun{ +#' runWrapperAncestry(pedStudy=ped, studyDF=studyDF, +#' pathProfileGDS=pathProfileGDS, +#' pathGeno=pathGeno, +#' pathOut=pathOut, +#' fileReferenceGDS=fileReferenceGDS, +#' fileReferenceAnnotGDS=fileAnnotGDS, +#' chrInfo=chrInfo, +#' syntheticRefDF=dataRef, +#' studyType="DNA" +#' genoSource="snp-pileup") +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' } +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom utils write.csv +#' @importFrom rlang arg_match +#' @encoding UTF-8 +#' @keywords @internal +runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, + pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic"), studyType=c("DNA", "RNA"), verbose=FALSE) { + + ## Validate parameters + validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, + syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) + + genoSource <- arg_match(genoSource) + + listProfiles <- pedStudy[, "Name.ID"] + + createStudy2GDS1KG(pathGeno=pathGeno, pedStudy=pedStudy, + fileNameGDS=fileReferenceGDS, listProfiles=listProfiles, + studyDF=studyDF, pathProfileGDS=pathProfileGDS, genoSource=genoSource, + verbose=verbose) + + ## Open the 1KG GDS file (demo version) + gdsReference <- snpgdsOpen(fileReferenceGDS) + ## Open the 1KG GDS file and 1KG SNV Annotation file + gdsRefAnnot <- openfn.gds(fileReferenceAnnotGDS) + + listProfileRef <- syntheticRefDF$sample.id + studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), + study.desc=paste0(studyDF$study.id, " synthetic data"), + study.platform=studyDF$study.platform, stringsAsFactors=FALSE) + + ## FOR_LOOP modification to be validated by Pascal + ## Remove commented code and this text after validation + + apply(pedStudy[,"Name.ID", drop=FALSE],1,FUN=function(x,gdsReference, gdsRefAnnot, + studyDF,pathProfileGDS, + pathOut, chrInfo, syntheticRefDF, studyDFSyn, + listProfileRef, + studyType, verbose){ + runProfileAncestry(gdsReference, gdsRefAnnot, studyDF, + currentProfile=x, pathProfileGDS, + pathOut, chrInfo, + syntheticRefDF, studyDFSyn, + listProfileRef, + studyType, verbose) + return(NULL) + }, gdsReference=gdsReference, gdsRefAnnot=gdsRefAnnot, + studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathOut=pathOut, + chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, + listProfileRef=listProfileRef, + studyDFSyn=studyDFSyn, studyType=studyType, verbose=verbose) + + # for(i in seq_len(length(listProfiles))) { + # pruningSample(gdsReference=gds1KG, currentProfile=listProfiles[i], + # studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS) + # file.GDSProfile <- file.path(pathProfileGDS, + # paste0(listProfiles[i], ".gds")) + # add1KG2SampleGDS(gdsReference=gds1KG, fileProfileGDS=file.GDSProfile, + # currentProfile=listProfiles[i], + # studyID=studyDF$study.id) + # addStudy1Kg(gds1KG, file.GDSProfile) + # + # gdsProfile <- openfn.gds(file.GDSProfile, readonly=FALSE) + # + # estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=gdsProfile, + # currentProfile=listProfiles[i], studyID=studyDF$study.id, + # chrInfo=chrInfo, verbose=verbose) + # closefn.gds(gdsProfile) + # + # ## Add information related to the synthetic profiles in Profile GDS file + # prepSynthetic(fileProfileGDS=file.GDSProfile, + # listSampleRef=listProfileRef, profileID=listProfiles[i], + # studyDF=studyDF.syn, prefix="1", verbose=verbose) + # + # resG <- syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gdsAnnot1KG, + # fileProfileGDS=file.GDSProfile, profileID=listProfiles[i], + # listSampleRef=listProfileRef, prefix="1") + # + # if(! file.exists(pathOut)) { + # dir.create(pathOut) + # } + # spRef <- getRef1KGPop(gds1KG, "superPop") + # sampleRM <- splitSelectByPop(syntheticRefDF) + # + # pathOutProfile <- file.path(pathOut, listProfiles[i]) + # if(! file.exists(pathOutProfile)) { + # dir.create(pathOutProfile) + # } + # + # ## Open the Profile GDS file + # gdsProfile <- snpgdsOpen(file.GDSProfile) + # + # ## This variable will contain the results from the PCA analyses + # ## For each row of the sampleRM matrix + # for(j in seq_len(nrow(sampleRM))) { + # ## Run a PCA analysis using 1 synthetic profile from each + # ## sub-continental ancestry + # ## The synthetic profiles are projected on the 1KG PCA space + # ## (the reference samples used to generate the synthetic profiles + # ## are removed from this PCA) + # ## The K-nearest neighbor analysis is done using + # ## a range of K and D values + # synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, + # sampleRM=sampleRM[j,], studyIDSyn=studyDF.syn$study.id, + # np=1L, spRef=spRef, eigenCount=15L, verbose=FALSE) + # + # ## Results are saved + # saveRDS(synthKNN$matKNN, file.path(pathOutProfile, + # paste0("KNN.synt.", listProfiles[i], ".", j, ".rds"))) + # } + # + # ## Directory where the KNN results have been saved + # pathKNN <- file.path(pathOut, listProfiles[i]) + # listFilesName <- dir(file.path(pathKNN), ".rds") + # ## List of the KNN result files from PCA on synthetic data + # listFiles <- file.path(file.path(pathKNN) , listFilesName) + # + # resCall <- computeAncestryFromSyntheticFile(gdsReference=gds1KG, + # gdsProfile=gdsProfile, listFiles=listFiles, + # currentProfile=listProfiles[i], spRef=spRef, + # studyIDSyn=studyDF.syn$study.id, np=1L) + # + # saveRDS(resCall, file.path(pathOut, + # paste0(listProfiles[i], ".infoCall", ".rds"))) + # + # write.csv(x=resCall$Ancestry, file=file.path(pathOut, + # paste0(listProfiles[i], ".Ancestry",".csv")), quote=FALSE, + # row.names=FALSE) + # + # ## Close Profile GDS file (important) + # closefn.gds(gdsProfile) + # } + + ## Close all GDS files + closefn.gds(gdsReference) + closefn.gds(gdsRefAnnot) + + ## Successful + return(0L) +} diff --git a/man/calcAFMLRNA.Rd b/man/calcAFMLRNA.Rd index c9081599e..c40f66477 100644 --- a/man/calcAFMLRNA.Rd +++ b/man/calcAFMLRNA.Rd @@ -5,10 +5,10 @@ \alias{calcAFMLRNA} \title{TODO} \usage{ -calcAFMLRNA(snp.pos.Hetero) +calcAFMLRNA(snpPosHetero) } \arguments{ -\item{snp.pos.Hetero}{For a specific gene (block) a \code{data.frame} with +\item{snpPosHetero}{For a specific gene (block) a \code{data.frame} with lap for the SNV heterozygote dataset with coverage > \code{minCov}. The \code{data.frame} must contain those columns: 'phase', 'cnt.ref', 'cnt.alt'. TODO} diff --git a/man/computeAlleleFraction.Rd b/man/computeAlleleFraction.Rd index d17fa259e..78c2a991f 100644 --- a/man/computeAlleleFraction.Rd +++ b/man/computeAlleleFraction.Rd @@ -5,10 +5,10 @@ \alias{computeAlleleFraction} \title{TODO} \usage{ -computeAlleleFraction(snp.pos, w = 10, cutOff = -3) +computeAlleleFraction(snpPos, w = 10, cutOff = -3) } \arguments{ -\item{snp.pos}{a \code{data.frame} containing the genotype information for +\item{snpPos}{a \code{data.frame} containing the genotype information for a SNV dataset. TODO} \item{w}{a single positive \code{numeric} representing the size of the @@ -21,9 +21,9 @@ Default: \code{10}.} a \code{matrix} of \code{numeric} with 3 columns where each row represent a segment of imbalanced SNVs. The first column represents the position, in -\code{snp.pos}, of the first +\code{snpPos}, of the first SNV in the segment. The second column represents the position, in the -\code{snp.pos}, of the last SNV in the segment. The third column represents +\code{snpPos}, of the last SNV in the segment. The third column represents the lower allelic frequency of the segment and is \code{NA} when the value cannot be calculated. The value \code{NULL} is returned when none of the SNVs @@ -50,7 +50,7 @@ snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), stringAsFactor=FALSE) ## The function returns NULL when there is not imbalanced SNVs -RAIDS:::computeAlleleFraction(snp.pos=snpInfo, w=10, cutOff=-3) +RAIDS:::computeAlleleFraction(snpPos=snpInfo, w=10, cutOff=-3) } diff --git a/man/computeAllelicImbDNAChr.Rd b/man/computeAllelicImbDNAChr.Rd index 004bd05de..124097f99 100644 --- a/man/computeAllelicImbDNAChr.Rd +++ b/man/computeAllelicImbDNAChr.Rd @@ -5,10 +5,10 @@ \alias{computeAllelicImbDNAChr} \title{Verify if SNVs are in an imbalance region} \usage{ -computeAllelicImbDNAChr(snp.pos, chr, wAR = 10, cutOffEmptyBox = -3) +computeAllelicImbDNAChr(snpPos, chr, wAR = 10, cutOffEmptyBox = -3) } \arguments{ -\item{snp.pos}{a \code{data.frame} containing the SNV information for the +\item{snpPos}{a \code{data.frame} containing the SNV information for the chromosome specified by the \code{chr} argument. The \code{data.frame} must contain: \itemize{ @@ -50,7 +50,7 @@ a \code{vector} of \code{integer} indicating if the SNV is in an imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; 1=tested positive for imbalance in at least 1 window). The vector as an entry for each SNV present in the -input \code{snp.pos}. +input \code{snpPos}. } \description{ The function verifies, for each SNV present in the data frame, @@ -94,7 +94,7 @@ snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), ## The function returns a data frame containing the information about the ## LOH regions in the specified chromosome -result <- RAIDS:::computeAllelicImbDNAChr(snp.pos=snpInfo, chr=1, wAR=10, +result <- RAIDS:::computeAllelicImbDNAChr(snpPos=snpInfo, chr=1, wAR=10, cutOffEmptyBox=-3) head(result) diff --git a/man/computeLOHBlocksDNAChr.Rd b/man/computeLOHBlocksDNAChr.Rd index 20e6908bd..c76eef2af 100644 --- a/man/computeLOHBlocksDNAChr.Rd +++ b/man/computeLOHBlocksDNAChr.Rd @@ -5,7 +5,7 @@ \alias{computeLOHBlocksDNAChr} \title{Identify regions of LOH on one chromosome using homozygote SNVs} \usage{ -computeLOHBlocksDNAChr(gdsReference, chrInfo, snp.pos, chr, genoN = 1e-04) +computeLOHBlocksDNAChr(gdsReference, chrInfo, snpPos, chr, genoN = 1e-04) } \arguments{ \item{gdsReference}{an object of class @@ -16,7 +16,7 @@ opened Reference GDS file.} the chromosomes. As an example, the information ca be obtained from package 'BSgenome.Hsapiens.UCSC.hg38'.} -\item{snp.pos}{a \code{data.frame} containing the SNV information for the +\item{snpPos}{a \code{data.frame} containing the SNV information for the chromosome specified by the \code{chr} argument. The \code{data.frame} must contain: \itemize{ @@ -113,7 +113,7 @@ snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), ## The function returns a data frame containing the information about the ## LOH regions in the specified chromosome result <- RAIDS:::computeLOHBlocksDNAChr(gdsReference=gds1KG, - chrInfo=chrInfo, snp.pos=snpInfo, chr=1L, genoN=0.0001) + chrInfo=chrInfo, snpPos=snpInfo, chr=1L, genoN=0.0001) head(result) ## Close Reference GDS file (important) diff --git a/man/getTableSNV.Rd b/man/getTableSNV.Rd index 723225449..77f3d9f06 100644 --- a/man/getTableSNV.Rd +++ b/man/getTableSNV.Rd @@ -52,7 +52,7 @@ the SNV.} the reference allele.} \item{cnt.alt} {a single \code{integer} representing the coverage for the alternative allele.} -\item{snp.pos} {a single \code{integer} representing the SNV position.} +\item{snpPos} {a single \code{integer} representing the SNV position.} \item{snp.chr} {a single \code{integer} representing the SNV chromosome.} \item{normal.geno} {a single \code{numeric} indicating the genotype of the SNV. The possibles are: \code{0} (wild-type homozygote), \code{1} diff --git a/man/runProfileAncestry.Rd b/man/runProfileAncestry.Rd new file mode 100644 index 000000000..679948a4b --- /dev/null +++ b/man/runProfileAncestry.Rd @@ -0,0 +1,120 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/processStudy_internal.R +\encoding{UTF-8} +\name{runProfileAncestry} +\alias{runProfileAncestry} +\title{TOREVIEW Run most steps leading to the ancestry inference call on a specific +profile} +\usage{ +runProfileAncestry( + gdsReference, + gdsRefAnnot, + studyDF, + currentProfile, + pathProfileGDS, + pathOut, + chrInfo, + syntheticRefDF, + studyDFSyn, + listProfileRef, + studyType = c("DNA", "RNA"), + verbose = FALSE +) +} +\arguments{ +\item{gdsReference}{an object of class \code{\link[gdsfmt]{gds.class}} +(a GDS file), the opened Reference GDS file.} + +\item{gdsRefAnnot}{an object of class \code{\link[gdsfmt]{gds.class}} +(a GDS file), the opened Reference SNV Annotation GDS file. +This parameter is RNA specific.} + +\item{studyDF}{a \code{data.frame} containing the information about the +study associated to the analysed sample(s). The \code{data.frame} must have +those 3 columns: "study.id", "study.desc", "study.platform". All columns +must be in \code{character} strings (no factor).} + +\item{currentProfile}{a \code{character} string representing the profile +identifier.} + +\item{pathProfileGDS}{a \code{character} string representing the path to +the directory where the GDS Profile files will be created. +Default: \code{NULL}.} + +\item{pathOut}{a \code{character} string representing the path to +the directory where the output files are created.} + +\item{chrInfo}{a \code{vector} of positive \code{integer} values +representing the length of the chromosomes. See 'details' section.} + +\item{syntheticRefDF}{a \code{data.frame} containing a subset of +reference profiles for each sub-population present in the Reference GDS +file. The \code{data.frame} must have those columns: +\itemize{ +\item{sample.id} { a \code{character} string representing the sample +identifier. } +\item{pop.group} { a \code{character} string representing the +subcontinental population assigned to the sample. } +\item{superPop} { a \code{character} string representing the +super-population assigned to the sample. } +}} + +\item{studyDFSyn}{a \code{data.frame} containing the information about the +synthetic data to the analysed sample(s). The \code{data.frame} must have +those 3 columns: "study.id", "study.desc", "study.platform". All columns +must be in \code{character} strings (no factor).} + +\item{listProfileRef}{a \code{vector} of \code{character} string +representing the +identifiers of the selected 1KG profiles that will be used as reference to +generate the synthetic profiles.} + +\item{studyType}{a \code{character} string representing the type of study. +The possible choices are: "DNA" and "RNA". The type of study affects the +way the estimation of the allelic fraction is done. Default: \code{"DNA"}.} + +\item{verbose}{a \code{logical} indicating if messages should be printed +to show how the different steps in the function. Default: \code{FALSE}.} +} +\value{ +The integer \code{0L} when successful. See details section for +more information about the generated output files. +} +\description{ +This function runs most steps leading to the ancestry inference +call on a specific profile. First, the function creates the Profile GDS file +for the specific profile using the information from a RDS Sample +description file and the 1KG reference GDS file. +} +\details{ +The runWrapperAncestry() function generates 3 types of files +in the OUTPUT directory. +\itemize{ +\item{Ancestry Inference}{The ancestry inference CSV file +(".Ancestry.csv" file)} +\item{Inference Informaton}{The inference information RDS file +(".infoCall.rds" file)} +\item{Synthetic Information}{The parameter information RDS files +from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +} + +In addition, a sub-directory (named using the profile ID) is +also created. +} +\examples{ + +## Required library for GDS +library(gdsfmt) +# TODO + +} +\references{ +Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{@internal} diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd new file mode 100644 index 000000000..9a1119610 --- /dev/null +++ b/man/runRNAAncestry.Rd @@ -0,0 +1,204 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/processStudy.R +\encoding{UTF-8} +\name{runRNAAncestry} +\alias{runRNAAncestry} +\title{Run most steps leading to the ancestry inference call on a specific +profile} +\usage{ +runRNAAncestry( + pedStudy, + studyDF, + pathProfileGDS, + pathGeno, + pathOut, + fileReferenceGDS, + fileReferenceAnnotGDS, + chrInfo, + syntheticRefDF, + genoSource = c("snp-pileup", "generic"), + verbose = FALSE +) +} +\arguments{ +\item{pedStudy}{a \code{data.frame} with those mandatory columns: "Name.ID", +"Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +\code{character} strings (no factor). The \code{data.frame} +must contain the information for all the samples passed in the +\code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +can be defined.} + +\item{studyDF}{a \code{data.frame} containing the information about the +study associated to the analysed sample(s). The \code{data.frame} must have +those 3 columns: "study.id", "study.desc", "study.platform". All columns +must be in \code{character} strings (no factor).} + +\item{pathProfileGDS}{a \code{character} string representing the path to +the directory where the GDS Profile files will be created. +Default: \code{NULL}.} + +\item{pathGeno}{a \code{character} string representing the path to the +directory containing the VCF output of SNP-pileup for each sample. The +SNP-pileup files must be compressed (gz files) and have the name identifiers +of the samples. A sample with "Name.ID" identifier would have an +associated SNP-pileup file called "Name.ID.txt.gz".} + +\item{pathOut}{a \code{character} string representing the path to +the directory where the output files are created.} + +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Reference GDS file. The file must exist.} + +\item{fileReferenceAnnotGDS}{a \code{character} string representing the +file name of the Reference GDS Annotation file. The file must exist.} + +\item{chrInfo}{a \code{vector} of positive \code{integer} values +representing the length of the chromosomes. See 'details' section.} + +\item{syntheticRefDF}{a \code{data.frame} containing a subset of +reference profiles for each sub-population present in the Reference GDS +file. The \code{data.frame} must have those columns: +\itemize{ +\item{sample.id} { a \code{character} string representing the sample +identifier. } +\item{pop.group} { a \code{character} string representing the +subcontinental population assigned to the sample. } +\item{superPop} { a \code{character} string representing the +super-population assigned to the sample. } +}} + +\item{genoSource}{a \code{stirng} with two possible values: +snp-pileup and generic. It specify if the genotype files +are generate by snp-pileup(Facets) or generic format csv +with the column at least the columns: +Chromosome,Position,Ref,Alt,Count,File1R,File1A +where Count is the deep at the position, +FileR is the deep of the reference allele, and +File1A is the deep of the specific alternative allele} + +\item{verbose}{a \code{logical} indicating if messages should be printed +to show how the different steps in the function. Default: \code{FALSE}.} +} +\value{ +The integer \code{0L} when successful. See details section for +more information about the generated output files. +} +\description{ +This function runs most steps leading to the ancestry inference +call on a specific profile. First, the function creates the Profile GDS file +for the specific profile using the information from a RDS Sample +description file and the 1KG reference GDS file. +} +\details{ +The runExomeAncestry() function generates 3 types of files +in the OUTPUT directory. +\itemize{ +\item{Ancestry Inference}{The ancestry inference CSV file +(".Ancestry.csv" file)} +\item{Inference Informaton}{The inference information RDS file +(".infoCall.rds" file)} +\item{Synthetic Information}{The parameter information RDS files +from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +} + +In addition, a sub-directory (named using the profile ID) is +also created. +} +\examples{ + +## Required library for GDS +library(gdsfmt) + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +################################################################# +## The path and file name for the PED RDS file +## will the information about the analyzed samples +################################################################# +filePED <- file.path(dataDir, "example", "pedEx.rds") +ped <- readRDS(filePED) +head(ped) + +################################################################# +## The 1KG GDS file and the 1KG SNV Annotation GDS file +## need to be located in the same directory +## Note that the 1KG GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +################################################################# +path1KG <- file.path(dataDir, "example", "gdsRef") + +fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") +fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") + +################################################################# +## The Sample SNP pileup files (one per sample) need +## to be located in the same directory. +################################################################# +pathGeno <- file.path(dataDir, "example", "snpPileup") + +################################################################# +## The path where the Profile GDS Files (one per sample) +## will be created need to be specified. +################################################################# +pathProfileGDS <- file.path(dataDir, "example", "out.tmp") + +pathOut <- file.path(dataDir, "example", "res.out") + +################################################################# +## A data frame containing general information about the study +## is also required. The data frame must have +## those 3 columns: "studyID", "study.desc", "study.platform" +################################################################# +studyDF <- data.frame(study.id="MYDATA", + study.desc="Description", + study.platform="PLATFORM", + stringsAsFactors=FALSE) + +#################################################################### +## Fix seed to ensure reproducible results +#################################################################### +set.seed(3043) + +gds1KG <- snpgdsOpen(fileReferenceGDS) +dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +closefn.gds(gds1KG) + +## Chromosome length information for hg38 +## chr23 is chrX, chr24 is chrY and chrM is 25 +chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, + 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, + 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, + 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, + 156040895L, 57227415L, 16569L) + +## A formal way to get the chromosome length information for hg38 +## library(GenomeInfoDb) +## library(BSgenome.Hsapiens.UCSC.hg38) +## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] + +\dontrun{ +runExomeAncestry(pedStudy=ped, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, + pathGeno=pathGeno, + pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + genoSource="snp-pileup") + +unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +unlink(pathOut, recursive=TRUE, force=TRUE) +} + +} +\references{ +Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} diff --git a/man/runWrapperAncestry.Rd b/man/runWrapperAncestry.Rd new file mode 100644 index 000000000..1e3e007d9 --- /dev/null +++ b/man/runWrapperAncestry.Rd @@ -0,0 +1,211 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/processStudy_internal.R +\encoding{UTF-8} +\name{runWrapperAncestry} +\alias{runWrapperAncestry} +\title{TOREVIEW Run most steps leading to the ancestry inference call on a specific +profile} +\usage{ +runWrapperAncestry( + pedStudy, + studyDF, + pathProfileGDS, + pathGeno, + pathOut, + fileReferenceGDS, + fileReferenceAnnotGDS, + chrInfo, + syntheticRefDF, + genoSource = c("snp-pileup", "generic"), + studyType = c("DNA", "RNA"), + verbose = FALSE +) +} +\arguments{ +\item{pedStudy}{a \code{data.frame} with those mandatory columns: "Name.ID", +"Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +\code{character} strings (no factor). The \code{data.frame} +must contain the information for all the samples passed in the +\code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +can be defined.} + +\item{studyDF}{a \code{data.frame} containing the information about the +study associated to the analysed sample(s). The \code{data.frame} must have +those 3 columns: "study.id", "study.desc", "study.platform". All columns +must be in \code{character} strings (no factor).} + +\item{pathProfileGDS}{a \code{character} string representing the path to +the directory where the GDS Profile files will be created. +Default: \code{NULL}.} + +\item{pathGeno}{a \code{character} string representing the path to the +directory containing the VCF output of SNP-pileup for each sample. The +SNP-pileup files must be compressed (gz files) and have the name identifiers +of the samples. A sample with "Name.ID" identifier would have an +associated SNP-pileup file called "Name.ID.txt.gz".} + +\item{pathOut}{a \code{character} string representing the path to +the directory where the output files are created.} + +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Reference GDS file. The file must exist.} + +\item{fileReferenceAnnotGDS}{a \code{character} string representing the +file name of the Reference GDS Annotation file. The file must exist.} + +\item{chrInfo}{a \code{vector} of positive \code{integer} values +representing the length of the chromosomes. See 'details' section.} + +\item{syntheticRefDF}{a \code{data.frame} containing a subset of +reference profiles for each sub-population present in the Reference GDS +file. The \code{data.frame} must have those columns: +\itemize{ +\item{sample.id} { a \code{character} string representing the sample +identifier. } +\item{pop.group} { a \code{character} string representing the +subcontinental population assigned to the sample. } +\item{superPop} { a \code{character} string representing the +super-population assigned to the sample. } +}} + +\item{genoSource}{a \code{stirng} with two possible values: +snp-pileup and generic. It specify if the genotype files +are generate by snp-pileup(Facets) or generic format csv +with the column at least the columns: +Chromosome,Position,Ref,Alt,Count,File1R,File1A +where Count is the deep at the position, +FileR is the deep of the reference allele, and +File1A is the deep of the specific alternative allele} + +\item{studyType}{a \code{character} string representing the type of study. +The possible choices are: "DNA" and "RNA". The type of study affects the +way the estimation of the allelic fraction is done. Default: \code{"DNA"}.} + +\item{verbose}{a \code{logical} indicating if messages should be printed +to show how the different steps in the function. Default: \code{FALSE}.} +} +\value{ +The integer \code{0L} when successful. See details section for +more information about the generated output files. +} +\description{ +This function runs most steps leading to the ancestry inference +call on a specific profile. First, the function creates the Profile GDS file +for the specific profile using the information from a RDS Sample +description file and the 1KG reference GDS file. +} +\details{ +The runWrapperAncestry() function generates 3 types of files +in the OUTPUT directory. +\itemize{ +\item{Ancestry Inference}{The ancestry inference CSV file +(".Ancestry.csv" file)} +\item{Inference Informaton}{The inference information RDS file +(".infoCall.rds" file)} +\item{Synthetic Information}{The parameter information RDS files +from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +} + +In addition, a sub-directory (named using the profile ID) is +also created. +} +\examples{ + +## Required library for GDS +library(gdsfmt) + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +################################################################# +## The path and file name for the PED RDS file +## will the information about the analyzed samples +################################################################# +filePED <- file.path(dataDir, "example", "pedEx.rds") +ped <- readRDS(filePED) +head(ped) + +################################################################# +## The 1KG GDS file and the 1KG SNV Annotation GDS file +## need to be located in the same directory +## Note that the 1KG GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +################################################################# +path1KG <- file.path(dataDir, "example", "gdsRef") + +fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") +fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") + +################################################################# +## The Sample SNP pileup files (one per sample) need +## to be located in the same directory. +################################################################# +pathGeno <- file.path(dataDir, "example", "snpPileup") + +################################################################# +## The path where the Profile GDS Files (one per sample) +## will be created need to be specified. +################################################################# +pathProfileGDS <- file.path(dataDir, "example", "out.tmp") + +pathOut <- file.path(dataDir, "example", "res.out") + +################################################################# +## A data frame containing general information about the study +## is also required. The data frame must have +## those 3 columns: "studyID", "study.desc", "study.platform" +################################################################# +studyDF <- data.frame(study.id="MYDATA", + study.desc="Description", + study.platform="PLATFORM", + stringsAsFactors=FALSE) + +#################################################################### +## Fix seed to ensure reproducible results +#################################################################### +set.seed(3043) + +gds1KG <- snpgdsOpen(fileReferenceGDS) +dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +closefn.gds(gds1KG) + +## Chromosome length information for hg38 +## chr23 is chrX, chr24 is chrY and chrM is 25 +chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, + 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, + 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, + 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, + 156040895L, 57227415L, 16569L) + +## A formal way to get the chromosome length information for hg38 +## library(GenomeInfoDb) +## library(BSgenome.Hsapiens.UCSC.hg38) +## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] + +\dontrun{ +runWrapperAncestry(pedStudy=ped, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, + pathGeno=pathGeno, + pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + studyType="DNA" + genoSource="snp-pileup") + +unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +unlink(pathOut, recursive=TRUE, force=TRUE) +} + +} +\references{ +Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{@internal} diff --git a/man/tableBlockAF.Rd b/man/tableBlockAF.Rd index c763940d5..3a7cd894d 100644 --- a/man/tableBlockAF.Rd +++ b/man/tableBlockAF.Rd @@ -6,10 +6,10 @@ \title{TOREVIEW Compile the info about the allelic fraction for each bloc. In the case of RNA-seq the blaocks are gene} \usage{ -tableBlockAF(snp.pos) +tableBlockAF(snpPos) } \arguments{ -\item{snp.pos}{For a specific chromosome a \code{data.frame} with lap for +\item{snpPos}{For a specific chromosome a \code{data.frame} with lap for the SNV dataset with coverage > \code{minCov}.} } diff --git a/tests/testthat/test-allelicFraction.R b/tests/testthat/test-allelicFraction.R index 77e9ec32a..e10de5250 100644 --- a/tests/testthat/test-allelicFraction.R +++ b/tests/testthat/test-allelicFraction.R @@ -30,7 +30,7 @@ test_that("computeAlleleFraction() must return expected results when not imbalan lap=rep(-1, 8), LOH=rep(0, 8), imbAR=rep(-1, 8), stringAsFactor=FALSE) - result <- RAIDS:::computeAlleleFraction(snp.pos=snpInfo, w=10, cutOff=-3) + result <- RAIDS:::computeAlleleFraction(snpPos=snpInfo, w=10, cutOff=-3) expect_equal(result, NULL) }) @@ -55,7 +55,7 @@ test_that("computeAlleleFraction() must return expected results when imbalanced lap=rep(-1, 8), LOH=rep(0, 8), imbAR=c(1, 1, 1, 1, 1, 0, 1, 1), stringAsFactor=FALSE) - result <- RAIDS:::computeAlleleFraction(snp.pos=snpInfo, w=10, cutOff=-3) + result <- RAIDS:::computeAlleleFraction(snpPos=snpInfo, w=10, cutOff=-3) expect_equal(result, matrix(c(1, 5, 0, 7, 8, NA), byrow=TRUE, nrow=2)) }) @@ -82,7 +82,7 @@ test_that("computeAlleleFraction() must return expected results with small w par lap=rep(-1, 12), LOH=rep(0, 12), imbAR=rep(1, 12), stringAsFactor=FALSE) - result <- RAIDS:::computeAlleleFraction(snp.pos=snpInfo, w=4, cutOff=-3) + result <- RAIDS:::computeAlleleFraction(snpPos=snpInfo, w=4, cutOff=-3) expect_equal(result, matrix(c(1, 12, 0.148714810281518), byrow=TRUE, nrow=1)) }) diff --git a/tests/testthat/test-allelicFraction_internal.R b/tests/testthat/test-allelicFraction_internal.R index 2b10b6009..1442c6511 100644 --- a/tests/testthat/test-allelicFraction_internal.R +++ b/tests/testthat/test-allelicFraction_internal.R @@ -73,7 +73,7 @@ test_that("computeLOHBlocksDNAChr() must return expected results", { stringAsFactor=FALSE) result <- RAIDS:::computeLOHBlocksDNAChr(gdsReference=gds1KG, - chrInfo=chrInfo, snp.pos=snpInfo, chr=1L, genoN=0.0001) + chrInfo=chrInfo, snpPos=snpInfo, chr=1L, genoN=0.0001) expected <- data.frame(chr=rep(1, 12), start=c(1, snpInfo$snp.pos[seq_len(8)]+1, 6313146, From f8a040ce6f7ea1b67a9e9abc3027b68a69e6552b Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 21:17:29 -0400 Subject: [PATCH 091/385] Add example for generateGDSgenotype() function --- R/gdsWrapper.R | 96 ++++++++++++++----- R/process1KG.R | 6 +- ...GDS1KGLDBlock.Rd => addBlockInGDSAnnot.Rd} | 8 +- man/gds2tfam.Rd | 4 +- man/gds2tfamSample.Rd | 4 +- man/gds2tped.Rd | 4 +- man/generateGDSgenotype.Rd | 56 ++++++++++- tests/testthat/test-gdsWrapper.R | 12 +-- 8 files changed, 141 insertions(+), 49 deletions(-) rename man/{addGDS1KGLDBlock.Rd => addBlockInGDSAnnot.Rd} (92%) diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 8d3cd66a7..4db31040e 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -114,17 +114,18 @@ generateGDSSNPinfo <- function(gdsReference, fileFreq, verbose) { } -#' @title Add information related to profile genotypes into a Reference -#' GDS file +#' @title Add information related to profile genotypes into a Population +#' Reference GDS file #' #' @description This function adds the genotype fields with the associated -#' information into the Reference GDS file for the selected profiles. +#' information into the Population Reference GDS file for the selected +#' profiles. #' #' @param gds an object of class #' \link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file. #' #' @param pathGeno a \code{character} string representing the path where -#' the 1K genotyping files for each sample are located. The name of the +#' the reference genotyping files for each sample are located. The name of the #' genotyping files must correspond to #' the individual identification (Individual.ID) in the pedigree file. #' @@ -143,7 +144,52 @@ generateGDSSNPinfo <- function(gdsReference, fileFreq, verbose) { #' #' @examples #' -#' # TODO +#' ## Required library +#' library(gdsfmt) +#' +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## The RDS file containing the pedigree information +#' pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +#' +#' ## The RDS file containing the indexes of the retained SNPs +#' snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") +#' +#' ## The RDS file containing the filtered SNP information +#' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") +#' +#' ## Temporary Reference GDS file +#' tempRefGDS <- file.path(getwd(), "Ref_TEMP01.gds") +#' +#' ## Only run example if the directory is writable +#' if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { +#' +#' ## Create temporary Reference GDS file +#' newGDS <- createfn.gds(tempRefGDS) +#' put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") +#' +#' ## Read the pedigree file +#' ped1KG <- readRDS(pedigreeFile) +#' +#' ## Add information about samples to the Reference GDS file +#' listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, +#' dfPedReference=ped1KG, listSamples=NULL) +#' +#' ## Add SNV information to the Reference GDS +#' RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, +#' verbose=FALSE) +#' +#' ## Add genotype information to the Reference GDS +#' RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, +#' fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS, verbose=FALSE) +#' +#' ## Close file +#' closefn.gds(newGDS) +#' +#' ## Remove temporary files +#' unlink(tempRefGDS, force=TRUE) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn write.gdsn @@ -154,8 +200,8 @@ generateGDSgenotype <- function(gds, pathGeno, fileSNPsRDS, listSamples, verbose) { # File with the description of the SNP keep - listMat1k <- dir(pathGeno, pattern=".+.csv.bz2") - listSample1k <- gsub(".csv.bz2", "", listMat1k) + listMatRef <- dir(pathGeno, pattern=".+.csv.bz2") + listSample1k <- gsub(".csv.bz2", "", listMatRef) listSNP <- readRDS(fileSNPsRDS) @@ -165,7 +211,7 @@ generateGDSgenotype <- function(gds, pathGeno, fileSNPsRDS, listSamples, if(verbose) { message(listSamples[i]) } if( length(pos) == 1) { - matSample <- read.csv2(file.path(pathGeno, listMat1k[pos]), + matSample <- read.csv2(file.path(pathGeno, listMatRef[pos]), row.names=NULL) matSample <- matSample[listSNP,, drop=FALSE] if(i == 1) { @@ -186,7 +232,7 @@ generateGDSgenotype <- function(gds, pathGeno, fileSNPsRDS, listSamples, rm(matSample) - if(verbose) { message(listMat1k[pos], " ", i) } + if(verbose) { message(listMatRef[pos], " ", i) } }else{ stop("Missing samples genotype in ", listSamples[i]) } @@ -227,8 +273,8 @@ appendGDSgenotype <- function(gds, listSample, pathGeno, fileSNPsRDS, verbose=FALSE) { # File with the description of the SNP keep - listMat1k <- dir(pathGeno, pattern = ".+.csv.bz2") - listSample1k <- gsub(".csv.bz2", "", listMat1k) + listMatRef <- dir(pathGeno, pattern = ".+.csv.bz2") + listSample1k <- gsub(".csv.bz2", "", listMatRef) listSNP <- readRDS(file=fileSNPsRDS) geno.var <- index.gdsn(gds, "genotype") @@ -238,7 +284,7 @@ appendGDSgenotype <- function(gds, listSample, pathGeno, fileSNPsRDS, for(i in seq_len(length(listSample))) { pos <- which(listSample1k == listSample[i]) if( length(pos) == 1) { - matSample <- read.csv2(file.path(pathGeno, listMat1k[pos]), + matSample <- read.csv2(file.path(pathGeno, listMatRef[pos]), row.names = NULL) matSample <- matSample[listSNP,, drop=FALSE] @@ -255,9 +301,9 @@ appendGDSgenotype <- function(gds, listSample, pathGeno, fileSNPsRDS, append.gdsn(geno.var,g, check=TRUE) rm(matSample) - if(verbose) { message(listMat1k[pos], " ", i) } + if(verbose) { message(listMatRef[pos], " ", i) } }else { - stop("Missing 1k samples ", listSample[i]) + stop("Missing reference samples ", listSample[i]) } } @@ -274,7 +320,7 @@ appendGDSgenotype <- function(gds, listSample, pathGeno, fileSNPsRDS, #' #' @param listSample a \code{array} with the sample to keep TODO #' -#' @param pedOUT TODO a PATH and file name to the output file +#' @param pedOut TODO a PATH and file name to the output file #' #' @return TODO a \code{vector} of \code{numeric} #' @@ -288,7 +334,7 @@ appendGDSgenotype <- function(gds, listSample, pathGeno, fileSNPsRDS, #' @importFrom utils write.table #' @encoding UTF-8 #' @keywords export -gds2tfam <- function(gdsReference, listSample, pedOUT) { +gds2tfam <- function(gdsReference, listSample, pedOut) { sampleGDS <- index.gdsn(gdsReference, "sample.id") sampleId <-read.gdsn(sampleGDS) @@ -305,7 +351,7 @@ gds2tfam <- function(gdsReference, listSample, pedOUT) { pheno=rep(1,length(listSample)), stringsAsFactors=FALSE) - write.table(dfPed, pedOUT, + write.table(dfPed, pedOut, quote=FALSE, sep="\t", row.names=FALSE, col.names=FALSE) @@ -324,7 +370,7 @@ gds2tfam <- function(gdsReference, listSample, pedOUT) { #' @param sampleANNO a \code{data.frame} with at least column sex and the name #' must be sample.id #' -#' @param pedOUT TODO a PATH and file name to the output file +#' @param pedOut TODO a PATH and file name to the output file #' #' #' @return TODO a \code{vector} of \code{numeric} @@ -339,7 +385,7 @@ gds2tfam <- function(gdsReference, listSample, pedOUT) { #' @importFrom utils write.table #' @encoding UTF-8 #' @keywords export -gds2tfamSample <- function(gdsProfile, listSample, sampleANNO, pedOUT) { +gds2tfamSample <- function(gdsProfile, listSample, sampleANNO, pedOut) { sampleGDS <- index.gdsn(gdsProfile, "sample.id") sampleId <-read.gdsn(sampleGDS) @@ -353,7 +399,7 @@ gds2tfamSample <- function(gdsProfile, listSample, sampleANNO, pedOUT) { pheno=rep(1,length(listSample)), stringsAsFactors=FALSE) - write.table(dfPed, pedOUT, quote=FALSE, sep="\t", + write.table(dfPed, pedOut, quote=FALSE, sep="\t", row.names=FALSE, col.names=FALSE) } @@ -368,7 +414,7 @@ gds2tfamSample <- function(gdsProfile, listSample, sampleANNO, pedOUT) { #' #' @param listSNP a \code{array} with the snp.id to keep #' -#' @param pedOUT TODO a PATH and file name to the output file +#' @param pedOut TODO a PATH and file name to the output file #' #' @return TODO a \code{vector} of \code{numeric} #' @@ -382,7 +428,7 @@ gds2tfamSample <- function(gdsProfile, listSample, sampleANNO, pedOUT) { #' @importFrom utils write.table #' @encoding UTF-8 #' @keywords export -gds2tped <- function(gds, listSample, listSNP, pedOUT) { +gds2tped <- function(gds, listSample, listSNP, pedOut) { sampleGDS <- index.gdsn(gds, "sample.id") sampleId <-read.gdsn(sampleGDS) @@ -420,7 +466,7 @@ gds2tped <- function(gds, listSample, listSNP, pedOUT) { } - write.table(tped, pedOUT, quote=FALSE, sep="\t", row.names=FALSE, + write.table(tped, pedOut, quote=FALSE, sep="\t", row.names=FALSE, col.names=FALSE) } @@ -473,7 +519,7 @@ gds2tped <- function(gds, listSample, listSNP, pedOUT) { #' ## The values for each entry related to the block (integers) #' blockEntries <- c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3) #' -#' RAIDS:::addGDS1KGLDBlock(gds=GDS_file_tmp, listBlock=blockEntries, +#' RAIDS:::addBlockInGDSAnnot(gds=GDS_file_tmp, listBlock=blockEntries, #' blockName=blockType, blockDesc=blockDescription) #' #' ## Read 'block.annot' node @@ -495,7 +541,7 @@ gds2tped <- function(gds, listSample, listSNP, pedOUT) { #' @importFrom gdsfmt append.gdsn sync.gds #' @encoding UTF-8 #' @keywords internal -addGDS1KGLDBlock <- function(gds, listBlock, blockName, blockDesc) { +addBlockInGDSAnnot <- function(gds, listBlock, blockName, blockDesc) { blockAnnot <- data.frame(block.id=blockName, block.desc=blockDesc, diff --git a/R/process1KG.R b/R/process1KG.R index e78e06a21..e06981693 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -883,7 +883,7 @@ addBlockFromPlink2GDS <- function(gds, gdsOut, PATHBLOCK, listBlock <- do.call(c, listBlock) ## Save the information into the GDS file - addGDS1KGLDBlock(gdsOut, listBlock, blockName, blockDesc) + addBlockInGDSAnnot(gdsOut, listBlock, blockName, blockDesc) ## Success return(0L) @@ -1021,10 +1021,10 @@ addGeneBlockGDSRefAnnot <- function(gdsReference, file.gdsRefAnnot, blockName <- paste0("Gene.", suffixe.blockName) blockDesc <- paste0("List of blocks including overlapping genes ", suffixe.blockName) - addGDS1KGLDBlock(gdsRefAnnot, dfGeneBlock$Gene, blockName, blockDesc) + addBlockInGDSAnnot(gdsRefAnnot, dfGeneBlock$Gene, blockName, blockDesc) blockName <- paste0("GeneS.", suffixe.blockName) blockDesc <- paste0("List of blocks of split by genes ", suffixe.blockName) - addGDS1KGLDBlock(gdsRefAnnot, dfGeneBlock$GeneS, blockName, blockDesc) + addBlockInGDSAnnot(gdsRefAnnot, dfGeneBlock$GeneS, blockName, blockDesc) ## Close GDS Reference annotation file closefn.gds(gdsRefAnnot) diff --git a/man/addGDS1KGLDBlock.Rd b/man/addBlockInGDSAnnot.Rd similarity index 92% rename from man/addGDS1KGLDBlock.Rd rename to man/addBlockInGDSAnnot.Rd index adb3f0bab..89ff0ecf8 100644 --- a/man/addGDS1KGLDBlock.Rd +++ b/man/addBlockInGDSAnnot.Rd @@ -1,11 +1,11 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/gdsWrapper.R \encoding{UTF-8} -\name{addGDS1KGLDBlock} -\alias{addGDS1KGLDBlock} +\name{addBlockInGDSAnnot} +\alias{addBlockInGDSAnnot} \title{Add block information in a Population Reference GDS Annotation file} \usage{ -addGDS1KGLDBlock(gds, listBlock, blockName, blockDesc) +addBlockInGDSAnnot(gds, listBlock, blockName, blockDesc) } \arguments{ \item{gds}{an object of class \code{gds} opened in writing mode.} @@ -56,7 +56,7 @@ if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { ## The values for each entry related to the block (integers) blockEntries <- c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3) - RAIDS:::addGDS1KGLDBlock(gds=GDS_file_tmp, listBlock=blockEntries, + RAIDS:::addBlockInGDSAnnot(gds=GDS_file_tmp, listBlock=blockEntries, blockName=blockType, blockDesc=blockDescription) ## Read 'block.annot' node diff --git a/man/gds2tfam.Rd b/man/gds2tfam.Rd index 3b361b420..0cf450b52 100644 --- a/man/gds2tfam.Rd +++ b/man/gds2tfam.Rd @@ -5,7 +5,7 @@ \alias{gds2tfam} \title{create a file tfam file for plink from the gdsReference file} \usage{ -gds2tfam(gdsReference, listSample, pedOUT) +gds2tfam(gdsReference, listSample, pedOut) } \arguments{ \item{gdsReference}{an object of class @@ -13,7 +13,7 @@ gds2tfam(gdsReference, listSample, pedOUT) \item{listSample}{a \code{array} with the sample to keep TODO} -\item{pedOUT}{TODO a PATH and file name to the output file} +\item{pedOut}{TODO a PATH and file name to the output file} } \value{ TODO a \code{vector} of \code{numeric} diff --git a/man/gds2tfamSample.Rd b/man/gds2tfamSample.Rd index 33c9d736f..57f051dfd 100644 --- a/man/gds2tfamSample.Rd +++ b/man/gds2tfamSample.Rd @@ -5,7 +5,7 @@ \alias{gds2tfamSample} \title{create a file tfam file for plink from the gdsProfile file} \usage{ -gds2tfamSample(gdsProfile, listSample, sampleANNO, pedOUT) +gds2tfamSample(gdsProfile, listSample, sampleANNO, pedOut) } \arguments{ \item{gdsProfile}{an object of class \link[gdsfmt]{gds.class} (a GDS @@ -16,7 +16,7 @@ file), the open Profile GDS file.} \item{sampleANNO}{a \code{data.frame} with at least column sex and the name must be sample.id} -\item{pedOUT}{TODO a PATH and file name to the output file} +\item{pedOut}{TODO a PATH and file name to the output file} } \value{ TODO a \code{vector} of \code{numeric} diff --git a/man/gds2tped.Rd b/man/gds2tped.Rd index be72b7509..03747600f 100644 --- a/man/gds2tped.Rd +++ b/man/gds2tped.Rd @@ -5,7 +5,7 @@ \alias{gds2tped} \title{create a file tped file for plink from the gds file} \usage{ -gds2tped(gds, listSample, listSNP, pedOUT) +gds2tped(gds, listSample, listSNP, pedOut) } \arguments{ \item{gds}{a \code{gds} object.} @@ -14,7 +14,7 @@ gds2tped(gds, listSample, listSNP, pedOUT) \item{listSNP}{a \code{array} with the snp.id to keep} -\item{pedOUT}{TODO a PATH and file name to the output file} +\item{pedOut}{TODO a PATH and file name to the output file} } \value{ TODO a \code{vector} of \code{numeric} diff --git a/man/generateGDSgenotype.Rd b/man/generateGDSgenotype.Rd index 950fe7336..d6c15cf0a 100644 --- a/man/generateGDSgenotype.Rd +++ b/man/generateGDSgenotype.Rd @@ -3,8 +3,8 @@ \encoding{UTF-8} \name{generateGDSgenotype} \alias{generateGDSgenotype} -\title{Add information related to profile genotypes into a Reference -GDS file} +\title{Add information related to profile genotypes into a Population +Reference GDS file} \usage{ generateGDSgenotype(gds, pathGeno, fileSNPsRDS, listSamples, verbose) } @@ -13,7 +13,7 @@ generateGDSgenotype(gds, pathGeno, fileSNPsRDS, listSamples, verbose) \link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file.} \item{pathGeno}{a \code{character} string representing the path where -the 1K genotyping files for each sample are located. The name of the +the reference genotyping files for each sample are located. The name of the genotyping files must correspond to the individual identification (Individual.ID) in the pedigree file.} @@ -33,11 +33,57 @@ The integer \code{0L} when successful. } \description{ This function adds the genotype fields with the associated -information into the Reference GDS file for the selected profiles. +information into the Population Reference GDS file for the selected +profiles. } \examples{ -# TODO +## Required library +library(gdsfmt) + +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +## The RDS file containing the pedigree information +pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") + +## The RDS file containing the indexes of the retained SNPs +snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") + +## The RDS file containing the filtered SNP information +filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") + +## Temporary Reference GDS file +tempRefGDS <- file.path(getwd(), "Ref_TEMP01.gds") + +## Only run example if the directory is writable +if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { + + ## Create temporary Reference GDS file + newGDS <- createfn.gds(tempRefGDS) + put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") + + ## Read the pedigree file + ped1KG <- readRDS(pedigreeFile) + + ## Add information about samples to the Reference GDS file + listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, + dfPedReference=ped1KG, listSamples=NULL) + + ## Add SNV information to the Reference GDS + RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, + verbose=FALSE) + + ## Add genotype information to the Reference GDS + RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, + fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS, verbose=FALSE) + + ## Close file + closefn.gds(newGDS) + + ## Remove temporary files + unlink(tempRefGDS, force=TRUE) +} } \author{ diff --git a/tests/testthat/test-gdsWrapper.R b/tests/testthat/test-gdsWrapper.R index f3b120968..003922245 100644 --- a/tests/testthat/test-gdsWrapper.R +++ b/tests/testthat/test-gdsWrapper.R @@ -161,16 +161,16 @@ test_that("addGDSRef() must return expected result", { ############################################################################# -### Tests addGDS1KGLDBlock() results +### Tests addBlockInGDSAnnot() results ############################################################################# -context("addGDS1KGLDBlock() results") +context("addBlockInGDSAnnot() results") -test_that("addGDS1KGLDBlock() must return expected result", { +test_that("addBlockInGDSAnnot() must return expected result", { ## Create and open a temporary GDS Annotation file - GDS_path <- test_path("fixtures", "GDS_addGDS1KGLDBlock_Temp_01.gds") + GDS_path <- test_path("fixtures", "GDS_addBlockInGDSAnnot_Temp_01.gds") GDS_file_tmp <- createfn.gds(filename=GDS_path) defer(unlink(x=GDS_path, force=TRUE), envir=parent.frame()) @@ -180,7 +180,7 @@ test_that("addGDS1KGLDBlock() must return expected result", { entries <- c(1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5) ## Add block to the GDS file - results1 <- RAIDS:::addGDS1KGLDBlock(gds=GDS_file_tmp, listBlock=entries, + results1 <- RAIDS:::addBlockInGDSAnnot(gds=GDS_file_tmp, listBlock=entries, blockName=blockType, blockDesc=blockDescription) @@ -190,7 +190,7 @@ test_that("addGDS1KGLDBlock() must return expected result", { entries2 <- c(1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5) ## Add block to the GDS file - results2 <- RAIDS:::addGDS1KGLDBlock(gds=GDS_file_tmp, listBlock=entries2, + results2 <- RAIDS:::addBlockInGDSAnnot(gds=GDS_file_tmp, listBlock=entries2, blockName=blockType2, blockDesc=blockDescription2) From d53e0ecc9b3e21da43fd4cbba19ca19f59ef134d Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 14 Aug 2023 22:14:56 -0400 Subject: [PATCH 092/385] Update addBlockFromPlink2GDS() documentation --- R/process1KG.R | 27 ++++++++++++++++++--------- man/addBlockFromPlink2GDS.Rd | 16 ++++++++++++---- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index e06981693..57f39fe4f 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -807,9 +807,15 @@ basePCASample <- function(gds, listSample.Ref=NULL, listSNP=NULL, np=1L) { return(listPCA) } -#' @title TODO contain the information from 1KG +#' @title Save the information about a specific block in a +#' Population Reference GDS Annotation file #' -#' @description TODO +#' @description This function extracts the information for all +#' SNVs related to a specific block from the Population Reference GDS file. It +#' uses this information and the information from the block files associated +#' to a specific super-population to generate the final block information. +#' The block information is then saved in a Population ReferenceG DS Annotation +#' file. #' #' @param gds an object of class #' \link[gdsfmt]{gds.class} (a GDS file), TODO @@ -820,9 +826,11 @@ basePCASample <- function(gds, listSample.Ref=NULL, listSNP=NULL, np=1L) { #' #' @param superPop TODO #' -#' @param blockName TODO +#' @param blockName a \code{character} string representing the unique +#' block name. #' -#' @param blockDesc TODO +#' @param blockDesc a \code{character} string representing the description of +#' the current block. #' #' @param verbose a \code{logical} indicating if message information should be #' printed. Default: \code{FALSE}. @@ -855,10 +863,10 @@ addBlockFromPlink2GDS <- function(gds, gdsOut, PATHBLOCK, validateLogical(verbose, "verbose") ## Extract the SNP chromosomes and positions - snp.chromosome <- read.gdsn(index.gdsn(gds, "snp.chromosome")) + snpChromosome <- read.gdsn(index.gdsn(gds, "snp.chromosome")) snp.position <- read.gdsn(index.gdsn(gds, "snp.position")) - listChr <- unique(snp.chromosome) + listChr <- unique(snpChromosome) listChr <- listChr[order(listChr)] listChr <- seq_len(22) @@ -866,7 +874,7 @@ addBlockFromPlink2GDS <- function(gds, gdsOut, PATHBLOCK, for(chr in listChr) { if(verbose) { message("chr", chr, " ", Sys.time()) } - snp.keep <- snp.position[snp.chromosome == chr] + snp.keep <- snp.position[snpChromosome == chr] listBlock[[chr]] <- processBlockChr(snp.keep, PATHBLOCK, superPop, chr) if(chr > 1) { @@ -882,8 +890,9 @@ addBlockFromPlink2GDS <- function(gds, gdsOut, PATHBLOCK, } listBlock <- do.call(c, listBlock) - ## Save the information into the GDS file - addBlockInGDSAnnot(gdsOut, listBlock, blockName, blockDesc) + ## Save the information into the GDS Annotation file + addBlockInGDSAnnot(gds=gdsOut, listBlock=listBlock, blockName=blockName, + blockDesc=blockDesc) ## Success return(0L) diff --git a/man/addBlockFromPlink2GDS.Rd b/man/addBlockFromPlink2GDS.Rd index e46600afb..f31fe5833 100644 --- a/man/addBlockFromPlink2GDS.Rd +++ b/man/addBlockFromPlink2GDS.Rd @@ -3,7 +3,8 @@ \encoding{UTF-8} \name{addBlockFromPlink2GDS} \alias{addBlockFromPlink2GDS} -\title{TODO contain the information from 1KG} +\title{Save the information about a specific block in a +Population Reference GDS Annotation file} \usage{ addBlockFromPlink2GDS( gds, @@ -25,9 +26,11 @@ addBlockFromPlink2GDS( \item{superPop}{TODO} -\item{blockName}{TODO} +\item{blockName}{a \code{character} string representing the unique +block name.} -\item{blockDesc}{TODO} +\item{blockDesc}{a \code{character} string representing the description of +the current block.} \item{verbose}{a \code{logical} indicating if message information should be printed. Default: \code{FALSE}.} @@ -36,7 +39,12 @@ printed. Default: \code{FALSE}.} \code{OL} when the function is successful. } \description{ -TODO +This function extracts the information for all +SNVs related to a specific block from the Population Reference GDS file. It +uses this information and the information from the block files associated +to a specific super-population to generate the final block information. +The block information is then saved in a Population ReferenceG DS Annotation +file. } \details{ More information about GDS file format can be found at the Bioconductor From 961d9a8aa788d1d4fcb44ad6ce95f0e95e772753 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 15 Aug 2023 11:35:19 -0400 Subject: [PATCH 093/385] Move admixture functions to admixture R file --- R/admixture.R | 161 ++++++++++++++++++++++++++++++++++++++++++ R/gdsWrapper.R | 160 ----------------------------------------- man/gds2tfam.Rd | 2 +- man/gds2tfamSample.Rd | 2 +- man/gds2tped.Rd | 2 +- 5 files changed, 164 insertions(+), 163 deletions(-) create mode 100644 R/admixture.R diff --git a/R/admixture.R b/R/admixture.R new file mode 100644 index 000000000..d48125b34 --- /dev/null +++ b/R/admixture.R @@ -0,0 +1,161 @@ + + +#' @title create a file tfam file for plink from the gdsReference file +#' +#' @description TODO +#' +#' @param gdsReference an object of class +#' \link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file. +#' +#' @param listSample a \code{array} with the sample to keep TODO +#' +#' @param pedOut TODO a PATH and file name to the output file +#' +#' @return TODO a \code{vector} of \code{numeric} +#' +#' @examples +#' +#' # TODO +#' gds <- "Demo GDS TODO" +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt index.gdsn read.gdsn +#' @importFrom utils write.table +#' @encoding UTF-8 +#' @keywords export +gds2tfam <- function(gdsReference, listSample, pedOut) { + + sampleGDS <- index.gdsn(gdsReference, "sample.id") + sampleId <-read.gdsn(sampleGDS) + listS <- which(sampleId %in% listSample) + + sampleGDS <- index.gdsn(gdsReference, "sample.annot") + sampleANNO <-read.gdsn(sampleGDS) + + dfPed <- data.frame(famId=paste0("F", seq_len(length(listSample))), + id=sampleId[listS], + fa=rep("0",length(listSample)), + mo=rep("0",length(listSample)), + sex=sampleANNO$sex[listS], + pheno=rep(1,length(listSample)), + stringsAsFactors=FALSE) + + write.table(dfPed, pedOut, + quote=FALSE, sep="\t", + row.names=FALSE, + col.names=FALSE) + +} + + +#' @title create a file tfam file for plink from the gdsProfile file +#' +#' @description TODO +#' +#' @param gdsProfile an object of class \link[gdsfmt]{gds.class} (a GDS +#' file), the open Profile GDS file. +#' +#' @param listSample a \code{array} with the sample to keep +#' +#' @param sampleANNO a \code{data.frame} with at least column sex and the name +#' must be sample.id +#' +#' @param pedOut TODO a PATH and file name to the output file +#' +#' +#' @return TODO a \code{vector} of \code{numeric} +#' +#' @examples +#' +#' # TODO +#' gds <- "Demo GDS TODO" +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt index.gdsn read.gdsn +#' @importFrom utils write.table +#' @encoding UTF-8 +#' @keywords export +gds2tfamSample <- function(gdsProfile, listSample, sampleANNO, pedOut) { + + sampleGDS <- index.gdsn(gdsProfile, "sample.id") + sampleId <-read.gdsn(sampleGDS) + listS <- which(sampleId %in% listSample) + + dfPed <- data.frame(famId=paste0("F", seq_len(length(listSample))), + id=sampleId[listS], + fa=rep("0",length(listSample)), + mo=rep("0",length(listSample)), + sex=sampleANNO[sampleId[listS], "sex"], + pheno=rep(1,length(listSample)), + stringsAsFactors=FALSE) + + write.table(dfPed, pedOut, quote=FALSE, sep="\t", + row.names=FALSE, col.names=FALSE) +} + + +#' @title create a file tped file for plink from the gds file +#' +#' @description TODO +#' +#' @param gds a \code{gds} object. +#' +#' @param listSample a \code{array} with the sample to keep +#' +#' @param listSNP a \code{array} with the snp.id to keep +#' +#' @param pedOut TODO a PATH and file name to the output file +#' +#' @return TODO a \code{vector} of \code{numeric} +#' +#' @examples +#' +#' # TODO +#' gds <- "Demo GDS TODO" +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt index.gdsn read.gdsn +#' @importFrom utils write.table +#' @encoding UTF-8 +#' @keywords export +gds2tped <- function(gds, listSample, listSNP, pedOut) { + + sampleGDS <- index.gdsn(gds, "sample.id") + sampleId <-read.gdsn(sampleGDS) + listS <- which(sampleId %in% listSample) + + snpGDS <- index.gdsn(gds, "snp.id") + snpId <- read.gdsn(snpGDS) + listKeep <- which(snpId %in% listSNP) + snpId <- snpId[listKeep] + + snpGDS <- index.gdsn(gds, "snp.chromosome") + snpChr <- read.gdsn(snpGDS) + snpChr <- snpChr[listKeep] + + snpGDS <- index.gdsn(gds, "snp.position") + snpPos <- read.gdsn(snpGDS) + snpPos <- snpPos[listKeep] + + tped <- list() + tped[[1]] <- snpChr + tped[[2]] <- snpId + tped[[3]] <- rep(0,length(snpId)) + tped[[4]] <- snpPos + k<-4 + geno.var <- index.gdsn(gds, "genotype") + for(i in listS){ + k <- k + 1 + + tmp <- read.gdsn(geno.var, start=c(1, i), count=c(-1,1))[listKeep] + + # 0 1 0 1 0 1 + tped[[k]] <- (tmp == 2) + 1 + k <- k + 1 + tped[[k]] <- (tmp > 0) + 1 + + } + + write.table(tped, pedOut, quote=FALSE, sep="\t", row.names=FALSE, + col.names=FALSE) +} diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 4db31040e..359daca6e 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -311,166 +311,6 @@ appendGDSgenotype <- function(gds, listSample, pathGeno, fileSNPsRDS, } -#' @title create a file tfam file for plink from the gdsReference file -#' -#' @description TODO -#' -#' @param gdsReference an object of class -#' \link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file. -#' -#' @param listSample a \code{array} with the sample to keep TODO -#' -#' @param pedOut TODO a PATH and file name to the output file -#' -#' @return TODO a \code{vector} of \code{numeric} -#' -#' @examples -#' -#' # TODO -#' gds <- "Demo GDS TODO" -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt index.gdsn read.gdsn -#' @importFrom utils write.table -#' @encoding UTF-8 -#' @keywords export -gds2tfam <- function(gdsReference, listSample, pedOut) { - - sampleGDS <- index.gdsn(gdsReference, "sample.id") - sampleId <-read.gdsn(sampleGDS) - listS <- which(sampleId %in% listSample) - - sampleGDS <- index.gdsn(gdsReference, "sample.annot") - sampleANNO <-read.gdsn(sampleGDS) - - dfPed <- data.frame(famId=paste0("F", seq_len(length(listSample))), - id=sampleId[listS], - fa=rep("0",length(listSample)), - mo=rep("0",length(listSample)), - sex=sampleANNO$sex[listS], - pheno=rep(1,length(listSample)), - stringsAsFactors=FALSE) - - write.table(dfPed, pedOut, - quote=FALSE, sep="\t", - row.names=FALSE, - col.names=FALSE) - -} - -#' @title create a file tfam file for plink from the gdsProfile file -#' -#' @description TODO -#' -#' @param gdsProfile an object of class \link[gdsfmt]{gds.class} (a GDS -#' file), the open Profile GDS file. -#' -#' @param listSample a \code{array} with the sample to keep -#' -#' @param sampleANNO a \code{data.frame} with at least column sex and the name -#' must be sample.id -#' -#' @param pedOut TODO a PATH and file name to the output file -#' -#' -#' @return TODO a \code{vector} of \code{numeric} -#' -#' @examples -#' -#' # TODO -#' gds <- "Demo GDS TODO" -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt index.gdsn read.gdsn -#' @importFrom utils write.table -#' @encoding UTF-8 -#' @keywords export -gds2tfamSample <- function(gdsProfile, listSample, sampleANNO, pedOut) { - - sampleGDS <- index.gdsn(gdsProfile, "sample.id") - sampleId <-read.gdsn(sampleGDS) - listS <- which(sampleId %in% listSample) - - dfPed <- data.frame(famId=paste0("F", seq_len(length(listSample))), - id=sampleId[listS], - fa=rep("0",length(listSample)), - mo=rep("0",length(listSample)), - sex=sampleANNO[sampleId[listS], "sex"], - pheno=rep(1,length(listSample)), - stringsAsFactors=FALSE) - - write.table(dfPed, pedOut, quote=FALSE, sep="\t", - row.names=FALSE, col.names=FALSE) -} - - -#' @title create a file tped file for plink from the gds file -#' -#' @description TODO -#' -#' @param gds a \code{gds} object. -#' -#' @param listSample a \code{array} with the sample to keep -#' -#' @param listSNP a \code{array} with the snp.id to keep -#' -#' @param pedOut TODO a PATH and file name to the output file -#' -#' @return TODO a \code{vector} of \code{numeric} -#' -#' @examples -#' -#' # TODO -#' gds <- "Demo GDS TODO" -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt index.gdsn read.gdsn -#' @importFrom utils write.table -#' @encoding UTF-8 -#' @keywords export -gds2tped <- function(gds, listSample, listSNP, pedOut) { - - sampleGDS <- index.gdsn(gds, "sample.id") - sampleId <-read.gdsn(sampleGDS) - listS <- which(sampleId %in% listSample) - - snpGDS <- index.gdsn(gds, "snp.id") - snpId <- read.gdsn(snpGDS) - listKeep <- which(snpId %in% listSNP) - snpId <- snpId[listKeep] - - snpGDS <- index.gdsn(gds, "snp.chromosome") - snpChr <- read.gdsn(snpGDS) - snpChr <- snpChr[listKeep] - - snpGDS <- index.gdsn(gds, "snp.position") - snpPos <- read.gdsn(snpGDS) - snpPos <- snpPos[listKeep] - - tped <- list() - tped[[1]] <- snpChr - tped[[2]] <- snpId - tped[[3]] <- rep(0,length(snpId)) - tped[[4]] <- snpPos - k<-4 - geno.var <- index.gdsn(gds, "genotype") - for(i in listS){ - k <- k + 1 - - tmp <- read.gdsn(geno.var, start=c(1, i), count=c(-1,1))[listKeep] - - # 0 1 0 1 0 1 - tped[[k]] <- (tmp == 2) + 1 - k <- k + 1 - tped[[k]] <- (tmp > 0) + 1 - - } - - write.table(tped, pedOut, quote=FALSE, sep="\t", row.names=FALSE, - col.names=FALSE) -} - - #' @title Add block information in a Population Reference GDS Annotation file #' #' @description This function appends the information for one specific type diff --git a/man/gds2tfam.Rd b/man/gds2tfam.Rd index 0cf450b52..77296fd48 100644 --- a/man/gds2tfam.Rd +++ b/man/gds2tfam.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gdsWrapper.R +% Please edit documentation in R/admixture.R \encoding{UTF-8} \name{gds2tfam} \alias{gds2tfam} diff --git a/man/gds2tfamSample.Rd b/man/gds2tfamSample.Rd index 57f051dfd..8a696a770 100644 --- a/man/gds2tfamSample.Rd +++ b/man/gds2tfamSample.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gdsWrapper.R +% Please edit documentation in R/admixture.R \encoding{UTF-8} \name{gds2tfamSample} \alias{gds2tfamSample} diff --git a/man/gds2tped.Rd b/man/gds2tped.Rd index 03747600f..9cdb27678 100644 --- a/man/gds2tped.Rd +++ b/man/gds2tped.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gdsWrapper.R +% Please edit documentation in R/admixture.R \encoding{UTF-8} \name{gds2tped} \alias{gds2tped} From 91da558fab8e4a16d4072e6b38984dcc331633b2 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 15 Aug 2023 13:37:03 -0400 Subject: [PATCH 094/385] Change documentation and internal variable names to camel case style in snvListVCF() function --- R/tools.R | 61 ++++++++++++++++++++++++++--------------------- man/snvListVCF.Rd | 26 ++++++++++++-------- 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/R/tools.R b/R/tools.R index 4fe868faa..da0a14e33 100644 --- a/R/tools.R +++ b/R/tools.R @@ -11,6 +11,7 @@ #' #' @param fileOut a \code{character} string representing the path and file #' name of the VCF file that will be created wit the retained SNP information. +#' The file should have the ".vcf" extension. #' #' @param offset a single \code{integer} that is added to the SNP position to #' switch from 0-based to 1-based coordinate when needed (or reverse). @@ -26,21 +27,26 @@ #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' -#' ## Demo 1KG GDS file +#' ## Demo 1KG Reference GDS file #' fileGDS <- openfn.gds(file.path(dataDir, "1KG_Demo.gds")) #' #' ## Output VCF file that will be created -#' vcfFile <- file.path(dataDir, "Demo_TMP_01.vcf") +#' vcfFile <- file.path(getwd(), "Demo_TMP_01.vcf") #' -#' ## Create a VCF file with the SNV dataset present in the GDS file -#' ## No cutoff on frequency, so all SNVs are saved -#' snvListVCF(gdsReference=fileGDS, fileOut=vcfFile, offset=0L, freqCutoff=NULL) +#' ## Run only if directory in writing mode +#' if (file.access(getwd()) == 0 && !dir.exists(vcfFile)) { #' -#' ## Close GDS file (IMPORTANT) -#' closefn.gds(fileGDS) +#' ## Create a VCF file with the SNV dataset present in the GDS file +#' ## No cutoff on frequency, so all SNVs are saved +#' snvListVCF(gdsReference=fileGDS, fileOut=vcfFile, offset=0L, +#' freqCutoff=NULL) #' -#' ## Remove temporary VCF file -#' unlink(vcfFile, force=TRUE) +#' ## Close GDS file (IMPORTANT) +#' closefn.gds(fileGDS) +#' +#' ## Remove temporary VCF file +#' unlink(vcfFile, force=TRUE) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt read.gdsn @@ -65,37 +71,38 @@ snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { stop("The \'freqCutoff\' must be a single numeric or NULL.") } - snp.chromosome <- read.gdsn(index.gdsn(gdsReference, "snp.chromosome")) - snp.position <- read.gdsn(index.gdsn(gdsReference, "snp.position")) - snp.allele <- read.gdsn(index.gdsn(gdsReference, "snp.allele")) + snpChromosome <- read.gdsn(index.gdsn(gdsReference, "snp.chromosome")) + snpPosition <- read.gdsn(index.gdsn(gdsReference, "snp.position")) + snpAllele <- read.gdsn(index.gdsn(gdsReference, "snp.allele")) - allele <- matrix(unlist(strsplit(snp.allele, "\\/")), nrow=2) + allele <- matrix(unlist(strsplit(snpAllele, "\\/")), nrow=2) df <- NULL if(is.null(freqCutoff)){ snp.AF <- read.gdsn(index.gdsn(gdsReference, "snp.AF")) - df <- data.frame(CHROM=snp.chromosome, - POS=as.integer(snp.position + offset), - ID=rep(".", length(snp.chromosome)), + df <- data.frame(CHROM=snpChromosome, + POS=as.integer(snpPosition + offset), + ID=rep(".", length(snpChromosome)), REF=allele[1,], ALT=allele[2,], - QUAL=rep(".", length(snp.chromosome)), - FILTER=rep(".", length(snp.chromosome)), + QUAL=rep(".", length(snpChromosome)), + FILTER=rep(".", length(snpChromosome)), INFO=paste0("AF=", snp.AF), stringsAsFactors=FALSE) } else { - freqDF <- data.frame(snp.AF=read.gdsn(index.gdsn(gdsReference, "snp.AF")), - snp.EAS_AF=read.gdsn(index.gdsn(gdsReference, "snp.EAS_AF")), - snp.EUR_AF=read.gdsn(index.gdsn(gdsReference, "snp.EUR_AF")), - snp.AFR_AF=read.gdsn(index.gdsn(gdsReference, "snp.AFR_AF")), - snp.AMR_AF=read.gdsn(index.gdsn(gdsReference, "snp.AMR_AF")), - snp.SAS_AF=read.gdsn(index.gdsn(gdsReference, "snp.SAS_AF"))) + freqDF <- data.frame( + snp.AF=read.gdsn(index.gdsn(gdsReference, "snp.AF")), + snp.EAS_AF=read.gdsn(index.gdsn(gdsReference, "snp.EAS_AF")), + snp.EUR_AF=read.gdsn(index.gdsn(gdsReference, "snp.EUR_AF")), + snp.AFR_AF=read.gdsn(index.gdsn(gdsReference, "snp.AFR_AF")), + snp.AMR_AF=read.gdsn(index.gdsn(gdsReference, "snp.AMR_AF")), + snp.SAS_AF=read.gdsn(index.gdsn(gdsReference, "snp.SAS_AF"))) listKeep <- which(rowSums(freqDF[,2:6] >= freqCutoff & freqDF[,2:6] <= 1 - freqCutoff) > 0) - df <- data.frame(CHROM=snp.chromosome[listKeep], - POS=as.integer(snp.position[listKeep] + offset), + df <- data.frame(CHROM=snpChromosome[listKeep], + POS=as.integer(snpPosition[listKeep] + offset), ID=rep(".", length(listKeep)), REF=allele[1,listKeep], ALT=allele[2,listKeep], @@ -179,7 +186,7 @@ groupChrPruning <- function(pathPrunedGDS, filePref, fileOut) { ## Save all the information into one file saveRDS(pruned, fileChr <- file.path(pathPrunedGDS, fileOut)) - ## Successfull + ## Successful return(0L) } diff --git a/man/snvListVCF.Rd b/man/snvListVCF.Rd index a46de8e93..6ca314419 100644 --- a/man/snvListVCF.Rd +++ b/man/snvListVCF.Rd @@ -13,7 +13,8 @@ snvListVCF(gdsReference, fileOut, offset = 0L, freqCutoff = NULL) (a GDS file), the 1KG GDS file.} \item{fileOut}{a \code{character} string representing the path and file -name of the VCF file that will be created wit the retained SNP information.} +name of the VCF file that will be created wit the retained SNP information. +The file should have the ".vcf" extension.} \item{offset}{a single \code{integer} that is added to the SNP position to switch from 0-based to 1-based coordinate when needed (or reverse). @@ -36,21 +37,26 @@ a VCF file. ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") -## Demo 1KG GDS file +## Demo 1KG Reference GDS file fileGDS <- openfn.gds(file.path(dataDir, "1KG_Demo.gds")) ## Output VCF file that will be created -vcfFile <- file.path(dataDir, "Demo_TMP_01.vcf") +vcfFile <- file.path(getwd(), "Demo_TMP_01.vcf") -## Create a VCF file with the SNV dataset present in the GDS file -## No cutoff on frequency, so all SNVs are saved -snvListVCF(gdsReference=fileGDS, fileOut=vcfFile, offset=0L, freqCutoff=NULL) +## Run only if directory in writing mode +if (file.access(getwd()) == 0 && !dir.exists(vcfFile)) { -## Close GDS file (IMPORTANT) -closefn.gds(fileGDS) + ## Create a VCF file with the SNV dataset present in the GDS file + ## No cutoff on frequency, so all SNVs are saved + snvListVCF(gdsReference=fileGDS, fileOut=vcfFile, offset=0L, + freqCutoff=NULL) -## Remove temporary VCF file -unlink(vcfFile, force=TRUE) + ## Close GDS file (IMPORTANT) + closefn.gds(fileGDS) + + ## Remove temporary VCF file + unlink(vcfFile, force=TRUE) +} } \author{ From e99bb3537febb343a0acabd6de510b81256f7ead Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 15 Aug 2023 15:01:02 -0400 Subject: [PATCH 095/385] Move groupChrPruning() to admixture file --- R/admixture.R | 57 ++++++++++++++++++++++++++++++++++++++++++ R/tools.R | 56 ----------------------------------------- man/groupChrPruning.Rd | 2 +- 3 files changed, 58 insertions(+), 57 deletions(-) diff --git a/R/admixture.R b/R/admixture.R index d48125b34..bda1e5d94 100644 --- a/R/admixture.R +++ b/R/admixture.R @@ -159,3 +159,60 @@ gds2tped <- function(gds, listSample, listSNP, pedOut) { write.table(tped, pedOut, quote=FALSE, sep="\t", row.names=FALSE, col.names=FALSE) } + + +#' @title Merge the pruning files by chromosome in one RDS file +#' +#' @description The function reads the information from all chromosomes. The +#' information is scattered in different files (one file per chromosome). +#' Once all information is loaded, the function merges +#' the information and saves it into a RDS file. +#' +#' @param pathPrunedGDS a \code{character} string representing the path where +#' the pruned files for each chromosome are located. +#' The path must exists. +#' +#' @param filePref a \code{character} string representing the prefix used for +#' the pruned files for each chromosome. The prefix represent the complete +#' string that is before the chromosome number in the file names. +#' +#' @param fileOut a \code{character} string representing name of the output +#' file that will be created. The file will contain the information for all +#' pruned chromosomes. The file must have a ".rds" extension. +#' +#' @return The integer \code{0L} when successful. +#' +#' @examples +#' +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## TODO +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @encoding UTF-8 +#' @keywords internal +groupChrPruning <- function(pathPrunedGDS, filePref, fileOut) { + + prunedList <- list() + + # Read the content of each file (one file per chromosome) + for(i in seq_len(22)) { + fileChr <- file.path(pathPrunedGDS, paste0(filePref, i, ".rds")) + + if(file.exists(fileChr)) { + prunedList[[i]] <- readRDS(fileChr) + } else { + stop("Problem with the file: ", fileChr) + } + } + + ## Merge the content of all files + pruned <- do.call(c, prunedList) + + ## Save all the information into one file + saveRDS(pruned, fileChr <- file.path(pathPrunedGDS, fileOut)) + + ## Successful + return(0L) +} diff --git a/R/tools.R b/R/tools.R index da0a14e33..b3f286d4d 100644 --- a/R/tools.R +++ b/R/tools.R @@ -134,62 +134,6 @@ snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { return(0L) } -#' @title Merge the pruning files by chromosome in one RDS file -#' -#' @description The function reads the information from all chromosomes. The -#' information is scattered in different files (one file per chromosome). -#' Once all information is loaded, the function merges -#' the information and saves it into a RDS file. -#' -#' @param pathPrunedGDS a \code{character} string representing the path where -#' the pruned files for each chromosome are located. -#' The path must exists. -#' -#' @param filePref a \code{character} string representing the prefix used for -#' the pruned files for each chromosome. The prefix represent the complete -#' string that is before the chromosome number in the file names. -#' -#' @param fileOut a \code{character} string representing name of the output -#' file that will be created. The file will contain the information for all -#' pruned chromosomes. The file must have a ".rds" extension. -#' -#' @return The integer \code{0L} when successful. -#' -#' @examples -#' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") -#' -#' ## TODO -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @encoding UTF-8 -#' @keywords internal -groupChrPruning <- function(pathPrunedGDS, filePref, fileOut) { - - prunedList <- list() - - # Read the content of each file (one file per chromosome) - for(i in seq_len(22)) { - fileChr <- file.path(pathPrunedGDS, paste0(filePref, i, ".rds")) - - if(file.exists(fileChr)) { - prunedList[[i]] <- readRDS(fileChr) - } else { - stop("Problem with the file: ", fileChr) - } - } - - ## Merge the content of all files - pruned <- do.call(c, prunedList) - - ## Save all the information into one file - saveRDS(pruned, fileChr <- file.path(pathPrunedGDS, fileOut)) - - ## Successful - return(0L) -} - #' @title Merge the genotyping files per chromosome into one file #' diff --git a/man/groupChrPruning.Rd b/man/groupChrPruning.Rd index d87abd2ee..3ee80a115 100644 --- a/man/groupChrPruning.Rd +++ b/man/groupChrPruning.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/tools.R +% Please edit documentation in R/admixture.R \encoding{UTF-8} \name{groupChrPruning} \alias{groupChrPruning} From bced9fcc87546bf3e495c72343104ae7d7faeb3e Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 15 Aug 2023 16:54:43 -0400 Subject: [PATCH 096/385] Update documentation for appendGDSgenotype() and generateGDSgenotype() functions --- R/gdsWrapper.R | 89 ++++++++++++++++++++++++++++++++------ man/appendGDSgenotype.Rd | 84 ++++++++++++++++++++++++++++++----- man/generateGDSgenotype.Rd | 3 +- 3 files changed, 151 insertions(+), 25 deletions(-) diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 359daca6e..2bb387910 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -122,7 +122,8 @@ generateGDSSNPinfo <- function(gdsReference, fileFreq, verbose) { #' profiles. #' #' @param gds an object of class -#' \link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file. +#' \link[gdsfmt]{gds.class} (a GDS file), the opened Population Reference +#' GDS file. #' #' @param pathGeno a \code{character} string representing the path where #' the reference genotyping files for each sample are located. The name of the @@ -241,28 +242,90 @@ generateGDSgenotype <- function(gds, pathGeno, fileSNPsRDS, listSamples, return(0L) } -#' @title This function append the field genotype in the gds file +#' @title Append information related to profile genotypes into a Population +#' Reference GDS file (associated node already present in the GDS) #' -#' @description TODO +#' @description This function appends the genotype fields with the associated +#' information into the Population Reference GDS file for the selected +#' profiles. The associated node must already present in the GDS file. #' -#' @param gds a \code{gds} object. +#' @param gds an object of class +#' \link[gdsfmt]{gds.class} (a GDS file), the opened Population Reference +#' GDS file. #' -#' @param pathGeno TODO a PATH to a directory with the a file for each -#' samples with the genotype. +#' @param pathGeno a \code{character} string representing the path where +#' the reference genotyping files for each sample are located. The name of the +#' genotyping files must correspond to +#' the individual identification (Individual.ID) in the pedigree file. #' -#' @param fileSNPsRDS TODO list of SNP to keep in the file genotype +#' @param fileSNPsRDS a \code{character} string representing the path and file +#' name of the RDS file that contains the indexes of the retained SNPs. The +#' file must exist. The file must be a RDS file. #' -#' @param listSamples a \code{array} with the sample to keep +#' @param listSamples a \code{character} string representing the path and file +#' name of the RDS file that contains the indexes of the retained SNPs. The +#' file must exist. The file must be a RDS file. #' #' @param verbose a \code{logical} indicating if the function must print -#' messages when running. Default: \code{FALSE}. +#' messages when running. #' #' @return The integer \code{0} when successful. #' #' @examples #' -#' # TODO -#' gds <- "Demo GDS TODO" +#' ## Required library +#' library(gdsfmt) +#' +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## The RDS file containing the pedigree information +#' pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +#' +#' ## The RDS file containing the indexes of the retained SNPs +#' snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") +#' +#' ## The RDS file containing the filtered SNP information +#' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") +#' +#' ## Temporary Reference GDS file +#' tempRefGDS <- file.path(getwd(), "Ref_TEMP02.gds") +#' +#' ## Only run example if the directory is writable +#' if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { +#' +#' ## Create temporary Reference GDS file +#' newGDS <- createfn.gds(tempRefGDS) +#' put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") +#' +#' ## Read the pedigree file +#' ped1KG <- readRDS(pedigreeFile) +#' +#' ## Add information about samples to the Reference GDS file +#' listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, +#' dfPedReference=ped1KG, listSamples=NULL) +#' +#' ## Add SNV information to the Reference GDS +#' RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, +#' verbose=FALSE) +#' +#' ## Add genotype information to the Reference GDS for the 3 first samples +#' RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, +#' fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS[1:3], +#' verbose=FALSE) +#' +#' ## Append genotype information to the Reference GDS for the other samples +#' RAIDS:::appendGDSgenotype(gds=newGDS, pathGeno=dataDir, +#' fileSNPsRDS=snpIndexFile, +#' listSample=listSampleGDS[4:length(listSampleGDS)], +#' verbose=FALSE) +#' +#' ## Close file +#' closefn.gds(newGDS) +#' +#' ## Remove temporary files +#' unlink(tempRefGDS, force=TRUE) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn @@ -270,7 +333,7 @@ generateGDSgenotype <- function(gds, pathGeno, fileSNPsRDS, listSamples, #' @encoding UTF-8 #' @keywords internal appendGDSgenotype <- function(gds, listSample, pathGeno, fileSNPsRDS, - verbose=FALSE) { + verbose) { # File with the description of the SNP keep listMatRef <- dir(pathGeno, pattern = ".+.csv.bz2") @@ -298,7 +361,7 @@ appendGDSgenotype <- function(gds, listSample, pathGeno, fileSNPsRDS, matSample[matSample[,1] == "1|1",1] <- 2 g <- as.matrix(matSample)[,1] - append.gdsn(geno.var,g, check=TRUE) + append.gdsn(geno.var, g, check=TRUE) rm(matSample) if(verbose) { message(listMatRef[pos], " ", i) } diff --git a/man/appendGDSgenotype.Rd b/man/appendGDSgenotype.Rd index 0de1e1f8e..bef183169 100644 --- a/man/appendGDSgenotype.Rd +++ b/man/appendGDSgenotype.Rd @@ -3,33 +3,95 @@ \encoding{UTF-8} \name{appendGDSgenotype} \alias{appendGDSgenotype} -\title{This function append the field genotype in the gds file} +\title{Append information related to profile genotypes into a Population +Reference GDS file (associated node already present in the GDS)} \usage{ -appendGDSgenotype(gds, listSample, pathGeno, fileSNPsRDS, verbose = FALSE) +appendGDSgenotype(gds, listSample, pathGeno, fileSNPsRDS, verbose) } \arguments{ -\item{gds}{a \code{gds} object.} +\item{gds}{an object of class +\link[gdsfmt]{gds.class} (a GDS file), the opened Population Reference +GDS file.} -\item{pathGeno}{TODO a PATH to a directory with the a file for each -samples with the genotype.} +\item{pathGeno}{a \code{character} string representing the path where +the reference genotyping files for each sample are located. The name of the +genotyping files must correspond to +the individual identification (Individual.ID) in the pedigree file.} -\item{fileSNPsRDS}{TODO list of SNP to keep in the file genotype} +\item{fileSNPsRDS}{a \code{character} string representing the path and file +name of the RDS file that contains the indexes of the retained SNPs. The +file must exist. The file must be a RDS file.} \item{verbose}{a \code{logical} indicating if the function must print -messages when running. Default: \code{FALSE}.} +messages when running.} -\item{listSamples}{a \code{array} with the sample to keep} +\item{listSamples}{a \code{character} string representing the path and file +name of the RDS file that contains the indexes of the retained SNPs. The +file must exist. The file must be a RDS file.} } \value{ The integer \code{0} when successful. } \description{ -TODO +This function appends the genotype fields with the associated +information into the Population Reference GDS file for the selected +profiles. The associated node must already present in the GDS file. } \examples{ -# TODO -gds <- "Demo GDS TODO" +## Required library +library(gdsfmt) + +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +## The RDS file containing the pedigree information +pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") + +## The RDS file containing the indexes of the retained SNPs +snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") + +## The RDS file containing the filtered SNP information +filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") + +## Temporary Reference GDS file +tempRefGDS <- file.path(getwd(), "Ref_TEMP02.gds") + +## Only run example if the directory is writable +if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { + + ## Create temporary Reference GDS file + newGDS <- createfn.gds(tempRefGDS) + put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") + + ## Read the pedigree file + ped1KG <- readRDS(pedigreeFile) + + ## Add information about samples to the Reference GDS file + listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, + dfPedReference=ped1KG, listSamples=NULL) + + ## Add SNV information to the Reference GDS + RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, + verbose=FALSE) + + ## Add genotype information to the Reference GDS for the 3 first samples + RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, + fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS[1:3], + verbose=FALSE) + + ## Append genotype information to the Reference GDS for the other samples + RAIDS:::appendGDSgenotype(gds=newGDS, pathGeno=dataDir, + fileSNPsRDS=snpIndexFile, + listSample=listSampleGDS[4:length(listSampleGDS)], + verbose=FALSE) + + ## Close file + closefn.gds(newGDS) + + ## Remove temporary files + unlink(tempRefGDS, force=TRUE) +} } \author{ diff --git a/man/generateGDSgenotype.Rd b/man/generateGDSgenotype.Rd index d6c15cf0a..2a0650672 100644 --- a/man/generateGDSgenotype.Rd +++ b/man/generateGDSgenotype.Rd @@ -10,7 +10,8 @@ generateGDSgenotype(gds, pathGeno, fileSNPsRDS, listSamples, verbose) } \arguments{ \item{gds}{an object of class -\link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file.} +\link[gdsfmt]{gds.class} (a GDS file), the opened Population Reference +GDS file.} \item{pathGeno}{a \code{character} string representing the path where the reference genotyping files for each sample are located. The name of the From f4c41bd1c9ce6ea6b8df321350c69e8e45df37c7 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 15 Aug 2023 21:27:01 -0400 Subject: [PATCH 097/385] Change comment in predPed1KG() function --- R/process1KG.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/process1KG.R b/R/process1KG.R index 57f39fe4f..dcfd83103 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -93,7 +93,7 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), row.names(pedAll) <- pedAll$sample.id ## Change column format for Sex information - ## TODO: could be done when the data.frame is created + ## NOTE: could be done when the data.frame is created pedAll$sex <- as.character(pedAll$sex) ## Only retained samples with existing genotyping file From fe664cda278e538cf3eebd8dd340145ba2a19691 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 15 Aug 2023 22:44:04 -0400 Subject: [PATCH 098/385] Change addBlockFromPlink2GDS() function parameters to fit camel cases --- R/process1KG.R | 10 +++++----- man/addBlockFromPlink2GDS.Rd | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index dcfd83103..5ee602b32 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -822,7 +822,7 @@ basePCASample <- function(gds, listSample.Ref=NULL, listSNP=NULL, np=1L) { #' #' @param gdsOut an object of class \code{gds} opened in writing mode. #' -#' @param PATHBLOCK TODO +#' @param pathBlock TODO #' #' @param superPop TODO #' @@ -852,7 +852,7 @@ basePCASample <- function(gds, listSample.Ref=NULL, listSNP=NULL, np=1L) { #' @importFrom gdsfmt createfn.gds put.attr.gdsn closefn.gds #' @encoding UTF-8 #' @export -addBlockFromPlink2GDS <- function(gds, gdsOut, PATHBLOCK, +addBlockFromPlink2GDS <- function(gds, gdsOut, pathBlock, superPop, blockName, blockDesc, verbose=FALSE) { @@ -864,7 +864,7 @@ addBlockFromPlink2GDS <- function(gds, gdsOut, PATHBLOCK, ## Extract the SNP chromosomes and positions snpChromosome <- read.gdsn(index.gdsn(gds, "snp.chromosome")) - snp.position <- read.gdsn(index.gdsn(gds, "snp.position")) + snpPosition <- read.gdsn(index.gdsn(gds, "snp.position")) listChr <- unique(snpChromosome) @@ -874,9 +874,9 @@ addBlockFromPlink2GDS <- function(gds, gdsOut, PATHBLOCK, for(chr in listChr) { if(verbose) { message("chr", chr, " ", Sys.time()) } - snp.keep <- snp.position[snpChromosome == chr] + snp.keep <- snpPosition[snpChromosome == chr] - listBlock[[chr]] <- processBlockChr(snp.keep, PATHBLOCK, superPop, chr) + listBlock[[chr]] <- processBlockChr(snp.keep, pathBlock, superPop, chr) if(chr > 1) { vMax <- max(listBlock[[chr-1]]) vMin <- min(listBlock[[chr-1]]) diff --git a/man/addBlockFromPlink2GDS.Rd b/man/addBlockFromPlink2GDS.Rd index f31fe5833..e7800de49 100644 --- a/man/addBlockFromPlink2GDS.Rd +++ b/man/addBlockFromPlink2GDS.Rd @@ -9,7 +9,7 @@ Population Reference GDS Annotation file} addBlockFromPlink2GDS( gds, gdsOut, - PATHBLOCK, + pathBlock, superPop, blockName, blockDesc, @@ -22,7 +22,7 @@ addBlockFromPlink2GDS( \item{gdsOut}{an object of class \code{gds} opened in writing mode.} -\item{PATHBLOCK}{TODO} +\item{pathBlock}{TODO} \item{superPop}{TODO} From 29ab791da4cbeb3058400606ee2d1eaab77a4a57 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 16 Aug 2023 12:16:42 -0400 Subject: [PATCH 099/385] Add unit tests for appendGDSgenotype() and generateGDSgenotype() functions --- tests/testthat/test-gdsWrapper.R | 197 ++++++++++++---------- tests/testthat/test-gdsWrapper_internal.R | 87 ++++++++++ 2 files changed, 199 insertions(+), 85 deletions(-) diff --git a/tests/testthat/test-gdsWrapper.R b/tests/testthat/test-gdsWrapper.R index 003922245..259e3f192 100644 --- a/tests/testthat/test-gdsWrapper.R +++ b/tests/testthat/test-gdsWrapper.R @@ -23,48 +23,6 @@ local_GDS_file <- function(path) { } -############################################################################# -### Tests appendGDSgenotypeMat() results -############################################################################# - -context("appendGDSgenotypeMat() results") - - -test_that("appendGDSgenotypeMat() must copy the expected entry in \"genotype\" node of the GDS file", { - - ## Create a temporary GDS file in an test directory - dataDir <- system.file("extdata/tests", package="RAIDS") - fileGDS <- file.path(dataDir, "GDS_TEMP_06.gds") - - ## Create and open a temporary GDS file - GDS_file_tmp <- local_GDS_file(fileGDS) - - ## Create a "genotype" node with initial matrix - geno_initial <- matrix(rep(0L, 24), nrow=6) - - add.gdsn(node=GDS_file_tmp, name="genotype", val=geno_initial) - sync.gds(GDS_file_tmp) - - ## new genotype to be added - geno_new <- matrix(rep(1L, 12), nrow=6) - - ## Add genotype to the GDS file - results0 <- RAIDS:::appendGDSgenotypeMat(gds=GDS_file_tmp, matG=geno_new) - - ## Read genotype names from GDS file - results1 <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="genotype")) - - ## Close GDS file - ## The file will automatically be deleted - closefn.gds(gdsfile=GDS_file_tmp) - - expected1 <- cbind(geno_initial, geno_new) - - expect_equal(results1, expected1) - expect_equal(results0, 0L) -}) - - ############################################################################# ### Tests generateGDSRefSample() results ############################################################################# @@ -116,49 +74,6 @@ test_that("generateGDSRefSample() must copy the expected entry in \"sample.annot }) -############################################################################# -### Tests addGDSRef() results -############################################################################# - -context("addGDSRef() results") - - -test_that("addGDSRef() must return expected result", { - - ## Create and open a temporary GDS file - GDS_path <- test_path("fixtures", "GDS_addGDSRef_Temp_01.gds") - GDS_file_tmp <- createfn.gds(filename=GDS_path) - defer(unlink(x=GDS_path, force=TRUE), envir=parent.frame()) - - ## Create "sample.id" node (the node must be present) - sampleIDs <- c("HG00104", "HG00105", "HG00106", "HG00109", "HG00110") - add.gdsn(node=GDS_file_tmp, name="sample.id", val=sampleIDs) - sync.gds(GDS_file_tmp) - - listD <- list(rels=c("HG00106", "HG00110"), unrels=c("HG00104", - "HG00105", "HG00109")) - - RDS_file_tmp <- test_path("fixtures", "RDS_addGDSRef_Temp_01.RDS") - - saveRDS(listD, RDS_file_tmp) - defer(unlink(RDS_file_tmp), envir=parent.frame()) - - ## Add samples to the GDS file - results3 <- RAIDS:::addGDSRef(gdsReference=GDS_file_tmp, filePart=RDS_file_tmp) - - ## Read sample names from GDS file - results1 <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.ref")) - - ## Close GDS file - ## The file will automatically be deleted - closefn.gds(gdsfile=GDS_file_tmp) - - expected1 <- c(1, 1, 0, 1, 0) - - expect_equal(results3, 0L) - expect_equal(results1, expected1) -}) - ############################################################################# ### Tests addBlockInGDSAnnot() results @@ -213,3 +128,115 @@ test_that("addBlockInGDSAnnot() must return expected result", { expect_equal(results4, matrix(data=c(entries, entries2), ncol=2, byrow=FALSE)) }) + +############################################################################# +### Tests generateGDSgenotype() results +############################################################################# + +context("generateGDSgenotype() results") + +test_that("generateGDSgenotype() must return expected result", { + + ## Create and open a temporary GDS Annotation file + GDS_path <- test_path("fixtures", "GDS_generateGDSgenotype_Temp_01.gds") + GDS_file_tmp <- createfn.gds(filename=GDS_path) + defer(unlink(x=GDS_path, force=TRUE), envir=parent.frame()) + + put.attr.gdsn(GDS_file_tmp$root, "FileFormat", "SNP_ARRAY") + + pedigree <- data.frame(sample.id=c("HG00100", "HG00101", "HG00102"), + Name.ID=c("HG00100", "HG00101", "HG00102"), + sex=c(1,2,2), pop.group=c("ACB", "ACB", "ACB"), + superPop=c("AFR", "AFR", "AFR"), batch=c(0, 0, 0), + stringsAsFactors=FALSE) + + rownames(pedigree) <- pedigree$sample.id + + filterSNVFile <- test_path("fixtures", "mapSNVSelected_Demo.rds") + + ## Add information about samples + listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=GDS_file_tmp, + dfPedReference=pedigree, listSamples=NULL) + + ## Add SNV information to the Reference GDS + RAIDS:::generateGDSSNPinfo(gdsReference=GDS_file_tmp, + fileFreq=filterSNVFile, verbose=FALSE) + + snpIndexFile <- test_path("fixtures", "listSNPIndexes_Demo.rds") + + ## Add genotype information to the Reference GDS + result1 <- RAIDS:::generateGDSgenotype(gds=GDS_file_tmp, + pathGeno=test_path("fixtures"), + fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS, verbose=FALSE) + + result2 <- read.gdsn(index.gdsn(GDS_file_tmp, "genotype")) + + ## Close GDS file + ## The file will automatically be deleted + closefn.gds(gdsfile=GDS_file_tmp) + + expect_equal(result1, 0L) + expect_equal(result2, matrix(data=c(0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, + 1, 0, 0, 2, 2, 0, 2, 1), nrow=7, byrow=FALSE)) + +}) + + +############################################################################# +### Tests appendGDSgenotype() results +############################################################################# + +context("appendGDSgenotype() results") + +test_that("appendGDSgenotype() must return expected result", { + + ## Create and open a temporary GDS Annotation file + GDS_path <- test_path("fixtures", "GDS_appendGDSgenotype_Temp_01.gds") + GDS_file_tmp <- createfn.gds(filename=GDS_path) + defer(unlink(x=GDS_path, force=TRUE), envir=parent.frame()) + + put.attr.gdsn(GDS_file_tmp$root, "FileFormat", "SNP_ARRAY") + + pedigree <- data.frame(sample.id=c("HG00100", "HG00101", "HG00102"), + Name.ID=c("HG00100", "HG00101", "HG00102"), + sex=c(1,2,2), pop.group=c("ACB", "ACB", "ACB"), + superPop=c("AFR", "AFR", "AFR"), batch=c(0, 0, 0), + stringsAsFactors=FALSE) + + rownames(pedigree) <- pedigree$sample.id + + filterSNVFile <- test_path("fixtures", "mapSNVSelected_Demo.rds") + + ## Add information about samples + listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=GDS_file_tmp, + dfPedReference=pedigree, listSamples=NULL) + + ## Add SNV information to the Reference GDS + RAIDS:::generateGDSSNPinfo(gdsReference=GDS_file_tmp, + fileFreq=filterSNVFile, verbose=FALSE) + + snpIndexFile <- test_path("fixtures", "listSNPIndexes_Demo.rds") + + ## Add genotype information to the Reference GDS + result1 <- RAIDS:::generateGDSgenotype(gds=GDS_file_tmp, + pathGeno=test_path("fixtures"), + fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS[1], verbose=FALSE) + + + ## Append genotype information to the Reference GDS + result1 <- RAIDS:::appendGDSgenotype(gds=GDS_file_tmp, + pathGeno=test_path("fixtures"), + fileSNPsRDS=snpIndexFile, listSample=listSampleGDS[2], + verbose=FALSE) + + result2 <- read.gdsn(index.gdsn(GDS_file_tmp, "genotype")) + + ## Close GDS file + ## The file will automatically be deleted + closefn.gds(gdsfile=GDS_file_tmp) + + expect_equal(result1, 0L) + expect_equal(result2, matrix(data=c(0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, + 1), nrow=7, byrow=FALSE)) + +}) diff --git a/tests/testthat/test-gdsWrapper_internal.R b/tests/testthat/test-gdsWrapper_internal.R index a8c0d5f98..4797701fa 100644 --- a/tests/testthat/test-gdsWrapper_internal.R +++ b/tests/testthat/test-gdsWrapper_internal.R @@ -23,6 +23,93 @@ local_GDS_file <- function(path) { } +############################################################################# +### Tests addGDSRef() results +############################################################################# + +context("addGDSRef() results") + + +test_that("addGDSRef() must return expected result", { + + ## Create and open a temporary GDS file + GDS_path <- test_path("fixtures", "GDS_addGDSRef_Temp_01.gds") + GDS_file_tmp <- createfn.gds(filename=GDS_path) + defer(unlink(x=GDS_path, force=TRUE), envir=parent.frame()) + + ## Create "sample.id" node (the node must be present) + sampleIDs <- c("HG00104", "HG00105", "HG00106", "HG00109", "HG00110") + add.gdsn(node=GDS_file_tmp, name="sample.id", val=sampleIDs) + sync.gds(GDS_file_tmp) + + listD <- list(rels=c("HG00106", "HG00110"), unrels=c("HG00104", + "HG00105", "HG00109")) + + RDS_file_tmp <- test_path("fixtures", "RDS_addGDSRef_Temp_01.RDS") + + saveRDS(listD, RDS_file_tmp) + defer(unlink(RDS_file_tmp), envir=parent.frame()) + + ## Add samples to the GDS file + results3 <- RAIDS:::addGDSRef(gdsReference=GDS_file_tmp, + filePart=RDS_file_tmp) + + ## Read sample names from GDS file + results1 <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.ref")) + + ## Close GDS file + ## The file will automatically be deleted + closefn.gds(gdsfile=GDS_file_tmp) + + expected1 <- c(1, 1, 0, 1, 0) + + expect_equal(results3, 0L) + expect_equal(results1, expected1) +}) + + +############################################################################# +### Tests appendGDSgenotypeMat() results +############################################################################# + +context("appendGDSgenotypeMat() results") + + +test_that("appendGDSgenotypeMat() must copy the expected entry in \"genotype\" node of the GDS file", { + + ## Create a temporary GDS file in an test directory + dataDir <- system.file("extdata/tests", package="RAIDS") + fileGDS <- file.path(dataDir, "GDS_TEMP_06.gds") + + ## Create and open a temporary GDS file + GDS_file_tmp <- local_GDS_file(fileGDS) + + ## Create a "genotype" node with initial matrix + geno_initial <- matrix(rep(0L, 24), nrow=6) + + add.gdsn(node=GDS_file_tmp, name="genotype", val=geno_initial) + sync.gds(GDS_file_tmp) + + ## new genotype to be added + geno_new <- matrix(rep(1L, 12), nrow=6) + + ## Add genotype to the GDS file + results0 <- RAIDS:::appendGDSgenotypeMat(gds=GDS_file_tmp, matG=geno_new) + + ## Read genotype names from GDS file + results1 <- read.gdsn(index.gdsn(node=GDS_file_tmp, path="genotype")) + + ## Close GDS file + ## The file will automatically be deleted + closefn.gds(gdsfile=GDS_file_tmp) + + expected1 <- cbind(geno_initial, geno_new) + + expect_equal(results1, expected1) + expect_equal(results0, 0L) +}) + + ############################################################################# ### Tests runIBDKING() results ############################################################################# From 24c48c98c05cbda05c98410fcd75943e78b6e545 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 16 Aug 2023 14:53:18 -0400 Subject: [PATCH 100/385] Change variables to fit camel cases in processBlockChr() function --- R/tools_internal.R | 34 +++++++++++++++++----------------- man/processBlockChr.Rd | 6 +++--- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/R/tools_internal.R b/R/tools_internal.R index 39ad201cc..0fd19649c 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -183,9 +183,9 @@ validatePositiveIntegerVector <- function(value, name) { #' #' @description TODO #' -#' @param snp.keep TODO +#' @param snpKeep TODO #' -#' @param PATHBLOCK TODO +#' @param pathBlock TODO #' #' @param superPop TODO #' @@ -202,47 +202,47 @@ validatePositiveIntegerVector <- function(value, name) { #' @importFrom gdsfmt add.gdsn #' @encoding UTF-8 #' @keywords internal -processBlockChr <- function(snp.keep, PATHBLOCK, superPop, chr) { +processBlockChr <- function(snpKeep, pathBlock, superPop, chr) { - blockChr <- read.delim(file.path(PATHBLOCK, + blockChr <- read.delim(file.path(pathBlock, paste0("block.sp.", superPop, ".f0.05.chr", chr, ".blocks.det")), sep="") - z <- cbind(c(blockChr$BP1, snp.keep, blockChr$BP2+1), + z <- cbind(c(blockChr$BP1, snpKeep, blockChr$BP2+1), c(seq_len(nrow(blockChr)), - rep(0, length(snp.keep)), -1*seq_len(nrow(blockChr)))) + rep(0, length(snpKeep)), -1*seq_len(nrow(blockChr)))) z <- z[order(z[,1]),] - block.snp <- cumsum(z[,2])[z[,2] == 0] + blockSnp <- cumsum(z[,2])[z[,2] == 0] curStart <- 0 activeBlock <- 0 blockState <- 0 - block.inter <- rep(0, length(which(block.snp == 0))) + blockInter <- rep(0, length(which(blockSnp == 0))) k <- 1 - for(i in seq_len(length(block.snp))){ - if(block.snp[i] == 0){ + for(i in seq_len(length(blockSnp))){ + if(blockSnp[i] == 0){ if(activeBlock == 1){ - if(snp.keep[i] - curStart >= 10000) { + if(snpKeep[i] - curStart >= 10000) { blockState <- blockState - 1 - curStart <- snp.keep[i] + curStart <- snpKeep[i] } } else{ blockState <- blockState - 1 - curStart <- snp.keep[i] - curStart <- snp.keep[i] + curStart <- snpKeep[i] + curStart <- snpKeep[i] activeBlock <- 1 } - block.inter[k] <- blockState + blockInter[k] <- blockState k <- k + 1 }else{ activeBlock <- 0 } } - block.snp[block.snp == 0] <- block.inter + blockSnp[blockSnp == 0] <- blockInter - return(block.snp) + return(blockSnp) } diff --git a/man/processBlockChr.Rd b/man/processBlockChr.Rd index a0e39ac5d..2aef2d7ed 100644 --- a/man/processBlockChr.Rd +++ b/man/processBlockChr.Rd @@ -5,12 +5,12 @@ \alias{processBlockChr} \title{TODO} \usage{ -processBlockChr(snp.keep, PATHBLOCK, superPop, chr) +processBlockChr(snpKeep, pathBlock, superPop, chr) } \arguments{ -\item{snp.keep}{TODO} +\item{snpKeep}{TODO} -\item{PATHBLOCK}{TODO} +\item{pathBlock}{TODO} \item{superPop}{TODO} From bbdb8566cbf876acfd63a1047f4d8a859cbe000d Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 16 Aug 2023 17:12:34 -0400 Subject: [PATCH 101/385] Update runRNAAncestry() documentation and correct indents --- R/processStudy.R | 32 ++++++++++++++++---------------- man/runRNAAncestry.Rd | 13 +++++++------ 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index a5c2fc856..3241a3604 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2524,12 +2524,12 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, } #' @title Run most steps leading to the ancestry inference call on a specific -#' profile +#' RNA profile #' #' @description This function runs most steps leading to the ancestry inference -#' call on a specific profile. First, the function creates the Profile GDS file -#' for the specific profile using the information from a RDS Sample -#' description file and the 1KG reference GDS file. +#' call on a specific RNA profile. First, the function creates the +#' Profile GDS file for the specific profile using the information from a +#' RDS Sample description file and the Population Reference GDS file. #' #' @param pedStudy a \code{data.frame} with those mandatory columns: "Name.ID", #' "Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in @@ -2557,10 +2557,11 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' the directory where the output files are created. #' #' @param fileReferenceGDS a \code{character} string representing the file -#' name of the Reference GDS file. The file must exist. +#' name of the Population Reference GDS file. The file must exist. #' #' @param fileReferenceAnnotGDS a \code{character} string representing the -#' file name of the Reference GDS Annotation file. The file must exist. +#' file name of the Population Reference GDS Annotation file. The file +#' must exist. #' #' @param chrInfo a \code{vector} of positive \code{integer} values #' representing the length of the chromosomes. See 'details' section. @@ -2709,23 +2710,22 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @encoding UTF-8 #' @export runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, - pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic"), verbose=FALSE) { + pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic"), verbose=FALSE) { ## Validate parameters validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, - pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, - fileReferenceGDS=fileReferenceGDS, - fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, - syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) + pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, + syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) genoSource <- arg_match(genoSource) r <- runWrapperAncestry(pedStudy, studyDF, pathProfileGDS, - pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, - genoSource, studyType="RNA", verbose) + pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, genoSource, studyType="RNA", verbose) ## Successful return(r) diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index 9a1119610..f5d9b61e2 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -4,7 +4,7 @@ \name{runRNAAncestry} \alias{runRNAAncestry} \title{Run most steps leading to the ancestry inference call on a specific -profile} +RNA profile} \usage{ runRNAAncestry( pedStudy, @@ -47,10 +47,11 @@ associated SNP-pileup file called "Name.ID.txt.gz".} the directory where the output files are created.} \item{fileReferenceGDS}{a \code{character} string representing the file -name of the Reference GDS file. The file must exist.} +name of the Population Reference GDS file. The file must exist.} \item{fileReferenceAnnotGDS}{a \code{character} string representing the -file name of the Reference GDS Annotation file. The file must exist.} +file name of the Population Reference GDS Annotation file. The file +must exist.} \item{chrInfo}{a \code{vector} of positive \code{integer} values representing the length of the chromosomes. See 'details' section.} @@ -85,9 +86,9 @@ more information about the generated output files. } \description{ This function runs most steps leading to the ancestry inference -call on a specific profile. First, the function creates the Profile GDS file -for the specific profile using the information from a RDS Sample -description file and the 1KG reference GDS file. +call on a specific RNA profile. First, the function creates the +Profile GDS file for the specific profile using the information from a +RDS Sample description file and the Population Reference GDS file. } \details{ The runExomeAncestry() function generates 3 types of files From 2f6bc78facd99de67e6a1d2df2da74dbf943b96d Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 16 Aug 2023 17:44:18 -0400 Subject: [PATCH 102/385] Correct indent in processStudy.R --- R/processStudy.R | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 3241a3604..f41ca314b 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2315,12 +2315,12 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' @title Run most steps leading to the ancestry inference call on a specific -#' profile +#' exome profile #' #' @description This function runs most steps leading to the ancestry inference -#' call on a specific profile. First, the function creates the Profile GDS file -#' for the specific profile using the information from a RDS Sample -#' description file and the 1KG reference GDS file. +#' call on a specific exome profile. First, the function creates the +#' Profile GDS file for the specific profile using the information from a +#' RDS Sample description file and the Population reference GDS file. #' #' @param pedStudy a \code{data.frame} with those mandatory columns: "Name.ID", #' "Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in @@ -2351,7 +2351,8 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' name of the Reference GDS file. The file must exist. #' #' @param fileReferenceAnnotGDS a \code{character} string representing the -#' file name of the Reference GDS Annotation file. The file must exist. +#' file name of the Population Reference GDS Annotation file. The file must +#' exist. #' #' @param chrInfo a \code{vector} of positive \code{integer} values #' representing the length of the chromosomes. See 'details' section. @@ -2515,9 +2516,8 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, r <- runWrapperAncestry(pedStudy, studyDF, pathProfileGDS, - pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, - genoSource, studyType="DNA", verbose) + pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, genoSource, studyType="DNA", verbose) ## Successful return(r) From 8bd3c14c88356ec84d80681b884abd97e1bbcc18 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 16 Aug 2023 17:50:14 -0400 Subject: [PATCH 103/385] Update runExomeAncestry man page --- man/runExomeAncestry.Rd | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index 42ce3e82f..6adc80f16 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -4,7 +4,7 @@ \name{runExomeAncestry} \alias{runExomeAncestry} \title{Run most steps leading to the ancestry inference call on a specific -profile} +exome profile} \usage{ runExomeAncestry( pedStudy, @@ -50,7 +50,8 @@ the directory where the output files are created.} name of the Reference GDS file. The file must exist.} \item{fileReferenceAnnotGDS}{a \code{character} string representing the -file name of the Reference GDS Annotation file. The file must exist.} +file name of the Population Reference GDS Annotation file. The file must +exist.} \item{chrInfo}{a \code{vector} of positive \code{integer} values representing the length of the chromosomes. See 'details' section.} @@ -85,9 +86,9 @@ more information about the generated output files. } \description{ This function runs most steps leading to the ancestry inference -call on a specific profile. First, the function creates the Profile GDS file -for the specific profile using the information from a RDS Sample -description file and the 1KG reference GDS file. +call on a specific exome profile. First, the function creates the +Profile GDS file for the specific profile using the information from a +RDS Sample description file and the Population reference GDS file. } \details{ The runExomeAncestry() function generates 3 types of files From ba6b3b67612dc4c5e752af9832ba030de64c8b52 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 16 Aug 2023 19:01:02 -0400 Subject: [PATCH 104/385] Add unit tests for generateGDSgenotype() and appendGDSgenotype() functions --- tests/testthat/test-gdsWrapper.R | 90 ++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/tests/testthat/test-gdsWrapper.R b/tests/testthat/test-gdsWrapper.R index 259e3f192..a33e49ef7 100644 --- a/tests/testthat/test-gdsWrapper.R +++ b/tests/testthat/test-gdsWrapper.R @@ -182,6 +182,46 @@ test_that("generateGDSgenotype() must return expected result", { }) +test_that("generateGDSgenotype() must return expected error when sample not present", { + + ## Create and open a temporary GDS Annotation file + GDS_path <- test_path("fixtures", "GDS_generateGDSgenotype_Temp_02.gds") + GDS_file_tmp <- createfn.gds(filename=GDS_path) + defer(closefn.gds(GDS_file_tmp), envir = parent.frame(), + priority = "first") + defer(unlink(x=GDS_path, force=TRUE), envir=parent.frame(), + priority = "last") + + put.attr.gdsn(GDS_file_tmp$root, "FileFormat", "SNP_ARRAY") + + pedigree <- data.frame(sample.id=c("HG00100", "HG00101", "HG00102"), + Name.ID=c("HG00100", "HG00101", "HG00102"), + sex=c(1,2,2), pop.group=c("ACB", "ACB", "ACB"), + superPop=c("AFR", "AFR", "AFR"), batch=c(0, 0, 0), + stringsAsFactors=FALSE) + + rownames(pedigree) <- pedigree$sample.id + + filterSNVFile <- test_path("fixtures", "mapSNVSelected_Demo.rds") + + ## Add information about samples + listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=GDS_file_tmp, + dfPedReference=pedigree, listSamples=NULL) + + ## Add SNV information to the Reference GDS + RAIDS:::generateGDSSNPinfo(gdsReference=GDS_file_tmp, + fileFreq=filterSNVFile, verbose=FALSE) + + snpIndexFile <- test_path("fixtures", "listSNPIndexes_Demo.rds") + + error_message <- "Missing samples genotype in BYEBYE" + + expect_error(RAIDS:::generateGDSgenotype(gds=GDS_file_tmp, + pathGeno=test_path("fixtures"), fileSNPsRDS=snpIndexFile, + listSamples="BYEBYE", verbose=FALSE), error_message, fixed=TRUE) +}) + + ############################################################################# ### Tests appendGDSgenotype() results ############################################################################# @@ -240,3 +280,53 @@ test_that("appendGDSgenotype() must return expected result", { 1), nrow=7, byrow=FALSE)) }) + +test_that("appendGDSgenotype() must return expected error when sample not present", { + + ## Create and open a temporary GDS Annotation file + GDS_path <- test_path("fixtures", "GDS_appendGDSgenotype_Temp_02.gds") + GDS_file_tmp <- createfn.gds(filename=GDS_path) + defer(closefn.gds(GDS_file_tmp), envir = parent.frame(), + priority = "first") + defer(unlink(x=GDS_path, force=TRUE), envir=parent.frame(), + priority = "last") + + put.attr.gdsn(GDS_file_tmp$root, "FileFormat", "SNP_ARRAY") + + pedigree <- data.frame(sample.id=c("HG00100", "HG00101", "HG00102"), + Name.ID=c("HG00100", "HG00101", "HG00102"), + sex=c(1,2,2), pop.group=c("ACB", "ACB", "ACB"), + superPop=c("AFR", "AFR", "AFR"), batch=c(0, 0, 0), + stringsAsFactors=FALSE) + + rownames(pedigree) <- pedigree$sample.id + + filterSNVFile <- test_path("fixtures", "mapSNVSelected_Demo.rds") + + ## Add information about samples + listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=GDS_file_tmp, + dfPedReference=pedigree, listSamples=NULL) + + ## Add SNV information to the Reference GDS + RAIDS:::generateGDSSNPinfo(gdsReference=GDS_file_tmp, + fileFreq=filterSNVFile, verbose=FALSE) + + snpIndexFile <- test_path("fixtures", "listSNPIndexes_Demo.rds") + + ## Add genotype information to the Reference GDS + result1 <- RAIDS:::generateGDSgenotype(gds=GDS_file_tmp, + pathGeno=test_path("fixtures"), + fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS[1], verbose=FALSE) + + ## Append genotype information to the Reference GDS + result1 <- RAIDS:::appendGDSgenotype(gds=GDS_file_tmp, + pathGeno=test_path("fixtures"), + fileSNPsRDS=snpIndexFile, listSample=listSampleGDS[2], + verbose=FALSE) + + error_message <- "Missing reference samples HELLO_CANADA" + + expect_error(RAIDS:::appendGDSgenotype(gds=GDS_file_tmp, + pathGeno=test_path("fixtures"), fileSNPsRDS=snpIndexFile, + listSample="HELLO_CANADA", verbose=FALSE), error_message, fixed=TRUE) +}) From 67b6036249387fe8a55c65228e324b3cc3e99957 Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 16 Aug 2023 20:45:16 -0400 Subject: [PATCH 105/385] Update wrappers --- R/allelicFraction_internal.R | 10 +++++-- R/processStudy.R | 21 +++++++++++--- R/processStudy_internal.R | 55 +++++++++++++++++++++++++++--------- man/runExomeAncestry.Rd | 4 +++ man/runProfileAncestry.Rd | 9 ++++++ man/runRNAAncestry.Rd | 9 ++++++ man/runWrapperAncestry.Rd | 9 ++++++ 7 files changed, 97 insertions(+), 20 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 901865f73..550532ead 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -763,9 +763,15 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, blockAF <- do.call(rbind, listBlock) listMissing <- which(abs(blockAF$aRF + 1) < 1e-6) - blockAF[listMissing, "aRF"] <- sample(blockAF$aRF[-1*listMissing], - length(listMissing), replace=TRUE) + if(length(listMissing) > 0){ + if(length(blockAF$aRF[-1*listMissing]) == 0){ + blockAF[listMissing, "aRF"] <- 0.5 + }else{ + blockAF[listMissing, "aRF"] <- sample(blockAF$aRF[-1*listMissing], + length(listMissing), replace=TRUE) + } + } for(b in seq_len(nrow(blockAF))) { snpPos$lap[snpPos$block.id == blockAF$block[b]] <- blockAF$aRF[b] diff --git a/R/processStudy.R b/R/processStudy.R index f41ca314b..97cfc6b60 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2378,6 +2378,9 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' FileR is the deep of the reference allele, and #' File1A is the deep of the specific alternative allele #' +#' @param np a single positive \code{integer} specifying the number of +#' threads to be used. Default: \code{1L}. +#' #' @param verbose a \code{logical} indicating if messages should be printed #' to show how the different steps in the function. Default: \code{FALSE}. #' @@ -2503,7 +2506,8 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic"), verbose=FALSE) { + genoSource=c("snp-pileup", "generic"), np=1L, + verbose=FALSE) { ## Validate parameters validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, @@ -2517,7 +2521,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, r <- runWrapperAncestry(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, genoSource, studyType="DNA", verbose) + chrInfo, syntheticRefDF, genoSource, studyType="DNA", np=np, verbose) ## Successful return(r) @@ -2587,6 +2591,13 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' FileR is the deep of the reference allele, and #' File1A is the deep of the specific alternative allele #' +#' @param np a single positive \code{integer} specifying the number of +#' threads to be used. Default: \code{1L}. +#' +#' @param blockTypeID a \code{character} string corresponding to the block +#' type used to extract the block identifiers. The block type must be +#' present in the GDS Reference Annotation file. +#' #' @param verbose a \code{logical} indicating if messages should be printed #' to show how the different steps in the function. Default: \code{FALSE}. #' @@ -2712,7 +2723,8 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic"), verbose=FALSE) { + genoSource=c("snp-pileup", "generic"), np=1L, + blockTypeID, verbose=FALSE) { ## Validate parameters validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, @@ -2725,7 +2737,8 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, r <- runWrapperAncestry(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, genoSource, studyType="RNA", verbose) + chrInfo, syntheticRefDF, genoSource, studyType="RNA", np=np, + blockTypeID=blockTypeID, verbose) ## Successful return(r) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 7070bedc5..de6f109a3 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2078,6 +2078,13 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' The possible choices are: "DNA" and "RNA". The type of study affects the #' way the estimation of the allelic fraction is done. Default: \code{"DNA"}. #' +#' @param np a single positive \code{integer} specifying the number of +#' threads to be used. Default: \code{1L}. +#' +#' @param blockTypeID a \code{character} string corresponding to the block +#' type used to extract the block identifiers. The block type must be +#' present in the GDS Reference Annotation file. +#' #' @param verbose a \code{logical} indicating if messages should be printed #' to show how the different steps in the function. Default: \code{FALSE}. #' @@ -2120,7 +2127,9 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' @keywords @internal runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfile, pathProfileGDS, pathOut, chrInfo, syntheticRefDF, studyDFSyn, listProfileRef, - studyType=c("DNA", "RNA"), verbose=FALSE) { + studyType=c("DNA", "RNA"), + np=1L, blockTypeID=NULL, + verbose=FALSE) { ## Validate parameters TODO # validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, @@ -2132,29 +2141,35 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil studyType <- arg_match(studyType) pruningSample(gdsReference=gdsReference, currentProfile=currentProfile, - studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS) + studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS, + np=np) + fileGDSProfile <- file.path(pathProfileGDS, paste0(currentProfile, ".gds")) add1KG2SampleGDS(gdsReference=gdsReference, fileProfileGDS=fileGDSProfile, - currentProfile=currentProfile, - studyID=studyDF$study.id) + currentProfile=currentProfile, + studyID=studyDF$study.id) + addStudy1Kg(gdsReference, fileGDSProfile) gdsProfile <- openfn.gds(fileGDSProfile, readonly=FALSE) estimateAllelicFraction(gdsReference=gdsReference, gdsProfile=gdsProfile, - currentProfile=currentProfile, studyID=studyDF$study.id, - chrInfo=chrInfo, studyType=studyType, gdsRefAnnot=gdsRefAnnot, verbose=verbose) + currentProfile=currentProfile, studyID=studyDF$study.id, + chrInfo=chrInfo, studyType=studyType, + gdsRefAnnot=gdsRefAnnot, + blockID=blockTypeID, + verbose=verbose) closefn.gds(gdsProfile) ## Add information related to the synthetic profiles in Profile GDS file prepSynthetic(fileProfileGDS=fileGDSProfile, - listSampleRef=listProfileRef, profileID=currentProfile, - studyDF=studyDFSyn, prefix="1", verbose=verbose) + listSampleRef=listProfileRef, profileID=currentProfile, + studyDF=studyDFSyn, prefix="1", verbose=verbose) resG <- syntheticGeno(gdsReference=gdsReference, gdsRefAnnot=gdsRefAnnot, - fileProfileGDS=fileGDSProfile, profileID=currentProfile, - listSampleRef=listProfileRef, prefix="1") + fileProfileGDS=fileGDSProfile, profileID=currentProfile, + listSampleRef=listProfileRef, prefix="1") if(! file.exists(pathOut)) { dir.create(pathOut) @@ -2182,7 +2197,7 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, sampleRM=sampleRM[x,], studyIDSyn=studyDFSyn$study.id, - np=1L, spRef=spRef, + np=np, spRef=spRef, eigenCount=15L, verbose=verbose) @@ -2220,7 +2235,7 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil resCall <- computeAncestryFromSyntheticFile(gdsReference=gdsReference, gdsProfile=gdsProfile, listFiles=listFiles, currentProfile=currentProfile, spRef=spRef, - studyIDSyn=studyDFSyn$study.id, np=1L) + studyIDSyn=studyDFSyn$study.id, np=np) saveRDS(resCall, file.path(pathOut, paste0(currentProfile, ".infoCall", ".rds"))) @@ -2303,6 +2318,13 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil #' FileR is the deep of the reference allele, and #' File1A is the deep of the specific alternative allele #' +#' @param np a single positive \code{integer} specifying the number of +#' threads to be used. Default: \code{1L}. +#' +#' @param blockTypeID a \code{character} string corresponding to the block +#' type used to extract the block identifiers. The block type must be +#' present in the GDS Reference Annotation file. +#' #' @param verbose a \code{logical} indicating if messages should be printed #' to show how the different steps in the function. Default: \code{FALSE}. #' @@ -2429,7 +2451,10 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic"), studyType=c("DNA", "RNA"), verbose=FALSE) { + genoSource=c("snp-pileup", "generic"), + studyType=c("DNA", "RNA"), + np=1L, blockTypeID=NULL, + verbose=FALSE) { ## Validate parameters validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, @@ -2470,7 +2495,9 @@ runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, pathOut, chrInfo, syntheticRefDF, studyDFSyn, listProfileRef, - studyType, verbose) + studyType, + np=np, blockTypeID=blockTypeID, + verbose) return(NULL) }, gdsReference=gdsReference, gdsRefAnnot=gdsRefAnnot, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathOut=pathOut, diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index 6adc80f16..aacbe47a4 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -17,6 +17,7 @@ runExomeAncestry( chrInfo, syntheticRefDF, genoSource = c("snp-pileup", "generic"), + np = 1L, verbose = FALSE ) } @@ -77,6 +78,9 @@ where Count is the deep at the position, FileR is the deep of the reference allele, and File1A is the deep of the specific alternative allele} +\item{np}{a single positive \code{integer} specifying the number of +threads to be used. Default: \code{1L}.} + \item{verbose}{a \code{logical} indicating if messages should be printed to show how the different steps in the function. Default: \code{FALSE}.} } diff --git a/man/runProfileAncestry.Rd b/man/runProfileAncestry.Rd index 679948a4b..1c8b243d6 100644 --- a/man/runProfileAncestry.Rd +++ b/man/runProfileAncestry.Rd @@ -18,6 +18,8 @@ runProfileAncestry( studyDFSyn, listProfileRef, studyType = c("DNA", "RNA"), + np = 1L, + blockTypeID = NULL, verbose = FALSE ) } @@ -73,6 +75,13 @@ generate the synthetic profiles.} The possible choices are: "DNA" and "RNA". The type of study affects the way the estimation of the allelic fraction is done. Default: \code{"DNA"}.} +\item{np}{a single positive \code{integer} specifying the number of +threads to be used. Default: \code{1L}.} + +\item{blockTypeID}{a \code{character} string corresponding to the block +type used to extract the block identifiers. The block type must be +present in the GDS Reference Annotation file.} + \item{verbose}{a \code{logical} indicating if messages should be printed to show how the different steps in the function. Default: \code{FALSE}.} } diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index f5d9b61e2..ad2418e00 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -17,6 +17,8 @@ runRNAAncestry( chrInfo, syntheticRefDF, genoSource = c("snp-pileup", "generic"), + np = 1L, + blockTypeID, verbose = FALSE ) } @@ -77,6 +79,13 @@ where Count is the deep at the position, FileR is the deep of the reference allele, and File1A is the deep of the specific alternative allele} +\item{np}{a single positive \code{integer} specifying the number of +threads to be used. Default: \code{1L}.} + +\item{blockTypeID}{a \code{character} string corresponding to the block +type used to extract the block identifiers. The block type must be +present in the GDS Reference Annotation file.} + \item{verbose}{a \code{logical} indicating if messages should be printed to show how the different steps in the function. Default: \code{FALSE}.} } diff --git a/man/runWrapperAncestry.Rd b/man/runWrapperAncestry.Rd index 1e3e007d9..35699b1c1 100644 --- a/man/runWrapperAncestry.Rd +++ b/man/runWrapperAncestry.Rd @@ -18,6 +18,8 @@ runWrapperAncestry( syntheticRefDF, genoSource = c("snp-pileup", "generic"), studyType = c("DNA", "RNA"), + np = 1L, + blockTypeID = NULL, verbose = FALSE ) } @@ -81,6 +83,13 @@ File1A is the deep of the specific alternative allele} The possible choices are: "DNA" and "RNA". The type of study affects the way the estimation of the allelic fraction is done. Default: \code{"DNA"}.} +\item{np}{a single positive \code{integer} specifying the number of +threads to be used. Default: \code{1L}.} + +\item{blockTypeID}{a \code{character} string corresponding to the block +type used to extract the block identifiers. The block type must be +present in the GDS Reference Annotation file.} + \item{verbose}{a \code{logical} indicating if messages should be printed to show how the different steps in the function. Default: \code{FALSE}.} } From 0c66627036411a230fe47098575b185b31b6704a Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 16 Aug 2023 22:27:26 -0400 Subject: [PATCH 106/385] Update example for createStudy2GDS1KG() to validate that the directory is writing mode --- R/processStudy.R | 30 ++++++++++++++++++------------ man/createStudy2GDS1KG.Rd | 30 ++++++++++++++++++------------ 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index f41ca314b..5924d46be 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -90,25 +90,31 @@ #' Source=rep("Databank B", 2), stringsAsFactors=FALSE) #' rownames(samplePED) <- samplePED$Name.ID #' -#' ## Create the Profile GDS File for sample in listSamples vector -#' ## (in this case, samples "ex1") -#' ## The Profile GDS file is created in the pathProfileGDS directory -#' result <- createStudy2GDS1KG(pathGeno=dataDir, +#' ## Run only if directory in writing mode +#' if (file.access(getwd()) == 0 && +#' !file.exists(file.path(file.path(getwd(), "ex1.gds")))) { +#' +#' ## Create the Profile GDS File for samples in 'listSamples' vector +#' ## (in this case, samples "ex1") +#' ## The Profile GDS file is created in the pathProfileGDS directory +#' result <- createStudy2GDS1KG(pathGeno=dataDir, #' pedStudy=samplePED, fileNameGDS=fileGDS, #' studyDF=studyDF, listProfiles=c("ex1"), -#' pathProfileGDS=dataDir, +#' pathProfileGDS=getwd(), #' genoSource="snp-pileup", #' verbose=FALSE) #' -#' ## The function returns OL when successful -#' result +#' ## The function returns OL when successful +#' result #' -#' ## The Profile GDS file 'ex1.gds' has been created in the -#' ## specified directory -#' list.files(dataDir) +#' ## The Profile GDS file 'ex1.gds' has been created in the +#' ## specified directory +#' list.files(getwd()) #' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink(file.path(dataDir, "ex1.gds")) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(file.path(getwd(), "ex1.gds")) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt createfn.gds put.attr.gdsn closefn.gds read.gdsn diff --git a/man/createStudy2GDS1KG.Rd b/man/createStudy2GDS1KG.Rd index a75744a92..e70286404 100644 --- a/man/createStudy2GDS1KG.Rd +++ b/man/createStudy2GDS1KG.Rd @@ -111,25 +111,31 @@ samplePED <- data.frame(Name.ID=c("ex1", "ex2"), Source=rep("Databank B", 2), stringsAsFactors=FALSE) rownames(samplePED) <- samplePED$Name.ID -## Create the Profile GDS File for sample in listSamples vector -## (in this case, samples "ex1") -## The Profile GDS file is created in the pathProfileGDS directory -result <- createStudy2GDS1KG(pathGeno=dataDir, +## Run only if directory in writing mode +if (file.access(getwd()) == 0 && + !file.exists(file.path(file.path(getwd(), "ex1.gds")))) { + + ## Create the Profile GDS File for samples in 'listSamples' vector + ## (in this case, samples "ex1") + ## The Profile GDS file is created in the pathProfileGDS directory + result <- createStudy2GDS1KG(pathGeno=dataDir, pedStudy=samplePED, fileNameGDS=fileGDS, studyDF=studyDF, listProfiles=c("ex1"), - pathProfileGDS=dataDir, + pathProfileGDS=getwd(), genoSource="snp-pileup", verbose=FALSE) -## The function returns OL when successful -result + ## The function returns OL when successful + result -## The Profile GDS file 'ex1.gds' has been created in the -## specified directory -list.files(dataDir) + ## The Profile GDS file 'ex1.gds' has been created in the + ## specified directory + list.files(getwd()) -## Unlink Profile GDS file (created for demo purpose) -unlink(file.path(dataDir, "ex1.gds")) + ## Remove Profile GDS file (created for demo purpose) + unlink(file.path(getwd(), "ex1.gds")) + +} } \author{ From abc9b6f91001d71e58b2f8c4825e3b89f231ca10 Mon Sep 17 00:00:00 2001 From: belleau Date: Thu, 17 Aug 2023 09:01:12 -0400 Subject: [PATCH 107/385] Update runRNAAncestry example --- R/processStudy.R | 3 ++- man/runRNAAncestry.Rd | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 97cfc6b60..cc40d0dee 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2701,7 +2701,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' #' \dontrun{ -#' runExomeAncestry(pedStudy=ped, studyDF=studyDF, +#' runRNAAncestry(pedStudy=ped, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, #' pathGeno=pathGeno, #' pathOut=pathOut, @@ -2709,6 +2709,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' fileReferenceAnnotGDS=fileAnnotGDS, #' chrInfo=chrInfo, #' syntheticRefDF=dataRef, +#' blockTypeID="GeneS.Ensembl.Hsapiens.v86", #' genoSource="snp-pileup") #' #' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index ad2418e00..c99633eb0 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -188,7 +188,7 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] \dontrun{ -runExomeAncestry(pedStudy=ped, studyDF=studyDF, +runRNAAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, @@ -196,6 +196,7 @@ runExomeAncestry(pedStudy=ped, studyDF=studyDF, fileReferenceAnnotGDS=fileAnnotGDS, chrInfo=chrInfo, syntheticRefDF=dataRef, + blockTypeID="GeneS.Ensembl.Hsapiens.v86", genoSource="snp-pileup") unlink(pathProfileGDS, recursive=TRUE, force=TRUE) From edd917aceba676a0f36f00332b6f4eaf62e59f25 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 12:39:59 -0400 Subject: [PATCH 108/385] Updating example for generatedMapSNVSel() function --- R/process1KG.R | 37 ++++++++++--------------------------- man/generateMapSnvSel.Rd | 33 ++++++++------------------------- 2 files changed, 18 insertions(+), 52 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index 5ee602b32..d5098d8e5 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -162,32 +162,15 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' ## Demo SNV information file used as input #' snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") #' -#' ## Different code depending of the withr package availability -#' if (requireNamespace("withr", quietly=TRUE)) { -#' -#' ## Temporary output files -#' ## The first file contains the indexes of the retained SNPs -#' ## The second file contains the filtered SNP information -#' snpIndexFile <- withr::local_file(file.path(dataDir, -#' "listSNP_TEMP.rds")) -#' filterSNVFile <- withr::local_file(file.path(dataDir, -#' "mapSNVSel_TEMP.rds")) -#' -#' ## Create a data.frame containing the information of the retained -#' ## samples (samples with existing genotyping files) -#' generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, -#' fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) -#' -#' ## Remove temporary files -#' withr::deferred_run() -#' -#' } else { +#' ## Temporary output files +#' ## The first file contains the indexes of the retained SNPs +#' ## The second file contains the filtered SNP information +#' snpIndexFile <- file.path(getwd(), "listSNP_TEMP.rds") +#' filterSNVFile <- file.path(getwd(), "mapSNVSel_TEMP.rds") #' -#' ## Temporary output files -#' ## The first file contains the indexes of the retained SNPs -#' ## The second file contains the filtered SNP information -#' snpIndexFile <- file.path(dataDir, "listSNP_TEMP.rds") -#' filterSNVFile <- file.path(dataDir, "mapSNVSel_TEMP.rds") +#' ## Run only if directory in writing mode +#' if (file.access(getwd()) == 0 && !file.exists(snpIndexTmp) && +#' !file.exists(filterSNVFile)) { #' #' ## Create a data.frame containing the information of the retained #' ## samples (samples with existing genotyping files) @@ -874,9 +857,9 @@ addBlockFromPlink2GDS <- function(gds, gdsOut, pathBlock, for(chr in listChr) { if(verbose) { message("chr", chr, " ", Sys.time()) } - snp.keep <- snpPosition[snpChromosome == chr] + snpKeep <- snpPosition[snpChromosome == chr] - listBlock[[chr]] <- processBlockChr(snp.keep, pathBlock, superPop, chr) + listBlock[[chr]] <- processBlockChr(snpKeep, pathBlock, superPop, chr) if(chr > 1) { vMax <- max(listBlock[[chr-1]]) vMin <- min(listBlock[[chr-1]]) diff --git a/man/generateMapSnvSel.Rd b/man/generateMapSnvSel.Rd index 97eb1bf66..fcf090c46 100644 --- a/man/generateMapSnvSel.Rd +++ b/man/generateMapSnvSel.Rd @@ -63,32 +63,15 @@ dataDir <- system.file("extdata", package="RAIDS") ## Demo SNV information file used as input snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") -## Different code depending of the withr package availability -if (requireNamespace("withr", quietly=TRUE)) { +## Temporary output files +## The first file contains the indexes of the retained SNPs +## The second file contains the filtered SNP information +snpIndexFile <- file.path(getwd(), "listSNP_TEMP.rds") +filterSNVFile <- file.path(getwd(), "mapSNVSel_TEMP.rds") - ## Temporary output files - ## The first file contains the indexes of the retained SNPs - ## The second file contains the filtered SNP information - snpIndexFile <- withr::local_file(file.path(dataDir, - "listSNP_TEMP.rds")) - filterSNVFile <- withr::local_file(file.path(dataDir, - "mapSNVSel_TEMP.rds")) - - ## Create a data.frame containing the information of the retained - ## samples (samples with existing genotyping files) - generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, - fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) - - ## Remove temporary files - withr::deferred_run() - -} else { - - ## Temporary output files - ## The first file contains the indexes of the retained SNPs - ## The second file contains the filtered SNP information - snpIndexFile <- file.path(dataDir, "listSNP_TEMP.rds") - filterSNVFile <- file.path(dataDir, "mapSNVSel_TEMP.rds") +## Run only if directory in writing mode +if (file.access(getwd()) == 0 && !file.exists(snpIndexTmp) && + !file.exists(filterSNVFile)) { ## Create a data.frame containing the information of the retained ## samples (samples with existing genotyping files) From 5a22c1b1670d97e80026168b9125dbb4c5f016a9 Mon Sep 17 00:00:00 2001 From: belleau Date: Thu, 17 Aug 2023 12:40:42 -0400 Subject: [PATCH 109/385] Update runExomeAncestry and runRNAAncestry example, mv computeAlleleFraction in allelicFraction_internal --- R/allelicFraction.R | 159 ------------------------------- R/allelicFraction_internal.R | 159 ++++++++++++++++++++++++++++++- R/processStudy.R | 66 +++++++------ man/computeAlleleFraction.Rd | 2 +- man/computeAllelicFractionRNA.Rd | 1 - man/runExomeAncestry.Rd | 32 ++++--- man/runRNAAncestry.Rd | 34 ++++--- 7 files changed, 233 insertions(+), 220 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index fee41b4ef..28b53ddd2 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -1,162 +1,3 @@ -#' @title TODO -#' -#' @description TODO -#' -#' @param snpPos a \code{data.frame} containing the genotype information for -#' a SNV dataset. TODO -#' -#' @param w a single positive \code{numeric} representing the size of the -#' window to compute the allelic fraction. -#' Default: \code{10}. -#' -#' @param cutOff a single \code{numeric} representing TODO. Default: \code{-3}. -#' -#' @return a \code{matrix} of \code{numeric} with 3 columns where each -#' row represent a segment -#' of imbalanced SNVs. The first column represents the position, in -#' \code{snpPos}, of the first -#' SNV in the segment. The second column represents the position, in the -#' \code{snpPos}, of the last SNV in the segment. The third column represents -#' the lower allelic frequency of the segment and is \code{NA} when the value -#' cannot be calculated. The value \code{NULL} is -#' returned when none of the SNVs -#' tested positive for the imbalance. -#' -#' @examples -#' -#' ## Data frame with SNV information for the specified chromosome (chr 1) -#' snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), -#' cnt.ref=c(40, 17, 27, 15, 4, 14, 16, 32), -#' cnt.alt=c(0, 0, 0, 0, 7, 23, 0, 0), -#' snp.pos=c(3722256, 3722328, 3767522, 3868160, 3869467, 4712655, -#' 6085318, 6213145), -#' snp.chr=c(rep(1, 8)), -#' normal.geno=c(rep(1, 8)), -#' pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), -#' snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), -#' keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), -#' homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), -#' lap=rep(-1, 8), LOH=rep(0, 8), imbAR=rep(-1, 8), -#' stringAsFactor=FALSE) -#' -#' ## The function returns NULL when there is not imbalanced SNVs -#' RAIDS:::computeAlleleFraction(snpPos=snpInfo, w=10, cutOff=-3) -#' -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom stats median -#' @importFrom S4Vectors isSingleNumber -#' @encoding UTF-8 -#' @keywords internal -computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { - - listBlockAR <- list() - j <- 1 - tmp <- as.integer(snpPos$imbAR == 1) - z <- cbind(c(tmp[1], tmp[-1] - tmp[seq_len(length(tmp) -1)]), - c(tmp[-1] - tmp[seq_len(length(tmp) -1)], tmp[length(tmp)] * -1)) - - ## Split SNVs by segment of continuous imbalanced SNVs - ## There must be at least one segment with imbalanced SNVs to go one - if(length(which(z[,1] == 1)) > 0) { - ## Find segmentsof imbalanced SNVs - segImb <- data.frame(start=seq_len(nrow(snpPos))[which(z[,1] > 0)], - end=seq_len(nrow(snpPos))[which(z[,2] < 0)]) - - for(i in seq_len(nrow(segImb))) { - # index of the segment - listSeg <- (segImb$start[i]):(segImb$end[i]) - # index hetero segment - listHetero <- listSeg[snpPos[listSeg,"hetero"] == TRUE] - # SNP hetero for the segment - snp.hetero <- snpPos[listHetero,] - - if(nrow(snp.hetero) >= 2 * w) { - lapCur <- median(apply(snp.hetero[seq_len(w), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[seq_len(w),c("cnt.ref", "cnt.alt")]))) - - start <- 1 - k <- w + 1 - while(k < nrow(snp.hetero)) { - # We have (k+w-1) <= nrow(snp.hetero) - # Case 1 true because (nrow(snp.hetero) >= 2 * w - # Other case nrow(snp.hetero) >= w+k - 1 - curWin <- testAlleleFractionChange(snp.hetero[k:(k+w-1), - c("cnt.ref", "cnt.alt")], cutOff, lapCur) - - if(curWin$pCut1 == 1){ # new Region the allelicFraction - # table of the index of the block with lapCur - listBlockAR[[j]] <- c(listHetero[start], - listHetero[k], lapCur) - - lapCur <- median(apply(snp.hetero[k:(k+w-1), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[k:(k+w-1), - c("cnt.ref", "cnt.alt")]))) - - start <- k - - if(nrow(snp.hetero) - start < w) { # Close the segment - lapCur <- - median(apply(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")]))) - - listBlockAR[[j]] <- c(listHetero[start], - segImb$end[i], lapCur) - - j <- j+1 - k <- nrow(snp.hetero) - }else{ # nrow(snp.hetero) >= w+k - k<- k + 1 - j <- j + 1 - - } - }else{ # keep the same region - if((nrow(snp.hetero) - k ) < w){ # close - lapCur <- - median(apply(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")]))) - - listBlockAR[[j]] <- c(listHetero[start], - segImb$end[i], lapCur) - - j <- j + 1 - - k <- nrow(snp.hetero) - } else{ # continue nrow(snp.hetero) >= w+k - lapCur <- median(apply(snp.hetero[start:k, - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[start:k,c("cnt.ref", - "cnt.alt")]))) - - k <- k + 1 - } - } - }# End while - }else { - lapCur <- median(apply(snp.hetero[, c("cnt.ref", "cnt.alt")], - 1, min) / (rowSums(snp.hetero[,c("cnt.ref", - "cnt.alt")]))) - - listBlockAR[[j]] <- c(segImb$start[i], segImb$end[i], lapCur) - - j <- j + 1 - } - } - } - - # note NULL if length(listBlockAR) == 0 - listBlockAR <- do.call(rbind, listBlockAR) - - return(listBlockAR) -} - - #' @title Estimate the allelic fraction of the pruned SNVs for a specific #' profile #' diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 550532ead..8f1b473b3 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -440,6 +440,164 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, return(homoBlock) } +#' @title TODO +#' +#' @description TODO +#' +#' @param snpPos a \code{data.frame} containing the genotype information for +#' a SNV dataset. TODO +#' +#' @param w a single positive \code{numeric} representing the size of the +#' window to compute the allelic fraction. +#' Default: \code{10}. +#' +#' @param cutOff a single \code{numeric} representing TODO. Default: \code{-3}. +#' +#' @return a \code{matrix} of \code{numeric} with 3 columns where each +#' row represent a segment +#' of imbalanced SNVs. The first column represents the position, in +#' \code{snpPos}, of the first +#' SNV in the segment. The second column represents the position, in the +#' \code{snpPos}, of the last SNV in the segment. The third column represents +#' the lower allelic frequency of the segment and is \code{NA} when the value +#' cannot be calculated. The value \code{NULL} is +#' returned when none of the SNVs +#' tested positive for the imbalance. +#' +#' @examples +#' +#' ## Data frame with SNV information for the specified chromosome (chr 1) +#' snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), +#' cnt.ref=c(40, 17, 27, 15, 4, 14, 16, 32), +#' cnt.alt=c(0, 0, 0, 0, 7, 23, 0, 0), +#' snp.pos=c(3722256, 3722328, 3767522, 3868160, 3869467, 4712655, +#' 6085318, 6213145), +#' snp.chr=c(rep(1, 8)), +#' normal.geno=c(rep(1, 8)), +#' pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), +#' snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), +#' keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), +#' homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), +#' lap=rep(-1, 8), LOH=rep(0, 8), imbAR=rep(-1, 8), +#' stringAsFactor=FALSE) +#' +#' ## The function returns NULL when there is not imbalanced SNVs +#' RAIDS:::computeAlleleFraction(snpPos=snpInfo, w=10, cutOff=-3) +#' +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom stats median +#' @importFrom S4Vectors isSingleNumber +#' @encoding UTF-8 +#' @keywords internal +computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { + + listBlockAR <- list() + j <- 1 + tmp <- as.integer(snpPos$imbAR == 1) + z <- cbind(c(tmp[1], tmp[-1] - tmp[seq_len(length(tmp) -1)]), + c(tmp[-1] - tmp[seq_len(length(tmp) -1)], tmp[length(tmp)] * -1)) + + ## Split SNVs by segment of continuous imbalanced SNVs + ## There must be at least one segment with imbalanced SNVs to go one + if(length(which(z[,1] == 1)) > 0) { + ## Find segmentsof imbalanced SNVs + segImb <- data.frame(start=seq_len(nrow(snpPos))[which(z[,1] > 0)], + end=seq_len(nrow(snpPos))[which(z[,2] < 0)]) + + for(i in seq_len(nrow(segImb))) { + # index of the segment + listSeg <- (segImb$start[i]):(segImb$end[i]) + # index hetero segment + listHetero <- listSeg[snpPos[listSeg,"hetero"] == TRUE] + # SNP hetero for the segment + snp.hetero <- snpPos[listHetero,] + + if(nrow(snp.hetero) >= 2 * w) { + lapCur <- median(apply(snp.hetero[seq_len(w), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[seq_len(w),c("cnt.ref", "cnt.alt")]))) + + start <- 1 + k <- w + 1 + while(k < nrow(snp.hetero)) { + # We have (k+w-1) <= nrow(snp.hetero) + # Case 1 true because (nrow(snp.hetero) >= 2 * w + # Other case nrow(snp.hetero) >= w+k - 1 + curWin <- testAlleleFractionChange(snp.hetero[k:(k+w-1), + c("cnt.ref", "cnt.alt")], cutOff, lapCur) + + if(curWin$pCut1 == 1){ # new Region the allelicFraction + # table of the index of the block with lapCur + listBlockAR[[j]] <- c(listHetero[start], + listHetero[k], lapCur) + + lapCur <- median(apply(snp.hetero[k:(k+w-1), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[k:(k+w-1), + c("cnt.ref", "cnt.alt")]))) + + start <- k + + if(nrow(snp.hetero) - start < w) { # Close the segment + lapCur <- + median(apply(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")]))) + + listBlockAR[[j]] <- c(listHetero[start], + segImb$end[i], lapCur) + + j <- j+1 + k <- nrow(snp.hetero) + }else{ # nrow(snp.hetero) >= w+k + k<- k + 1 + j <- j + 1 + + } + }else{ # keep the same region + if((nrow(snp.hetero) - k ) < w){ # close + lapCur <- + median(apply(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")]))) + + listBlockAR[[j]] <- c(listHetero[start], + segImb$end[i], lapCur) + + j <- j + 1 + + k <- nrow(snp.hetero) + } else{ # continue nrow(snp.hetero) >= w+k + lapCur <- median(apply(snp.hetero[start:k, + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[start:k,c("cnt.ref", + "cnt.alt")]))) + + k <- k + 1 + } + } + }# End while + }else { + lapCur <- median(apply(snp.hetero[, c("cnt.ref", "cnt.alt")], + 1, min) / (rowSums(snp.hetero[,c("cnt.ref", + "cnt.alt")]))) + + listBlockAR[[j]] <- c(segImb$start[i], segImb$end[i], lapCur) + + j <- j + 1 + } + } + } + + # note NULL if length(listBlockAR) == 0 + listBlockAR <- do.call(rbind, listBlockAR) + + return(listBlockAR) +} + #' @title Estimate the allelic fraction of the pruned SNVs for a specific #' DNA-seq profile @@ -649,7 +807,6 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' #' @description The function creates a \code{data.frame} containing the #' allelic fraction for the pruned SNV dataset specific to a RNA-seq sample. -#' TODO #' #' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} #' (a GDS file), the opened Reference GDS file. diff --git a/R/processStudy.R b/R/processStudy.R index cc40d0dee..8c93024b3 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2447,9 +2447,9 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' ## The path where the Profile GDS Files (one per sample) #' ## will be created need to be specified. #' ################################################################# -#' pathProfileGDS <- file.path(dataDir, "example", "out.tmp") +#' pathProfileGDS <- file.path(getwd(), "out.tmp") #' -#' pathOut <- file.path(dataDir, "example", "res.out") +#' pathOut <- file.path(getwd(), "res.out") #' #' ################################################################# #' ## A data frame containing general information about the study @@ -2484,18 +2484,22 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' #' \dontrun{ -#' runExomeAncestry(pedStudy=ped, studyDF=studyDF, -#' pathProfileGDS=pathProfileGDS, -#' pathGeno=pathGeno, -#' pathOut=pathOut, -#' fileReferenceGDS=fileReferenceGDS, -#' fileReferenceAnnotGDS=fileAnnotGDS, -#' chrInfo=chrInfo, -#' syntheticRefDF=dataRef, -#' genoSource="snp-pileup") -#' -#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) +#' && !file.exists(pathOut)) { +#' +#' runExomeAncestry(pedStudy=ped, studyDF=studyDF, +#' pathProfileGDS=pathProfileGDS, +#' pathGeno=pathGeno, +#' pathOut=pathOut, +#' fileReferenceGDS=fileReferenceGDS, +#' fileReferenceAnnotGDS=fileAnnotGDS, +#' chrInfo=chrInfo, +#' syntheticRefDF=dataRef, +#' genoSource="snp-pileup") +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' } #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz @@ -2664,9 +2668,9 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ## The path where the Profile GDS Files (one per sample) #' ## will be created need to be specified. #' ################################################################# -#' pathProfileGDS <- file.path(dataDir, "example", "out.tmp") +#' pathProfileGDS <- file.path(getwd(), "out.tmp") #' -#' pathOut <- file.path(dataDir, "example", "res.out") +#' pathOut <- file.path(getwd(), "res.out") #' #' ################################################################# #' ## A data frame containing general information about the study @@ -2701,19 +2705,23 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' #' \dontrun{ -#' runRNAAncestry(pedStudy=ped, studyDF=studyDF, -#' pathProfileGDS=pathProfileGDS, -#' pathGeno=pathGeno, -#' pathOut=pathOut, -#' fileReferenceGDS=fileReferenceGDS, -#' fileReferenceAnnotGDS=fileAnnotGDS, -#' chrInfo=chrInfo, -#' syntheticRefDF=dataRef, -#' blockTypeID="GeneS.Ensembl.Hsapiens.v86", -#' genoSource="snp-pileup") -#' -#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) +#' && !file.exists(pathOut)) { +#' +#' runRNAAncestry(pedStudy=ped, studyDF=studyDF, +#' pathProfileGDS=pathProfileGDS, +#' pathGeno=pathGeno, +#' pathOut=pathOut, +#' fileReferenceGDS=fileReferenceGDS, +#' fileReferenceAnnotGDS=fileAnnotGDS, +#' chrInfo=chrInfo, +#' syntheticRefDF=dataRef, +#' blockTypeID="GeneS.Ensembl.Hsapiens.v86", +#' genoSource="snp-pileup") +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' } #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/man/computeAlleleFraction.Rd b/man/computeAlleleFraction.Rd index 78c2a991f..85d633264 100644 --- a/man/computeAlleleFraction.Rd +++ b/man/computeAlleleFraction.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/allelicFraction.R +% Please edit documentation in R/allelicFraction_internal.R \encoding{UTF-8} \name{computeAlleleFraction} \alias{computeAlleleFraction} diff --git a/man/computeAllelicFractionRNA.Rd b/man/computeAllelicFractionRNA.Rd index edb3127bd..dccc72b08 100644 --- a/man/computeAllelicFractionRNA.Rd +++ b/man/computeAllelicFractionRNA.Rd @@ -73,7 +73,6 @@ coverage > \code{minCov}. TODO \description{ The function creates a \code{data.frame} containing the allelic fraction for the pruned SNV dataset specific to a RNA-seq sample. -TODO } \examples{ diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index aacbe47a4..1fe013226 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -146,9 +146,9 @@ pathGeno <- file.path(dataDir, "example", "snpPileup") ## The path where the Profile GDS Files (one per sample) ## will be created need to be specified. ################################################################# -pathProfileGDS <- file.path(dataDir, "example", "out.tmp") +pathProfileGDS <- file.path(getwd(), "out.tmp") -pathOut <- file.path(dataDir, "example", "res.out") +pathOut <- file.path(getwd(), "res.out") ################################################################# ## A data frame containing general information about the study @@ -183,18 +183,22 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] \dontrun{ -runExomeAncestry(pedStudy=ped, studyDF=studyDF, - pathProfileGDS=pathProfileGDS, - pathGeno=pathGeno, - pathOut=pathOut, - fileReferenceGDS=fileReferenceGDS, - fileReferenceAnnotGDS=fileAnnotGDS, - chrInfo=chrInfo, - syntheticRefDF=dataRef, - genoSource="snp-pileup") - -unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -unlink(pathOut, recursive=TRUE, force=TRUE) + if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) + && !file.exists(pathOut)) { + + runExomeAncestry(pedStudy=ped, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, + pathGeno=pathGeno, + pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + genoSource="snp-pileup") + + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + } } } diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index c99633eb0..f101f2f50 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -151,9 +151,9 @@ pathGeno <- file.path(dataDir, "example", "snpPileup") ## The path where the Profile GDS Files (one per sample) ## will be created need to be specified. ################################################################# -pathProfileGDS <- file.path(dataDir, "example", "out.tmp") +pathProfileGDS <- file.path(getwd(), "out.tmp") -pathOut <- file.path(dataDir, "example", "res.out") +pathOut <- file.path(getwd(), "res.out") ################################################################# ## A data frame containing general information about the study @@ -188,19 +188,23 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] \dontrun{ -runRNAAncestry(pedStudy=ped, studyDF=studyDF, - pathProfileGDS=pathProfileGDS, - pathGeno=pathGeno, - pathOut=pathOut, - fileReferenceGDS=fileReferenceGDS, - fileReferenceAnnotGDS=fileAnnotGDS, - chrInfo=chrInfo, - syntheticRefDF=dataRef, - blockTypeID="GeneS.Ensembl.Hsapiens.v86", - genoSource="snp-pileup") - -unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -unlink(pathOut, recursive=TRUE, force=TRUE) + if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) + && !file.exists(pathOut)) { + + runRNAAncestry(pedStudy=ped, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, + pathGeno=pathGeno, + pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + blockTypeID="GeneS.Ensembl.Hsapiens.v86", + genoSource="snp-pileup") + + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + } } } From 740215a44c81b1e62d6e3bee71103e7155c59884 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 13:05:15 -0400 Subject: [PATCH 110/385] Update generateMapSnvSel() example --- R/process1KG.R | 2 +- man/generateMapSnvSel.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index d5098d8e5..f5f032510 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -169,7 +169,7 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' filterSNVFile <- file.path(getwd(), "mapSNVSel_TEMP.rds") #' #' ## Run only if directory in writing mode -#' if (file.access(getwd()) == 0 && !file.exists(snpIndexTmp) && +#' if (file.access(getwd()) == 0 && !file.exists(snpIndexFile) && #' !file.exists(filterSNVFile)) { #' #' ## Create a data.frame containing the information of the retained diff --git a/man/generateMapSnvSel.Rd b/man/generateMapSnvSel.Rd index fcf090c46..8af9646d1 100644 --- a/man/generateMapSnvSel.Rd +++ b/man/generateMapSnvSel.Rd @@ -70,7 +70,7 @@ snpIndexFile <- file.path(getwd(), "listSNP_TEMP.rds") filterSNVFile <- file.path(getwd(), "mapSNVSel_TEMP.rds") ## Run only if directory in writing mode -if (file.access(getwd()) == 0 && !file.exists(snpIndexTmp) && +if (file.access(getwd()) == 0 && !file.exists(snpIndexFile) && !file.exists(filterSNVFile)) { ## Create a data.frame containing the information of the retained From 319eb3beaf7f5a6677220578d8a7a96bcc3c6d47 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 13:25:18 -0400 Subject: [PATCH 111/385] Update function documentation and error messages to remove reference to 1KG --- R/process1KG_internal.R | 36 +++++++------- R/processStudy_internal.R | 47 +++++++++++-------- man/pruning1KGbyChr.Rd | 15 +++--- man/validateAdd1KG2SampleGDS.Rd | 5 +- man/validateAppendStudy2GDS1KG.Rd | 3 +- ...alidateComputeAncestryFromSyntheticFile.Rd | 7 +-- man/validateComputePoolSyntheticAncestryGr.Rd | 9 ++-- man/validateCreateStudy2GDS1KG.Rd | 3 +- man/validateEstimateAllelicFraction.Rd | 6 +-- man/validatePruningSample.Rd | 4 +- man/validateRunExomeAncestry.Rd | 6 ++- tests/testthat/test-processStudy.R | 6 +-- 12 files changed, 80 insertions(+), 67 deletions(-) diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index 190a70ded..a95675acd 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -1,9 +1,10 @@ -#' @title Extract the pruned SNVs in a reference data set (1KG) by chromosome -#' and/or allelic frequency +#' @title Extract the pruned SNVs in a population reference data set (ex:1KG) +#' by chromosome and/or allelic frequency #' -#' @description The function extracts the pruned SNVs in a reference data -#' set (1KG) by chromosome and/or allelic frequency. The pruning is done -#' through the linkage disequilibrium analysis. +#' @description The function extracts the pruned SNVs in a population +#' reference data set (ex: 1KG) by chromosome and/or allelic frequency. +#' The pruning is done through the linkage disequilibrium analysis. The +#' pruned SNVs are saved in a RDS file. #' #' @param gdsReference an object of class #' \code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, an @@ -45,10 +46,10 @@ #' Default: \code{NULL}. #' #' @param outPrefix a \code{character} string that represents the prefix of the -#' RDS files that will be generated. Default: \code{"pruned_1KG"}. +#' RDS file(s) that will be generated. Default: \code{"pruned_1KG"}. #' #' @param keepObj a \code{logical} specifying if the function must save the -#' the processed information into a RDS object. Default: \code{FALSE}. +#' the processed information into a second RDS file. Default: \code{FALSE}. #' #' @return The function returns \code{0L} when successful. #' @@ -72,25 +73,21 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, fileObj <- file.path(paste0(outPrefix, "Obj.rds")) snpGDS <- index.gdsn(gdsReference, "snp.id") listKeep <- NULL - if(is.null(minAF)){ - if(!is.null(chr)){ - snpGDS <- index.gdsn(gdsReference, "snp.id") + if (is.null(minAF)) { + if (!is.null(chr)) { snpID <- read.gdsn(snpGDS) - chrGDS <- index.gdsn(gdsReference, "snp.chromosome") - snpCHR <- read.gdsn(chrGDS) + snpCHR <- read.gdsn(index.gdsn(gdsReference, "snp.chromosome")) listKeep <- snpID[which(snpCHR == chr)] } - } else{ - snpGDS <- index.gdsn(gdsReference, "snp.id") + } else { snpID <- read.gdsn(snpGDS) - afGDS <- index.gdsn(gdsReference, "snp.AF") - snpAF <- read.gdsn(afGDS) + snpAF <- read.gdsn(index.gdsn(gdsReference, "snp.AF")) - if(is.null(chr)){ + if (is.null(chr)) { listKeep <- snpID[which(snpAF >= minAF & snpAF <= 1-minAF)] - } else{ + } else { chrGDS <- index.gdsn(gdsReference, "snp.chromosome") snpCHR <- read.gdsn(chrGDS) @@ -99,6 +96,7 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, } } + ## SNP pruning based on linkage disequilibrium (LD) snpset <- runLDPruning(gds=gdsReference, method=method, listSamples=listSamples, listKeep=listKeep, slideWindowMaxBP=slideWindowMaxBP, @@ -106,7 +104,7 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, pruned <- unlist(snpset, use.names=FALSE) saveRDS(pruned, filePruned) - if(keepObj){ + if (keepObj) { saveRDS(snpset, fileObj) } diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index de6f109a3..0c5a716df 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -3,8 +3,8 @@ #' @description This function validates the input parameters for the #' \code{\link{pruningSample}} function. #' -#' @param gdsReference an object of class \link[gdsfmt]{gds.class} (a GDS file), the -#' 1 KG GDS file. +#' @param gdsReference an object of class \link[gdsfmt]{gds.class} +#' (a GDS file), the Population Reference GDS file. #' #' @param method a \code{character} string that represents the method that will #' be used to calculate the linkage disequilibrium in the @@ -160,11 +160,12 @@ validatePruningSample <- function(gdsReference, method, currentProfile, studyID, #' opened Profile GDS file. #' #' @param sampleRM a \code{vector} of \code{character} strings representing -#' the identifiers of the 1KG reference samples that should not be used to -#' create the reference PCA. +#' the identifiers of the population reference samples that should not +#' be used to create the reference PCA. #' #' @param spRef a \code{vector} of \code{character} strings representing the -#' known super population ancestry for the 1KG profiles. The 1KG profile +#' known super population ancestry for the population reference profiles. +#' The population reference profile #' identifiers are used as names for the \code{vector}. #' #' @param studyIDSyn a \code{character} string corresponding to the study @@ -224,7 +225,7 @@ validatePruningSample <- function(gdsReference, method, currentProfile, studyID, #' gdsSample <- openfn.gds(file.path(dataDir, #' "GDS_Sample_with_study_demo.gds"), readonly=TRUE) #' -#' ## The known super population ancestry for the 1KG profiles +#' ## The known super population ancestry for the population reference profiles #' spRef <- c("EUR", "SAS", "EAS", "EUR", "AFR") #' names(spRef) <- c("HG00100", "HG00101", "HG00102", "HG00103", "HG00104") #' @@ -311,7 +312,7 @@ validateComputePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, #' \code{\link{estimateAllelicFraction}} function. #' #' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), the 1KG GDS file. +#' (a GDS file), the Population Reference GDS file. #' #' @param gdsProfile an object of class \code{\link[gdsfmt]{gds.class}} #' (a GDS file), the Profile GDS file. @@ -352,7 +353,7 @@ validateComputePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, #' log score, that the SNVs in a gene are allelic fraction different from 0.5. #' #' @param gdsRefAnnot an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), the1 1KG SNV Annotation GDS file. +#' (a GDS file), the1 Population Reference SNV Annotation GDS file. #' This parameter is RNA specific. #' #' @param blockID a \code{character} string corresponding to the block @@ -368,7 +369,7 @@ validateComputePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, #' ## Directory where demo GDS files are located #' dataDir <- system.file("extdata", package="RAIDS") #' -#' ## The 1KG GDS file (opened) +#' ## The 1KG Population Reference GDS Demo file (opened) #' gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) #' #' ## The GDS Sample (opened) @@ -477,7 +478,7 @@ validateEstimateAllelicFraction <- function(gdsReference, gdsProfile, #' can be defined. #' #' @param fileNameGDS a \code{character} string representing the file name of -#' the 1KG GDS file. The file must exist. +#' the Population Reference GDS file. The file must exist. #' #' @param batch a single positive \code{integer} representing the current #' identifier for the batch. Beware, this field is not stored anymore. @@ -506,6 +507,7 @@ validateEstimateAllelicFraction <- function(gdsReference, gdsProfile, #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' +#' ## Demo 1KG Population Reference GDS file #' gds1KG <- file.path(dataDir, "gds1KG.gds") #' #' ## The data.frame containing the information about the study @@ -548,7 +550,7 @@ validateCreateStudy2GDS1KG <- function(pathGeno, pedStudy, fileNameGDS, batch, ## The fileNameGDS must be a character string and the file must exists if (!(is.character(fileNameGDS) && (file.exists(fileNameGDS)))) { stop("The \'fileNameGDS\' must be a character string representing ", - "the GDS 1KG file. The file must exist.") + "the Population Reference GDS file. The file must exist.") } ## The batch must be a single numeric @@ -590,7 +592,7 @@ validateCreateStudy2GDS1KG <- function(pathGeno, pedStudy, fileNameGDS, batch, #' \code{\link{computeAncestryFromSyntheticFile}} function. #' #' @param gdsReference an object of class \link[gdsfmt]{gds.class} (a GDS -#' file), the opened 1KG GDS file. +#' file), the opened Population Reference GDS file. #' #' @param gdsProfile an object of class \code{\link[gdsfmt]{gds.class}} #' (a GDS file), the opened Profile GDS file. @@ -604,7 +606,8 @@ validateCreateStudy2GDS1KG <- function(pathGeno, pedStudy, fileNameGDS, batch, #' identifier of the current profile on which ancestry will be inferred. #' #' @param spRef a \code{vector} of \code{character} strings representing the -#' known super population ancestry for the 1KG profiles. The 1KG profile +#' known super population ancestry for the 1KG profiles. The Population +#' Reference profile #' identifiers are used as names for the \code{vector}. #' #' @param studyIDSyn a \code{character} string corresponding to the study @@ -661,7 +664,7 @@ validateCreateStudy2GDS1KG <- function(pathGeno, pedStudy, fileNameGDS, batch, #' ## Directory where demo GDS files are located #' dataDir <- system.file("extdata", package="RAIDS") #' -#' ## The 1KG GDS file (opened) +#' ## The 1KG Population Reference GDS demo file (opened) #' gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) #' #' ## The Profile GDS (opened) @@ -861,7 +864,7 @@ validateComputePCARefSample <- function(gdsProfile, currentProfile, studyIDRef, #' RDS file that contains the information about the sample to analyse. #' #' @param fileNameGDS a \code{character} string representing the file name of -#' the 1KG GDS file. The file must exist. +#' the Population Reference GDS file. The file must exist. #' #' @param batch a single positive \code{integer} representing the current #' identifier for the batch. Beware, this field is not stored anymore. @@ -894,6 +897,7 @@ validateComputePCARefSample <- function(gdsProfile, currentProfile, studyIDRef, #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' +#' ## Demo 1KG Population reference GDS file #' gds1KG <- file.path(dataDir, "1KG_Demo.gds") #' ped <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") #' @@ -935,7 +939,7 @@ validateAppendStudy2GDS1KG <- function(pathGeno, filePedRDS, fileNameGDS, ## The fileNameGDS must be a character string and the file must exists if (!(is.character(fileNameGDS) && (file.exists(fileNameGDS)))) { stop("The \'fileNameGDS\' must be a character string representing ", - "the GDS 1KG file. The file must exist.") + "the Population Reference GDS file. The file must exist.") } ## The batch must be a single numeric @@ -972,7 +976,8 @@ validateAppendStudy2GDS1KG <- function(pathGeno, filePedRDS, fileNameGDS, #' \code{\link{add1KG2SampleGDS}} function. #' #' @param gdsReference an object of class -#' \link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file. +#' \link[gdsfmt]{gds.class} (a GDS file), the opened Population Reference +#' GDS file. #' #' @param gdsProfileFile a \code{character} string representing the path and #' file name of the Profile GDS file. The Profile GDS file must exist. @@ -990,7 +995,7 @@ validateAppendStudy2GDS1KG <- function(pathGeno, filePedRDS, fileNameGDS, #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' -#' ## The 1KG GDS file (opened) +#' ## The 1KG Population Reference GDS demo file (opened) #' gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) #' #' ## The validatiion should be successful @@ -1065,10 +1070,11 @@ validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, currentProfil #' the directory where the output files are created. #' #' @param fileReferenceGDS a \code{character} string representing the file -#' name of the 1KG GDS file. The file must exist. +#' name of the Population Reference GDS file. The file must exist. #' #' @param fileReferenceAnnotGDS a \code{character} string representing the -#' file name of the 1KG GDS annotation file. The file must exist. +#' file name of the Population Reference GDS annotation file. +#' The file must exist. #' #' @param chrInfo a \code{vector} of positive \code{integer} values #' representing the length of the chromosomes. See 'details' section. @@ -1102,6 +1108,7 @@ validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, currentProfil #' study.platform = "PLATFORM", #' stringsAsFactors = FALSE) #' +#' ## Population Reference GDS demo file #' gds1KG <- file.path(dataDir, "gds1KG.gds") #' #' gdsAnnot1KG <- file.path(dataDir, "gdsAnnot1KG.gds") diff --git a/man/pruning1KGbyChr.Rd b/man/pruning1KGbyChr.Rd index 5c7f873ff..36c3b3b2d 100644 --- a/man/pruning1KGbyChr.Rd +++ b/man/pruning1KGbyChr.Rd @@ -3,8 +3,8 @@ \encoding{UTF-8} \name{pruning1KGbyChr} \alias{pruning1KGbyChr} -\title{Extract the pruned SNVs in a reference data set (1KG) by chromosome -and/or allelic frequency} +\title{Extract the pruned SNVs in a population reference data set (ex:1KG) +by chromosome and/or allelic frequency} \usage{ pruning1KGbyChr( gdsReference, @@ -61,18 +61,19 @@ allelic frequency is not used as a filtering criterion. Default: \code{NULL}.} \item{outPrefix}{a \code{character} string that represents the prefix of the -RDS files that will be generated. Default: \code{"pruned_1KG"}.} +RDS file(s) that will be generated. Default: \code{"pruned_1KG"}.} \item{keepObj}{a \code{logical} specifying if the function must save the -the processed information into a RDS object. Default: \code{FALSE}.} +the processed information into a second RDS file. Default: \code{FALSE}.} } \value{ The function returns \code{0L} when successful. } \description{ -The function extracts the pruned SNVs in a reference data -set (1KG) by chromosome and/or allelic frequency. The pruning is done -through the linkage disequilibrium analysis. +The function extracts the pruned SNVs in a population +reference data set (ex: 1KG) by chromosome and/or allelic frequency. +The pruning is done through the linkage disequilibrium analysis. The +pruned SNVs are saved in a RDS file. } \examples{ diff --git a/man/validateAdd1KG2SampleGDS.Rd b/man/validateAdd1KG2SampleGDS.Rd index 2c9328572..5552db1f7 100644 --- a/man/validateAdd1KG2SampleGDS.Rd +++ b/man/validateAdd1KG2SampleGDS.Rd @@ -9,7 +9,8 @@ validateAdd1KG2SampleGDS(gdsReference, gdsProfileFile, currentProfile, studyID) } \arguments{ \item{gdsReference}{an object of class -\link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file.} +\link[gdsfmt]{gds.class} (a GDS file), the opened Population Reference +GDS file.} \item{gdsProfileFile}{a \code{character} string representing the path and file name of the Profile GDS file. The Profile GDS file must exist.} @@ -32,7 +33,7 @@ This function validates the input parameters for the ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") -## The 1KG GDS file (opened) +## The 1KG Population Reference GDS demo file (opened) gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) ## The validatiion should be successful diff --git a/man/validateAppendStudy2GDS1KG.Rd b/man/validateAppendStudy2GDS1KG.Rd index 66cb4c3dd..f3c9253ed 100644 --- a/man/validateAppendStudy2GDS1KG.Rd +++ b/man/validateAppendStudy2GDS1KG.Rd @@ -26,7 +26,7 @@ each sample.} RDS file that contains the information about the sample to analyse.} \item{fileNameGDS}{a \code{character} string representing the file name of -the 1KG GDS file. The file must exist.} +the Population Reference GDS file. The file must exist.} \item{batch}{a single positive \code{integer} representing the current identifier for the batch. Beware, this field is not stored anymore.} @@ -64,6 +64,7 @@ This function validates the input parameters for the ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") +## Demo 1KG Population reference GDS file gds1KG <- file.path(dataDir, "1KG_Demo.gds") ped <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") diff --git a/man/validateComputeAncestryFromSyntheticFile.Rd b/man/validateComputeAncestryFromSyntheticFile.Rd index 2efe1c63a..a8bc0397a 100644 --- a/man/validateComputeAncestryFromSyntheticFile.Rd +++ b/man/validateComputeAncestryFromSyntheticFile.Rd @@ -27,7 +27,7 @@ validateComputeAncestryFromSyntheticFile( } \arguments{ \item{gdsReference}{an object of class \link[gdsfmt]{gds.class} (a GDS -file), the opened 1KG GDS file.} +file), the opened Population Reference GDS file.} \item{gdsProfile}{an object of class \code{\link[gdsfmt]{gds.class}} (a GDS file), the opened Profile GDS file.} @@ -41,7 +41,8 @@ exist.} identifier of the current profile on which ancestry will be inferred.} \item{spRef}{a \code{vector} of \code{character} strings representing the -known super population ancestry for the 1KG profiles. The 1KG profile +known super population ancestry for the 1KG profiles. The Population +Reference profile identifiers are used as names for the \code{vector}.} \item{studyIDSyn}{a \code{character} string corresponding to the study @@ -96,7 +97,7 @@ This function validates the input parameters for the ## Directory where demo GDS files are located dataDir <- system.file("extdata", package="RAIDS") -## The 1KG GDS file (opened) +## The 1KG Population Reference GDS demo file (opened) gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) ## The Profile GDS (opened) diff --git a/man/validateComputePoolSyntheticAncestryGr.Rd b/man/validateComputePoolSyntheticAncestryGr.Rd index 838226d42..984236ebf 100644 --- a/man/validateComputePoolSyntheticAncestryGr.Rd +++ b/man/validateComputePoolSyntheticAncestryGr.Rd @@ -28,11 +28,12 @@ validateComputePoolSyntheticAncestryGr( opened Profile GDS file.} \item{sampleRM}{a \code{vector} of \code{character} strings representing -the identifiers of the 1KG reference samples that should not be used to -create the reference PCA.} +the identifiers of the population reference samples that should not +be used to create the reference PCA.} \item{spRef}{a \code{vector} of \code{character} strings representing the -known super population ancestry for the 1KG profiles. The 1KG profile +known super population ancestry for the population reference profiles. +The population reference profile identifiers are used as names for the \code{vector}.} \item{studyIDSyn}{a \code{character} string corresponding to the study @@ -90,7 +91,7 @@ dataDir <- system.file("extdata", package="RAIDS") gdsSample <- openfn.gds(file.path(dataDir, "GDS_Sample_with_study_demo.gds"), readonly=TRUE) -## The known super population ancestry for the 1KG profiles +## The known super population ancestry for the population reference profiles spRef <- c("EUR", "SAS", "EAS", "EUR", "AFR") names(spRef) <- c("HG00100", "HG00101", "HG00102", "HG00103", "HG00104") diff --git a/man/validateCreateStudy2GDS1KG.Rd b/man/validateCreateStudy2GDS1KG.Rd index ed66c2d05..e40050792 100644 --- a/man/validateCreateStudy2GDS1KG.Rd +++ b/man/validateCreateStudy2GDS1KG.Rd @@ -33,7 +33,7 @@ must contain the information for all the samples passed in the can be defined.} \item{fileNameGDS}{a \code{character} string representing the file name of -the 1KG GDS file. The file must exist.} +the Population Reference GDS file. The file must exist.} \item{batch}{a single positive \code{integer} representing the current identifier for the batch. Beware, this field is not stored anymore.} @@ -67,6 +67,7 @@ This function validates the input parameters for the ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") +## Demo 1KG Population Reference GDS file gds1KG <- file.path(dataDir, "gds1KG.gds") ## The data.frame containing the information about the study diff --git a/man/validateEstimateAllelicFraction.Rd b/man/validateEstimateAllelicFraction.Rd index 6d71268e0..a357eaf4a 100644 --- a/man/validateEstimateAllelicFraction.Rd +++ b/man/validateEstimateAllelicFraction.Rd @@ -26,7 +26,7 @@ validateEstimateAllelicFraction( } \arguments{ \item{gdsReference}{an object of class \code{\link[gdsfmt]{gds.class}} -(a GDS file), the 1KG GDS file.} +(a GDS file), the Population Reference GDS file.} \item{gdsProfile}{an object of class \code{\link[gdsfmt]{gds.class}} (a GDS file), the Profile GDS file.} @@ -67,7 +67,7 @@ the window used to compute an empty box.} log score, that the SNVs in a gene are allelic fraction different from 0.5.} \item{gdsRefAnnot}{an object of class \code{\link[gdsfmt]{gds.class}} -(a GDS file), the1 1KG SNV Annotation GDS file. +(a GDS file), the1 Population Reference SNV Annotation GDS file. This parameter is RNA specific.} \item{blockID}{a \code{character} string corresponding to the block @@ -88,7 +88,7 @@ This function validates the input parameters for the ## Directory where demo GDS files are located dataDir <- system.file("extdata", package="RAIDS") -## The 1KG GDS file (opened) +## The 1KG Population Reference GDS Demo file (opened) gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) ## The GDS Sample (opened) diff --git a/man/validatePruningSample.Rd b/man/validatePruningSample.Rd index 65f9c042e..ce82c664b 100644 --- a/man/validatePruningSample.Rd +++ b/man/validatePruningSample.Rd @@ -25,8 +25,8 @@ validatePruningSample( ) } \arguments{ -\item{gdsReference}{an object of class \link[gdsfmt]{gds.class} (a GDS file), the -1 KG GDS file.} +\item{gdsReference}{an object of class \link[gdsfmt]{gds.class} +(a GDS file), the Population Reference GDS file.} \item{method}{a \code{character} string that represents the method that will be used to calculate the linkage disequilibrium in the diff --git a/man/validateRunExomeAncestry.Rd b/man/validateRunExomeAncestry.Rd index fc07eb073..34c7bf4b3 100644 --- a/man/validateRunExomeAncestry.Rd +++ b/man/validateRunExomeAncestry.Rd @@ -47,10 +47,11 @@ exist.} the directory where the output files are created.} \item{fileReferenceGDS}{a \code{character} string representing the file -name of the 1KG GDS file. The file must exist.} +name of the Population Reference GDS file. The file must exist.} \item{fileReferenceAnnotGDS}{a \code{character} string representing the -file name of the 1KG GDS annotation file. The file must exist.} +file name of the Population Reference GDS annotation file. +The file must exist.} \item{chrInfo}{a \code{vector} of positive \code{integer} values representing the length of the chromosomes. See 'details' section.} @@ -90,6 +91,7 @@ study <- data.frame(study.id = "MYDATA", study.platform = "PLATFORM", stringsAsFactors = FALSE) +## Population Reference GDS demo file gds1KG <- file.path(dataDir, "gds1KG.gds") gdsAnnot1KG <- file.path(dataDir, "gdsAnnot1KG.gds") diff --git a/tests/testthat/test-processStudy.R b/tests/testthat/test-processStudy.R index 3b6f300ff..7ea009793 100644 --- a/tests/testthat/test-processStudy.R +++ b/tests/testthat/test-processStudy.R @@ -132,7 +132,7 @@ test_that("appendStudy2GDS1KG() must return error when fileNameGDS is numeric", stringsAsFactors=FALSE) error_message <- paste0("The \'fileNameGDS\' must be a character string ", - "representing the GDS 1KG file. The file must exist.") + "representing the Population Reference GDS file. The file must exist.") expect_error(appendStudy2GDS1KG(pathGeno=test_path("fixtures"), filePedRDS=sampleRDS, fileNameGDS=33, batch=1, @@ -1206,8 +1206,8 @@ test_that("createStudy2GDS1KG() must return error when fileNameGDS is numerical Sample.Type=rep("Primary Tumor", 3), Source=rep("Databank B", 3), stringsAsFactors=FALSE) - error_message <- paste0("The \'fileNameGDS\' must be a character ", - "string representing the GDS 1KG file. The file must exist.") + error_message <- paste0("The \'fileNameGDS\' must be a character string ", + "representing the Population Reference GDS file. The file must exist.") expect_error(createStudy2GDS1KG(pathGeno=dataDir, filePedRDS=NULL, pedStudy=pedDF, fileNameGDS=33, From 2ffb1d80068c840bbedbe9b757d8e0da0d3bd940 Mon Sep 17 00:00:00 2001 From: belleau Date: Thu, 17 Aug 2023 14:06:24 -0400 Subject: [PATCH 112/385] Update runExomeAncestry runRNAAncestry, and runWrapperAncestry examples --- R/processStudy.R | 8 ++++---- R/processStudy_internal.R | 34 +++++++++++++++++++--------------- man/runExomeAncestry.Rd | 4 ++-- man/runRNAAncestry.Rd | 4 ++-- man/runWrapperAncestry.Rd | 34 +++++++++++++++++++--------------- 5 files changed, 46 insertions(+), 38 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 825901dee..80731f779 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2490,8 +2490,8 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' #' \dontrun{ -#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) -#' && !file.exists(pathOut)) { +#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && +#' !file.exists(pathOut)) { #' #' runExomeAncestry(pedStudy=ped, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, @@ -2711,8 +2711,8 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' #' \dontrun{ -#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) -#' && !file.exists(pathOut)) { +#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && +#' !file.exists(pathOut)) { #' #' runRNAAncestry(pedStudy=ped, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index de6f109a3..8e650ac6f 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2391,9 +2391,9 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil #' ## The path where the Profile GDS Files (one per sample) #' ## will be created need to be specified. #' ################################################################# -#' pathProfileGDS <- file.path(dataDir, "example", "out.tmp") +#' pathProfileGDS <- file.path(getwd(), "out.tmp") #' -#' pathOut <- file.path(dataDir, "example", "res.out") +#' pathOut <- file.path(getwd(), "res.out") #' #' ################################################################# #' ## A data frame containing general information about the study @@ -2428,19 +2428,23 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil #' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' #' \dontrun{ -#' runWrapperAncestry(pedStudy=ped, studyDF=studyDF, -#' pathProfileGDS=pathProfileGDS, -#' pathGeno=pathGeno, -#' pathOut=pathOut, -#' fileReferenceGDS=fileReferenceGDS, -#' fileReferenceAnnotGDS=fileAnnotGDS, -#' chrInfo=chrInfo, -#' syntheticRefDF=dataRef, -#' studyType="DNA" -#' genoSource="snp-pileup") -#' -#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && +#' !file.exists(pathOut)) { +#' +#' RAIDS:::runWrapperAncestry(pedStudy=ped, studyDF=studyDF, +#' pathProfileGDS=pathProfileGDS, +#' pathGeno=pathGeno, +#' pathOut=pathOut, +#' fileReferenceGDS=fileReferenceGDS, +#' fileReferenceAnnotGDS=fileAnnotGDS, +#' chrInfo=chrInfo, +#' syntheticRefDF=dataRef, +#' studyType="DNA", +#' genoSource="snp-pileup") +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' } #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index 1fe013226..e519fea5f 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -183,8 +183,8 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] \dontrun{ - if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) - && !file.exists(pathOut)) { + if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && + !file.exists(pathOut)) { runExomeAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index f101f2f50..9d8f43afe 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -188,8 +188,8 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] \dontrun{ - if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) - && !file.exists(pathOut)) { + if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && + !file.exists(pathOut)) { runRNAAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, diff --git a/man/runWrapperAncestry.Rd b/man/runWrapperAncestry.Rd index 35699b1c1..2ca954cf2 100644 --- a/man/runWrapperAncestry.Rd +++ b/man/runWrapperAncestry.Rd @@ -155,9 +155,9 @@ pathGeno <- file.path(dataDir, "example", "snpPileup") ## The path where the Profile GDS Files (one per sample) ## will be created need to be specified. ################################################################# -pathProfileGDS <- file.path(dataDir, "example", "out.tmp") +pathProfileGDS <- file.path(getwd(), "out.tmp") -pathOut <- file.path(dataDir, "example", "res.out") +pathOut <- file.path(getwd(), "res.out") ################################################################# ## A data frame containing general information about the study @@ -192,19 +192,23 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] \dontrun{ -runWrapperAncestry(pedStudy=ped, studyDF=studyDF, - pathProfileGDS=pathProfileGDS, - pathGeno=pathGeno, - pathOut=pathOut, - fileReferenceGDS=fileReferenceGDS, - fileReferenceAnnotGDS=fileAnnotGDS, - chrInfo=chrInfo, - syntheticRefDF=dataRef, - studyType="DNA" - genoSource="snp-pileup") - -unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -unlink(pathOut, recursive=TRUE, force=TRUE) + if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && + !file.exists(pathOut)) { + + RAIDS:::runWrapperAncestry(pedStudy=ped, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, + pathGeno=pathGeno, + pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + studyType="DNA", + genoSource="snp-pileup") + + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + } } } From bd72c1d73492ae639ebbb0dc4ddaba696f28d1fc Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 14:11:29 -0400 Subject: [PATCH 113/385] Remove admixture functions --- R/admixture.R | 218 -------------------------------------------------- 1 file changed, 218 deletions(-) delete mode 100644 R/admixture.R diff --git a/R/admixture.R b/R/admixture.R deleted file mode 100644 index bda1e5d94..000000000 --- a/R/admixture.R +++ /dev/null @@ -1,218 +0,0 @@ - - -#' @title create a file tfam file for plink from the gdsReference file -#' -#' @description TODO -#' -#' @param gdsReference an object of class -#' \link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file. -#' -#' @param listSample a \code{array} with the sample to keep TODO -#' -#' @param pedOut TODO a PATH and file name to the output file -#' -#' @return TODO a \code{vector} of \code{numeric} -#' -#' @examples -#' -#' # TODO -#' gds <- "Demo GDS TODO" -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt index.gdsn read.gdsn -#' @importFrom utils write.table -#' @encoding UTF-8 -#' @keywords export -gds2tfam <- function(gdsReference, listSample, pedOut) { - - sampleGDS <- index.gdsn(gdsReference, "sample.id") - sampleId <-read.gdsn(sampleGDS) - listS <- which(sampleId %in% listSample) - - sampleGDS <- index.gdsn(gdsReference, "sample.annot") - sampleANNO <-read.gdsn(sampleGDS) - - dfPed <- data.frame(famId=paste0("F", seq_len(length(listSample))), - id=sampleId[listS], - fa=rep("0",length(listSample)), - mo=rep("0",length(listSample)), - sex=sampleANNO$sex[listS], - pheno=rep(1,length(listSample)), - stringsAsFactors=FALSE) - - write.table(dfPed, pedOut, - quote=FALSE, sep="\t", - row.names=FALSE, - col.names=FALSE) - -} - - -#' @title create a file tfam file for plink from the gdsProfile file -#' -#' @description TODO -#' -#' @param gdsProfile an object of class \link[gdsfmt]{gds.class} (a GDS -#' file), the open Profile GDS file. -#' -#' @param listSample a \code{array} with the sample to keep -#' -#' @param sampleANNO a \code{data.frame} with at least column sex and the name -#' must be sample.id -#' -#' @param pedOut TODO a PATH and file name to the output file -#' -#' -#' @return TODO a \code{vector} of \code{numeric} -#' -#' @examples -#' -#' # TODO -#' gds <- "Demo GDS TODO" -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt index.gdsn read.gdsn -#' @importFrom utils write.table -#' @encoding UTF-8 -#' @keywords export -gds2tfamSample <- function(gdsProfile, listSample, sampleANNO, pedOut) { - - sampleGDS <- index.gdsn(gdsProfile, "sample.id") - sampleId <-read.gdsn(sampleGDS) - listS <- which(sampleId %in% listSample) - - dfPed <- data.frame(famId=paste0("F", seq_len(length(listSample))), - id=sampleId[listS], - fa=rep("0",length(listSample)), - mo=rep("0",length(listSample)), - sex=sampleANNO[sampleId[listS], "sex"], - pheno=rep(1,length(listSample)), - stringsAsFactors=FALSE) - - write.table(dfPed, pedOut, quote=FALSE, sep="\t", - row.names=FALSE, col.names=FALSE) -} - - -#' @title create a file tped file for plink from the gds file -#' -#' @description TODO -#' -#' @param gds a \code{gds} object. -#' -#' @param listSample a \code{array} with the sample to keep -#' -#' @param listSNP a \code{array} with the snp.id to keep -#' -#' @param pedOut TODO a PATH and file name to the output file -#' -#' @return TODO a \code{vector} of \code{numeric} -#' -#' @examples -#' -#' # TODO -#' gds <- "Demo GDS TODO" -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt index.gdsn read.gdsn -#' @importFrom utils write.table -#' @encoding UTF-8 -#' @keywords export -gds2tped <- function(gds, listSample, listSNP, pedOut) { - - sampleGDS <- index.gdsn(gds, "sample.id") - sampleId <-read.gdsn(sampleGDS) - listS <- which(sampleId %in% listSample) - - snpGDS <- index.gdsn(gds, "snp.id") - snpId <- read.gdsn(snpGDS) - listKeep <- which(snpId %in% listSNP) - snpId <- snpId[listKeep] - - snpGDS <- index.gdsn(gds, "snp.chromosome") - snpChr <- read.gdsn(snpGDS) - snpChr <- snpChr[listKeep] - - snpGDS <- index.gdsn(gds, "snp.position") - snpPos <- read.gdsn(snpGDS) - snpPos <- snpPos[listKeep] - - tped <- list() - tped[[1]] <- snpChr - tped[[2]] <- snpId - tped[[3]] <- rep(0,length(snpId)) - tped[[4]] <- snpPos - k<-4 - geno.var <- index.gdsn(gds, "genotype") - for(i in listS){ - k <- k + 1 - - tmp <- read.gdsn(geno.var, start=c(1, i), count=c(-1,1))[listKeep] - - # 0 1 0 1 0 1 - tped[[k]] <- (tmp == 2) + 1 - k <- k + 1 - tped[[k]] <- (tmp > 0) + 1 - - } - - write.table(tped, pedOut, quote=FALSE, sep="\t", row.names=FALSE, - col.names=FALSE) -} - - -#' @title Merge the pruning files by chromosome in one RDS file -#' -#' @description The function reads the information from all chromosomes. The -#' information is scattered in different files (one file per chromosome). -#' Once all information is loaded, the function merges -#' the information and saves it into a RDS file. -#' -#' @param pathPrunedGDS a \code{character} string representing the path where -#' the pruned files for each chromosome are located. -#' The path must exists. -#' -#' @param filePref a \code{character} string representing the prefix used for -#' the pruned files for each chromosome. The prefix represent the complete -#' string that is before the chromosome number in the file names. -#' -#' @param fileOut a \code{character} string representing name of the output -#' file that will be created. The file will contain the information for all -#' pruned chromosomes. The file must have a ".rds" extension. -#' -#' @return The integer \code{0L} when successful. -#' -#' @examples -#' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") -#' -#' ## TODO -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @encoding UTF-8 -#' @keywords internal -groupChrPruning <- function(pathPrunedGDS, filePref, fileOut) { - - prunedList <- list() - - # Read the content of each file (one file per chromosome) - for(i in seq_len(22)) { - fileChr <- file.path(pathPrunedGDS, paste0(filePref, i, ".rds")) - - if(file.exists(fileChr)) { - prunedList[[i]] <- readRDS(fileChr) - } else { - stop("Problem with the file: ", fileChr) - } - } - - ## Merge the content of all files - pruned <- do.call(c, prunedList) - - ## Save all the information into one file - saveRDS(pruned, fileChr <- file.path(pathPrunedGDS, fileOut)) - - ## Successful - return(0L) -} From 88c25c92a9f2cf2144eb47d4df418cd8f5999382 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 16:12:34 -0400 Subject: [PATCH 114/385] Remove doc related to admixture functions --- NAMESPACE | 1 - man/gds2tfam.Rd | 33 --------------------------------- man/gds2tfamSample.Rd | 36 ------------------------------------ man/gds2tped.Rd | 34 ---------------------------------- 4 files changed, 104 deletions(-) delete mode 100644 man/gds2tfam.Rd delete mode 100644 man/gds2tfamSample.Rd delete mode 100644 man/gds2tped.Rd diff --git a/NAMESPACE b/NAMESPACE index 0ab3f8b45..0fcf09033 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -87,4 +87,3 @@ importFrom(utils,read.csv2) importFrom(utils,read.delim) importFrom(utils,write.csv) importFrom(utils,write.csv2) -importFrom(utils,write.table) diff --git a/man/gds2tfam.Rd b/man/gds2tfam.Rd deleted file mode 100644 index 77296fd48..000000000 --- a/man/gds2tfam.Rd +++ /dev/null @@ -1,33 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/admixture.R -\encoding{UTF-8} -\name{gds2tfam} -\alias{gds2tfam} -\title{create a file tfam file for plink from the gdsReference file} -\usage{ -gds2tfam(gdsReference, listSample, pedOut) -} -\arguments{ -\item{gdsReference}{an object of class -\link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file.} - -\item{listSample}{a \code{array} with the sample to keep TODO} - -\item{pedOut}{TODO a PATH and file name to the output file} -} -\value{ -TODO a \code{vector} of \code{numeric} -} -\description{ -TODO -} -\examples{ - -# TODO -gds <- "Demo GDS TODO" - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{export} diff --git a/man/gds2tfamSample.Rd b/man/gds2tfamSample.Rd deleted file mode 100644 index 8a696a770..000000000 --- a/man/gds2tfamSample.Rd +++ /dev/null @@ -1,36 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/admixture.R -\encoding{UTF-8} -\name{gds2tfamSample} -\alias{gds2tfamSample} -\title{create a file tfam file for plink from the gdsProfile file} -\usage{ -gds2tfamSample(gdsProfile, listSample, sampleANNO, pedOut) -} -\arguments{ -\item{gdsProfile}{an object of class \link[gdsfmt]{gds.class} (a GDS -file), the open Profile GDS file.} - -\item{listSample}{a \code{array} with the sample to keep} - -\item{sampleANNO}{a \code{data.frame} with at least column sex and the name -must be sample.id} - -\item{pedOut}{TODO a PATH and file name to the output file} -} -\value{ -TODO a \code{vector} of \code{numeric} -} -\description{ -TODO -} -\examples{ - -# TODO -gds <- "Demo GDS TODO" - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{export} diff --git a/man/gds2tped.Rd b/man/gds2tped.Rd deleted file mode 100644 index 9cdb27678..000000000 --- a/man/gds2tped.Rd +++ /dev/null @@ -1,34 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/admixture.R -\encoding{UTF-8} -\name{gds2tped} -\alias{gds2tped} -\title{create a file tped file for plink from the gds file} -\usage{ -gds2tped(gds, listSample, listSNP, pedOut) -} -\arguments{ -\item{gds}{a \code{gds} object.} - -\item{listSample}{a \code{array} with the sample to keep} - -\item{listSNP}{a \code{array} with the snp.id to keep} - -\item{pedOut}{TODO a PATH and file name to the output file} -} -\value{ -TODO a \code{vector} of \code{numeric} -} -\description{ -TODO -} -\examples{ - -# TODO -gds <- "Demo GDS TODO" - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{export} From 655a659ad46f4c4651b55dc1c1d45fb14c8d9264 Mon Sep 17 00:00:00 2001 From: belleau Date: Thu, 17 Aug 2023 17:11:33 -0400 Subject: [PATCH 115/385] Update runExomeAncestry runRNAAncestry runWrapperAncestry, and runProfileAncestry examples --- R/processStudy.R | 4 +- R/processStudy_internal.R | 113 +++++++++++++++++++++++++++++++++++++- man/runExomeAncestry.Rd | 2 +- man/runProfileAncestry.Rd | 111 ++++++++++++++++++++++++++++++++++++- man/runRNAAncestry.Rd | 2 +- man/runWrapperAncestry.Rd | 2 +- 6 files changed, 224 insertions(+), 10 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 80731f779..64472d5ff 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2419,7 +2419,7 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' @examples #' #' ## Required library for GDS -#' library(gdsfmt) +#' library(SNPRelate) #' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") @@ -2640,7 +2640,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @examples #' #' ## Required library for GDS -#' library(gdsfmt) +#' library(SNPRelate) #' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 44b638c15..ca75ecc15 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2124,8 +2124,115 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' @examples #' #' ## Required library for GDS -#' library(gdsfmt) -#' # TODO +#' library(SNPRelate) +#' +#' ## Path to the demo 1KG GDS file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ################################################################# +#' ## The path and file name for the PED RDS file +#' ## will the information about the analyzed samples +#' ################################################################# +#' filePED <- file.path(dataDir, "example", "pedEx.rds") +#' ped <- readRDS(filePED) +#' head(ped) +#' +#' ################################################################# +#' ## The 1KG GDS file and the 1KG SNV Annotation GDS file +#' ## need to be located in the same directory +#' ## Note that the 1KG GDS file used for this example is a +#' ## simplified version and CANNOT be used for any real analysis +#' ################################################################# +#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' +#' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") +#' fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +#' +#' ################################################################# +#' ## The Sample SNP pileup files (one per sample) need +#' ## to be located in the same directory. +#' ################################################################# +#' pathGeno <- file.path(dataDir, "example", "snpPileup") +#' +#' ################################################################# +#' ## The path where the Profile GDS Files (one per sample) +#' ## will be created need to be specified. +#' ################################################################# +#' +#' pathProfileGDS <- file.path(getwd(), "out.tmp") +#' +#' pathOut <- file.path(getwd(), "res.out") +#' +#' ################################################################# +#' ## A data frame containing general information about the study +#' ## is also required. The data frame must have +#' ## those 3 columns: "studyID", "study.desc", "study.platform" +#' ################################################################# +#' studyDF <- data.frame(study.id="MYDATA", +#' study.desc="Description", +#' study.platform="PLATFORM", +#' stringsAsFactors=FALSE) +#' +#' #################################################################### +#' ## Fix seed to ensure reproducible results +#' #################################################################### +#' set.seed(3043) +#' +#' gdsReference <- snpgdsOpen(fileReferenceGDS) +#' dataRef <- select1KGPop(gdsReference, nbProfiles=2L) +#' closefn.gds(gdsReference) +#' +#' ## Chromosome length information for hg38 +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, +#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, +#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, +#' 156040895L, 57227415L, 16569L) +#' +#' ## A formal way to get the chromosome length information for hg38 +#' ## library(GenomeInfoDb) +#' ## library(BSgenome.Hsapiens.UCSC.hg38) +#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] +#' +#' studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), +#' study.desc=paste0(studyDF$study.id, " synthetic data"), +#' study.platform=studyDF$study.platform, stringsAsFactors=FALSE) +#' +#' listProfileRef <- dataRef$sample.id +#' profileFile <- file.path(pathProfileGDS, "ex1.gds") +#' +#' \dontrun{ +#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && +#' !file.exists(pathOut)) { +#' +#' dir.create(pathProfileGDS) +#' dir.create(pathOut) +#' file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) +#' +#' gdsReference <- snpgdsOpen(fileReferenceGDS) +#' gdsRefAnnot <- openfn.gds(fileAnnotGDS) +#' +#' RAIDS:::runProfileAncestry(gdsReference=gdsReference, +#' gdsRefAnnot=gdsRefAnnot, +#' studyDF=studyDF, currentProfile=ped[1,"Name.ID"], +#' pathProfileGDS=pathProfileGDS, +#' pathOut=pathOut, +#' chrInfo=chrInfo, +#' syntheticRefDF=dataRef, +#' studyDFSyn=studyDFSyn, +#' listProfileRef=listProfileRef, +#' studyType="DNA") +#' +#' closefn.gds(gdsReference) +#' closefn.gds(gdsRefAnnot) +#' +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' } +#' } +#' #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom utils write.csv @@ -2364,7 +2471,7 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil #' @examples #' #' ## Required library for GDS -#' library(gdsfmt) +#' library(SNPRelate) #' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index e519fea5f..1ce2d91df 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -112,7 +112,7 @@ also created. \examples{ ## Required library for GDS -library(gdsfmt) +library(SNPRelate) ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata", package="RAIDS") diff --git a/man/runProfileAncestry.Rd b/man/runProfileAncestry.Rd index 1c8b243d6..728f43dbd 100644 --- a/man/runProfileAncestry.Rd +++ b/man/runProfileAncestry.Rd @@ -113,8 +113,115 @@ also created. \examples{ ## Required library for GDS -library(gdsfmt) -# TODO +library(SNPRelate) + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +################################################################# +## The path and file name for the PED RDS file +## will the information about the analyzed samples +################################################################# +filePED <- file.path(dataDir, "example", "pedEx.rds") +ped <- readRDS(filePED) +head(ped) + +################################################################# +## The 1KG GDS file and the 1KG SNV Annotation GDS file +## need to be located in the same directory +## Note that the 1KG GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +################################################################# +path1KG <- file.path(dataDir, "example", "gdsRef") + +fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") +fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") + +################################################################# +## The Sample SNP pileup files (one per sample) need +## to be located in the same directory. +################################################################# +pathGeno <- file.path(dataDir, "example", "snpPileup") + +################################################################# +## The path where the Profile GDS Files (one per sample) +## will be created need to be specified. +################################################################# + +pathProfileGDS <- file.path(getwd(), "out.tmp") + +pathOut <- file.path(getwd(), "res.out") + +################################################################# +## A data frame containing general information about the study +## is also required. The data frame must have +## those 3 columns: "studyID", "study.desc", "study.platform" +################################################################# +studyDF <- data.frame(study.id="MYDATA", + study.desc="Description", + study.platform="PLATFORM", + stringsAsFactors=FALSE) + +#################################################################### +## Fix seed to ensure reproducible results +#################################################################### +set.seed(3043) + +gdsReference <- snpgdsOpen(fileReferenceGDS) +dataRef <- select1KGPop(gdsReference, nbProfiles=2L) +closefn.gds(gdsReference) + +## Chromosome length information for hg38 +## chr23 is chrX, chr24 is chrY and chrM is 25 +chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, + 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, + 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, + 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, + 156040895L, 57227415L, 16569L) + +## A formal way to get the chromosome length information for hg38 +## library(GenomeInfoDb) +## library(BSgenome.Hsapiens.UCSC.hg38) +## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] + +studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), + study.desc=paste0(studyDF$study.id, " synthetic data"), + study.platform=studyDF$study.platform, stringsAsFactors=FALSE) + +listProfileRef <- dataRef$sample.id +profileFile <- file.path(pathProfileGDS, "ex1.gds") + +\dontrun{ + if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && + !file.exists(pathOut)) { + + dir.create(pathProfileGDS) + dir.create(pathOut) + file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) + + gdsReference <- snpgdsOpen(fileReferenceGDS) + gdsRefAnnot <- openfn.gds(fileAnnotGDS) + + RAIDS:::runProfileAncestry(gdsReference=gdsReference, + gdsRefAnnot=gdsRefAnnot, + studyDF=studyDF, currentProfile=ped[1,"Name.ID"], + pathProfileGDS=pathProfileGDS, + pathOut=pathOut, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + studyDFSyn=studyDFSyn, + listProfileRef=listProfileRef, + studyType="DNA") + + closefn.gds(gdsReference) + closefn.gds(gdsRefAnnot) + + + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + } +} + } \references{ diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index 9d8f43afe..b760fdf06 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -117,7 +117,7 @@ also created. \examples{ ## Required library for GDS -library(gdsfmt) +library(SNPRelate) ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata", package="RAIDS") diff --git a/man/runWrapperAncestry.Rd b/man/runWrapperAncestry.Rd index 2ca954cf2..5cd9c1163 100644 --- a/man/runWrapperAncestry.Rd +++ b/man/runWrapperAncestry.Rd @@ -121,7 +121,7 @@ also created. \examples{ ## Required library for GDS -library(gdsfmt) +library(SNPRelate) ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata", package="RAIDS") From 63456ebe27a2a524dd03b3df7bd81962ddbdbcdc Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 17:41:42 -0400 Subject: [PATCH 116/385] Remove deleted function doc --- man/groupChrPruning.Rd | 43 ------------------------------------------ 1 file changed, 43 deletions(-) delete mode 100644 man/groupChrPruning.Rd diff --git a/man/groupChrPruning.Rd b/man/groupChrPruning.Rd deleted file mode 100644 index 3ee80a115..000000000 --- a/man/groupChrPruning.Rd +++ /dev/null @@ -1,43 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/admixture.R -\encoding{UTF-8} -\name{groupChrPruning} -\alias{groupChrPruning} -\title{Merge the pruning files by chromosome in one RDS file} -\usage{ -groupChrPruning(pathPrunedGDS, filePref, fileOut) -} -\arguments{ -\item{pathPrunedGDS}{a \code{character} string representing the path where -the pruned files for each chromosome are located. -The path must exists.} - -\item{filePref}{a \code{character} string representing the prefix used for -the pruned files for each chromosome. The prefix represent the complete -string that is before the chromosome number in the file names.} - -\item{fileOut}{a \code{character} string representing name of the output -file that will be created. The file will contain the information for all -pruned chromosomes. The file must have a ".rds" extension.} -} -\value{ -The integer \code{0L} when successful. -} -\description{ -The function reads the information from all chromosomes. The -information is scattered in different files (one file per chromosome). -Once all information is loaded, the function merges -the information and saves it into a RDS file. -} -\examples{ - -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", package="RAIDS") - -## TODO - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{internal} From e82a9880e787c9f34c7a2da30b39dec5ff9f3b77 Mon Sep 17 00:00:00 2001 From: belleau Date: Thu, 17 Aug 2023 17:46:32 -0400 Subject: [PATCH 117/385] Removed loop in runWrapperAncestry, and runProfileAncestry --- R/processStudy_internal.R | 113 +------------------------------------- man/groupChrPruning.Rd | 43 --------------- 2 files changed, 1 insertion(+), 155 deletions(-) delete mode 100644 man/groupChrPruning.Rd diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index ca75ecc15..79065c1d4 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2245,12 +2245,6 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil np=1L, blockTypeID=NULL, verbose=FALSE) { - ## Validate parameters TODO - # validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, - # pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, - # fileReferenceGDS=fileReferenceGDS, - # fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, - # syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) studyType <- arg_match(studyType) @@ -2299,8 +2293,6 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil ## Open the Profile GDS file gdsProfile <- snpgdsOpen(fileGDSProfile) - ## FOR_LOOP modification to be validated by Pascal - ## Remove commented code and this text after validation ## This variable will contain the results from the PCA analyses ## For each row of the sampleRM matrix @@ -2323,22 +2315,6 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil studyDFSyn=studyDFSyn, spRef=spRef, pathOutProfile=pathOutProfile, currentProfile=currentProfile) - # for(j in seq_len(nrow(sampleRM))) { - # ## Run a PCA analysis using 1 synthetic profile from each - # ## sub-continental ancestry - # ## The synthetic profiles are projected on the 1KG PCA space - # ## (the reference samples used to generate the synthetic profiles - # ## are removed from this PCA) - # ## The K-nearest neighbor analysis is done using - # ## a range of K and D values - # synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, - # sampleRM=sampleRM[j,], studyIDSyn=studyDFSyn$study.id, - # np=1L, spRef=spRef, eigenCount=15L, verbose=FALSE) - # - # ## Results are saved - # saveRDS(synthKNN$matKNN, file.path(pathOutProfile, - # paste0("KNN.synt.", currentProfile, ".", j, ".rds"))) - # } ## Directory where the KNN results have been saved pathKNN <- file.path(pathOut, currentProfile) @@ -2574,12 +2550,6 @@ runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, np=1L, blockTypeID=NULL, verbose=FALSE) { - ## Validate parameters - validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, - pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, - fileReferenceGDS=fileReferenceGDS, - fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, - syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) genoSource <- arg_match(genoSource) @@ -2600,8 +2570,6 @@ runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, study.desc=paste0(studyDF$study.id, " synthetic data"), study.platform=studyDF$study.platform, stringsAsFactors=FALSE) - ## FOR_LOOP modification to be validated by Pascal - ## Remove commented code and this text after validation apply(pedStudy[,"Name.ID", drop=FALSE],1,FUN=function(x,gdsReference, gdsRefAnnot, studyDF,pathProfileGDS, @@ -2623,86 +2591,7 @@ runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, listProfileRef=listProfileRef, studyDFSyn=studyDFSyn, studyType=studyType, verbose=verbose) - # for(i in seq_len(length(listProfiles))) { - # pruningSample(gdsReference=gds1KG, currentProfile=listProfiles[i], - # studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS) - # file.GDSProfile <- file.path(pathProfileGDS, - # paste0(listProfiles[i], ".gds")) - # add1KG2SampleGDS(gdsReference=gds1KG, fileProfileGDS=file.GDSProfile, - # currentProfile=listProfiles[i], - # studyID=studyDF$study.id) - # addStudy1Kg(gds1KG, file.GDSProfile) - # - # gdsProfile <- openfn.gds(file.GDSProfile, readonly=FALSE) - # - # estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=gdsProfile, - # currentProfile=listProfiles[i], studyID=studyDF$study.id, - # chrInfo=chrInfo, verbose=verbose) - # closefn.gds(gdsProfile) - # - # ## Add information related to the synthetic profiles in Profile GDS file - # prepSynthetic(fileProfileGDS=file.GDSProfile, - # listSampleRef=listProfileRef, profileID=listProfiles[i], - # studyDF=studyDF.syn, prefix="1", verbose=verbose) - # - # resG <- syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gdsAnnot1KG, - # fileProfileGDS=file.GDSProfile, profileID=listProfiles[i], - # listSampleRef=listProfileRef, prefix="1") - # - # if(! file.exists(pathOut)) { - # dir.create(pathOut) - # } - # spRef <- getRef1KGPop(gds1KG, "superPop") - # sampleRM <- splitSelectByPop(syntheticRefDF) - # - # pathOutProfile <- file.path(pathOut, listProfiles[i]) - # if(! file.exists(pathOutProfile)) { - # dir.create(pathOutProfile) - # } - # - # ## Open the Profile GDS file - # gdsProfile <- snpgdsOpen(file.GDSProfile) - # - # ## This variable will contain the results from the PCA analyses - # ## For each row of the sampleRM matrix - # for(j in seq_len(nrow(sampleRM))) { - # ## Run a PCA analysis using 1 synthetic profile from each - # ## sub-continental ancestry - # ## The synthetic profiles are projected on the 1KG PCA space - # ## (the reference samples used to generate the synthetic profiles - # ## are removed from this PCA) - # ## The K-nearest neighbor analysis is done using - # ## a range of K and D values - # synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, - # sampleRM=sampleRM[j,], studyIDSyn=studyDF.syn$study.id, - # np=1L, spRef=spRef, eigenCount=15L, verbose=FALSE) - # - # ## Results are saved - # saveRDS(synthKNN$matKNN, file.path(pathOutProfile, - # paste0("KNN.synt.", listProfiles[i], ".", j, ".rds"))) - # } - # - # ## Directory where the KNN results have been saved - # pathKNN <- file.path(pathOut, listProfiles[i]) - # listFilesName <- dir(file.path(pathKNN), ".rds") - # ## List of the KNN result files from PCA on synthetic data - # listFiles <- file.path(file.path(pathKNN) , listFilesName) - # - # resCall <- computeAncestryFromSyntheticFile(gdsReference=gds1KG, - # gdsProfile=gdsProfile, listFiles=listFiles, - # currentProfile=listProfiles[i], spRef=spRef, - # studyIDSyn=studyDF.syn$study.id, np=1L) - # - # saveRDS(resCall, file.path(pathOut, - # paste0(listProfiles[i], ".infoCall", ".rds"))) - # - # write.csv(x=resCall$Ancestry, file=file.path(pathOut, - # paste0(listProfiles[i], ".Ancestry",".csv")), quote=FALSE, - # row.names=FALSE) - # - # ## Close Profile GDS file (important) - # closefn.gds(gdsProfile) - # } + ## Close all GDS files closefn.gds(gdsReference) diff --git a/man/groupChrPruning.Rd b/man/groupChrPruning.Rd deleted file mode 100644 index 3ee80a115..000000000 --- a/man/groupChrPruning.Rd +++ /dev/null @@ -1,43 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/admixture.R -\encoding{UTF-8} -\name{groupChrPruning} -\alias{groupChrPruning} -\title{Merge the pruning files by chromosome in one RDS file} -\usage{ -groupChrPruning(pathPrunedGDS, filePref, fileOut) -} -\arguments{ -\item{pathPrunedGDS}{a \code{character} string representing the path where -the pruned files for each chromosome are located. -The path must exists.} - -\item{filePref}{a \code{character} string representing the prefix used for -the pruned files for each chromosome. The prefix represent the complete -string that is before the chromosome number in the file names.} - -\item{fileOut}{a \code{character} string representing name of the output -file that will be created. The file will contain the information for all -pruned chromosomes. The file must have a ".rds" extension.} -} -\value{ -The integer \code{0L} when successful. -} -\description{ -The function reads the information from all chromosomes. The -information is scattered in different files (one file per chromosome). -Once all information is loaded, the function merges -the information and saves it into a RDS file. -} -\examples{ - -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", package="RAIDS") - -## TODO - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{internal} From ff02182d23defe4a20075486f7592801b5d1a378 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 17:58:58 -0400 Subject: [PATCH 118/385] Update documentation for some functions --- NAMESPACE | 1 + R/process1KG.R | 8 +++++-- R/process1KG_internal.R | 23 ++++++++++++++++++- R/processStudy_internal.R | 13 +++++++++++ R/tools.R | 4 ++++ R/tools_internal.R | 8 ++++--- man/addBlockFromPlink2GDS.Rd | 6 +++-- man/processBlockChr.Rd | 8 ++++--- man/pruning1KGbyChr.Rd | 23 ++++++++++++++++++- man/snvListVCF.Rd | 3 +++ man/validateAdd1KG2SampleGDS.Rd | 3 +++ ...alidateComputeAncestryFromSyntheticFile.Rd | 3 +++ man/validateEstimateAllelicFraction.Rd | 4 ++++ man/validatePruningSample.Rd | 3 +++ 14 files changed, 98 insertions(+), 12 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 0fcf09033..0ab3f8b45 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -87,3 +87,4 @@ importFrom(utils,read.csv2) importFrom(utils,read.delim) importFrom(utils,write.csv) importFrom(utils,write.csv2) +importFrom(utils,write.table) diff --git a/R/process1KG.R b/R/process1KG.R index f5f032510..f9376edf7 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -805,9 +805,11 @@ basePCASample <- function(gds, listSample.Ref=NULL, listSNP=NULL, np=1L) { #' #' @param gdsOut an object of class \code{gds} opened in writing mode. #' -#' @param pathBlock TODO +#' @param pathBlock a \code{character} string representing the path where +#' the block files are located. #' -#' @param superPop TODO +#' @param superPop a \code{character} string representing the specific +#' continental population. #' #' @param blockName a \code{character} string representing the unique #' block name. @@ -838,6 +840,8 @@ basePCASample <- function(gds, listSample.Ref=NULL, listSNP=NULL, np=1L) { addBlockFromPlink2GDS <- function(gds, gdsOut, pathBlock, superPop, blockName, blockDesc, verbose=FALSE) { + ## NOTE + ## add validations ## The gds must be an object of class "gds.class" validateGDSClass(gds=gds, name="gds") diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index a95675acd..53b39e7c0 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -55,10 +55,31 @@ #' #' @examples #' +#' ## Required library +#' library(SNPRelate) +#' #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' -#' ## TODO +#' ## The 1KG Population Reference GDS demo file (opened) +#' gds1KG <- snpgdsOpen(file.path(dataDir, "gds1KG.gds")) +#' +#' ## The prefix of the RDS file to be created and containing the pruned SNVs +#' outPrefix <- "Pruned_Demo_Reference" +#' +#' ## Run only if directory in writing mode +#' if (file.access(getwd()) == 0 && +#' !file.exists(file.path(getwd(), outPrefix, ".rds"))) { +#' +#' ## Create a RDS file with the pruned SNVs +#' RAIDS:::pruning1KGbyChr(gdsReference=gds1KG, outPrefix=outPrefix) +#' +#' prunedSNVs <- readRDS(file.path(getwd(), outPrefix, ".rds")) +#' prunedSNVs +#' } +#' +#' ## Close 1K GDS file +#' closefn.gds(gds1KG) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 44b638c15..2d6249670 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -68,6 +68,9 @@ #' #' @examples #' +#' ## Required library +#' library(gdsfmt) +#' #' ## Directory where demo GDS files are located #' dataDir <- system.file("extdata", package="RAIDS") #' @@ -366,6 +369,10 @@ validateComputePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, #' #' @examples #' +#' +#' ## Required library +#' library(gdsfmt) +#' #' ## Directory where demo GDS files are located #' dataDir <- system.file("extdata", package="RAIDS") #' @@ -661,6 +668,9 @@ validateCreateStudy2GDS1KG <- function(pathGeno, pedStudy, fileNameGDS, batch, #' #' @examples #' +#' ## Required library +#' library(gdsfmt) +#' #' ## Directory where demo GDS files are located #' dataDir <- system.file("extdata", package="RAIDS") #' @@ -992,6 +1002,9 @@ validateAppendStudy2GDS1KG <- function(pathGeno, filePedRDS, fileNameGDS, #' #' @examples #' +#' ## Required library +#' library(gdsfmt) +#' #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' diff --git a/R/tools.R b/R/tools.R index b3f286d4d..68f5bd882 100644 --- a/R/tools.R +++ b/R/tools.R @@ -24,6 +24,9 @@ #' #' @examples #' +#' ## Required library +#' library(gdsfmt) +#' #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' @@ -52,6 +55,7 @@ #' @importFrom gdsfmt read.gdsn #' @importFrom methods is #' @importFrom S4Vectors isSingleNumber +#' @importFrom utils write.table #' @encoding UTF-8 #' @export snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { diff --git a/R/tools_internal.R b/R/tools_internal.R index 0fd19649c..3a13787d2 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -185,11 +185,13 @@ validatePositiveIntegerVector <- function(value, name) { #' #' @param snpKeep TODO #' -#' @param pathBlock TODO +#' @param pathBlock a \code{character} string representing the path to the +#' block files. #' -#' @param superPop TODO +#' @param superPop a \code{character} string representing the current +#' continental population (ex: EUR, AFR, etc.). #' -#' @param chr TODO +#' @param chr a \code{integer} representing the current chromosome. #' #' #' @return the a \code{array} with the sample from pedDF keept diff --git a/man/addBlockFromPlink2GDS.Rd b/man/addBlockFromPlink2GDS.Rd index e7800de49..b3d7b0d0f 100644 --- a/man/addBlockFromPlink2GDS.Rd +++ b/man/addBlockFromPlink2GDS.Rd @@ -22,9 +22,11 @@ addBlockFromPlink2GDS( \item{gdsOut}{an object of class \code{gds} opened in writing mode.} -\item{pathBlock}{TODO} +\item{pathBlock}{a \code{character} string representing the path where +the block files are located.} -\item{superPop}{TODO} +\item{superPop}{a \code{character} string representing the specific +continental population.} \item{blockName}{a \code{character} string representing the unique block name.} diff --git a/man/processBlockChr.Rd b/man/processBlockChr.Rd index 2aef2d7ed..c1ad4adb8 100644 --- a/man/processBlockChr.Rd +++ b/man/processBlockChr.Rd @@ -10,11 +10,13 @@ processBlockChr(snpKeep, pathBlock, superPop, chr) \arguments{ \item{snpKeep}{TODO} -\item{pathBlock}{TODO} +\item{pathBlock}{a \code{character} string representing the path to the +block files.} -\item{superPop}{TODO} +\item{superPop}{a \code{character} string representing the current +continental population (ex: EUR, AFR, etc.).} -\item{chr}{TODO} +\item{chr}{a \code{integer} representing the current chromosome.} } \value{ the a \code{array} with the sample from pedDF keept diff --git a/man/pruning1KGbyChr.Rd b/man/pruning1KGbyChr.Rd index 36c3b3b2d..3ac2ba4a6 100644 --- a/man/pruning1KGbyChr.Rd +++ b/man/pruning1KGbyChr.Rd @@ -77,10 +77,31 @@ pruned SNVs are saved in a RDS file. } \examples{ +## Required library +library(SNPRelate) + ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") -## TODO +## The 1KG Population Reference GDS demo file (opened) +gds1KG <- snpgdsOpen(file.path(dataDir, "gds1KG.gds")) + +## The prefix of the RDS file to be created and containing the pruned SNVs +outPrefix <- "Pruned_Demo_Reference" + +## Run only if directory in writing mode +if (file.access(getwd()) == 0 && + !file.exists(file.path(getwd(), outPrefix, ".rds"))) { + + ## Create a RDS file with the pruned SNVs + RAIDS:::pruning1KGbyChr(gdsReference=gds1KG, outPrefix=outPrefix) + + prunedSNVs <- readRDS(file.path(getwd(), outPrefix, ".rds")) + prunedSNVs +} + +## Close 1K GDS file +closefn.gds(gds1KG) } \author{ diff --git a/man/snvListVCF.Rd b/man/snvListVCF.Rd index 6ca314419..7c1f5b6d0 100644 --- a/man/snvListVCF.Rd +++ b/man/snvListVCF.Rd @@ -34,6 +34,9 @@ a VCF file. } \examples{ +## Required library +library(gdsfmt) + ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") diff --git a/man/validateAdd1KG2SampleGDS.Rd b/man/validateAdd1KG2SampleGDS.Rd index 5552db1f7..5ee82b863 100644 --- a/man/validateAdd1KG2SampleGDS.Rd +++ b/man/validateAdd1KG2SampleGDS.Rd @@ -30,6 +30,9 @@ This function validates the input parameters for the } \examples{ +## Required library +library(gdsfmt) + ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") diff --git a/man/validateComputeAncestryFromSyntheticFile.Rd b/man/validateComputeAncestryFromSyntheticFile.Rd index a8bc0397a..1478a8738 100644 --- a/man/validateComputeAncestryFromSyntheticFile.Rd +++ b/man/validateComputeAncestryFromSyntheticFile.Rd @@ -94,6 +94,9 @@ This function validates the input parameters for the } \examples{ +## Required library +library(gdsfmt) + ## Directory where demo GDS files are located dataDir <- system.file("extdata", package="RAIDS") diff --git a/man/validateEstimateAllelicFraction.Rd b/man/validateEstimateAllelicFraction.Rd index a357eaf4a..06424c570 100644 --- a/man/validateEstimateAllelicFraction.Rd +++ b/man/validateEstimateAllelicFraction.Rd @@ -85,6 +85,10 @@ This function validates the input parameters for the } \examples{ + +## Required library +library(gdsfmt) + ## Directory where demo GDS files are located dataDir <- system.file("extdata", package="RAIDS") diff --git a/man/validatePruningSample.Rd b/man/validatePruningSample.Rd index ce82c664b..b0aef51df 100644 --- a/man/validatePruningSample.Rd +++ b/man/validatePruningSample.Rd @@ -95,6 +95,9 @@ This function validates the input parameters for the } \examples{ +## Required library +library(gdsfmt) + ## Directory where demo GDS files are located dataDir <- system.file("extdata", package="RAIDS") From 7eafff4aba5e4a07765def34cf540bdc240044af Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 18:09:08 -0400 Subject: [PATCH 119/385] Change Ref GDS to one that can be opened by SNPRelate --- R/process1KG_internal.R | 2 +- man/pruning1KGbyChr.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index 53b39e7c0..bd7978abd 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -62,7 +62,7 @@ #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG Population Reference GDS demo file (opened) -#' gds1KG <- snpgdsOpen(file.path(dataDir, "gds1KG.gds")) +#' gds1KG <- snpgdsOpen(file.path(dataDir, "1KG_Demo.gds")) #' #' ## The prefix of the RDS file to be created and containing the pruned SNVs #' outPrefix <- "Pruned_Demo_Reference" diff --git a/man/pruning1KGbyChr.Rd b/man/pruning1KGbyChr.Rd index 3ac2ba4a6..1748359fe 100644 --- a/man/pruning1KGbyChr.Rd +++ b/man/pruning1KGbyChr.Rd @@ -84,7 +84,7 @@ library(SNPRelate) dataDir <- system.file("extdata", package="RAIDS") ## The 1KG Population Reference GDS demo file (opened) -gds1KG <- snpgdsOpen(file.path(dataDir, "gds1KG.gds")) +gds1KG <- snpgdsOpen(file.path(dataDir, "1KG_Demo.gds")) ## The prefix of the RDS file to be created and containing the pruned SNVs outPrefix <- "Pruned_Demo_Reference" From 3166fb9e99077d67051f757df195f721ac864083 Mon Sep 17 00:00:00 2001 From: belleau Date: Thu, 17 Aug 2023 18:19:38 -0400 Subject: [PATCH 120/385] Removed loop in estimateAllelicFraction, and computeAllelicFractionRNA --- R/allelicFraction.R | 3 +- R/allelicFraction_internal.R | 129 ----------------------------------- 2 files changed, 1 insertion(+), 131 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index 28b53ddd2..41ae0285b 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -177,8 +177,7 @@ estimateAllelicFraction <- function(gdsReference, gdsProfile, cutOffLOH=cutOffLOH, cutOffAR=cutOffAR, verbose=verbose) } - ## FOR_LOOP modification to be validated by Pascal - ## Remove commented code and this text after validation + ## Calculate the cumulative sum for each chromosome cumSumResult <- lapply(unique(snpPos$snp.chr), function(i) { diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 8f1b473b3..b7c5ea483 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -895,8 +895,6 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, # for each chromosome # listBlock <- list() - ## FOR_LOOP modification to be validated by Pascal - ## Remove commented code and this text after validation listBlock <- lapply(unique(snpPos$snp.chr), FUN = function(x, snpPos, verbose){ if (verbose) { message("chr ", x) @@ -933,47 +931,6 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, for(b in seq_len(nrow(blockAF))) { snpPos$lap[snpPos$block.id == blockAF$block[b]] <- blockAF$aRF[b] } - # listMissing <- which(abs(blockAF$aRF + 1) < 1e-6) - # blockAF[listMissing, "aRF"] <- sample(blockAF$aRF[-1*listMissing], - # length(listMissing), replace=TRUE) - - # listBlock <- list() - # print(system.time(for(chr in unique(snp.pos$snp.chr)) { - # - # if (verbose) { - # message("chr ", chr) - # message("Step 1 ", Sys.time()) - # } - # - # #listHetero <- dfHetero[dfHetero$snp.chr == chr, "snp.pos"] - # listChr <- which(snp.pos$snp.chr == chr) - # # snp.pos.chr <- snp.pos[listChr,] - # - # blockAF <- tableBlockAF(snp.pos=snp.pos[listChr,]) - # # LOH - # blockAF$aRF[blockAF$lRhomo <= cutOffLOH] <- 0 - # blockAF$aRF[blockAF$lR >= cutOffAR] <- blockAF$aFraction[blockAF$lR - # >= cutOffAR] - # blockAF$aRF[blockAF$lR < cutOffAR & blockAF$nbHetero > 1] <- 0.5 - # - # listBlock[[chr]] <- blockAF - # - # if (verbose) { - # message("Step 1 done ", Sys.time()) - # } - # })) - # - # blockAF1 <- do.call(rbind, listBlock) - # - # listMissing <- which(abs(blockAF1$aRF + 1) < 1e-6) - # set.seed(654) - # blockAF1[listMissing, "aRF"] <- sample(blockAF1$aRF[-1*listMissing], - # length(listMissing), replace=TRUE) - # - # - # for(b in seq_len(nrow(blockAF1))) { - # snp.pos$lap[snp.pos$block.id == blockAF1$block[b]] <- blockAF1$aRF[b] - # } return(snpPos) } @@ -1426,19 +1383,6 @@ tableBlockAF <- function(snpPos) { listBlocks <- unique(snpPos$block.id) - # resBlock <- data.frame(block = listBlocks, - # aRF = rep(-1, length(listBlocks)), - # aFraction = rep(-1, length(listBlocks)), - # lR = rep(-1, length(listBlocks)), - # nPhase = rep(-1, length(listBlocks)), - # sumAlleleLow = rep(-1, length(listBlocks)), - # sumAlleleHigh = rep(-1, length(listBlocks)), - # lH = rep(-1, length(listBlocks)), - # lM = rep(-1, length(listBlocks)), - # lRhomo = rep(1, length(listBlocks))) - - ## FOR_LOOP modification to be validated by Pascal - ## Remove commented code and this text after validation resBlock <- data.frame(block=listBlocks) @@ -1552,79 +1496,6 @@ tableBlockAF <- function(snpPos) { return(resBlock) }, snpPos=snpPos) resBlock <- do.call(rbind, resBlock) - # for (i in seq_len(length(listBlocks))) { - # # start with LOH - # - # lH <- 1 - # lM <- 1 - # # if at least 1 homozygote variants and no more than 1 hetrozygote - # # to check for LOH - # if (resBlock[i, "nbKeep"] > 0 & - # (resBlock[i, "nbKeep"] == resBlock[i, "nbHomo"] | - # (resBlock[i, "nbHomo"] > 0 & resBlock[i, "nbHetero"] == 1)) ) { - # - # # Check if 1 hetero with allelic fraction (<=0.05) - # # it is considered as all homozygote - # flag <- TRUE - # if (resBlock[i, "nbHetero"] == 1) { - # tmp <- min(snp.pos[snp.pos$block.id == resBlock$block[i] & - # snp.pos$hetero, c("cnt.ref" , "cnt.alt")])/ - # sum(snp.pos[snp.pos$block.id == resBlock$block[i] & - # snp.pos$hetero, c("cnt.ref" , "cnt.alt")]) - # # flag is true if allelic fraction <= 0.05 - # flag <- ifelse(tmp > 0.05, FALSE,TRUE) - # } - # - # if(flag){ - # # List homozygote ref - # listRef <- which(snp.pos$block.id == resBlock$block[i] & - # snp.pos$homo & - # snp.pos$cnt.ref > snp.pos$cnt.alt) - # # list homozygote alt - # listAlt <- which(snp.pos$block.id == resBlock$block[i] & - # snp.pos$homo & - # snp.pos$cnt.ref < snp.pos$cnt.alt) - # # freq of the Ref allele in population of listRef - # tmp <- snp.pos$freq[listRef] - # # min freq is 0.01 - # tmp[which(tmp < 0.01)] <- 0.01 - # # log10 of the product of the frequency of the alternative allele in pop for listRef - # lH <- ifelse(length(listRef) > 0, sum(log10(1-tmp)*2), 0) - # # freq of the Ref allele in population of listAlt - # tmp <- snp.pos$freq[listAlt] - # tmp[which(tmp < 0.01)] <- 0.01 - # # log10 of the product of the frequency of the alternative allele in pop for listRef - # # plus log10 of the product of the frequency of the reference allele in pop for listAlt - # lH <- lH + ifelse(length(listAlt) > 0, sum(log10(tmp)*2), 0) - # - # lM <- sum(log10(apply(snp.pos[which(snp.pos$block.id == - # resBlock$block[i] & snp.pos$homo), - # "freq", drop=FALSE], 1, - # FUN = function(x) { - # return(max(x^2, 2*(x * (1-x)), (1-x)^2)) - # }))) - # resBlock$sumAlleleLow[i] <- 0 - # resBlock$sumAlleleHigh[i] <- sum(snp.pos[listRef, "cnt.ref"]) + - # sum(snp.pos[listAlt, "cnt.alt"]) - # } - # } - # # compute the score of the homozygote on the block - # # if heterozygote present lH = lM = 1 and lRhomo = 0 - # resBlock[i, c("lH", "lM", "lRhomo")] <- c(lH, lM, lH - lM) - # - # # get hetero and compute AF nbHetero > 1 - # if (resBlock[i, "nbKeep"] > 0 & resBlock[i, "nbHetero"] > 1) { - # - # resML <- calcAFMLRNA(snp.pos[which(snp.pos$block.id == - # resBlock$block[i] & snp.pos$hetero),]) - # - # resBlock$aFraction[i] <- resML$aFraction - # resBlock$lR[i] <- resML$lR - # resBlock$nPhase[i] <- resML$nPhase - # resBlock$sumAlleleLow[i] <- resML$sumAlleleLow - # resBlock$sumAlleleHigh[i] <- resML$sumAlleleHigh - # } - # } return(resBlock) } From f13ac605edf8061739ae6424df5d1f1e782f9ae0 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 21:35:04 -0400 Subject: [PATCH 121/385] Add example to pruning1KGbyChr() function --- R/process1KG.R | 2 +- R/process1KG_internal.R | 4 ++-- man/addBlockFromPlink2GDS.Rd | 2 +- man/pruning1KGbyChr.Rd | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index f9376edf7..d4789d53e 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -797,7 +797,7 @@ basePCASample <- function(gds, listSample.Ref=NULL, listSNP=NULL, np=1L) { #' SNVs related to a specific block from the Population Reference GDS file. It #' uses this information and the information from the block files associated #' to a specific super-population to generate the final block information. -#' The block information is then saved in a Population ReferenceG DS Annotation +#' The block information is then saved in a Population Reference GDS Annotation #' file. #' #' @param gds an object of class diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index bd7978abd..0247e87ef 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -69,12 +69,12 @@ #' #' ## Run only if directory in writing mode #' if (file.access(getwd()) == 0 && -#' !file.exists(file.path(getwd(), outPrefix, ".rds"))) { +#' !file.exists(file.path(getwd(), paste0(outPrefix, ".rds")))) { #' #' ## Create a RDS file with the pruned SNVs #' RAIDS:::pruning1KGbyChr(gdsReference=gds1KG, outPrefix=outPrefix) #' -#' prunedSNVs <- readRDS(file.path(getwd(), outPrefix, ".rds")) +#' prunedSNVs <- readRDS(file.path(getwd(), paste0(outPrefix, ".rds"))) #' prunedSNVs #' } #' diff --git a/man/addBlockFromPlink2GDS.Rd b/man/addBlockFromPlink2GDS.Rd index b3d7b0d0f..c8826d8af 100644 --- a/man/addBlockFromPlink2GDS.Rd +++ b/man/addBlockFromPlink2GDS.Rd @@ -45,7 +45,7 @@ This function extracts the information for all SNVs related to a specific block from the Population Reference GDS file. It uses this information and the information from the block files associated to a specific super-population to generate the final block information. -The block information is then saved in a Population ReferenceG DS Annotation +The block information is then saved in a Population Reference GDS Annotation file. } \details{ diff --git a/man/pruning1KGbyChr.Rd b/man/pruning1KGbyChr.Rd index 1748359fe..0f48c71a3 100644 --- a/man/pruning1KGbyChr.Rd +++ b/man/pruning1KGbyChr.Rd @@ -91,12 +91,12 @@ outPrefix <- "Pruned_Demo_Reference" ## Run only if directory in writing mode if (file.access(getwd()) == 0 && - !file.exists(file.path(getwd(), outPrefix, ".rds"))) { + !file.exists(file.path(getwd(), paste0(outPrefix, ".rds")))) { ## Create a RDS file with the pruned SNVs RAIDS:::pruning1KGbyChr(gdsReference=gds1KG, outPrefix=outPrefix) - prunedSNVs <- readRDS(file.path(getwd(), outPrefix, ".rds")) + prunedSNVs <- readRDS(file.path(getwd(), paste0(outPrefix, ".rds"))) prunedSNVs } From fd18ee04c223a271a368182b13173b481ccaf1ae Mon Sep 17 00:00:00 2001 From: belleau Date: Thu, 17 Aug 2023 22:08:53 -0400 Subject: [PATCH 122/385] Update estimateAllelicFraction, computeAllelicFractionDNA, and computeAllelicFractionRNA examples --- R/allelicFraction_internal.R | 56 ++++++++++++++++++++++++++++++-- man/computeAllelicFractionDNA.Rd | 3 ++ man/computeAllelicFractionRNA.Rd | 53 ++++++++++++++++++++++++++++-- 3 files changed, 106 insertions(+), 6 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index b7c5ea483..d1914921c 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -673,6 +673,9 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { #' #' @examples #' +#' ## Required library for GDS +#' library(SNPRelate) +#' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") @@ -856,10 +859,57 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' #' @examples #' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") +#' ## Required library for GDS +#' library(SNPRelate) +#' +#' #' ## Path to the demo 1KG GDS file is located in this package +#' dataDir <- system.file("extdata/tests", package="RAIDS") +#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +#' fileAnnotGDS <- file.path(dataDir, "ex1_good_small_1KG_Annot_GDS.gds") +#' +#' ## Temporary Profile GDS file for one profile +#' fileProfile <- file.path(getwd(), "ex1.gds") +#' +#' ## Example can only be run if the current directory is in writing mode +#' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { +#' +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' fileProfile) +#' +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileGDS) +#' gdsRefAnnot <- openfn.gds(fileAnnotGDS) +#' ## Open Profile GDS file for one profile +#' profileGDS <- openfn.gds(fileProfile) #' -#' ## TODO +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, +#' 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, +#' 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, +#' 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) +#' +#' ## The function returns a data frame containing the allelic fraction info +#' result <- RAIDS:::computeAllelicFractionRNA(gdsReference=gds1KG, +#' gdsSample=profileGDS, gdsRefAnnot=gdsRefAnnot, +#' currentProfile="ex1", studyID="MYDATA", +#' blockID="GeneS.Ensembl.Hsapiens.v86", +#' chrInfo=chrInfo, minCov=10L, +#' minProb=0.999, eProb=0.001, cutOffLOH=-5, +#' cutOffAR=3, verbose=FALSE) +#' head(result) +#' +#' ## Close both GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) +#' closefn.gds(gdsRefAnnot) +#' +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn ls.gdsn diff --git a/man/computeAllelicFractionDNA.Rd b/man/computeAllelicFractionDNA.Rd index fd683cc5b..6cb4048e3 100644 --- a/man/computeAllelicFractionDNA.Rd +++ b/man/computeAllelicFractionDNA.Rd @@ -95,6 +95,9 @@ allelic fraction for the pruned SNV dataset specific to a DNA-seq profile } \examples{ +## Required library for GDS +library(SNPRelate) + ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") diff --git a/man/computeAllelicFractionRNA.Rd b/man/computeAllelicFractionRNA.Rd index dccc72b08..5d2b55e16 100644 --- a/man/computeAllelicFractionRNA.Rd +++ b/man/computeAllelicFractionRNA.Rd @@ -76,10 +76,57 @@ allelic fraction for the pruned SNV dataset specific to a RNA-seq sample. } \examples{ -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", package="RAIDS") +## Required library for GDS +library(SNPRelate) -## TODO +#' ## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata/tests", package="RAIDS") +fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +fileAnnotGDS <- file.path(dataDir, "ex1_good_small_1KG_Annot_GDS.gds") + +## Temporary Profile GDS file for one profile +fileProfile <- file.path(getwd(), "ex1.gds") + +## Example can only be run if the current directory is in writing mode +if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { + + ## Copy the Profile GDS file demo that has been pruned and annotated + file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), + fileProfile) + + ## Open the reference GDS file (demo version) + gds1KG <- snpgdsOpen(fileGDS) + gdsRefAnnot <- openfn.gds(fileAnnotGDS) + ## Open Profile GDS file for one profile + profileGDS <- openfn.gds(fileProfile) + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, + 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, + 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, + 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, + 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) + + ## The function returns a data frame containing the allelic fraction info + result <- RAIDS:::computeAllelicFractionRNA(gdsReference=gds1KG, + gdsSample=profileGDS, gdsRefAnnot=gdsRefAnnot, + currentProfile="ex1", studyID="MYDATA", + blockID="GeneS.Ensembl.Hsapiens.v86", + chrInfo=chrInfo, minCov=10L, + minProb=0.999, eProb=0.001, cutOffLOH=-5, + cutOffAR=3, verbose=FALSE) + head(result) + + ## Close both GDS files (important) + closefn.gds(profileGDS) + closefn.gds(gds1KG) + closefn.gds(gdsRefAnnot) + + ## Remove Profile GDS file (created for demo purpose) + unlink(fileProfile, force=TRUE) + +} } \author{ From 3227da28936034c285c2e2a575776a7987bbcd8a Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 22:24:40 -0400 Subject: [PATCH 123/385] Update doc for processBlockChr() function --- R/tools_internal.R | 13 ++++++++----- man/processBlockChr.Rd | 10 +++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/R/tools_internal.R b/R/tools_internal.R index 3a13787d2..b1fd4f940 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -179,11 +179,15 @@ validatePositiveIntegerVector <- function(value, name) { -#' @title TODO +#' @title Extract the block information from the block file associated to a +#' specific population and chromosome #' -#' @description TODO +#' @description The function reads the information form the specified block +#' file associated to a specified population and a specified chromosome. The +#' the block information for a list of SNV positions is formatted and returned. #' -#' @param snpKeep TODO +#' @param snpKeep a \code{vector} of \code{integer} representing the +#' positions of the retained SNVs for the current chromosome. #' #' @param pathBlock a \code{character} string representing the path to the #' block files. @@ -193,7 +197,6 @@ validatePositiveIntegerVector <- function(value, name) { #' #' @param chr a \code{integer} representing the current chromosome. #' -#' #' @return the a \code{array} with the sample from pedDF keept #' #' @examples @@ -202,6 +205,7 @@ validatePositiveIntegerVector <- function(value, name) { #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn +#' @importFrom utils read.delim #' @encoding UTF-8 #' @keywords internal processBlockChr <- function(snpKeep, pathBlock, superPop, chr) { @@ -227,7 +231,6 @@ processBlockChr <- function(snpKeep, pathBlock, superPop, chr) { if(activeBlock == 1){ if(snpKeep[i] - curStart >= 10000) { blockState <- blockState - 1 - curStart <- snpKeep[i] } } else{ diff --git a/man/processBlockChr.Rd b/man/processBlockChr.Rd index c1ad4adb8..f6525c2aa 100644 --- a/man/processBlockChr.Rd +++ b/man/processBlockChr.Rd @@ -3,12 +3,14 @@ \encoding{UTF-8} \name{processBlockChr} \alias{processBlockChr} -\title{TODO} +\title{Extract the block information from the block file associated to a +specific population and chromosome} \usage{ processBlockChr(snpKeep, pathBlock, superPop, chr) } \arguments{ -\item{snpKeep}{TODO} +\item{snpKeep}{a \code{vector} of \code{integer} representing the +positions of the retained SNVs for the current chromosome.} \item{pathBlock}{a \code{character} string representing the path to the block files.} @@ -22,7 +24,9 @@ continental population (ex: EUR, AFR, etc.).} the a \code{array} with the sample from pedDF keept } \description{ -TODO +The function reads the information form the specified block +file associated to a specified population and a specified chromosome. The +the block information for a list of SNV positions is formatted and returned. } \examples{ From a59fffa5fffa769a8cc36947d0d5040cd08888dc Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 22:41:16 -0400 Subject: [PATCH 124/385] Update doc for estimateAllelicFraction() doc --- R/allelicFraction.R | 3 ++- man/estimateAllelicFraction.Rd | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index 41ae0285b..301b5fc65 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -29,7 +29,8 @@ #' @param minCov a single positive \code{integer} representing the minimum #' required coverage. Default: \code{10L}. #' -#' @param minProb a single \code{numeric} between 0 and 1 representing TODO. +#' @param minProb a single \code{numeric} between 0 and 1 representing the +#' probability that the calculated genotype call is correct. TOREVIEW #' Default: \code{0.999}. #' #' @param eProb a single \code{numeric} between 0 and 1 representing the diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index 8bf9207b6..b5727e654 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -49,7 +49,8 @@ way the estimation of the allelic fraction is done. Default: \code{"DNA"}.} \item{minCov}{a single positive \code{integer} representing the minimum required coverage. Default: \code{10L}.} -\item{minProb}{a single \code{numeric} between 0 and 1 representing TODO. +\item{minProb}{a single \code{numeric} between 0 and 1 representing the +probability that the calculated genotype call is correct. TOREVIEW Default: \code{0.999}.} \item{eProb}{a single \code{numeric} between 0 and 1 representing the From 6a14c0cd8d1aa629338cf85d1d11d785103d58bd Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 22:54:56 -0400 Subject: [PATCH 125/385] Update main vignette to introduce wrapper function for RNA --- vignettes/RAIDS.Rmd | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 5cf9365d4..b0fddce09 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -166,24 +166,28 @@ hg38 [@Lowy-Gallego2019a]. This section can be skipped if you choose to use the pre-processed files. +

+## Step 2 - Ancestry Inference -## Step 2 - Wrapper function to run ancestry inference on DNA data in one command - -The final step can be run with a wrapper function -that encapsulates multiple steps of the workflow. +A wrapper function encapsulates multiple steps of the workflow. ```{r graphWrapper, echo=FALSE, fig.align="center", fig.cap="Final step - The wrapper function encapsulates multiple steps of the workflow.", out.width='120%', results='asis', warning=FALSE, message=FALSE} knitr::include_graphics("MainSteps_Wrapper_v04.png") ``` - -In summary, the wrapper function generates the synthetic dataset and uses it -to selected the optimal parameters before calling the genetic ancestry on -the current profiles. + +In summary, the wrapper function generates the synthetic dataset and uses +it to selected the optimal parameters before calling the genetic ancestry +on the current profiles. + +According to the type of input data (RNA or DNA), a specific wrapper function +is available.
+### DNA Data - Wrapper function to run ancestry inference on DNA data + The wrapper function, called _runExomeAncestry()_, requires 4 files as input: - The **population reference GDS file** @@ -389,6 +393,15 @@ also created.
+ +### RNA data - Wrapper function to run ancestry inference on RNA data + + +TODO + +
+
+ # Pre-processed reference files are available for 1000 Genomes (1KG) in hg38 Pre-processed files, such as the 1KG GDS file, are available at this address: From 78a095580f40f73f0e2b1bdbbc084a2189f4e4f1 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 23:26:26 -0400 Subject: [PATCH 126/385] validateRunExomeAncestry() is now validateRunExomeOrRNAAncestry() --- R/processStudy.R | 4 +- R/processStudy_internal.R | 107 ++++++++---------- man/computePCARefRMMulti.Rd | 3 + man/runProfileAncestry.Rd | 6 +- man/runWrapperAncestry.Rd | 8 +- ...ry.Rd => validateRunExomeOrRNAAncestry.Rd} | 6 +- tests/testthat/test-processStudy_internal.R | 9 +- 7 files changed, 67 insertions(+), 76 deletions(-) rename man/{validateRunExomeAncestry.Rd => validateRunExomeOrRNAAncestry.Rd} (97%) diff --git a/R/processStudy.R b/R/processStudy.R index 64472d5ff..20d5e64f4 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2520,7 +2520,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, verbose=FALSE) { ## Validate parameters - validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, + validateRunExomeOrRNAAncestry(pedStudy=pedStudy, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, fileReferenceGDS=fileReferenceGDS, fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, @@ -2742,7 +2742,7 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, blockTypeID, verbose=FALSE) { ## Validate parameters - validateRunExomeAncestry(pedStudy=pedStudy, studyDF=studyDF, + validateRunExomeOrRNAAncestry(pedStudy=pedStudy, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, fileReferenceGDS=fileReferenceGDS, fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 042f3dc91..e0e0c35b7 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -1155,7 +1155,7 @@ validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, currentProfil #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @encoding UTF-8 #' @keywords internal -validateRunExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, +validateRunExomeOrRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, genoSource, verbose) { @@ -1793,6 +1793,9 @@ validateComputeKNNRefSample <- function(listEigenvector, listCatPop, spRef, #' #' @examples #' +#' ## Required library +#' library(SNPRelate) +#' #' ## Path to the demo Profile GDS file is located in this package #' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' @@ -2039,8 +2042,8 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, return(res) } -#' @title TOREVIEW Run most steps leading to the ancestry inference call on a specific -#' profile +#' @title TOREVIEW Run most steps leading to the ancestry inference call on a +#' specific profile #' #' @description This function runs most steps leading to the ancestry inference #' call on a specific profile. First, the function creates the Profile GDS file @@ -2251,25 +2254,21 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' @importFrom utils write.csv #' @importFrom rlang arg_match #' @encoding UTF-8 -#' @keywords @internal -runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfile, pathProfileGDS, - pathOut, chrInfo, syntheticRefDF, studyDFSyn, listProfileRef, - studyType=c("DNA", "RNA"), - np=1L, blockTypeID=NULL, - verbose=FALSE) { - +#' @keywords internal +runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, + currentProfile, pathProfileGDS, pathOut, chrInfo, syntheticRefDF, + studyDFSyn, listProfileRef, studyType=c("DNA", "RNA"), + np=1L, blockTypeID=NULL, verbose=FALSE) { studyType <- arg_match(studyType) pruningSample(gdsReference=gdsReference, currentProfile=currentProfile, - studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS, - np=np) + studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS, np=np) fileGDSProfile <- file.path(pathProfileGDS, paste0(currentProfile, ".gds")) add1KG2SampleGDS(gdsReference=gdsReference, fileProfileGDS=fileGDSProfile, - currentProfile=currentProfile, - studyID=studyDF$study.id) + currentProfile=currentProfile, studyID=studyDF$study.id) addStudy1Kg(gdsReference, fileGDSProfile) @@ -2277,10 +2276,8 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil estimateAllelicFraction(gdsReference=gdsReference, gdsProfile=gdsProfile, currentProfile=currentProfile, studyID=studyDF$study.id, - chrInfo=chrInfo, studyType=studyType, - gdsRefAnnot=gdsRefAnnot, - blockID=blockTypeID, - verbose=verbose) + chrInfo=chrInfo, studyType=studyType, gdsRefAnnot=gdsRefAnnot, + blockID=blockTypeID, verbose=verbose) closefn.gds(gdsProfile) ## Add information related to the synthetic profiles in Profile GDS file @@ -2309,10 +2306,9 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil ## This variable will contain the results from the PCA analyses ## For each row of the sampleRM matrix - apply(t(t(seq_len(nrow(sampleRM)))), 1, FUN=function(x, sampleRM, gdsProfile, - studyDFSyn, spRef, - pathOutProfile, - currentProfile){ + apply(t(t(seq_len(nrow(sampleRM)))), 1, FUN=function(x, sampleRM, + gdsProfile, studyDFSyn, spRef, + pathOutProfile, currentProfile) { synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, sampleRM=sampleRM[x,], studyIDSyn=studyDFSyn$study.id, @@ -2336,16 +2332,16 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil listFiles <- file.path(file.path(pathKNN) , listFilesName) resCall <- computeAncestryFromSyntheticFile(gdsReference=gdsReference, - gdsProfile=gdsProfile, listFiles=listFiles, - currentProfile=currentProfile, spRef=spRef, - studyIDSyn=studyDFSyn$study.id, np=np) + gdsProfile=gdsProfile, listFiles=listFiles, + currentProfile=currentProfile, spRef=spRef, + studyIDSyn=studyDFSyn$study.id, np=np) saveRDS(resCall, file.path(pathOut, paste0(currentProfile, ".infoCall", ".rds"))) write.csv(x=resCall$Ancestry, file=file.path(pathOut, - paste0(currentProfile, ".Ancestry",".csv")), quote=FALSE, - row.names=FALSE) + paste0(currentProfile, ".Ancestry",".csv")), quote=FALSE, + row.names=FALSE) ## Close Profile GDS file (important) closefn.gds(gdsProfile) @@ -2354,13 +2350,13 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil } -#' @title TOREVIEW Run most steps leading to the ancestry inference call on a specific -#' profile +#' @title TOREVIEW Run most steps leading to the ancestry inference call +#' on a specific profile (RNA or DNA) #' #' @description This function runs most steps leading to the ancestry inference #' call on a specific profile. First, the function creates the Profile GDS file #' for the specific profile using the information from a RDS Sample -#' description file and the 1KG reference GDS file. +#' description file and the Population reference GDS file. #' #' @param pedStudy a \code{data.frame} with those mandatory columns: "Name.ID", #' "Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in @@ -2554,24 +2550,21 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, currentProfil #' @importFrom utils write.csv #' @importFrom rlang arg_match #' @encoding UTF-8 -#' @keywords @internal +#' @keywords internal runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, - pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic"), - studyType=c("DNA", "RNA"), - np=1L, blockTypeID=NULL, - verbose=FALSE) { - + pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, genoSource=c("snp-pileup", "generic"), + studyType=c("DNA", "RNA"), np=1L, blockTypeID=NULL, + verbose=FALSE) { genoSource <- arg_match(genoSource) listProfiles <- pedStudy[, "Name.ID"] createStudy2GDS1KG(pathGeno=pathGeno, pedStudy=pedStudy, - fileNameGDS=fileReferenceGDS, listProfiles=listProfiles, - studyDF=studyDF, pathProfileGDS=pathProfileGDS, genoSource=genoSource, - verbose=verbose) + fileNameGDS=fileReferenceGDS, listProfiles=listProfiles, + studyDF=studyDF, pathProfileGDS=pathProfileGDS, genoSource=genoSource, + verbose=verbose) ## Open the 1KG GDS file (demo version) gdsReference <- snpgdsOpen(fileReferenceGDS) @@ -2580,31 +2573,25 @@ runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, listProfileRef <- syntheticRefDF$sample.id studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), - study.desc=paste0(studyDF$study.id, " synthetic data"), - study.platform=studyDF$study.platform, stringsAsFactors=FALSE) + study.desc=paste0(studyDF$study.id, " synthetic data"), + study.platform=studyDF$study.platform, stringsAsFactors=FALSE) - apply(pedStudy[,"Name.ID", drop=FALSE],1,FUN=function(x,gdsReference, gdsRefAnnot, - studyDF,pathProfileGDS, - pathOut, chrInfo, syntheticRefDF, studyDFSyn, - listProfileRef, - studyType, verbose){ + apply(pedStudy[,"Name.ID", drop=FALSE],1,FUN=function(x,gdsReference, + gdsRefAnnot, studyDF,pathProfileGDS, + pathOut, chrInfo, syntheticRefDF, studyDFSyn, + listProfileRef, studyType, verbose) { runProfileAncestry(gdsReference, gdsRefAnnot, studyDF, - currentProfile=x, pathProfileGDS, - pathOut, chrInfo, - syntheticRefDF, studyDFSyn, - listProfileRef, - studyType, - np=np, blockTypeID=blockTypeID, + currentProfile=x, pathProfileGDS, pathOut, chrInfo, + syntheticRefDF, studyDFSyn, listProfileRef, + studyType, np=np, blockTypeID=blockTypeID, verbose) return(NULL) }, gdsReference=gdsReference, gdsRefAnnot=gdsRefAnnot, - studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathOut=pathOut, - chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, - listProfileRef=listProfileRef, - studyDFSyn=studyDFSyn, studyType=studyType, verbose=verbose) - - + studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathOut=pathOut, + chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, + listProfileRef=listProfileRef, + studyDFSyn=studyDFSyn, studyType=studyType, verbose=verbose) ## Close all GDS files closefn.gds(gdsReference) diff --git a/man/computePCARefRMMulti.Rd b/man/computePCARefRMMulti.Rd index f8205f908..26244faab 100644 --- a/man/computePCARefRMMulti.Rd +++ b/man/computePCARefRMMulti.Rd @@ -67,6 +67,9 @@ for a list of pruned SNVs present in a Profile GDS file. The } \examples{ +## Required library +library(SNPRelate) + ## Path to the demo Profile GDS file is located in this package dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") diff --git a/man/runProfileAncestry.Rd b/man/runProfileAncestry.Rd index 728f43dbd..d80cacff1 100644 --- a/man/runProfileAncestry.Rd +++ b/man/runProfileAncestry.Rd @@ -3,8 +3,8 @@ \encoding{UTF-8} \name{runProfileAncestry} \alias{runProfileAncestry} -\title{TOREVIEW Run most steps leading to the ancestry inference call on a specific -profile} +\title{TOREVIEW Run most steps leading to the ancestry inference call on a +specific profile} \usage{ runProfileAncestry( gdsReference, @@ -233,4 +233,4 @@ doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. \author{ Pascal Belleau, Astrid Deschênes and Alexander Krasnitz } -\keyword{@internal} +\keyword{internal} diff --git a/man/runWrapperAncestry.Rd b/man/runWrapperAncestry.Rd index 5cd9c1163..e073de9eb 100644 --- a/man/runWrapperAncestry.Rd +++ b/man/runWrapperAncestry.Rd @@ -3,8 +3,8 @@ \encoding{UTF-8} \name{runWrapperAncestry} \alias{runWrapperAncestry} -\title{TOREVIEW Run most steps leading to the ancestry inference call on a specific -profile} +\title{TOREVIEW Run most steps leading to the ancestry inference call +on a specific profile (RNA or DNA)} \usage{ runWrapperAncestry( pedStudy, @@ -101,7 +101,7 @@ more information about the generated output files. This function runs most steps leading to the ancestry inference call on a specific profile. First, the function creates the Profile GDS file for the specific profile using the information from a RDS Sample -description file and the 1KG reference GDS file. +description file and the Population reference GDS file. } \details{ The runWrapperAncestry() function generates 3 types of files @@ -221,4 +221,4 @@ doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. \author{ Pascal Belleau, Astrid Deschênes and Alexander Krasnitz } -\keyword{@internal} +\keyword{internal} diff --git a/man/validateRunExomeAncestry.Rd b/man/validateRunExomeOrRNAAncestry.Rd similarity index 97% rename from man/validateRunExomeAncestry.Rd rename to man/validateRunExomeOrRNAAncestry.Rd index 34c7bf4b3..efae0125f 100644 --- a/man/validateRunExomeAncestry.Rd +++ b/man/validateRunExomeOrRNAAncestry.Rd @@ -1,11 +1,11 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/processStudy_internal.R \encoding{UTF-8} -\name{validateRunExomeAncestry} -\alias{validateRunExomeAncestry} +\name{validateRunExomeOrRNAAncestry} +\alias{validateRunExomeOrRNAAncestry} \title{Validate the parameters of the runExomeAncestry() function} \usage{ -validateRunExomeAncestry( +validateRunExomeOrRNAAncestry( pedStudy, studyDF, pathProfileGDS, diff --git a/tests/testthat/test-processStudy_internal.R b/tests/testthat/test-processStudy_internal.R index d89c8acd1..53a97d440 100644 --- a/tests/testthat/test-processStudy_internal.R +++ b/tests/testthat/test-processStudy_internal.R @@ -208,13 +208,13 @@ test_that("validateAdd1KG2SampleGDS() must return expected results when all inpu ############################################################################# -### Tests validateRunExomeAncestry() results +### Tests validateRunExomeOrRNAAncestry() results ############################################################################# -context("validateRunExomeAncestry() results") +context("validateRunExomeOrRNAAncestry() results") -test_that("validateRunExomeAncestry() must return expected results when all input are valid", { +test_that("validateRunExomeOrRNAAncestry() must return expected results when all input are valid", { dataDir <- test_path("fixtures") gdsRefFile <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") @@ -237,7 +237,8 @@ test_that("validateRunExomeAncestry() must return expected results when all inpu chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L) - result <- RAIDS:::validateRunExomeAncestry(pedStudy=ped, studyDF=studyInfo, + result <- RAIDS:::validateRunExomeOrRNAAncestry(pedStudy=ped, + studyDF=studyInfo, pathProfileGDS=dataDir, pathGeno=dataDir, pathOut=dataDir, fileReferenceGDS=gdsRefFile, fileReferenceAnnotGDS=gdsRefAnnotFile, chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, From 810e8d8dba70a22b20b211f015f5934c4d02fce9 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 23:33:43 -0400 Subject: [PATCH 127/385] Remove old vignettes --- vignettes/Ancestry_Inference_Step_by_Step.Rmd | 778 ------------------ vignettes/Create_1KG_GDS_File.Rmd | 503 ----------- 2 files changed, 1281 deletions(-) delete mode 100644 vignettes/Ancestry_Inference_Step_by_Step.Rmd delete mode 100644 vignettes/Create_1KG_GDS_File.Rmd diff --git a/vignettes/Ancestry_Inference_Step_by_Step.Rmd b/vignettes/Ancestry_Inference_Step_by_Step.Rmd deleted file mode 100644 index 7920f2bae..000000000 --- a/vignettes/Ancestry_Inference_Step_by_Step.Rmd +++ /dev/null @@ -1,778 +0,0 @@ ---- -title: "Genetic Ancestry Inference Step by Step (optional)" -author: Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -output: - BiocStyle::html_document: - number_sections: no - toc: true - pkgdown: - number_sections: no - as_is: true -urlcolor: darkred -linkcolor: darkred -vignette: > - %\VignetteIndexEntry{Genetic Ancestry Inference Step by Step (optional)} - %\VignettePackage{RAIDS} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r style, echo=FALSE, results='hide', warning=FALSE, message=FALSE} -BiocStyle::markdown() - -suppressPackageStartupMessages({ - library(knitr) - library(RAIDS) -}) - -set.seed(121444) -``` - -
-**Package**: `r Rpackage("RAIDS")`
-**Authors**: `r packageDescription("RAIDS")[["Author"]]`
-**Version**: `r packageDescription("RAIDS")$Version`
-**Compiled date**: `r Sys.Date()`
-**License**: `r packageDescription("RAIDS")[["License"]]`
- -# Introduction - - -This is an overview of genetic ancestry inference from cancer-derived -molecular data: - -```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference process.", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_v03.png") -``` - -The main steps are: - -1. Format reference data from the 1000 Genomes (1KG) (optional) -2. Format cancer-derived data set starting from BAM files -3. Optimize ancestry inference parameters -4. Infer ancestry for the subjects of the external study - -All steps from Step 2, sub-step 4, to Step 4 can be run through a -wrapper (as described in [Main vignette](RAIDS.html). Those steps can also be -run separately; this has the advantage of allowing finer parameter -selection. - -This vignette describes, in details, the process done by the wrapper from -Step 2, sub-step 4, to Step 4. - -
-
- -## Step 1 - Format reference data from the 1000 Genomes (optional) - - -```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from the population reference dataset (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step1_v03.png") -``` - - -The detail execution of this step is presented in -the [Formatting the information from 1000 Genomes (optional)](Create_1KG_GDS_file.html) -vignette. - -In addition, the available pre-processed files are described in -the [Main vignette](RAIDS.html). - - -
- -## Step 2 - Prepare cancer-derived data for ancestry inference - -Molecular profiles in a cancer-derived data set must be formatted -following a series of sub-steps. - -```{r graphStep2, echo=FALSE, fig.align="center", fig.cap="Step 2 - Formatting the information from an external study", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step2_v03.png") -``` - -
- -These are: - -1. Create a directory containing the 3 reference files from 1KG -2. Make a SNP pileup file for the profile -3. Create an RDS file containing information about the samples -4. Create a Profile GDS file (one GDS file per profile) -5. Generate a pruned subset of the single nucleotide variants (SNVs) -6. Estimate the allelic frequency for the pruned SNVs - -The first steps, from Sub-step 1 to Sub-step 3, are described in the -[Main vigette](RAIDS.html). - -### Sub-Step 2.4 Create a Profile GDS file (one GDS file per profile) - -This step requires 3 files as input: - -- The **1KG GDS file** -- The **Profile SNP pileup file** (one per profile present in the study) -- The **Profile PED RDS file** (one file with information for all profiles in the study) - -A *data.frame* containing the general information about the study is -also required. The *data.frame* must contain those 3 columns: - -- **study.id**: The study identifier (example: TCGA-BRCA). -- **study.desc**: The description of the study. -- **study.platform**: The type of sequencing (example: RNA-seq). - -Using all those inputs, the *createStudy2GDS1KG()* function will -generate a **Profile GDS file**. One **Profile GDS file** is created for each -profile passed to the *listProfiles* argument. - -```{r appendStudy2GDS1KG, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -################################################################# -## Load required package -################################################################# -library(RAIDS) - -################################################################# -## The 1KG GDS file location -## Note that the 1KG GDS file used for this example is a -## simplified version and CANNOT be used for any real analysis -################################################################# -dataDir <- system.file("extdata", package="RAIDS") -path1KG <- file.path(dataDir, "example", "gdsRef") - -gds1KG <- file.path(path1KG, "ex1kg.gds") - -################################################################# -## The Profile SNP pileup files (one per profile) need -## to be located in the same directory. -################################################################# -pathGeno <- file.path(dataDir, "example", "snpPileup") - -################################################################# -## The path where the Profile GDS files (one per profile) -## will be created need to be specified. -################################################################# -pathProfileGDS <- file.path(dataDir, "example", "out") - -################################################################# -## The path and file name for the PED RDS file -## will the information about the analyzed samples -################################################################# -filePED <- file.path(dataDir, "example", "pedEx.rds") -ped <- readRDS(filePED) -head(ped) - -################################################################# -## A data frame containing general information about the study -## is also required. The data frame must have -## those 3 columns: "study.id", "study.desc", "study.platform" -################################################################# -studyDF <- data.frame(study.id="MYDATA", - study.desc="Description", - study.platform="PLATFORM", - stringsAsFactors=FALSE) - -################################################################# -## The list of profiles to analyzed is passed to the function. -## The profiles must be present in the Profile PED RDS file see -## sub-step 4 and must have an associated Profile SNP pileup file. -## Not all profiles present in the Profile PED file need to -## be selected. -################################################################# -listSamples <- ped[, "Name.ID"] - -################################################################# -## This function creates one Profile GDS file for each -## profile present in the 'listProfiles' parameter. -################################################################# -createStudy2GDS1KG(pathGeno=pathGeno, - pedStudy=ped, - fileNameGDS=gds1KG, - listProfiles=listSamples, - studyDF=studyDF, - pathProfileGDS=pathProfileGDS, - genoSource="snp-pileup") - -################################################################# -## The Profile GDS file has been created in the -## directory pathProfileGDS using the name of the sample (ex1) -################################################################# -list.files(path=pathProfileGDS) -``` - -
- -A **Profile GDS file** is created for each profile. The GDS file contains those -nodes: - -```{r graphStep24, echo=FALSE, fig.align="left", fig.cap="Step 2.4 - The nodes present in the newly created Profile GDS file (one GDS file per profile).", out.width='100%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("ProfileGDSdemo_when_created.png") -``` - -
- - -### Sub-Step 2.5 Generate a pruned subset of the single nucleotide variants (SNVs) - -The initial list of 1KG SNVs is pruned, using linkage disequilibrium analysis, -and a profile-specific subset of SNVs is retained for each profile. This -information is added to the **Profile GDS file**. - -The __pruningSample()__ function requires the **1KG GDS file** as input. It -also requires the path to the **Profile GDS file(s)**. - -Note that this step can require large disk space. - -```{r pruningProfile, echo=TRUE, eval=TRUE, warning=FALSE, message=FALSE} -############################################################################# -## Load required package -############################################################################# -library(RAIDS) - -############################################################################# -## The 1KG GDS file is required (demo version) -## Note that the 1KG GDS file used for this example is a -## simplified version and CANNOT be used for any real analyses -############################################################################# -path1KG <- file.path(dataDir, "example", "gdsRef") - -fileGDS <- file.path(path1KG, "ex1kg.gds") - -## Open the 1KG GDS file (demo version) -gds1KG <- snpgdsOpen(fileGDS) - -############################################################################# -## The pruning function is called with one profile as input at the time -############################################################################# -for(i in seq_len(length(listSamples))) { - ## Compute the SNV pruned subset - ## studyID: Study identifier as defined in the preceding sub-step. - ## The study identifier must be the same that the one present in - ## Profile GDS file. - ## pathProfileGDS: All Profile GDS files must be in the same directory. - pruningSample(gdsReference=gds1KG, - currentProfile=listSamples[i], - studyID=studyDF$study.id, - pathProfileGDS=pathProfileGDS) - - ## Profile GDS file for the current profile - ## The file name corresponds to the path + profile identifier + ".gds" - fileGDSProfile <- file.path(pathProfileGDS, paste0(listSamples[i], ".gds")) - - ## Add the genotype information for the list of pruned SNVs - ## into the Profile GDS file - ## The genotype information is extracted from the 1KG GDS file - add1KG2SampleGDS(gdsReference=gds1KG, fileProfileGDS=fileGDSProfile, - currentProfile=listSamples[i], - studyID=studyDF$study.id) - - ## Add annotation from the 1KG GDS file to the Profile GDS file - ## This is required. - addStudy1Kg(gdsReference=gds1KG, fileProfileGDS=fileGDSProfile, - verbose=FALSE) -} - -## Close the 1KG GDS file (it is important to always close the GDS files) -closefn.gds(gds1KG) -``` - -
- -The nodes, with the genotype information for the pruned SNVs, are added into -the **Profile GDS file**: - -```{r graphStep25, echo=FALSE, fig.align="left", fig.cap="Step 2.5 - The nodes added to the Profile GDS file are in light blue.", out.width='100%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("ProfileGDSdemo_after_add1KG2SampleGDS.png") -``` - -
- -### Sub-Step 2.6 Estimate the allelic fraction for the pruned SNVs - -The __estimateAllelicFraction()__ estimates the allele fraction for all -SNVs present in the pruned SNV list. Note that the function requires -different inputs for DNA and RNA profiles. - -For the DNA profiles, these 2 files are required: - -1. The **Profile GDS file** -2. The **1KG GDS file** - -For the RNA profiles, these 3 files are required: - -1. The **Profile GDS file** -2. The **1KG GDS file** -3. The **1KG SNV Annotation GDS file** - -In both cases, the other required inputs are: - -1. The information about the length of the chromosomes -2. The profile identifier (it corresponds to the Profile GDS file name) -3. The study identifier (it should correspond to the one used previously) - -The information about the length of the chromosomes must be assigned into a -*vector* object. This is an example on how to retrieve the information. -There are alternative ways to retrieve this information, e.g., - -```{r extractChrLength, echo=TRUE, message=FALSE, warning=FALSE, collapse=TRUE} -################################################################### -## Load required library -################################################################### -library(BSgenome.Hsapiens.UCSC.hg38) -library(GenomeInfoDb) -################################################################### -## The length of each chromosome is required -## Chromosomes X, Y and M need relabeling (see below) -## There are alternative ways to retrieve this information -################################################################### -chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] -``` - -
-
- -The __estimateAllelicFraction()__ function processes one profile at the time, -as shown in this example. - - -```{r estimateAllelicFraction, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -##################################################################### -## Load the required packages -##################################################################### -library(RAIDS) -library(gdsfmt) - -##################################################################### -## The 1KG GDS file is required -## The 1KG SNV Annotation GDS file is only required for RNA profiles -##################################################################### -path1KG <- file.path(dataDir, "example", "gdsRef") - -file1KG <- file.path(path1KG, "ex1kg.gds") -fileAnnot1KG <- file.path(path1KG, "exAnnot1kg.gds") - -## Open the 1KG GDS file -gds <- snpgdsOpen(file1KG) - -##################################################################### -## The information about the length of the chromosomes -##################################################################### -head(chrInfo) - -##################################################################### -## The function must be called for each profile -## This example only uses one profile -##################################################################### -## The first profile is used in the demo -profileName <- listSamples[1] - -##################################################################### -## The Profile GDS file is required -##################################################################### -## The name must correspond to the profile identifier -fileProfile <- file.path(pathProfileGDS, paste0(profileName, ".gds")) - -## Open the Profile GDS file in writing mode -gdsProfile <- openfn.gds(fileProfile, readonly=FALSE) - -################################################################### -## The estimation of the allelic fraction -################################################################### -## Estimate the allele fraction of the pruned SNVs -## The current example is for a DNA sample -## In the case of RNA sample, the function needs different inputs -## such as the 1KG Annotation GDS file and -## the 'blockID' should be as listed in the 1KG Annotation GDS file -## for the gene annotation of the SNVs -estimateAllelicFraction(gdsReference=gds, gdsProfile=gdsProfile, - currentProfile=profileName, - studyID=studyDF$study.id, - chrInfo=chrInfo) - -## Close both GDS files (important) -closefn.gds(gdsProfile) -closefn.gds(gds) -``` - -
- -This step must be executed for each profile present in the study. - -The information is added into the 'lap' and 'segment' nodes: - -```{r graphStep26, echo=FALSE, fig.align="left", fig.cap="Step 2.6 - The information is added into the nodes in light blue.", out.width='100%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("ProfileGDSdemo_after_estimateAllelicFraction.png") -``` - - -
- - -## Step 3 - Optimize the ancestry inference parameters - -At this step, optimization of the parameters is required to maximize the -the ancestry inference accuracy (next step). - -```{r graphStep3, echo=FALSE, fig.align="center", fig.cap="Step 3 - Find the optimized parameters for the ancestry inference", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step3_v03.png") -``` - -Two inference parameters to be optimized: - -- _K_: the number of neighbors used to call the ancestry -- _D_: the number of PCA components retained - -The accuracy is evaluated using a synthetic data set created from merging one -cancer profile with multiple population referecne profiles of known ancestry. Using the -synthetic profiles, a range of _K_ and _D_ values are tested. Through that -process, the _K_ and _D_ values are tuned to maximize accuracy. - -This step consists of two sub-steps: - -1. Generate the synthetic dataset -2. Compute the PCA-KNN ancestry call for each synthetic profile - -
- -### Sub-Step 3.1 Generate the synthetic dataset - -A synthetic profile is generated through the merging of one cancer profile -with one 1KG profile of known ancestry. Multiple 1KG profiles of different -ancestry are required to create a synthetic data set that will be able to -show the specific accuracy for each super-population. All the synthetic -profiles are saved in the **Profile GDS file** corresponding to the -cancer profile used to generate the synthetic dataset. - -In summary, a fixed number of profiles for each super-population are extracted -from the 1KG study. The information is saved into the **Profile GDS file** -associated to the selected cancer profile. A synthetic profile is created for -each combination of one 1KG profile and cancer profile. All synthetic profiles -are then saved into the **Profile GDS file**. - -The three functions _select1KGPop()_, _prepSynthetic()_ and _syntheticGeno()_ -are required to process the synthetic data synthesis step. - -These 3 files are required: - -1. The **Profile GDS file** -2. The **1KG GDS file** -3. The **1KG Annotation GDS file** - - -```{r generateSynthetic, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -#################################################################### -## Load required packages -#################################################################### -library(RAIDS) -library(gdsfmt) - -#################################################################### -## Randomly extract a fixed number of profiles for each -## subcontinental population present in the 1KG GDS file. -## When not enough profiles are available, all profiles are selected. -#################################################################### -gds1KG <- snpgdsOpen(file1KG) - -#################################################################### -## Fix seed to ensure reproducible results -#################################################################### -set.seed(3043) - -#################################################################### -## Select the profiles from 1KG for the synthetic data. -## Here we select 2 profiles from 1KG for each subcontinental-level -## Normally, we use 30 profiles from 1KG for each -## subcontinental-level but it is too big for the example. -## The 1KG GDS file in this example only has 6 profiles for each -## subcontinental-level (for demo purpose only) -#################################################################### -dataRef <- select1KGPop(gds1KG, nbProfiles=2L) - -## Extract the list of selected 1KG sample identifiers -listProfileRef <- dataRef$sample.id - -#################################################################### -## A data.frame with the description of the study for the synthetic -## data is required. -## The column names must be as shown -#################################################################### -syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", - study.desc="MYDATA synthetic data", - study.platform="PLATFORM", - stringsAsFactors=FALSE) - -## The Profile GDS file is needed -fileProfile <- file.path(pathProfileGDS, paste0(profileName, ".gds")) - -#################################################################### -## The prepSynthetic() function prepares the annotation for -## the synthetic data -## The information is saved into the Profile GDS file -#################################################################### -prepSynthetic(fileProfileGDS=fileProfile, - listSampleRef=listProfileRef, - profileID=profileName, - studyDF=syntheticStudyDF, - prefix="1") - -#################################################################### -## Both the 1KG GDS file and the 1KG Annotation GDS file -## are required -#################################################################### -path1KG <- file.path(dataDir, "example", "gdsRef") -fileRefAnnot <- file.path(path1KG, "exAnnot1kg.gds") - -## Open 1KG Annotation GDS file -gdsRefAnnot <- openfn.gds(fileRefAnnot) - -#################################################################### -## The syntheticGeno() function generates the synthetic profiles. -## The synthetic profiles are saved in the Profile GDS file -#################################################################### -resG <- syntheticGeno(gdsReference=gds1KG, - gdsRefAnnot=gdsRefAnnot, - fileProfileGDS=fileProfile, - profileID=profileName, - listSampleRef=listProfileRef, - prefix="1") - -## Close both GDS files -closefn.gds(gds1KG) -closefn.gds(gdsRefAnnot) -``` - -
- - -### Sub-Step 3.2 Perform the PCA-KNN ancestry call for each synthetic profile - -The ancestry is inferred for each synthetic profile. As the ancestry of origin -of the 1KG profile used to generate the synthetic profile is known, the -accuracy of the calls will be assessed for different parameters. - -```{r PCA.KNN.Synthetic, collapse=TRUE, echo=TRUE, eval=TRUE, warning=FALSE, message=FALSE} -##################################################################### -## Load required packages -##################################################################### -library(RAIDS) -library(gdsfmt) - -#################################################################### -## The 1KG GDS file is required -##################################################################### -## Open the 1KG GDS file -gds <- openfn.gds(file1KG) - -##################################################################### -## The path to the directory where the PCA results will be saved -## in RDS files. -## The directory must exist. -##################################################################### -pathOut <- file.path(pathProfileGDS) - -if(! file.exists(pathOut)) { - dir.create(pathOut) -} - -##################################################################### -## Get the super-population information (known ancestry) for the -## reference profiles. This is the ground truth for the 1KG profiles. -##################################################################### -refKnownSuperPop <- getRef1KGPop(gds, "superPop") - -##################################################################### -## Fix the RNG seed as in step 6 to ensure the same results -##################################################################### -set.seed(3043) - -## Select the 1KG samples used to generate the synthetic dataset -## Already done in step 6, no need to repeat if the results have been saved -dataRef <- select1KGPop(gds, nbProfiles=2L) - -##################################################################### -## The function splitSelectByPop() generates a matrix with the -## reference samples split by sub-continental population -##################################################################### -sampleRM <- splitSelectByPop(dataRef) - -## Loop for all cancer samples with associated synthetic data -for(i in seq_len(length(listSamples))) { - - ## The Profile GDS file associated to the cancer profile - fileProfile <- file.path(pathProfileGDS, - paste0(listSamples[i], ".gds")) - - ## A sub-directory is created for the cancer sample - ## Beware that the number of files created will correspond to the - ## number of rows in the sampleRM matrix - pathOutProfile <- file.path(pathOut, listSamples[i]) - if(! file.exists(pathOutProfile)) { - dir.create(pathOutProfile) - } - - ## Open the Profile GDS file - gdsProfile <- snpgdsOpen(fileProfile) - - ## For each row of the sampleRM matrix - for(j in seq_len(nrow(sampleRM))) { - ## Run a PCA analysis using 1 synthetic profile from each - ## sub-continental ancestry - ## The synthetic profiles are projected on the 1KG PCA space - ## (the 1KG reference profiles used to generate the synthetic profiles - ## are removed from this PCA) - ## The K-nearest neighbors analysis is done using - ## a range of K and D values - syntKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, - sampleRM=sampleRM[j,], - studyIDSyn=syntheticStudyDF$study.id, - np=4L, - spRef=refKnownSuperPop, - eigenCount=15L) - - ## Results are saved - saveRDS(syntKNN$matKNN, file.path(pathOutProfile, - paste0("KNN.synt.", listSamples[i], ".", j, ".rds"))) - } - - ## Close Sample GDS file (important) - closefn.gds(gdsProfile) -} - -## Close 1KG GDS file (important) -closefn.gds(gds) -``` - - -
- -## Step 4 - Run the ancestry inference in the input data set - -The ancestry inference is done with the optimized _K_ and _D_ parameters. More -specifically, a PCA is generated using the 1KG reference samples and the -cancer sample. The _D_ parameter specifies the number of dimension for the -PCA. Then, the ancestry of the cancer sample is inferred using -a k-nearest neighbors classification method. The _K_ parameter specifies the -number of neighbors used for the classification. - - -```{r graphStep4, echo=FALSE, fig.align="center", fig.cap="Step 4 - Run the ancestry inference on the external study", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step4_v02.png") -``` - -
- -The PCA of the sample and KNN sample and Call the ancestry with the optimal -_K_ and _D_ parameters. - -Note: The formal selection of _K_ and _D_ parameters is done at this step but -all the synthetic data are prepared in the previous step. - - -```{r PCA.KNN.Sample, warning=FALSE, message=FALSE, collapse=TRUE, echo=TRUE, eval=TRUE} -#################################################################### -## Load required packages -#################################################################### -library(RAIDS) -library(gdsfmt) - -#################################################################### -## The reference 1KG GDS file is required -#################################################################### - -## Open the 1KG GDS file -gdsReference <- openfn.gds(file1KG) - -## A directory where result files are going to be saved, -## where a sub-directory will be set up for each input profile -pathOut <- file.path(pathProfileGDS) - -if(! file.exists(pathOut)) { - dir.create(pathOut) -} - -#################################################################### -## The getRef1KGPop() function extract the known super-population -## of the reference samples. -## We expect the ancestry call from a synthetic profile to -## correspond to the known ancestry of the reference sample used to -## synthesize it. -#################################################################### -refKnownSuperPop <- getRef1KGPop(gdsReference, "superPop") - -## Loop on each profile -## Can also be run in parallel or on different clusters... -for(i in seq_len(length(listSamples))){ - - ## Extract the GDS file name and path for the current profile - fileProfile <- file.path(pathProfileGDS, paste0(listSamples[i], ".gds")) - - ## Directory where the KNN results of the synthetic profiles have been saved - pathKNN <- file.path(pathOut, listSamples[i]) - listFilesName <- dir(file.path(pathKNN), ".rds") - - ## List of the KNN result files from PCA run on synthetic data - listFiles <- file.path(file.path(pathKNN) , listFilesName) - - ## Open the Profile GDS file - gdsProfile <- snpgdsOpen(fileProfile) - - ## Select the optimal K and D parameters from the synthetic data results - ## Use those parameter to infer the ancestry of the specific profile - resCall <- computeAncestryFromSyntheticFile(gdsReference=gdsReference, - gdsProfile=gdsProfile, - listFiles=listFiles, - currentProfile=listSamples[i], - spRef=refKnownSuperPop, - studyIDSyn=syntheticStudyDF$study.id, - np=1L) - - saveRDS(resCall, file.path(pathOut, - paste0(listSamples[i], ".infoCall", ".rds"))) - - write.csv(resCall$Ancestry, - file.path(pathOut, paste0(listSamples[i], ".Ancestry",".csv")), - quote=FALSE, row.names=FALSE) - - ## Close the Profile GDS file (important) - closefn.gds(gdsProfile) -} - -## Close the 1KG GDS file (important) -closefn.gds(gdsReference) - -#################################################################### -## Show the ancestry inference (SuperPop) and -## optimal number of PCA components D -## optimal number of neighbours K -#################################################################### -resAncestry <- read.csv(file.path(pathOut, - paste0(ped$Name.ID[1], ".Ancestry.csv"))) -resAncestry - -## Clean-up demo files -unlink(fileProfile, force=TRUE) -unlink(pathOut, recursive=TRUE, force=TRUE) -``` - - -The *computeAncestryFromSyntheticFile()* function generates 3 types of files -in the *OUTPUT* directory. - -* The ancestry inference CSV file (".Ancestry.csv" file) -* The inference information RDS file (".infoCall.rds" file) -* The parameter information RDS files from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory) - -In addition, a sub-directory (named using the *profile ID*) is -also created. - - -# Session info - -Here is the output of `sessionInfo()` in the environment in which this -document was compiled: - -```{r sessionInfo, echo=FALSE} -sessionInfo() -``` - -
-
- - diff --git a/vignettes/Create_1KG_GDS_File.Rmd b/vignettes/Create_1KG_GDS_File.Rmd deleted file mode 100644 index e2ea8e37d..000000000 --- a/vignettes/Create_1KG_GDS_File.Rmd +++ /dev/null @@ -1,503 +0,0 @@ ---- -title: "Formatting the information from the population reference dataset (optional)" -author: Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -output: - BiocStyle::html_document: - number_sections: yes - toc: true - pkgdown: - number_sections: yes - as_is: true -urlcolor: darkred -linkcolor: darkred -bibliography: aicsBiblio.bibtex -vignette: > - %\VignetteIndexEntry{Formatting the information from the population reference dataset (optional)} - %\VignettePackage{RAIDS} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r style, echo=FALSE, results='hide', warning=FALSE, message=FALSE} -BiocStyle::markdown() - -suppressPackageStartupMessages({ - library(knitr) - library(RAIDS) -}) - -set.seed(121444) -``` - -
-**Package**: `r Rpackage("RAIDS")`
-**Authors**: `r packageDescription("RAIDS")[["Author"]]`
-**Version**: `r packageDescription("RAIDS")$Version`
-**Compiled date**: `r Sys.Date()`
-**License**: `r packageDescription("RAIDS")[["License"]]`
- - -
-
- -# Step 1 - Formatting the information from the population reference dataset (optional) - - -This is an overview of the main steps to infer the genetic ancestry -from cancer-derived molecular data: - -1. Format the information from 1000 Genomes (1KG) into a 1KG GDS file (optional) -2. Format the information from an external study -3. Find the optimized parameters for the ancestry inference -4. Run the ancestry inference on the external study - - -```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from 1000 Genomes (optional)", out.width = '120%', results='asis'} -knitr::include_graphics("MainSteps_Step1_v03.png") -``` - - -****** - -Beware that a pre-processed 1KG -GDS file is available at this address: - - -[https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper/matGeno1000g.gds](https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper/matGeno1000g.gds) - - -The size of the file is 15GB. -This section can be skipped if you choose to use this file. - -****** - - -This section explains in further details how to generate the 1000 Genomes (1KG) -GDS file that is needed to run the ancestry inference tool (step 1). Beware -that it is unnecessary to re-run those steps as the 1KG GDS file is -publicly available. - -More specifically, the formatting of the 1KG information includes all those -sub-steps: - -1. Download the required files from 1KG -2. Split the 1KG genotyping file to one file per sample per chromosome -3. Combine the chromosomes to obtain one genotyping file per sample -4. Create a pedigree file in RDS format -5. Prepare a bulk SNP information file based on 1KG VCF -6. Filter the bulk SNP information file -7. Generate the GDS file with the 1KG information -8. Identify genetically related patients present in 1KG GDS file -9. Add information about unrelated patients to the 1KG GDS file -10. Create a second GDS file containing the 1KG phase information - -Beware that those sub-steps are time, as well as, space consuming. - -In the following sections, those sub-steps are described in details. - -
- -## Download the required files from 1KG - -First, the pedigree file with the description of the 1KG samples -needs to be downloaded from the 1KG ftp site: - -> ftp://ftp.1000genomes.ebi.ac.uk/vol1/ftp/technical/working/20130606_sample_info/20130606_g1k.ped - -The genotyping files for the 1KG samples also needs to be downloaded. Beware -that there is one file per chromosome: - -> ftp.1000genomes.ebi.ac.uk/vol1/ftp/data_collections/1000_genomes_project/release/20181203_biallelic_SNV - -As the genotyping files are split by chromosome, all files corresponding to -this pattern must be downloaded: - -> ALL.chr\*.shapeit2_integrated_v1a.GRCh38.20181129.phased.vcf.gz - -All files are related to GRCh38 genome. - -
-
- -## Split the 1KG genotyping file to one file per sample per chromosome - -To facilitate the manipulation of the genotyping data, the large 1KG -genotyping files are split into smaller files (one per sample). - -As there is one genotyping file per chromosome, the process must be executed -for each of chromosome - -The splitting is done through a bash script: - -```bash -## This in not a R script -## This script is in bash - -## The script has to be run separately for each chromosome - -## Create one directory for the specific chromosome -## -## Two variables need to be assigned -## The variable PATHGENO is the path where the split 1KG genotyping -## files will be located -## The variable chrCur is the current chromosome (ex: "chr1"), a sub-directory -## with the name of the chromosome will be created. The variable must -## include the prefix "chr". -## -## Ex: PATHGENO=./genotypingPerSample -## Ex: chrCur=chr1 -## -mkdir ${PATHGENO}/${chrCur} -cd ${PATHGENO}/${chrCur} - -## The variable FILECUR is the associated 1KG genotyping VCF file for the -## specific chromosome -## The variable FILECUR must also contain the relative or complete path to -## the VCF file -## Ex: FILECUR=../../1KG_files/ALL.chr1.shapeit2_integrated_v1a.GRCh38.20181129.phased.vcf.gz - -## There is 2548 samples in one phase VCF file -## The information associated to each sample is extracted and a VCF file -## specific to each sample for the current chromosome is generated -## -for i in `seq 1 2548` -do - j=$(( $i + 9 )) - SAMPLE=$(zcat $FILECUR||head -n 1000 |grep "#CHROM"|cut -d$'\t' -f$j) - zcat $FILECUR|grep -v "##"|cut -d$'\t' -f$j |bzip2 -c > ${SAMPLE}.${CHR}.vcf.bz2 -done -``` - -
-
- -## Combine the chromosomes to obtain one genotyping file per sample - -The genotyping information for all chromosomes is merged so that there is only -one genotyping file per sample. - - -```{r graphChr1KGSNV, echo = FALSE, fig.align="center", fig.cap="The function groupChr1KGSNV() merge samples that are split by chromosomes into one file.", out.width = '120%', results='asis'} -knitr::include_graphics("groupChr1KGSNV_v01.png") -``` - - -The __groupChr1KGSNV()__ function is used to combine the genotyping information -from multiple files. - -```{r fileGenopart2, echo=TRUE, eval=FALSE} -## Load required package -library(RAIDS) - -## The path where the genotyping files are located -pathGenoChr <- file.path("data", "pathgenochr") - -## The path where the merged genotyping files will be created -PATHOUT <- file.path("data", "pathgenoOUT") - -## Combining the genotyping information for all chromosome in one file per -## profile -groupChr1KGSNV(pathGenoChr=pathGenoChr, pathOut=PATHOUT) - -``` - -
-
- -## Create a predigree file in RDS format - -The function __prepPed1KG()__ is used to create the pedigree file -in RDS format: - -```{r prepPed1KG, eval=FALSE, echo=TRUE} -## Load required package -library(RAIDS) - -## The path to the pedigree file from 1KG -## In this example, the file is in the current directory -filePED1KGOri <- "20130606_g1k.ped" - -## Extract needed information from the pedigree file from 1KG into a data.frame -## Only the samples with genotyping information (sample file present -## in pathGeno parameter) are retained to create the final data.frame -ped <- prepPed1KG(filePed=filePED1KGOri, - pathGeno=file.path("data", "sampleGeno")) - -## Save the pedigree information data.frame as a RDS file -## In this example, the file is saved here ./data/metadata/ped1KG.rds -filePED1KG <- file.path("data", "metadata","ped1KG.rds") -saveRDS(ped, filePED1KG) - -``` - - -
-
- -## Prepare a bulk SNP information file based on 1KG VCF - -Some intermediate file containing the SNP information from 1KG need to be -generated so the information can ultimately be imported in a GDS file -using Bioconductor [gdsfmt](https://bioconductor.org/packages/gdsfmt/). - -The bulk intermediate SNP file contains the SNP position as well as the -frequency in each super population. - -```{r intermediateVCF, echo=TRUE, eval=FALSE} -## This is not done in R -## The python script is in the 'scriptsPy' directory - -for i in `ls PATHVCF/*shapeit2_integrated_v1a.GRCh38.20181129.phased.vcf.gz` -do - chr=$(echo $FILECUR|perl -n -e '/ALL\.(chr[^\.]+)/;print $1') - python PATH2SCRIPT/extract1000gFreq.py ${FILECUR} matFreq.${chr} -done - -for i in `seq 1 22` -do - cat matFreq.chr${i}.txt >matFreqSNV.txt - bzip2 matFreqSNV.txt -done - -``` - -The bulk SNP info file is called __matFreqSNV.txt.bz2__. - -
-
- -## Filter the bulk SNP information file - -The bulk SNP file is filtered to only retain the SNPs with frequency -higher then a specific cut-off (here >=0.01) for at least one super -population. - -The filter SNP file is saved in RDS format (_fileSNPsRDS_ parameter). A -second file containing the index of the retained SNPs is also -created (*fileSNPsRDS* parameter) - -The function __generateMapSnvSel()__ is used to filter the SNP file and -generated the needed RDS files: - -```{r filterVCF, echo=TRUE, eval=FALSE} -## Load required package -library(RAIDS) - -## The path to the bulk SNP info file -fileSNV.v <- file.path(pathGeno, "matFreqSNV.txt.bz2") - -## The paths and names of the two output files -## One file contains the index of retained SNPs ("listSNP.rds") -## One file contains the filter SNP information ("mapSNVSel.rds") -fileSNPsRDS <- file.path(PATHSEL, "listSNP.rds") -fileFREQ.v <- file.path(PATHSEL, "mapSNVSel.rds") - -## Filter the bulk SNP file (fileSNV parameter) -## Create a RDS with filter SNPs (fileFREQ parameter) -## Also creates a RDS with the indexes of the retained SNPs (fileFREQ parameter) -generateMapSnvSel(cutOff=0.01, fileSNV=fileSNV.v, - fileSNPsRDS=fileSNPsRDS, - fileFREQ=fileFREQ.v) -``` - - -
-
- - -## Generate the GDS file with the 1KG information - -The CoreArray Genomic Data Structure (GDS) data files are files suited for -large-scale datasets, especially for data which are much larger than the -available random-access memory. - -The function __generateGDS1KG()__ is used to generate the GDS file that will -contain the information related to 1KG: - -```{r gdsCreation, echo=TRUE, eval=FALSE} -## TODO: what is PATHMETA and PATHSEL - -## The path and file names of the required files -## First, the RDS file containing the pedigree information -## Second, the RDS file with the indexes of the retained SNPs -## Third, the RDS file with the filtered SNP information -filePED1KG <- file.path(PATHMETA,"ped1KG.rds") -fileSNPsRDS <- file.path(PATHSEL, "listSNP.rds") -fileFREQ.v <- file.path(PATHSEL, "mapSNVSel.rds") - -## The name of the GDS file that will be created -fileNameGDS <- "matGeno1000g.gds" -fileGDS <- file.path(PATHGDS, fileNameGDS) - -## Generate GDS file containing the 1KG information -generateGDS1KG(pathGeno=file.path("data", "sampleGeno"), - filePedRDS=filePED1KG, - fileSNVSelected=fileFREQ.v, - fileSNVIndex=fileSNPsRDS, - fileNameGDS=fileGDS) -``` - - -
-
- -## Identify genetically related patients present in 1KG GDS file - -As only unrelated patients can be used in the following analyses, the -genetically related patients in 1KG must be identified. - -The function __identifyRelative()__ identifies patients that are genetically -related in the 1KG files. It generates a RDS file with the unrelated patient -information (_filePart_ parameter) as well as a RDS file with the kinship -coefficient between the patients (_fileIBD_ parameter). - -```{r identifyRelative, echo=TRUE, eval=FALSE} -## Load required package -library(gdsfmt) - -## TODO: what is PATHMETA - -## The name of the GDS file that contains the 1KG information -fileNameGDS <- "matGeno1000g.gds" -fileGDS <- file.path(PATHGDS, fileNameGDS) - -## Files that will be created by the identifyRelative() function -## The first RDS file will contain the kinship information between patients -## The second RDS file will contain the list of unrelated patients -fileIBD <- file.path(PATHMETA,"ibd.All.0.05.rds") -filePart <- file.path(PATHMETA,"part.All.0.05.rds") - -## Open the 1KG GDS file -gds <- snpgdsOpen(fileGDS) - -## Identify the genetically related patients in 1KG -identifyRelative(gds=fileGDS, maf=0.05, thresh = 2^(-11/2), - fileIBD=fileIBD, filePart=filePart) - -## Close the 1KG GDS file -closefn.gds(gds) -``` - -
-
- - -## Add information about unrelated patients to the 1KG GDS file - -Only the unrelated patients from 1KG are used in the following ancestry -inference and kept in the GDS 1KG file. The function __identifyRelative()__ -identifies the unrelated patients and saves the information about those -patients in an intermediate external file. - -The function __addRef2GDS1KG()__ is adding the information about the unrelated -patients to the GDS 1KG file using the intermediate external file. - -```{r addRef2GDS1KG, echo=TRUE, eval=FALSE} -## Add the information about the unrelated 1KG patients to the 1KG GDS file -addRef2GDS1KG(fileGDS=gds, filePart=filePart) -``` - -
-
- -## Create a second GDS containing the 1KG phase information - -We generate a GDS with the phase information. - -The function __generatePhase1KG2GDS()__ is adding the phase information -into the newly created 1KG GDS phase file. - -```{r addPhaseGDS1KG, echo=TRUE, eval=FALSE} -## Load required package -library(gdsfmt) - -## The name of the 1KG GDS file that already exists -fileGDS1KG <- file.path(PATHGDS, "matGeno1000g.gds") - -## The name of the 1KG Phase GDS file that will be created -fileGDSPhase <- file.path(PATHGDS, "matPhase1000g.gds") - -## Open the 1KG GDS file -gds <- openfn.gds(fileGDS1KG) - -## Create the 1KG Phase GDS file -gdsPhase <- createfn.gds(fileGDSPhase) - -## Add the phase information to the 1KG Phase GDSfile -generatePhase1KG2GDS(gds, gdsPhase, pathGeno, fileSNPsRDS) - -## Close both files -closefn.gds(gdsPhase) -closefn.gds(gds) -``` - -
-
- -### Create a VCF file containing the retained SNP positions from 1KG GDS file - -The __snvListVCF()__ function is used to generate a VCF file that contains -the information of all retained SNPs from 1KG GDS file: - -```{r snvListVCF, echo=TRUE, eval=FALSE} -## Load required package -library(RAIDS) - -## Open the 1KG GDS file -gds <- snpgdsOpen(fileGDS1kg) - -## The VCF file that will be created -fileOut <- "SNPretained.VCF" - -## Generate the VCF with the retained SNP position -snvListVCF(gdsReference=gds, fileOut=fileOut, offset=1, freqCutoff=NULL) - -## Close the 1KG GDS file -closefn.gds(gds) -``` - -You should compress and indexing the newly created VCF file. Do do so, -you need to install [HTSlib](http://www.htslib.org/download/) [@Bonfield2021]. - -In a terminal: - -```bash -## This in not a R script -## This script is in bash - -## Compress the new VCF file (fileOut parameter) -bgzip fileOut - -## Index the new VCF file -## HTSlib software is needed -tabix -p vcf fileOut.gz -``` - - -
-
- -# Pre-processed files are available - -Pre-processed files, such as the 1KG GDS file, are available at this address: - - -[https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper](https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper) - -Beware that some of those files are voluminous. - -
-
- -# Session info - -Here is the output of `sessionInfo()` on the system on which this document was -compiled: - -```{r sessionInfo, echo=FALSE} -sessionInfo() -``` - -
-
- From ac18fb7a07c8dadda89acfd22293e46c4535f14c Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 17 Aug 2023 23:34:21 -0400 Subject: [PATCH 128/385] Update example in validateRunExomeOrRNAAncestry() doc --- R/processStudy_internal.R | 2 +- man/validateRunExomeOrRNAAncestry.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index e0e0c35b7..717c81787 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -1146,7 +1146,7 @@ validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, currentProfil #' superPop=c("EUR", "EUR", "EUR", "EUR"), stringsAsFactors=FALSE) #' #' ## Returns OL when all parameters are valid -#' RAIDS:::validateRunExomeAncestry(pedStudy=ped, studyDF=study, +#' RAIDS:::validateRunExomeOrRNAAncestry(pedStudy=ped, studyDF=study, #' pathProfileGDS=dataDir, pathGeno=dataDir, pathOut=pathOut, #' fileReferenceGDS=gds1KG, fileReferenceAnnotGDS=gdsAnnot1KG, #' chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, genoSource="snp-pileup", diff --git a/man/validateRunExomeOrRNAAncestry.Rd b/man/validateRunExomeOrRNAAncestry.Rd index efae0125f..b6e44ba38 100644 --- a/man/validateRunExomeOrRNAAncestry.Rd +++ b/man/validateRunExomeOrRNAAncestry.Rd @@ -116,7 +116,7 @@ syntheticRefDF <- data.frame(sample.id=c("HG00150", "HG00138", "HG00330", superPop=c("EUR", "EUR", "EUR", "EUR"), stringsAsFactors=FALSE) ## Returns OL when all parameters are valid -RAIDS:::validateRunExomeAncestry(pedStudy=ped, studyDF=study, +RAIDS:::validateRunExomeOrRNAAncestry(pedStudy=ped, studyDF=study, pathProfileGDS=dataDir, pathGeno=dataDir, pathOut=pathOut, fileReferenceGDS=gds1KG, fileReferenceAnnotGDS=gdsAnnot1KG, chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, genoSource="snp-pileup", From d55c6b082b933d92a02d20b4dcba246043f4c50c Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 18 Aug 2023 02:11:18 -0400 Subject: [PATCH 129/385] Update link to second vignette --- vignettes/RAIDS.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index b0fddce09..0e8d973e2 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -145,7 +145,7 @@ At this step three important reference files are created: - The population reference SNV Retained VCF file -The format of those files are described the [Population reference dataset GDS files](Create_Reference_GDS_file.html) +The format of those files are described the [Population reference dataset GDS files](Create_Reference_GDS_File.html) vignette. The reference files associated to From 37734cb7a9831b91e250e0da8668586dada8b3a3 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 18 Aug 2023 08:31:51 -0400 Subject: [PATCH 130/385] Removed loop computeAllelicFractionDNA --- R/allelicFraction.R | 2 +- R/allelicFraction_internal.R | 89 ++++++++++++++++++---------------- man/estimateAllelicFraction.Rd | 2 +- 3 files changed, 48 insertions(+), 45 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index 301b5fc65..bc230c4ea 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -30,7 +30,7 @@ #' required coverage. Default: \code{10L}. #' #' @param minProb a single \code{numeric} between 0 and 1 representing the -#' probability that the calculated genotype call is correct. TOREVIEW +#' probability that the calculated genotype call is correct. #' Default: \code{0.999}. #' #' @param eProb a single \code{numeric} between 0 and 1 representing the diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index d1914921c..9e85c4f6e 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -742,63 +742,66 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, snpPos$imbAR <- rep(-1, nrow(snpPos)) - homoBlock <- list() - for(chr in unique(snpPos$snp.chr)) { - - if (verbose) { - message("chr ", chr) - message("Step 1 ", Sys.time()) - } - - listChr <- which(snpPos$snp.chr == chr) - - ## Identify LOH regions - homoBlock[[chr]] <- computeLOHBlocksDNAChr(gdsReference=gdsReference, - chrInfo=chrInfo, snpPos=snpPos[listChr,], chr=chr) + snpPos <- lapply(unique(snpPos$snp.chr), + FUN=function(chr,snpPos){ + if (verbose) { + message("chr ", chr) + message("Step 1 ", Sys.time()) + } + homoBlock <- list() + listChr <- which(snpPos$snp.chr == chr) + ## Identify LOH regions + homoBlock[[chr]] <- computeLOHBlocksDNAChr( + gdsReference=gdsReference, + chrInfo=chrInfo, + snpPos=snpPos[listChr,], + chr=chr) - if (verbose) { message("Step 2 ", Sys.time()) } + if (verbose) { message("Step 2 ", Sys.time()) } - homoBlock[[chr]]$LOH <- as.integer(homoBlock[[chr]]$logLHR <= - cutOffLOH & homoBlock[[chr]]$homoScore <= cutOffHomoScore) + homoBlock[[chr]]$LOH <- as.integer(homoBlock[[chr]]$logLHR <= + cutOffLOH & homoBlock[[chr]]$homoScore <= cutOffHomoScore) - z <- cbind(c(homoBlock[[chr]]$start, homoBlock[[chr]]$end, + z <- cbind(c(homoBlock[[chr]]$start, homoBlock[[chr]]$end, snpPos[listChr, "snp.pos"]), - c(rep(0, 2* nrow(homoBlock[[chr]])), + c(rep(0, 2* nrow(homoBlock[[chr]])), rep(1, length(listChr))), - c(homoBlock[[chr]]$LOH, -1 * homoBlock[[chr]]$LOH, - rep(0, length(listChr)) ), - c(rep(0, 2 * nrow(homoBlock[[chr]])), + c(homoBlock[[chr]]$LOH, -1 * homoBlock[[chr]]$LOH, + rep(0, length(listChr)) ), + c(rep(0, 2 * nrow(homoBlock[[chr]])), seq_len(length(listChr)))) - z <- z[order(z[,1], z[,2]), ] - pos <- z[cumsum(z[,3]) > 0 & z[,4] > 0, 4] - snpPos[listChr[pos], "lap"] <- 0 - snpPos[listChr[pos], "LOH"] <- 1 + z <- z[order(z[,1], z[,2]), ] + pos <- z[cumsum(z[,3]) > 0 & z[,4] > 0, 4] + snpPos[listChr[pos], "lap"] <- 0 + snpPos[listChr[pos], "LOH"] <- 1 - if (verbose) { message("Step 3 ", Sys.time()) } + if (verbose) { message("Step 3 ", Sys.time()) } - ## Identify imbalanced SNVs in specified chromosome - snpPos[listChr, "imbAR"] <- - computeAllelicImbDNAChr(snpPos=snpPos[listChr, ], chr=chr, - wAR=10, cutOffEmptyBox=-3) + ## Identify imbalanced SNVs in specified chromosome + snpPos[listChr, "imbAR"] <- + computeAllelicImbDNAChr(snpPos=snpPos[listChr, ], chr=chr, + wAR=10, cutOffEmptyBox=-3) - if (verbose) { message("Step 4 ", Sys.time()) } + if (verbose) { message("Step 4 ", Sys.time()) } - ## Compute allelic fraction for SNVs in specified chromosome - blockAF <- computeAlleleFraction(snpPos=snpPos[listChr, ], - w=10, cutOff=-3) + ## Compute allelic fraction for SNVs in specified chromosome + blockAF <- computeAlleleFraction(snpPos=snpPos[listChr, ], + w=10, cutOff=-3) - if (verbose) { message("Step 5 ", Sys.time()) } - - if(! is.null(blockAF)) { - for(i in seq_len(nrow(blockAF))) { - snpPos[listChr[blockAF[i, 1]:blockAF[i, 2]], "lap"] <- - blockAF[i, 3] - } - } - } + if (verbose) { message("Step 5 ", Sys.time()) } + if(! is.null(blockAF)) { + for(i in seq_len(nrow(blockAF))) { + snpPos[listChr[blockAF[i, 1]:blockAF[i, 2]], "lap"] <- + blockAF[i, 3] + } + } + return(snpPos[listChr,]) + }, + snpPos=snpPos) + snpPos <- do.call(rbind, snpPos) snpPos[which(snpPos[, "lap"] == -1), "lap"] <- 0.5 return(snpPos) diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index b5727e654..45cc3fb85 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -50,7 +50,7 @@ way the estimation of the allelic fraction is done. Default: \code{"DNA"}.} required coverage. Default: \code{10L}.} \item{minProb}{a single \code{numeric} between 0 and 1 representing the -probability that the calculated genotype call is correct. TOREVIEW +probability that the calculated genotype call is correct. Default: \code{0.999}.} \item{eProb}{a single \code{numeric} between 0 and 1 representing the From 89fed0c34e5e698532d5297706d10c07ed3b3165 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 18 Aug 2023 09:36:32 -0400 Subject: [PATCH 131/385] Removed loop computeLOHBlocksDNAChr --- R/allelicFraction_internal.R | 112 ++++++++++++++++++---------------- man/computeLOHBlocksDNAChr.Rd | 2 +- 2 files changed, 60 insertions(+), 54 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 9e85c4f6e..f6c1f1602 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -298,7 +298,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' @examples #' #' ## Required library for GDS -#' library(gdsfmt) +#' library(SNPRelate) #' #' ## Path to the demo Reference GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") @@ -383,59 +383,65 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, # Include a field for LOH but will be fill elsewhere homoBlock$LOH <- rep(0, nrow(homoBlock)) - for (i in seq_len(nrow(homoBlock))) { - blcCur <- blcSNV[blcSNV$block == i, ] - snvH <- snpPos[blcCur$snv, ] - lH1 <- 0 - lM1 <- 0 - logLHR <- 0 - homoBlock$nbSNV[i] <- nrow(blcCur) - homoBlock$nbPruned[i] <- length(which(snvH$pruned)) - if (length(which(snvH$normal.geno != 3)) > 0) { - listCount <- snvH$cnt.tot[which(snvH$normal.geno == 1)] - homoBlock$nbNorm[i] <- length(listCount) - - lH1 <-sum(log10(apply(snvH[which(snvH$normal.geno == 1), - c("cnt.ref", "cnt.tot"), drop=FALSE], - 1, FUN=function(x){ - return(dbinom(x[1], x[2], 0.5)) - # genoN1 * dbinom(x[1], x[2], 0.5) + genoN - }))) - - lM1 <- sum(log10(apply(snvH[which(snvH$normal.geno == 1), - c("cnt.ref", "cnt.tot"), drop=FALSE], - 1, FUN=function(x){ - return(dbinom((x[2] + x[2]%%2)/2, x[2], 0.5)) - #genoN1 *dbinom((x[2] + x[2]%%2)/2, x[2], 0.5) + genoN - }))) - logLHR <- -100 - - } else if (length(which(snvH$pruned)) > 2) { - afSNV <- listAF[snvH$snp.index[which(snvH$pruned)]] - afSNV <- apply(X=matrix(afSNV, ncol=1), MARGIN=1, - FUN=function(x){max(x, 0.01)}) - snvR <- snvH$cnt.ref[which(snvH$pruned)] > - snvH$cnt.alt[which(snvH$pruned)] - - # Check if it is unlikely the genotype are homo by error - lH1 <- -100 - # Freq of the more likely geno - - tmp <- apply(matrix(afSNV, ncol=1), 1, - FUN=function(x){max(max(x, 1-x)^2, 2* x *(1-x)) }) - # log10 (prod(FreqAllele^2) / prod(freq of more likely genotype)) - # snvR * 1 + (-1)^snvR * afSNV freq of the genotype - # (snvR = 1 homo ref - # and 0 if homo alt) - logLHR <- sum(2 * log10(snvR * 1 + (-1)^snvR * afSNV)) - - sum(log10(tmp)) - } + homoBlock <- lapply(seq_len(nrow(homoBlock)), + FUN=function(i, homoBlock, blcSNV, + listAF,snpPos){ + blcCur <- blcSNV[blcSNV$block == i, ] + snvH <- snpPos[blcCur$snv, ] + lH1 <- 0 + lM1 <- 0 + logLHR <- 0 + homoBlock$nbSNV[i] <- nrow(blcCur) + homoBlock$nbPruned[i] <- length(which(snvH$pruned)) + if (length(which(snvH$normal.geno != 3)) > 0) { + listCount <- snvH$cnt.tot[which(snvH$normal.geno == 1)] + homoBlock$nbNorm[i] <- length(listCount) + + lH1 <-sum(log10(apply(snvH[which(snvH$normal.geno == 1), + c("cnt.ref", "cnt.tot"), drop=FALSE], + 1, FUN=function(x){ + return(dbinom(x[1], x[2], 0.5)) + # genoN1 * dbinom(x[1], x[2], 0.5) + genoN + }))) + + lM1 <- sum(log10(apply(snvH[which(snvH$normal.geno == 1), + c("cnt.ref", "cnt.tot"), drop=FALSE], + 1, FUN=function(x){ + return(dbinom((x[2] + x[2]%%2)/2, x[2], 0.5)) + #genoN1 *dbinom((x[2] + x[2]%%2)/2, x[2], 0.5) + genoN + }))) + logLHR <- -100 + + } else if (length(which(snvH$pruned)) > 2) { + afSNV <- listAF[snvH$snp.index[which(snvH$pruned)]] + afSNV <- apply(X=matrix(afSNV, ncol=1), MARGIN=1, + FUN=function(x){max(x, 0.01)}) + snvR <- snvH$cnt.ref[which(snvH$pruned)] > + snvH$cnt.alt[which(snvH$pruned)] + + # Check if it is unlikely the genotype are homo by error + lH1 <- -100 + # Freq of the more likely geno + + tmp <- apply(matrix(afSNV, ncol=1), 1, + FUN=function(x){max(max(x, 1-x)^2, 2* x *(1-x)) }) + # log10 (prod(FreqAllele^2) / prod(freq of more likely genotype)) + # snvR * 1 + (-1)^snvR * afSNV freq of the genotype + # (snvR = 1 homo ref + # and 0 if homo alt) + logLHR <- sum(2 * log10(snvR * 1 + (-1)^snvR * afSNV)) - + sum(log10(tmp)) + } - homoBlock$logLHR[i] <- max(logLHR, -100) - homoBlock$LH1[i] <- lH1 - homoBlock$LM1[i] <- lM1 - homoBlock$homoScore[i] <- lH1 - lM1 - } # end for each block + homoBlock$logLHR[i] <- max(logLHR, -100) + homoBlock$LH1[i] <- lH1 + homoBlock$LM1[i] <- lM1 + homoBlock$homoScore[i] <- lH1 - lM1 + return(homoBlock[i,]) + }, homoBlock=homoBlock, + blcSNV=blcSNV, listAF=listAF, + snpPos=snpPos) + homoBlock = do.call(rbind,homoBlock) return(homoBlock) } diff --git a/man/computeLOHBlocksDNAChr.Rd b/man/computeLOHBlocksDNAChr.Rd index c76eef2af..9025dc885 100644 --- a/man/computeLOHBlocksDNAChr.Rd +++ b/man/computeLOHBlocksDNAChr.Rd @@ -78,7 +78,7 @@ chromosome using the homozygote SNVs present on the chromosome. \examples{ ## Required library for GDS -library(gdsfmt) +library(SNPRelate) ## Path to the demo Reference GDS file is located in this package dataDir <- system.file("extdata/tests", package="RAIDS") From ee7bd7bac0fec3e68eaa6a800665f1e04cc67457 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 18 Aug 2023 16:04:01 -0400 Subject: [PATCH 132/385] Removed loop in computeAlleleFraction and manual page for allelicFraction --- R/allelicFraction_internal.R | 325 ++++++++++++++++++++++--------- man/computeAlleleFraction.Rd | 8 +- man/computeAllelicFractionRNA.Rd | 35 +++- man/tableBlockAF.Rd | 9 +- 4 files changed, 272 insertions(+), 105 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index f6c1f1602..3c6ab7ef1 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -446,12 +446,14 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, return(homoBlock) } -#' @title TODO +#' @title TOREVIEW For each imbalance segments compute the allelic fraction #' -#' @description TODO +#' @description TOREVIEW Compute the allelic fraction for each segment different +#' than 0.5. The allelic fraction of the segment can be decomposed in +#' sub-segments. #' #' @param snpPos a \code{data.frame} containing the genotype information for -#' a SNV dataset. TODO +#' a SNV dataset. #' #' @param w a single positive \code{numeric} representing the size of the #' window to compute the allelic fraction. @@ -499,7 +501,7 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { listBlockAR <- list() - j <- 1 + tmp <- as.integer(snpPos$imbAR == 1) z <- cbind(c(tmp[1], tmp[-1] - tmp[seq_len(length(tmp) -1)]), c(tmp[-1] - tmp[seq_len(length(tmp) -1)], tmp[length(tmp)] * -1)) @@ -511,96 +513,192 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { segImb <- data.frame(start=seq_len(nrow(snpPos))[which(z[,1] > 0)], end=seq_len(nrow(snpPos))[which(z[,2] < 0)]) - for(i in seq_len(nrow(segImb))) { - # index of the segment - listSeg <- (segImb$start[i]):(segImb$end[i]) - # index hetero segment - listHetero <- listSeg[snpPos[listSeg,"hetero"] == TRUE] - # SNP hetero for the segment - snp.hetero <- snpPos[listHetero,] - - if(nrow(snp.hetero) >= 2 * w) { - lapCur <- median(apply(snp.hetero[seq_len(w), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[seq_len(w),c("cnt.ref", "cnt.alt")]))) - - start <- 1 - k <- w + 1 - while(k < nrow(snp.hetero)) { - # We have (k+w-1) <= nrow(snp.hetero) - # Case 1 true because (nrow(snp.hetero) >= 2 * w - # Other case nrow(snp.hetero) >= w+k - 1 - curWin <- testAlleleFractionChange(snp.hetero[k:(k+w-1), - c("cnt.ref", "cnt.alt")], cutOff, lapCur) - - if(curWin$pCut1 == 1){ # new Region the allelicFraction - # table of the index of the block with lapCur - listBlockAR[[j]] <- c(listHetero[start], - listHetero[k], lapCur) - - lapCur <- median(apply(snp.hetero[k:(k+w-1), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[k:(k+w-1), - c("cnt.ref", "cnt.alt")]))) - - start <- k - - if(nrow(snp.hetero) - start < w) { # Close the segment - lapCur <- - median(apply(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")]))) - - listBlockAR[[j]] <- c(listHetero[start], - segImb$end[i], lapCur) - - j <- j+1 - k <- nrow(snp.hetero) - }else{ # nrow(snp.hetero) >= w+k - k<- k + 1 - j <- j + 1 - - } - }else{ # keep the same region - if((nrow(snp.hetero) - k ) < w){ # close - lapCur <- - median(apply(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")]))) - - listBlockAR[[j]] <- c(listHetero[start], - segImb$end[i], lapCur) - - j <- j + 1 - - k <- nrow(snp.hetero) - } else{ # continue nrow(snp.hetero) >= w+k - lapCur <- median(apply(snp.hetero[start:k, - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[start:k,c("cnt.ref", - "cnt.alt")]))) - - k <- k + 1 - } - } - }# End while - }else { - lapCur <- median(apply(snp.hetero[, c("cnt.ref", "cnt.alt")], - 1, min) / (rowSums(snp.hetero[,c("cnt.ref", - "cnt.alt")]))) - - listBlockAR[[j]] <- c(segImb$start[i], segImb$end[i], lapCur) - - j <- j + 1 - } - } + # FORLOOP TOREVIEW Pascal + # after remove the comment code + listBlockAR <- lapply(seq_len(nrow(segImb)), + FUN=function(i, segImb, snpPos, w, + cutOff){ + listBlockAR <- list() + j<-1 + listSeg <- (segImb$start[i]):(segImb$end[i]) + # index hetero segment + listHetero <- listSeg[snpPos[listSeg,"hetero"] == TRUE] + # SNP hetero for the segment + snp.hetero <- snpPos[listHetero,] + + if(nrow(snp.hetero) >= 2 * w) { + lapCur <- median(apply(snp.hetero[seq_len(w), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[seq_len(w),c("cnt.ref", "cnt.alt")]))) + + start <- 1 + k <- w + 1 + while(k < nrow(snp.hetero)) { + # We have (k+w-1) <= nrow(snp.hetero) + # Case 1 true because (nrow(snp.hetero) >= 2 * w + # Other case nrow(snp.hetero) >= w+k - 1 + curWin <- testAlleleFractionChange(snp.hetero[k:(k+w-1), + c("cnt.ref", "cnt.alt")], cutOff, lapCur) + + if(curWin$pCut1 == 1){ # new Region the allelicFraction + # table of the index of the block with lapCur + listBlockAR[[j]] <- c(listHetero[start], + listHetero[k], lapCur) + + lapCur <- median(apply(snp.hetero[k:(k+w-1), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[k:(k+w-1), + c("cnt.ref", "cnt.alt")]))) + + start <- k + + if(nrow(snp.hetero) - start < w) { # Close the segment + lapCur <- + median(apply(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")]))) + + listBlockAR[[j]] <- c(listHetero[start], + segImb$end[i], lapCur) + + j <- j+1 + k <- nrow(snp.hetero) + }else{ # nrow(snp.hetero) >= w+k + k<- k + 1 + j <- j + 1 + + } + }else{ # keep the same region + if((nrow(snp.hetero) - k ) < w){ # close + lapCur <- + median(apply(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")]))) + + listBlockAR[[j]] <- c(listHetero[start], + segImb$end[i], lapCur) + + j <- j + 1 + + k <- nrow(snp.hetero) + } else{ # continue nrow(snp.hetero) >= w+k + lapCur <- median(apply(snp.hetero[start:k, + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[start:k,c("cnt.ref", + "cnt.alt")]))) + + k <- k + 1 + } + } + }# End while + }else { + lapCur <- median(apply(snp.hetero[, c("cnt.ref", "cnt.alt")], + 1, min) / (rowSums(snp.hetero[,c("cnt.ref", + "cnt.alt")]))) + + listBlockAR[[j]] <- c(segImb$start[i], segImb$end[i], lapCur) + + j <- j + 1 + } + listBlockAR <- do.call(rbind, listBlockAR) + return(listBlockAR) + }, + segImb=segImb, snpPos=snpPos, + w=w, cutOff=cutOff) + listBlockAR <- do.call(rbind, listBlockAR) + # j <- 1 + # for(i in seq_len(nrow(segImb))) { + # # index of the segment + # listSeg <- (segImb$start[i]):(segImb$end[i]) + # # index hetero segment + # listHetero <- listSeg[snpPos[listSeg,"hetero"] == TRUE] + # # SNP hetero for the segment + # snp.hetero <- snpPos[listHetero,] + # + # if(nrow(snp.hetero) >= 2 * w) { + # lapCur <- median(apply(snp.hetero[seq_len(w), + # c("cnt.ref", "cnt.alt")], 1, min) / + # (rowSums(snp.hetero[seq_len(w),c("cnt.ref", "cnt.alt")]))) + # + # start <- 1 + # k <- w + 1 + # while(k < nrow(snp.hetero)) { + # # We have (k+w-1) <= nrow(snp.hetero) + # # Case 1 true because (nrow(snp.hetero) >= 2 * w + # # Other case nrow(snp.hetero) >= w+k - 1 + # curWin <- testAlleleFractionChange(snp.hetero[k:(k+w-1), + # c("cnt.ref", "cnt.alt")], cutOff, lapCur) + # + # if(curWin$pCut1 == 1){ # new Region the allelicFraction + # # table of the index of the block with lapCur + # listBlockAR[[j]] <- c(listHetero[start], + # listHetero[k], lapCur) + # + # lapCur <- median(apply(snp.hetero[k:(k+w-1), + # c("cnt.ref", "cnt.alt")], 1, min) / + # (rowSums(snp.hetero[k:(k+w-1), + # c("cnt.ref", "cnt.alt")]))) + # + # start <- k + # + # if(nrow(snp.hetero) - start < w) { # Close the segment + # lapCur <- + # median(apply(snp.hetero[start:nrow(snp.hetero), + # c("cnt.ref", "cnt.alt")], 1, min) / + # (rowSums(snp.hetero[start:nrow(snp.hetero), + # c("cnt.ref", "cnt.alt")]))) + # + # listBlockAR[[j]] <- c(listHetero[start], + # segImb$end[i], lapCur) + # + # j <- j+1 + # k <- nrow(snp.hetero) + # }else{ # nrow(snp.hetero) >= w+k + # k<- k + 1 + # j <- j + 1 + # + # } + # }else{ # keep the same region + # if((nrow(snp.hetero) - k ) < w){ # close + # lapCur <- + # median(apply(snp.hetero[start:nrow(snp.hetero), + # c("cnt.ref", "cnt.alt")], 1, min) / + # (rowSums(snp.hetero[start:nrow(snp.hetero), + # c("cnt.ref", "cnt.alt")]))) + # + # listBlockAR[[j]] <- c(listHetero[start], + # segImb$end[i], lapCur) + # + # j <- j + 1 + # + # k <- nrow(snp.hetero) + # } else{ # continue nrow(snp.hetero) >= w+k + # lapCur <- median(apply(snp.hetero[start:k, + # c("cnt.ref", "cnt.alt")], 1, min) / + # (rowSums(snp.hetero[start:k,c("cnt.ref", + # "cnt.alt")]))) + # + # k <- k + 1 + # } + # } + # }# End while + # }else { + # lapCur <- median(apply(snp.hetero[, c("cnt.ref", "cnt.alt")], + # 1, min) / (rowSums(snp.hetero[,c("cnt.ref", + # "cnt.alt")]))) + # + # listBlockAR[[j]] <- c(segImb$start[i], segImb$end[i], lapCur) + # + # j <- j + 1 + # } + # } } # note NULL if length(listBlockAR) == 0 listBlockAR <- do.call(rbind, listBlockAR) - + # print(all.equal(listBlockAR, listBlockAR1)) return(listBlockAR) } @@ -852,7 +950,7 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' @param eProb a single \code{numeric} between 0 and 1 representing the #' probability of sequencing error. Default: \code{0.001}. #' -#' @param cutOffLOH a single log of the score to be LOH TODO. +#' @param cutOffLOH a single \code{numeric} log of the score to be LOH. #' Default: \code{-5}. #' #' @param cutOffAR a single \code{numeric} representing the cutoff, in @@ -863,8 +961,37 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' @param verbose a \code{logicial} indicating if the function should print #' message when running. #' -#' @return a \code{data.frame} with lap for the pruned SNV dataset with -#' coverage > \code{minCov}. TODO +#' @return a \code{data.frame} containing the allelic information for the +#' pruned SNV dataset with coverage > \code{minCov}. The \code{data.frame} +#' contains those columns: +#' \itemize{ +#' \item{cnt.tot} {a \code{integer} representing the total allele count} +#' \item{cnt.ref} {a \code{integer} representing the reference allele count} +#' \item{cnt.alt} {a \code{integer} representing the alternative allele count} +#' \item{snp.pos} {a \code{integer} representing the position on the chromosome} +#' \item{snp.chr} {a \code{integer} representing the chromosome} +#' \item{normal.geno} {a \code{integer} representing the genotype +#' (0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown)} +#' \item{pruned} {a \code{logical} indicating if the SNV is retained after +#' pruning} +#' \item{snp.index} {a \code{integer} representing the index position of the +#' SNV in the Reference GDS file that contains all SNVs} +#' \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} +#' \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} +#' \item{homo} {a \code{logical} indicating if the SNV is homozygote} +#' \item{block.id} {TOREVIEW a \code{integer} indicating the block.id in gdsRefAnnot the +#' vairant is in} +#' \item{phase} {TOREVIEW a \code{integer} indicating the phase of the vairant +#' if known, 3 if not known} +#' \item{lap} {a \code{numeric} indicating lower allelic fraction} +#' \item{LOH} {a \code{integer} indicating if the SNV is in an LOH region +#' (0=not LOH, 1=in LOH)} +#' \item{imbAR} {a \code{integer} indicating if the SNV is in an imbalanced +#' region (-1=not classified as imbalanced or LOH, 0=in LOH; 1=tested +#' positive for imbalance in at least 1 window)} +#' \item{freq} {a \code{numeric} indicating the frequency of the variant +#' in the the reference} +#' } #' #' @examples #' @@ -1344,6 +1471,9 @@ calcAFMLRNA <- function(snpPosHetero) { listPhase <- which(snpPosHetero$phase < 2) m <- data.frame(aL=rep(0, nrow(snpPosHetero)), aH=rep(0, nrow(snpPosHetero))) + # For the vairants phase + # sum the coverage for each haplotype + # if (length(listPhase) > 0) { mPhase <- data.frame(a1=rep(0, length(listPhase)), a2=rep(0, length(listPhase))) @@ -1389,11 +1519,13 @@ calcAFMLRNA <- function(snpPosHetero) { } -#' @title TOREVIEW Compile the information about the allelic fraction +#' @title TOREVIEW Compile the information about the variants #' for each bloc. #' #' @description TOREVIEW For each block, the function evaluates a score -#' about lost of heterizygocity and allelic fration. +#' about lost of heterizygocity and allelic fration. It generates some +#' information about the variants in the block like number of homozigte or +#' heterozygote. #' In the case of RNA-seq the blocks are genes. #' #' @param snpPos For a specific chromosome a \code{data.frame} with lap for @@ -1414,7 +1546,8 @@ calcAFMLRNA <- function(snpPosHetero) { #' the alternative allele.} #' \item{nPhase} {a single \code{integer} representin the number of SNV #' phases.} -#' \item{sumAlleleLow} {a single \code{integer} TODO.} +#' \item{sumAlleleLow} {a single \code{integer} sum of the allele with +#' the minimum coverage.} #' \item{sumAlleleHigh} {a single \code{integer} TODO.} #' \item{lH} {a single \code{numeric} for the homozygotes log10 of the product #' frequencies of the allele not found in the profile (not a probability).} diff --git a/man/computeAlleleFraction.Rd b/man/computeAlleleFraction.Rd index 85d633264..b77a894a2 100644 --- a/man/computeAlleleFraction.Rd +++ b/man/computeAlleleFraction.Rd @@ -3,13 +3,13 @@ \encoding{UTF-8} \name{computeAlleleFraction} \alias{computeAlleleFraction} -\title{TODO} +\title{TOREVIEW For each imbalance segments compute the allelic fraction} \usage{ computeAlleleFraction(snpPos, w = 10, cutOff = -3) } \arguments{ \item{snpPos}{a \code{data.frame} containing the genotype information for -a SNV dataset. TODO} +a SNV dataset.} \item{w}{a single positive \code{numeric} representing the size of the window to compute the allelic fraction. @@ -30,7 +30,9 @@ returned when none of the SNVs tested positive for the imbalance. } \description{ -TODO +TOREVIEW Compute the allelic fraction for each segment different +than 0.5. The allelic fraction of the segment can be decomposed in +sub-segments. } \examples{ diff --git a/man/computeAllelicFractionRNA.Rd b/man/computeAllelicFractionRNA.Rd index 5d2b55e16..62951a4e1 100644 --- a/man/computeAllelicFractionRNA.Rd +++ b/man/computeAllelicFractionRNA.Rd @@ -55,7 +55,7 @@ Default: \code{0.999}.} \item{eProb}{a single \code{numeric} between 0 and 1 representing the probability of sequencing error. Default: \code{0.001}.} -\item{cutOffLOH}{a single log of the score to be LOH TODO. +\item{cutOffLOH}{a single \code{numeric} log of the score to be LOH. Default: \code{-5}.} \item{cutOffAR}{a single \code{numeric} representing the cutoff, in @@ -67,8 +67,37 @@ Default: \code{3}.} message when running.} } \value{ -a \code{data.frame} with lap for the pruned SNV dataset with -coverage > \code{minCov}. TODO +a \code{data.frame} containing the allelic information for the +pruned SNV dataset with coverage > \code{minCov}. The \code{data.frame} +contains those columns: +\itemize{ +\item{cnt.tot} {a \code{integer} representing the total allele count} +\item{cnt.ref} {a \code{integer} representing the reference allele count} +\item{cnt.alt} {a \code{integer} representing the alternative allele count} +\item{snp.pos} {a \code{integer} representing the position on the chromosome} +\item{snp.chr} {a \code{integer} representing the chromosome} +\item{normal.geno} {a \code{integer} representing the genotype +(0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown)} +\item{pruned} {a \code{logical} indicating if the SNV is retained after +pruning} +\item{snp.index} {a \code{integer} representing the index position of the +SNV in the Reference GDS file that contains all SNVs} +\item{keep} {a \code{logical} indicating if the genotype exists for the SNV} +\item{hetero} {a \code{logical} indicating if the SNV is heterozygote} +\item{homo} {a \code{logical} indicating if the SNV is homozygote} +\item{block.id} {TOREVIEW a \code{integer} indicating the block.id in gdsRefAnnot the +vairant is in} +\item{phase} {TOREVIEW a \code{integer} indicating the phase of the vairant +if known, 3 if not known} +\item{lap} {a \code{numeric} indicating lower allelic fraction} +\item{LOH} {a \code{integer} indicating if the SNV is in an LOH region +(0=not LOH, 1=in LOH)} +\item{imbAR} {a \code{integer} indicating if the SNV is in an imbalanced +region (-1=not classified as imbalanced or LOH, 0=in LOH; 1=tested +positive for imbalance in at least 1 window)} +\item{freq} {a \code{numeric} indicating the frequency of the variant +in the the reference} +} } \description{ The function creates a \code{data.frame} containing the diff --git a/man/tableBlockAF.Rd b/man/tableBlockAF.Rd index dc276040d..f75cb8a0e 100644 --- a/man/tableBlockAF.Rd +++ b/man/tableBlockAF.Rd @@ -3,7 +3,7 @@ \encoding{UTF-8} \name{tableBlockAF} \alias{tableBlockAF} -\title{TOREVIEW Compile the information about the allelic fraction +\title{TOREVIEW Compile the information about the variants for each bloc.} \usage{ tableBlockAF(snpPos) @@ -28,7 +28,8 @@ fraction in absence of LOH.} the alternative allele.} \item{nPhase} {a single \code{integer} representin the number of SNV phases.} -\item{sumAlleleLow} {a single \code{integer} TODO.} +\item{sumAlleleLow} {a single \code{integer} sum of the allele with +the minimum coverage.} \item{sumAlleleHigh} {a single \code{integer} TODO.} \item{lH} {a single \code{numeric} for the homozygotes log10 of the product frequencies of the allele not found in the profile (not a probability).} @@ -45,7 +46,9 @@ heterozygote SNVs per block.} } \description{ TOREVIEW For each block, the function evaluates a score -about lost of heterizygocity and allelic fration. +about lost of heterizygocity and allelic fration. It generates some +information about the variants in the block like number of homozigte or +heterozygote. In the case of RNA-seq the blocks are genes. } \examples{ From 690f3d4e8f4076e7e3542d9a931b770f26404f29 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 18 Aug 2023 16:21:43 -0400 Subject: [PATCH 133/385] Corrected computeAlleleFraction --- R/allelicFraction_internal.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 3c6ab7ef1..7cbf81cca 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -607,7 +607,7 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { }, segImb=segImb, snpPos=snpPos, w=w, cutOff=cutOff) - listBlockAR <- do.call(rbind, listBlockAR) + # listBlockAR <- do.call(rbind, listBlockAR) # j <- 1 # for(i in seq_len(nrow(segImb))) { # # index of the segment From 6dff87bf234e149ccc4cf218ad7e4f462a8dbadb Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 18 Aug 2023 17:34:12 -0400 Subject: [PATCH 134/385] Update RAIDS-package information --- R/RAIDS.R | 28 ++++++++-------------------- man/RAIDS-package.Rd | 44 ++++++++++++++++---------------------------- 2 files changed, 24 insertions(+), 48 deletions(-) diff --git a/R/RAIDS.R b/R/RAIDS.R index b7741e1c3..8a83324e0 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -39,26 +39,10 @@ #' #' @seealso #' \itemize{ -#' \item \code{\link{prepPed1KG}} {This function extracts the -#' needed information from the 1000 Genomes pedigree file and formats it -#' into a \code{data.frame} so in can be used in following steps -#' of the ancestry inference process.} -#' \item \code{\link{generateMapSnvSel}} {The function applies a cut-off -#' filter to the SNP information file to retain only the SNP that have a -#' frequency superior or equal to the specified cut-off in at least one -#' super population.} -#' \item \code{\link{generateGDS1KG}} {This function generates the GDS -#' file that will contain the information from 1KG. } -#' \item \code{\link{identifyRelative}} {The function identify patients -#' that are genetically related in the 1KG GDS file. } -#' \item \code{\link{addRef2GDS1KG}} { This function adds the information -#' about the unrelated patients to the 1KG GDS file. } -#' \item \code{\link{add1KG2SampleGDS}} { This function adds the genotype -#' information for the list of pruned SNVs into the Profile GDS file } -#' \item \code{\link{appendStudy2GDS1KG}} { This function creates the -#' Sample GDS file(s) for one or multiple specific samples -#' using the information from a Sample RDS description file and the 1KG -#' GDS file. } +#' \item \code{\link{runExomeAncestry}} {This function runs most steps +#' leading to the ancestry inference call on a specific exome profile.} +#' \item \code{\link{runExomeAncestry}} {This function runs most steps +#' leading to the ancestry inference call on a specific RNA profile.} #' \item \code{\link{estimateAllelicFraction}} { This function estimates #' the allelic fraction of the pruned SNVs for a specific sample and add #' the information to the associated GDS Sample file. The allelic fraction @@ -66,6 +50,10 @@ #' \item \code{\link{computeSyntheticROC}} { This function calculate the #' AUROC of the inferences for specific values of D and K using the #' inferred ancestry results from the synthetic profiles.} +#' \item \code{\link{generateMapSnvSel}} {The function applies a cut-off +#' filter to the SNV information file to retain only the SNV that have a +#' frequency superior or equal to the specified cut-off in at least one +#' super population.} #' } #' #' @return RAIDS diff --git a/man/RAIDS-package.Rd b/man/RAIDS-package.Rd index 78fdd67a8..30509c2dd 100644 --- a/man/RAIDS-package.Rd +++ b/man/RAIDS-package.Rd @@ -36,33 +36,21 @@ https://doi.org/10.1158/0008-5472.CAN-22-0682 } \seealso{ \itemize{ - \item \code{\link{prepPed1KG}} {This function extracts the - needed information from the 1000 Genomes pedigree file and formats it - into a \code{data.frame} so in can be used in following steps - of the ancestry inference process.} - \item \code{\link{generateMapSnvSel}} {The function applies a cut-off - filter to the SNP information file to retain only the SNP that have a - frequency superior or equal to the specified cut-off in at least one - super population.} - \item \code{\link{generateGDS1KG}} {This function generates the GDS - file that will contain the information from 1KG. } - \item \code{\link{identifyRelative}} {The function identify patients - that are genetically related in the 1KG GDS file. } - \item \code{\link{addRef2GDS1KG}} { This function adds the information - about the unrelated patients to the 1KG GDS file. } - \item \code{\link{add1KG2SampleGDS}} { This function adds the genotype - information for the list of pruned SNVs into the Profile GDS file } - \item \code{\link{appendStudy2GDS1KG}} { This function creates the - Sample GDS file(s) for one or multiple specific samples - using the information from a Sample RDS description file and the 1KG - GDS file. } - \item \code{\link{estimateAllelicFraction}} { This function estimates - the allelic fraction of the pruned SNVs for a specific sample and add - the information to the associated GDS Sample file. The allelic fraction - estimation method is adapted to the type of study (DNA or RNA). } - \item \code{\link{computeSyntheticROC}} { This function calculate the - AUROC of the inferences for specific values of D and K using the - inferred ancestry results from the synthetic profiles.} +\item \code{\link{runExomeAncestry}} {This function runs most steps +leading to the ancestry inference call on a specific exome profile.} +\item \code{\link{runExomeAncestry}} {This function runs most steps +leading to the ancestry inference call on a specific RNA profile.} +\item \code{\link{estimateAllelicFraction}} { This function estimates +the allelic fraction of the pruned SNVs for a specific sample and add +the information to the associated GDS Sample file. The allelic fraction +estimation method is adapted to the type of study (DNA or RNA). } +\item \code{\link{computeSyntheticROC}} { This function calculate the +AUROC of the inferences for specific values of D and K using the +inferred ancestry results from the synthetic profiles.} +\item \code{\link{generateMapSnvSel}} {The function applies a cut-off +filter to the SNV information file to retain only the SNV that have a +frequency superior or equal to the specified cut-off in at least one +super population.} } } \author{ @@ -70,6 +58,6 @@ Pascal Belleau, Astrid Deschênes and Alexander Krasnitz Maintainer: -Pascal Belleau +Pascal Belleau \href{mailto:pascal_belleau@hotmail.com}{pascal_belleau@hotmail.com} } \keyword{package} From 45a437d85a23cbf79af2bbafbc5f0e78f02b9605 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 18 Aug 2023 18:41:26 -0400 Subject: [PATCH 135/385] Update vignette about Reference GDS --- vignettes/Create_Reference_GDS_File.Rmd | 58 ++++++++++++++++++++++--- vignettes/aicsBiblio.bibtex | 17 ++++++++ 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 9cfed8f5c..974f7670b 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -45,20 +45,34 @@ set.seed(121444) -This section explains in further details the format of the population reference -GDS files that are needed to run the ancestry inference tool. +This section explains in further details the format of the population +reference files that are required to run the ancestry inference tool. -Three different files are generated from the reference dataset: +Three different files are generated from a reference dataset: -- The population reference GDS File -- The population reference SNV Annotation GDS file -- The population reference SNV Retained VCF file +- The Population Reference GDS File +- The Population Reference SNV Annotation GDS file +- The Population Reference SNV Retained VCF file +The third file is only required for RNA ancestry inference. + +
+
# Population Reference GDS File +The *Population Reference GDS file* should contain the genome-wide SNV +information related to the population data set with known genetic ancestry. +This reference data set will be used to generate the simulated samples. It is +also used to generate the PCA on which the samples of interest are going to +be projected. + +The *Population Reference GDS file* is a GDS object of class +[SNPGDSFileClass](https://www.bioconductor.org/packages/release/bioc/vignettes/SNPRelate/inst/doc/SNPRelate.html#data-formats-used-in-snprelate) +from [SNPRelate](https://www.bioconductor.org/packages/release/bioc/html/SNPRelate.html) +package [@Zheng2012]. -All related samples must be removed. +Beware that only unrelated samples should be present in the GDS file. ```{r runRefGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# @@ -79,6 +93,35 @@ print(gdsRef) closefn.gds(gdsRef) ``` +This output lists all variables stored in the *Population Reference GDS file". +At the first level, it stores variables *sample.id*, *snp.id*, etc. +The additional information displayed in the braces indicate the data type, +size, compressed or not + compression ratio. + +The mandatory fields are: + +* *sample.id*: a unique identifier for each sample. +* *snp.id*: a unique identifier for each SNV. +* *sample.annot*: a *data.frame* where each row correspond to a sample and containing those columns: + * *sex*: a identifier of the sex of the sample + * *pop.Group*: TODO + * *superPop*: a identifier of the super-population ancestry of the sample + * *batch*: a unique number representing the batch of provenance of the sample +* *snp.chromosome*: an integer or character mapping for each chromosome. Integer: numeric values 1-26, mapped in order from 1-22, 23=X, 24=XY (the pseudoautosomal region), 25=Y, 26=M (the mitochondrial probes), and 0 for probes with unknown positions; it does not allow NA. Character: “X”, “XY”, “Y” and “M” can be used here, and a blank string indicating unknown position. +* *snp.position*: the base position of each SNV on the chromosome, and 0 for unknown position; it does not allow NA. +* *snp.allele*: TODO +* *snp.AF*: TODO +* *snp.[Population_ID]_AF*: TODO +* *snp.EUR_AF*: TODO +* *snp.AFR_AF*: TODO +* *snp.AMR_AF*: TODO +* *snp.SAS_AF*: TODO +* *genotype*: a SNV genotypic matrix (i.e., the number of A alleles) in individual-major mode nsnp×nsample +* *sample.ref*: TODO + +
+
+ # Population Reference Annotation GDS file @@ -127,3 +170,4 @@ sessionInfo()

+# References diff --git a/vignettes/aicsBiblio.bibtex b/vignettes/aicsBiblio.bibtex index b421e5961..90f8d9be9 100644 --- a/vignettes/aicsBiblio.bibtex +++ b/vignettes/aicsBiblio.bibtex @@ -87,3 +87,20 @@ year = {2023} } +@article{Zheng2012, + author = {Zheng, Xiuwen and Levine, David and Shen, Jess and Gogarten, Stephanie M. and Laurie, Cathy and Weir, Bruce S.}, + title = "{A high-performance computing toolset for relatedness and principal component analysis of SNP data}", + journal = {Bioinformatics}, + volume = {28}, + number = {24}, + pages = {3326-3328}, + year = {2012}, + month = {10}, + issn = {1367-4803}, + doi = {10.1093/bioinformatics/bts606}, + url = {https://doi.org/10.1093/bioinformatics/bts606}, + eprint = {https://academic.oup.com/bioinformatics/article-pdf/28/24/3326/48879518/bioinformatics\_28\_24\_3326.pdf}, +} + + + From f38c0969ca24d5c1ec6e075cb7e9709b28cd0578 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 18 Aug 2023 19:11:03 -0400 Subject: [PATCH 136/385] Update Reference GDS vignette --- vignettes/Create_Reference_GDS_File.Rmd | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 974f7670b..52d9965fb 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -48,11 +48,10 @@ set.seed(121444) This section explains in further details the format of the population reference files that are required to run the ancestry inference tool. -Three different files are generated from a reference dataset: +Two different files are generated from a reference dataset: - The Population Reference GDS File - The Population Reference SNV Annotation GDS file -- The Population Reference SNV Retained VCF file The third file is only required for RNA ancestry inference. @@ -145,6 +144,10 @@ closefn.gds(gdsRefAnnot) ``` +
+
+ + # Pre-processed files, from 1000 Genomes in hg38, are available Pre-processed files used in the RAIDS associated publication, are From 55df54880f118be9d3145d08162559d5f013113a Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 18 Aug 2023 19:11:24 -0400 Subject: [PATCH 137/385] Update documentation --- DESCRIPTION | 1 + R/gdsWrapper.R | 6 ++--- man/basePCASample.Rd | 4 ++-- man/computeAncestryFromSyntheticFile.Rd | 10 ++++----- man/computeKNNRefSample.Rd | 4 ++-- man/computePoolSyntheticAncestryGr.Rd | 4 ++-- man/computeSyntheticConfMat.Rd | 4 ++-- man/computeSyntheticROC.Rd | 2 +- man/estimateAllelicFraction.Rd | 13 +++++------ man/getRef1KGPop.Rd | 2 +- man/prepSynthetic.Rd | 2 +- man/projectSample2PCA.Rd | 12 +++++----- man/runIBDKING.Rd | 22 +++++++++---------- man/selParaPCAUpQuartile.Rd | 6 ++--- ...alidateComputeAncestryFromSyntheticFile.Rd | 6 ++--- man/validateComputePoolSyntheticAncestryGr.Rd | 4 ++-- man/validateComputeSyntheticRoc.Rd | 2 +- 17 files changed, 52 insertions(+), 52 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 123740630..946b83cc5 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -48,4 +48,5 @@ BugReports: https://github.com/KrasnitzLab/RAIDS/issues URL: https://krasnitzlab.github.io/RAIDS/ biocViews: Genetics, Software, Sequencing, WholeGenome, PrincipalComponent, GeneticVariability, DimensionReduction +Roxygen: list(markdown = TRUE) RoxygenNote: 7.2.3 diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 2bb387910..acb1a8bb1 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -1,7 +1,7 @@ -#' @title Add information related to SNVs into a Reference GDS file +#' @title Add information related to SNVs into a Population Reference GDS file #' -#' @description the function adds the SNV information into a Reference -#' GDS file. +#' @description The function adds the SNV information into a Population +#' Reference GDS file. #' #' @param gdsReference an object of class #' \link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file. diff --git a/man/basePCASample.Rd b/man/basePCASample.Rd index f55b52ddc..ed0c535d2 100644 --- a/man/basePCASample.Rd +++ b/man/basePCASample.Rd @@ -41,8 +41,8 @@ function. } The function runs a Principal Component Analysis (PCA) on the SNv genotype data. The function also loads SNVs into the PCA to calculate the SNV eigenvectors. Those 2 steps are done with the - \code{\link[SNPRelate]{snpgdsPCA}} and - \code{\link[SNPRelate]{snpgdsPCASNPLoading}} +\code{\link[SNPRelate]{snpgdsPCA}} and +\code{\link[SNPRelate]{snpgdsPCASNPLoading}} functions. } \examples{ diff --git a/man/computeAncestryFromSyntheticFile.Rd b/man/computeAncestryFromSyntheticFile.Rd index 6eac914ba..fd68cca55 100644 --- a/man/computeAncestryFromSyntheticFile.Rd +++ b/man/computeAncestryFromSyntheticFile.Rd @@ -34,7 +34,7 @@ file), the opened 1KG GDS file.} \item{listFiles}{a \code{vector} of \code{character} strings representing the name of files that contain the results of ancestry inference done on -the synthetic profiles for multiple values of _D_ and _K_. The files must +the synthetic profiles for multiple values of \emph{D} and \emph{K}. The files must exist.} \item{currentProfile}{a \code{character} string representing the profile @@ -63,13 +63,13 @@ the column that will contain the inferred ancestry for the specified profiles. Default: \code{"SuperPop"}.} \item{kList}{a \code{vector} of \code{integer} representing the list of -values tested for the _K_ parameter. The _K_ parameter represents the +values tested for the \emph{K} parameter. The \emph{K} parameter represents the number of neighbors used in the K-nearest neighbor analysis. If \code{NULL}, the value \code{seq(2,15,1)} is assigned. Default: \code{seq(2,15,1)}.} \item{pcaList}{a \code{vector} of \code{integer} representing the list of -values tested for the _D_ parameter. The _D_ parameter represents the +values tested for the \emph{D} parameter. The \emph{D} parameter represents the number of dimensions used in the PCA analysis. If \code{NULL}, the value \code{seq(2,15,1)} is assigned. Default: \code{seq(2,15,1)}.} @@ -162,12 +162,12 @@ number of dimensions).} number of neighbors).} \item{\code{Call}}{ a \code{character} string representing the super-population.} -\item{\code{L}}{ a \code{numeric} representing the lower value of the 95% +\item{\code{L}}{ a \code{numeric} representing the lower value of the 95\% confidence interval for the AUROC obtained for the fixed values of super-population, \code{D} and \code{K}.} \item{\code{AUR}}{ a \code{numeric} representing the AUROC obtained for the fixed values of super-population, \code{D} and \code{K}.} -\item{\code{H}}{ a \code{numeric} representing the higher value of the 95% +\item{\code{H}}{ a \code{numeric} representing the higher value of the 95\% confidence interval for the AUROC obtained for the fixed values of super-population, \code{D} and \code{K}.} } diff --git a/man/computeKNNRefSample.Rd b/man/computeKNNRefSample.Rd index ec0e79fb0..d4ba1f40a 100644 --- a/man/computeKNNRefSample.Rd +++ b/man/computeKNNRefSample.Rd @@ -34,13 +34,13 @@ the column that will contain the inferred ancestry for the specified profile. Default: \code{"SuperPop"}.} \item{kList}{a \code{vector} of \code{integer} representing the list of -values tested for the _K_ parameter. The _K_ parameter represents the +values tested for the \emph{K} parameter. The \emph{K} parameter represents the number of neighbors used in the K-nearest neighbor analysis. If \code{NULL}, the value \code{seq(2,15,1)} is assigned. Default: \code{seq(2,15,1)}.} \item{pcaList}{a \code{vector} of \code{integer} representing the list of -values tested for the _D_ parameter. The D parameter represents the +values tested for the \emph{D} parameter. The D parameter represents the number of dimensions used in the PCA analysis. If \code{NULL}, the value \code{seq(2, 15, 1)} is assigned. Default: \code{seq(2, 15, 1)}.} diff --git a/man/computePoolSyntheticAncestryGr.Rd b/man/computePoolSyntheticAncestryGr.Rd index fbf43ba93..7d67dfd2b 100644 --- a/man/computePoolSyntheticAncestryGr.Rd +++ b/man/computePoolSyntheticAncestryGr.Rd @@ -56,13 +56,13 @@ the column that will contain the inferred ancestry for the specified dataset. Default: \code{"SuperPop"}.} \item{kList}{a \code{vector} of \code{integer} representing the list of -values tested for the _K_ parameter. The _K_ parameter represents the +values tested for the \emph{K} parameter. The \emph{K} parameter represents the number of neighbors used in the K-nearest neighbor analysis. If \code{NULL}, the value \code{seq(2,15,1)} is assigned. Default: \code{seq(2,15,1)}.} \item{pcaList}{a \code{vector} of \code{integer} representing the list of -values tested for the _D_ parameter. The _D_ parameter represents the +values tested for the \emph{D} parameter. The \emph{D} parameter represents the number of dimensions used in the PCA analysis. If \code{NULL}, the value \code{seq(2,15,1)} is assigned. Default: \code{seq(2,15,1)}.} diff --git a/man/computeSyntheticConfMat.Rd b/man/computeSyntheticConfMat.Rd index c0cad93d7..ca849346e 100644 --- a/man/computeSyntheticConfMat.Rd +++ b/man/computeSyntheticConfMat.Rd @@ -17,7 +17,7 @@ computeSyntheticConfMat( } \arguments{ \item{matKNN}{a \code{data.frame} containing the inferred ancestry results -for fixed values of _D_ and _K_. The \code{data.frame} must contained +for fixed values of \emph{D} and \emph{K}. The \code{data.frame} must contained those columns: "sample.id", "D", "K" and the fourth column name must correspond to the \code{matKNNAncestryColumn} argument.} @@ -49,7 +49,7 @@ associated to the confusion matrix} } \description{ The function calculates the confusion matrix of the inferences -for fixed values of _D_ and _K_ using the inferred ancestry results done +for fixed values of \emph{D} and \emph{K} using the inferred ancestry results done on the synthetic profiles. } \examples{ diff --git a/man/computeSyntheticROC.Rd b/man/computeSyntheticROC.Rd index 8ab8bfe88..c9c3366ed 100644 --- a/man/computeSyntheticROC.Rd +++ b/man/computeSyntheticROC.Rd @@ -17,7 +17,7 @@ computeSyntheticROC( } \arguments{ \item{matKNN}{a \code{data.frame} containing the inferred ancestry results -for fixed values of _D_ and _K_. On of the column names of the +for fixed values of \emph{D} and \emph{K}. On of the column names of the \code{data.frame} must correspond to the \code{matKNNAncestryColumn} argument.} diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index b5727e654..5171d6e6e 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -77,7 +77,7 @@ This parameter is RNA specific. Default: \code{NULL}.} \item{blockID}{a \code{character} string corresponding to the block -identifier in \code{gdsRefAnnot}. **This parameter is RNA specific.** +identifier in \code{gdsRefAnnot}. \strong{This parameter is RNA specific.} Default: \code{NULL}} \item{verbose}{a \code{logicial} indicating if the function should print @@ -93,21 +93,20 @@ Profile GDS file. The allelic fraction estimation method is adapted to the type of study (DNA or RNA). } \details{ -The `chrInfo` parameter contains the length of the chromosomes. The +The \code{chrInfo} parameter contains the length of the chromosomes. The length of the chromosomes can be obtain through the \code{\link[GenomeInfoDb]{seqlengths}} library. As example, for hg38 genome: -``` - +\if{html}{\out{

}}\preformatted{ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && - requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) \{ chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] -} +\} -``` +}\if{html}{\out{
}} } \examples{ diff --git a/man/getRef1KGPop.Rd b/man/getRef1KGPop.Rd index 3ba200dad..c0f082445 100644 --- a/man/getRef1KGPop.Rd +++ b/man/getRef1KGPop.Rd @@ -15,7 +15,7 @@ getRef1KGPop(gdsReference, popName = "superPop") \item{popName}{a \code{character} string representing the name of the column that will be fetched in the \code{data.frame} present in the Reference GDS "sample.ref" node. The column must be present in the \code{data.frame}. - Default: \code{"superPop"}.} +Default: \code{"superPop"}.} } \value{ \code{vector} of \code{character} strings representing the content diff --git a/man/prepSynthetic.Rd b/man/prepSynthetic.Rd index f1623332c..3e879485e 100644 --- a/man/prepSynthetic.Rd +++ b/man/prepSynthetic.Rd @@ -63,7 +63,7 @@ the Profile GDS file "study.annot" node. Both the "Source" and the "Sample.Type" entries are always set to 'Synthetic'. The synthetic profiles are assigned unique names by combining: -[prefix].[data.id.profile].[listSampleRef].[simulation number(1 to nbSim)] +\link{prefix}.\link{data.id.profile}.\link{listSampleRef}.\link{simulation number(1 to nbSim)} } \examples{ diff --git a/man/projectSample2PCA.Rd b/man/projectSample2PCA.Rd index 4d986924f..9a789c72d 100644 --- a/man/projectSample2PCA.Rd +++ b/man/projectSample2PCA.Rd @@ -36,12 +36,12 @@ Default: \code{FALSE}.} \value{ a \code{snpgdsPCAClass} object, a \code{list} that contains: \itemize{ - \item{sample.id} {the sample ids used in the analysis} - \item{snp.id} {the SNP ids used in the analysis} - \item{eigenvalues} {eigenvalues} - \item{eigenvect} {eigenvactors, “# of samples” x “eigen.cnt”} - \item{TraceXTX} {the trace of the genetic covariance matrix} - \item{Bayesian} {whether use bayerisan normalization} +\item{sample.id} {the sample ids used in the analysis} +\item{snp.id} {the SNP ids used in the analysis} +\item{eigenvalues} {eigenvalues} +\item{eigenvect} {eigenvactors, “# of samples” x “eigen.cnt”} +\item{TraceXTX} {the trace of the genetic covariance matrix} +\item{Bayesian} {whether use bayerisan normalization} } } \description{ diff --git a/man/runIBDKING.Rd b/man/runIBDKING.Rd index 4ed5f2610..bc74b36c8 100644 --- a/man/runIBDKING.Rd +++ b/man/runIBDKING.Rd @@ -30,17 +30,17 @@ the process in the \code{\link[SNPRelate]{snpgdsIBDKING}}() function.} \value{ a \code{list} containing: \itemize{ - \item{sample.id}{a \code{character} string representing the sample - ids used in the analysis} - \item{snp.id}{a \code{character} string representing the SNP ids - used in the analysis} - \item{k0}{a \code{numeric}, the IBD coefficient, the probability of - sharing zero IBD} - \item{k1}{a \code{numeric}, the IBD coefficient, the probability of - sharing one IBD} - \item{IBS0}{a \code{numeric}, the proportion of SNPs with zero IBS} - \item{kinship}{a \code{numeric}, the proportion of SNPs with zero IBS, - if the parameter kinship=TRUE} +\item{sample.id}{a \code{character} string representing the sample +ids used in the analysis} +\item{snp.id}{a \code{character} string representing the SNP ids +used in the analysis} +\item{k0}{a \code{numeric}, the IBD coefficient, the probability of +sharing zero IBD} +\item{k1}{a \code{numeric}, the IBD coefficient, the probability of +sharing one IBD} +\item{IBS0}{a \code{numeric}, the proportion of SNPs with zero IBS} +\item{kinship}{a \code{numeric}, the proportion of SNPs with zero IBS, +if the parameter kinship=TRUE} } } \description{ diff --git a/man/selParaPCAUpQuartile.Rd b/man/selParaPCAUpQuartile.Rd index db96ee1c8..a669fbd38 100644 --- a/man/selParaPCAUpQuartile.Rd +++ b/man/selParaPCAUpQuartile.Rd @@ -19,7 +19,7 @@ selParaPCAUpQuartile( } \arguments{ \item{matKNN}{a \code{data.frame} containing the inferred ancestry for the -synthetic profiles for different _K_ and _D_ values. The \code{data.frame} +synthetic profiles for different \emph{K} and \emph{D} values. The \code{data.frame} must contained those columns: "sample.id", "D", "K" and the fourth column name must correspond to the \code{predCall} argument.} @@ -41,12 +41,12 @@ argument.} the list of possible ancestry assignations.} \item{kList}{a \code{vector} of \code{integer} representing the list of -values tested for the _K_ parameter. The _K_ parameter represents the +values tested for the \emph{K} parameter. The \emph{K} parameter represents the number of neighbors used in the K-nearest neighbor analysis. Default: \code{seq(3,15,1)}.} \item{pcaList}{a \code{vector} of \code{integer} representing the list of -values tested for the _D_ parameter. The _D_ parameter represents the +values tested for the \emph{D} parameter. The \emph{D} parameter represents the number of dimensions used in the PCA analysis. Default: \code{seq(2,15,1)}.} } diff --git a/man/validateComputeAncestryFromSyntheticFile.Rd b/man/validateComputeAncestryFromSyntheticFile.Rd index 1478a8738..4b6ae5294 100644 --- a/man/validateComputeAncestryFromSyntheticFile.Rd +++ b/man/validateComputeAncestryFromSyntheticFile.Rd @@ -34,7 +34,7 @@ file), the opened Population Reference GDS file.} \item{listFiles}{a \code{vector} of \code{character} strings representing the name of files that contain the results of ancestry inference done on -the synthetic profiles for multiple values of _D_ and _K_. The files must +the synthetic profiles for multiple values of \emph{D} and \emph{K}. The files must exist.} \item{currentProfile}{a \code{character} string representing the profile @@ -63,11 +63,11 @@ the column that will contain the inferred ancestry for the specified dataset. Default: \code{"SuperPop"}.} \item{kList}{a \code{vector} of \code{integer} representing the list of -values tested for the _K_ parameter. The _K_ parameter represents the +values tested for the \emph{K} parameter. The \emph{K} parameter represents the number of neighbors used in the K-nearest neighbor analysis.} \item{pcaList}{a \code{vector} of \code{integer} representing the list of -values tested for the _D_ parameter. The _D_ parameter represents the +values tested for the \emph{D} parameter. The \emph{D} parameter represents the number of dimensions used in the PCA analysis.} \item{algorithm}{a \code{character} string representing the algorithm used diff --git a/man/validateComputePoolSyntheticAncestryGr.Rd b/man/validateComputePoolSyntheticAncestryGr.Rd index 984236ebf..ac2fe4724 100644 --- a/man/validateComputePoolSyntheticAncestryGr.Rd +++ b/man/validateComputePoolSyntheticAncestryGr.Rd @@ -51,11 +51,11 @@ the column that will contain the inferred ancestry for the specified dataset.} \item{kList}{a \code{vector} of \code{integer} representing the list of -values tested for the _K_ parameter. The _K_ parameter represents the +values tested for the \emph{K} parameter. The \emph{K} parameter represents the number of neighbors used in the K-nearest neighbor analysis.} \item{pcaList}{a \code{vector} of \code{integer} representing the list of -values tested for the _D_ parameter. The _D_ parameter represents the +values tested for the \emph{D} parameter. The \emph{D} parameter represents the number of dimensions used in the PCA analysis.} \item{algorithm}{a \code{character} string representing the algorithm used diff --git a/man/validateComputeSyntheticRoc.Rd b/man/validateComputeSyntheticRoc.Rd index 2a0ca55b3..b2924f4e4 100644 --- a/man/validateComputeSyntheticRoc.Rd +++ b/man/validateComputeSyntheticRoc.Rd @@ -15,7 +15,7 @@ validateComputeSyntheticRoc( } \arguments{ \item{matKNN}{a \code{data.frame} containing the inferred ancestry results -for fixed values of _D_ and _K_. On of the column names of the +for fixed values of \emph{D} and \emph{K}. On of the column names of the \code{data.frame} must correspond to the \code{matKNNAncestryColumn} argument.} From bba1c344365fc4968ca8a1f93d4a9b581d93fb7d Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 18 Aug 2023 20:28:41 -0400 Subject: [PATCH 138/385] Update Reference GDS vignette --- vignettes/Create_Reference_GDS_File.Rmd | 1 - 1 file changed, 1 deletion(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 52d9965fb..cefc68704 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -53,7 +53,6 @@ Two different files are generated from a reference dataset: - The Population Reference GDS File - The Population Reference SNV Annotation GDS file -The third file is only required for RNA ancestry inference.

From 80443f6e454d12cd7572c6824875e9bcfc6543b0 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 18 Aug 2023 20:30:56 -0400 Subject: [PATCH 139/385] Update Reference GDS vignette --- vignettes/Create_Reference_GDS_File.Rmd | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index cefc68704..a6f8bb1e8 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -45,7 +45,7 @@ set.seed(121444) -This section explains in further details the format of the population +This vignette explains, in further details, the format of the population reference files that are required to run the ancestry inference tool. Two different files are generated from a reference dataset: @@ -123,6 +123,9 @@ The mandatory fields are: # Population Reference Annotation GDS file +The *Population Reference Annotation GDS file* should contain TODO + + ```{r runRefAnnotGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# ## Load required packages From 887f1c444466d5be64aa48942ac4bd8273fde9a9 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 18 Aug 2023 20:32:51 -0400 Subject: [PATCH 140/385] Removed loop part 2 computeAlleleFraction --- R/allelicFraction_internal.R | 89 ------------------------------------ 1 file changed, 89 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 7cbf81cca..25150df1b 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -513,8 +513,6 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { segImb <- data.frame(start=seq_len(nrow(snpPos))[which(z[,1] > 0)], end=seq_len(nrow(snpPos))[which(z[,2] < 0)]) - # FORLOOP TOREVIEW Pascal - # after remove the comment code listBlockAR <- lapply(seq_len(nrow(segImb)), FUN=function(i, segImb, snpPos, w, cutOff){ @@ -607,93 +605,6 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { }, segImb=segImb, snpPos=snpPos, w=w, cutOff=cutOff) - # listBlockAR <- do.call(rbind, listBlockAR) - # j <- 1 - # for(i in seq_len(nrow(segImb))) { - # # index of the segment - # listSeg <- (segImb$start[i]):(segImb$end[i]) - # # index hetero segment - # listHetero <- listSeg[snpPos[listSeg,"hetero"] == TRUE] - # # SNP hetero for the segment - # snp.hetero <- snpPos[listHetero,] - # - # if(nrow(snp.hetero) >= 2 * w) { - # lapCur <- median(apply(snp.hetero[seq_len(w), - # c("cnt.ref", "cnt.alt")], 1, min) / - # (rowSums(snp.hetero[seq_len(w),c("cnt.ref", "cnt.alt")]))) - # - # start <- 1 - # k <- w + 1 - # while(k < nrow(snp.hetero)) { - # # We have (k+w-1) <= nrow(snp.hetero) - # # Case 1 true because (nrow(snp.hetero) >= 2 * w - # # Other case nrow(snp.hetero) >= w+k - 1 - # curWin <- testAlleleFractionChange(snp.hetero[k:(k+w-1), - # c("cnt.ref", "cnt.alt")], cutOff, lapCur) - # - # if(curWin$pCut1 == 1){ # new Region the allelicFraction - # # table of the index of the block with lapCur - # listBlockAR[[j]] <- c(listHetero[start], - # listHetero[k], lapCur) - # - # lapCur <- median(apply(snp.hetero[k:(k+w-1), - # c("cnt.ref", "cnt.alt")], 1, min) / - # (rowSums(snp.hetero[k:(k+w-1), - # c("cnt.ref", "cnt.alt")]))) - # - # start <- k - # - # if(nrow(snp.hetero) - start < w) { # Close the segment - # lapCur <- - # median(apply(snp.hetero[start:nrow(snp.hetero), - # c("cnt.ref", "cnt.alt")], 1, min) / - # (rowSums(snp.hetero[start:nrow(snp.hetero), - # c("cnt.ref", "cnt.alt")]))) - # - # listBlockAR[[j]] <- c(listHetero[start], - # segImb$end[i], lapCur) - # - # j <- j+1 - # k <- nrow(snp.hetero) - # }else{ # nrow(snp.hetero) >= w+k - # k<- k + 1 - # j <- j + 1 - # - # } - # }else{ # keep the same region - # if((nrow(snp.hetero) - k ) < w){ # close - # lapCur <- - # median(apply(snp.hetero[start:nrow(snp.hetero), - # c("cnt.ref", "cnt.alt")], 1, min) / - # (rowSums(snp.hetero[start:nrow(snp.hetero), - # c("cnt.ref", "cnt.alt")]))) - # - # listBlockAR[[j]] <- c(listHetero[start], - # segImb$end[i], lapCur) - # - # j <- j + 1 - # - # k <- nrow(snp.hetero) - # } else{ # continue nrow(snp.hetero) >= w+k - # lapCur <- median(apply(snp.hetero[start:k, - # c("cnt.ref", "cnt.alt")], 1, min) / - # (rowSums(snp.hetero[start:k,c("cnt.ref", - # "cnt.alt")]))) - # - # k <- k + 1 - # } - # } - # }# End while - # }else { - # lapCur <- median(apply(snp.hetero[, c("cnt.ref", "cnt.alt")], - # 1, min) / (rowSums(snp.hetero[,c("cnt.ref", - # "cnt.alt")]))) - # - # listBlockAR[[j]] <- c(segImb$start[i], segImb$end[i], lapCur) - # - # j <- j + 1 - # } - # } } # note NULL if length(listBlockAR) == 0 From c29db1edb8b9aad14b89330e9bf2a10fd2922879 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 18 Aug 2023 21:31:27 -0400 Subject: [PATCH 141/385] Update doc for validatePepSynthetic() and validateSyntheticGeno() functions --- R/gdsWrapper.R | 4 +- R/synthetic_internal.R | 4 +- R/tools.R | 25 +++++++-- .../demoGenoChr/chr1/NA12003.chr1.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr1/NA12004.chr1.vcf.bz2 | Bin 0 -> 79 bytes .../demoGenoChr/chr1/NA12005.chr1.vcf.bz2 | Bin 0 -> 80 bytes .../demoGenoChr/chr10/NA12003.chr10.vcf.bz2 | Bin 0 -> 73 bytes .../demoGenoChr/chr10/NA12004.chr10.vcf.bz2 | Bin 0 -> 75 bytes .../demoGenoChr/chr10/NA12005.chr10.vcf.bz2 | Bin 0 -> 74 bytes .../demoGenoChr/chr11/NA12003.chr11.vcf.bz2 | Bin 0 -> 73 bytes .../demoGenoChr/chr11/NA12004.chr11.vcf.bz2 | Bin 0 -> 81 bytes .../demoGenoChr/chr11/NA12005.chr11.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr12/NA12003.chr12.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr12/NA12004.chr12.vcf.bz2 | Bin 0 -> 66 bytes .../demoGenoChr/chr12/NA12005.chr12.vcf.bz2 | Bin 0 -> 65 bytes .../demoGenoChr/chr13/NA12003.chr13.vcf.bz2 | Bin 0 -> 73 bytes .../demoGenoChr/chr13/NA12004.chr13.vcf.bz2 | Bin 0 -> 74 bytes .../demoGenoChr/chr13/NA12005.chr13.vcf.bz2 | Bin 0 -> 72 bytes .../demoGenoChr/chr14/NA12003.chr14.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr14/NA12004.chr14.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr14/NA12005.chr14.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr15/NA12003.chr15.vcf.bz2 | Bin 0 -> 73 bytes .../demoGenoChr/chr15/NA12004.chr15.vcf.bz2 | Bin 0 -> 65 bytes .../demoGenoChr/chr15/NA12005.chr15.vcf.bz2 | Bin 0 -> 68 bytes .../demoGenoChr/chr16/NA12003.chr16.vcf.bz2 | Bin 0 -> 64 bytes .../demoGenoChr/chr16/NA12004.chr16.vcf.bz2 | Bin 0 -> 70 bytes .../demoGenoChr/chr16/NA12005.chr16.vcf.bz2 | Bin 0 -> 62 bytes .../demoGenoChr/chr17/NA12003.chr17.vcf.bz2 | Bin 0 -> 60 bytes .../demoGenoChr/chr17/NA12004.chr17.vcf.bz2 | Bin 0 -> 64 bytes .../demoGenoChr/chr17/NA12005.chr17.vcf.bz2 | Bin 0 -> 68 bytes .../demoGenoChr/chr18/NA12003.chr18.vcf.bz2 | Bin 0 -> 60 bytes .../demoGenoChr/chr18/NA12004.chr18.vcf.bz2 | Bin 0 -> 62 bytes .../demoGenoChr/chr18/NA12005.chr18.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr19/NA12003.chr19.vcf.bz2 | Bin 0 -> 74 bytes .../demoGenoChr/chr19/NA12004.chr19.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr19/NA12005.chr19.vcf.bz2 | Bin 0 -> 63 bytes .../demoGenoChr/chr2/NA12003.chr2.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr2/NA12004.chr2.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr2/NA12005.chr2.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr20/NA12003.chr20.vcf.bz2 | Bin 0 -> 64 bytes .../demoGenoChr/chr20/NA12004.chr20.vcf.bz2 | Bin 0 -> 65 bytes .../demoGenoChr/chr20/NA12005.chr20.vcf.bz2 | Bin 0 -> 60 bytes .../demoGenoChr/chr21/NA12003.chr21.vcf.bz2 | Bin 0 -> 72 bytes .../demoGenoChr/chr21/NA12004.chr21.vcf.bz2 | Bin 0 -> 71 bytes .../demoGenoChr/chr21/NA12005.chr21.vcf.bz2 | Bin 0 -> 65 bytes .../demoGenoChr/chr22/NA12003.chr22.vcf.bz2 | Bin 0 -> 77 bytes .../demoGenoChr/chr22/NA12004.chr22.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr22/NA12005.chr22.vcf.bz2 | Bin 0 -> 79 bytes .../demoGenoChr/chr3/NA12003.chr3.vcf.bz2 | Bin 0 -> 74 bytes .../demoGenoChr/chr3/NA12004.chr3.vcf.bz2 | Bin 0 -> 71 bytes .../demoGenoChr/chr3/NA12005.chr3.vcf.bz2 | Bin 0 -> 76 bytes .../demoGenoChr/chr4/NA12003.chr4.vcf.bz2 | Bin 0 -> 64 bytes .../demoGenoChr/chr4/NA12004.chr4.vcf.bz2 | Bin 0 -> 68 bytes .../demoGenoChr/chr4/NA12005.chr4.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr5/NA12003.chr5.vcf.bz2 | Bin 0 -> 71 bytes .../demoGenoChr/chr5/NA12004.chr5.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr5/NA12005.chr5.vcf.bz2 | Bin 0 -> 71 bytes .../demoGenoChr/chr6/NA12003.chr6.vcf.bz2 | Bin 0 -> 72 bytes .../demoGenoChr/chr6/NA12004.chr6.vcf.bz2 | Bin 0 -> 70 bytes .../demoGenoChr/chr6/NA12005.chr6.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr7/NA12003.chr7.vcf.bz2 | Bin 0 -> 70 bytes .../demoGenoChr/chr7/NA12004.chr7.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr7/NA12005.chr7.vcf.bz2 | Bin 0 -> 72 bytes .../demoGenoChr/chr8/NA12003.chr8.vcf.bz2 | Bin 0 -> 77 bytes .../demoGenoChr/chr8/NA12004.chr8.vcf.bz2 | Bin 0 -> 75 bytes .../demoGenoChr/chr8/NA12005.chr8.vcf.bz2 | Bin 0 -> 78 bytes .../demoGenoChr/chr9/NA12003.chr9.vcf.bz2 | Bin 0 -> 62 bytes .../demoGenoChr/chr9/NA12004.chr9.vcf.bz2 | Bin 0 -> 68 bytes .../demoGenoChr/chr9/NA12005.chr9.vcf.bz2 | Bin 0 -> 67 bytes man/generateGDSSNPinfo.Rd | 10 ++-- man/groupChr1KGSNV.Rd | 23 +++++++- man/validatePepSynthetic.Rd | 2 +- man/validateSyntheticGeno.Rd | 2 +- .../demoGenoChr/chr1/NA12003.chr1.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr1/NA12004.chr1.vcf.bz2 | Bin 0 -> 79 bytes .../demoGenoChr/chr1/NA12005.chr1.vcf.bz2 | Bin 0 -> 80 bytes .../demoGenoChr/chr1/NA12006.chr1.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr10/NA12003.chr10.vcf.bz2 | Bin 0 -> 73 bytes .../demoGenoChr/chr10/NA12004.chr10.vcf.bz2 | Bin 0 -> 75 bytes .../demoGenoChr/chr10/NA12005.chr10.vcf.bz2 | Bin 0 -> 74 bytes .../demoGenoChr/chr10/NA12006.chr10.vcf.bz2 | Bin 0 -> 72 bytes .../demoGenoChr/chr11/NA12003.chr11.vcf.bz2 | Bin 0 -> 73 bytes .../demoGenoChr/chr11/NA12004.chr11.vcf.bz2 | Bin 0 -> 81 bytes .../demoGenoChr/chr11/NA12005.chr11.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr11/NA12006.chr11.vcf.bz2 | Bin 0 -> 74 bytes .../demoGenoChr/chr12/NA12003.chr12.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr12/NA12004.chr12.vcf.bz2 | Bin 0 -> 66 bytes .../demoGenoChr/chr12/NA12005.chr12.vcf.bz2 | Bin 0 -> 65 bytes .../demoGenoChr/chr12/NA12006.chr12.vcf.bz2 | Bin 0 -> 63 bytes .../demoGenoChr/chr13/NA12003.chr13.vcf.bz2 | Bin 0 -> 73 bytes .../demoGenoChr/chr13/NA12004.chr13.vcf.bz2 | Bin 0 -> 74 bytes .../demoGenoChr/chr13/NA12005.chr13.vcf.bz2 | Bin 0 -> 72 bytes .../demoGenoChr/chr13/NA12006.chr13.vcf.bz2 | Bin 0 -> 70 bytes .../demoGenoChr/chr14/NA12003.chr14.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr14/NA12004.chr14.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr14/NA12005.chr14.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr14/NA12006.chr14.vcf.bz2 | Bin 0 -> 65 bytes .../demoGenoChr/chr15/NA12003.chr15.vcf.bz2 | Bin 0 -> 73 bytes .../demoGenoChr/chr15/NA12004.chr15.vcf.bz2 | Bin 0 -> 65 bytes .../demoGenoChr/chr15/NA12005.chr15.vcf.bz2 | Bin 0 -> 68 bytes .../demoGenoChr/chr15/NA12006.chr15.vcf.bz2 | Bin 0 -> 64 bytes .../demoGenoChr/chr16/NA12003.chr16.vcf.bz2 | Bin 0 -> 64 bytes .../demoGenoChr/chr16/NA12004.chr16.vcf.bz2 | Bin 0 -> 70 bytes .../demoGenoChr/chr16/NA12005.chr16.vcf.bz2 | Bin 0 -> 62 bytes .../demoGenoChr/chr16/NA12006.chr16.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr17/NA12003.chr17.vcf.bz2 | Bin 0 -> 60 bytes .../demoGenoChr/chr17/NA12004.chr17.vcf.bz2 | Bin 0 -> 64 bytes .../demoGenoChr/chr17/NA12005.chr17.vcf.bz2 | Bin 0 -> 68 bytes .../demoGenoChr/chr17/NA12006.chr17.vcf.bz2 | Bin 0 -> 71 bytes .../demoGenoChr/chr18/NA12003.chr18.vcf.bz2 | Bin 0 -> 60 bytes .../demoGenoChr/chr18/NA12004.chr18.vcf.bz2 | Bin 0 -> 62 bytes .../demoGenoChr/chr18/NA12005.chr18.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr18/NA12006.chr18.vcf.bz2 | Bin 0 -> 76 bytes .../demoGenoChr/chr19/NA12003.chr19.vcf.bz2 | Bin 0 -> 74 bytes .../demoGenoChr/chr19/NA12004.chr19.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr19/NA12005.chr19.vcf.bz2 | Bin 0 -> 63 bytes .../demoGenoChr/chr19/NA12006.chr19.vcf.bz2 | Bin 0 -> 60 bytes .../demoGenoChr/chr2/NA12003.chr2.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr2/NA12004.chr2.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr2/NA12005.chr2.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr2/NA12006.chr2.vcf.bz2 | Bin 0 -> 60 bytes .../demoGenoChr/chr20/NA12003.chr20.vcf.bz2 | Bin 0 -> 64 bytes .../demoGenoChr/chr20/NA12004.chr20.vcf.bz2 | Bin 0 -> 65 bytes .../demoGenoChr/chr20/NA12005.chr20.vcf.bz2 | Bin 0 -> 60 bytes .../demoGenoChr/chr20/NA12006.chr20.vcf.bz2 | Bin 0 -> 60 bytes .../demoGenoChr/chr21/NA12003.chr21.vcf.bz2 | Bin 0 -> 72 bytes .../demoGenoChr/chr21/NA12004.chr21.vcf.bz2 | Bin 0 -> 71 bytes .../demoGenoChr/chr21/NA12005.chr21.vcf.bz2 | Bin 0 -> 65 bytes .../demoGenoChr/chr21/NA12006.chr21.vcf.bz2 | Bin 0 -> 64 bytes .../demoGenoChr/chr22/NA12003.chr22.vcf.bz2 | Bin 0 -> 77 bytes .../demoGenoChr/chr22/NA12004.chr22.vcf.bz2 | Bin 0 -> 61 bytes .../demoGenoChr/chr22/NA12005.chr22.vcf.bz2 | Bin 0 -> 79 bytes .../demoGenoChr/chr22/NA12006.chr22.vcf.bz2 | Bin 0 -> 79 bytes .../demoGenoChr/chr3/NA12003.chr3.vcf.bz2 | Bin 0 -> 74 bytes .../demoGenoChr/chr3/NA12004.chr3.vcf.bz2 | Bin 0 -> 71 bytes .../demoGenoChr/chr3/NA12005.chr3.vcf.bz2 | Bin 0 -> 76 bytes .../demoGenoChr/chr3/NA12006.chr3.vcf.bz2 | Bin 0 -> 76 bytes .../demoGenoChr/chr4/NA12003.chr4.vcf.bz2 | Bin 0 -> 64 bytes .../demoGenoChr/chr4/NA12004.chr4.vcf.bz2 | Bin 0 -> 68 bytes .../demoGenoChr/chr4/NA12005.chr4.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr4/NA12006.chr4.vcf.bz2 | Bin 0 -> 64 bytes .../demoGenoChr/chr5/NA12003.chr5.vcf.bz2 | Bin 0 -> 71 bytes .../demoGenoChr/chr5/NA12004.chr5.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr5/NA12005.chr5.vcf.bz2 | Bin 0 -> 71 bytes .../demoGenoChr/chr5/NA12006.chr5.vcf.bz2 | Bin 0 -> 68 bytes .../demoGenoChr/chr6/NA12003.chr6.vcf.bz2 | Bin 0 -> 72 bytes .../demoGenoChr/chr6/NA12004.chr6.vcf.bz2 | Bin 0 -> 70 bytes .../demoGenoChr/chr6/NA12005.chr6.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr6/NA12006.chr6.vcf.bz2 | Bin 0 -> 70 bytes .../demoGenoChr/chr7/NA12003.chr7.vcf.bz2 | Bin 0 -> 70 bytes .../demoGenoChr/chr7/NA12004.chr7.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr7/NA12005.chr7.vcf.bz2 | Bin 0 -> 72 bytes .../demoGenoChr/chr7/NA12006.chr7.vcf.bz2 | Bin 0 -> 74 bytes .../demoGenoChr/chr8/NA12003.chr8.vcf.bz2 | Bin 0 -> 77 bytes .../demoGenoChr/chr8/NA12004.chr8.vcf.bz2 | Bin 0 -> 75 bytes .../demoGenoChr/chr8/NA12005.chr8.vcf.bz2 | Bin 0 -> 78 bytes .../demoGenoChr/chr8/NA12006.chr8.vcf.bz2 | Bin 0 -> 69 bytes .../demoGenoChr/chr9/NA12003.chr9.vcf.bz2 | Bin 0 -> 62 bytes .../demoGenoChr/chr9/NA12004.chr9.vcf.bz2 | Bin 0 -> 68 bytes .../demoGenoChr/chr9/NA12005.chr9.vcf.bz2 | Bin 0 -> 67 bytes .../demoGenoChr/chr9/NA12006.chr9.vcf.bz2 | Bin 0 -> 62 bytes tests/testthat/test-tools.R | 49 ++++++++++++++++++ 162 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 inst/extdata/demoGenoChr/chr1/NA12003.chr1.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr1/NA12004.chr1.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr1/NA12005.chr1.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr10/NA12003.chr10.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr10/NA12004.chr10.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr10/NA12005.chr10.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr11/NA12003.chr11.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr11/NA12004.chr11.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr11/NA12005.chr11.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr12/NA12003.chr12.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr12/NA12004.chr12.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr12/NA12005.chr12.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr13/NA12003.chr13.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr13/NA12004.chr13.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr13/NA12005.chr13.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr14/NA12003.chr14.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr14/NA12004.chr14.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr14/NA12005.chr14.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr15/NA12003.chr15.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr15/NA12004.chr15.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr15/NA12005.chr15.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr16/NA12003.chr16.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr16/NA12004.chr16.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr16/NA12005.chr16.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr17/NA12003.chr17.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr17/NA12004.chr17.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr17/NA12005.chr17.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr18/NA12003.chr18.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr18/NA12004.chr18.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr18/NA12005.chr18.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr19/NA12003.chr19.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr19/NA12004.chr19.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr19/NA12005.chr19.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr2/NA12003.chr2.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr2/NA12004.chr2.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr2/NA12005.chr2.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr20/NA12003.chr20.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr20/NA12004.chr20.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr20/NA12005.chr20.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr21/NA12003.chr21.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr21/NA12004.chr21.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr21/NA12005.chr21.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr22/NA12003.chr22.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr22/NA12004.chr22.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr22/NA12005.chr22.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr3/NA12003.chr3.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr3/NA12004.chr3.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr3/NA12005.chr3.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr4/NA12003.chr4.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr4/NA12004.chr4.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr4/NA12005.chr4.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr5/NA12003.chr5.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr5/NA12004.chr5.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr5/NA12005.chr5.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr6/NA12003.chr6.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr6/NA12004.chr6.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr6/NA12005.chr6.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr7/NA12003.chr7.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr7/NA12004.chr7.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr7/NA12005.chr7.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr8/NA12003.chr8.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr8/NA12004.chr8.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr8/NA12005.chr8.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr9/NA12003.chr9.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr9/NA12004.chr9.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/chr9/NA12005.chr9.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr1/NA12003.chr1.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr1/NA12004.chr1.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr1/NA12005.chr1.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr1/NA12006.chr1.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr10/NA12003.chr10.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr10/NA12004.chr10.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr10/NA12005.chr10.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr10/NA12006.chr10.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr11/NA12003.chr11.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr11/NA12004.chr11.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr11/NA12005.chr11.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr11/NA12006.chr11.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr12/NA12003.chr12.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr12/NA12004.chr12.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr12/NA12005.chr12.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr12/NA12006.chr12.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr13/NA12003.chr13.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr13/NA12004.chr13.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr13/NA12005.chr13.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr13/NA12006.chr13.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr14/NA12003.chr14.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr14/NA12004.chr14.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr14/NA12005.chr14.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr14/NA12006.chr14.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr15/NA12003.chr15.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr15/NA12004.chr15.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr15/NA12005.chr15.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr15/NA12006.chr15.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr16/NA12003.chr16.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr16/NA12004.chr16.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr16/NA12005.chr16.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr16/NA12006.chr16.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr17/NA12003.chr17.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr17/NA12004.chr17.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr17/NA12005.chr17.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr17/NA12006.chr17.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr18/NA12003.chr18.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr18/NA12004.chr18.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr18/NA12005.chr18.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr18/NA12006.chr18.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr19/NA12003.chr19.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr19/NA12004.chr19.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr19/NA12005.chr19.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr19/NA12006.chr19.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr2/NA12003.chr2.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr2/NA12004.chr2.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr2/NA12005.chr2.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr2/NA12006.chr2.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr20/NA12003.chr20.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr20/NA12004.chr20.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr20/NA12005.chr20.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr20/NA12006.chr20.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr21/NA12003.chr21.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr21/NA12004.chr21.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr21/NA12005.chr21.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr21/NA12006.chr21.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr22/NA12003.chr22.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr22/NA12004.chr22.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr22/NA12005.chr22.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr22/NA12006.chr22.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr3/NA12003.chr3.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr3/NA12004.chr3.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr3/NA12005.chr3.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr3/NA12006.chr3.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr4/NA12003.chr4.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr4/NA12004.chr4.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr4/NA12005.chr4.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr4/NA12006.chr4.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr5/NA12003.chr5.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr5/NA12004.chr5.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr5/NA12005.chr5.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr5/NA12006.chr5.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr6/NA12003.chr6.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr6/NA12004.chr6.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr6/NA12005.chr6.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr6/NA12006.chr6.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr7/NA12003.chr7.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr7/NA12004.chr7.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr7/NA12005.chr7.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr7/NA12006.chr7.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr8/NA12003.chr8.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr8/NA12004.chr8.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr8/NA12005.chr8.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr8/NA12006.chr8.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr9/NA12003.chr9.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr9/NA12004.chr9.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr9/NA12005.chr9.vcf.bz2 create mode 100644 tests/testthat/fixtures/demoGenoChr/chr9/NA12006.chr9.vcf.bz2 diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index acb1a8bb1..9c88fe089 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -19,10 +19,8 @@ #' ## Required package #' library(gdsfmt) #' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") -#' #' ## The RDS file containing the filtered SNP information +#' dataDir <- system.file("extdata", package="RAIDS") #' fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' #' ## Different code depending of the withr package availability diff --git a/R/synthetic_internal.R b/R/synthetic_internal.R index a60d54cfa..393ef80f6 100644 --- a/R/synthetic_internal.R +++ b/R/synthetic_internal.R @@ -1,7 +1,7 @@ #' @title Validate input parameters for syntheticGeno() function #' #' @description This function validates the input parameters for the -#' \code{\link{syntheticGeno}} function. +#' [syntheticGeno()] function. #' #' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} #' (a GDS file), the 1KG GDS file. @@ -133,7 +133,7 @@ validateSyntheticGeno <- function(gdsReference, gdsRefAnnot, fileProfileGDS, #' @title Validate input parameters for prepSynthetic() function #' #' @description This function validates the input parameters for the -#' \code{\link{prepSynthetic}} function. +#' [prepSynthetic()] function. #' #' @param fileProfileGDS a \code{character} string representing the file name #' of the GDS Sample file containing the information about the sample diff --git a/R/tools.R b/R/tools.R index 68f5bd882..85e2e0bba 100644 --- a/R/tools.R +++ b/R/tools.R @@ -161,10 +161,29 @@ snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { #' #' @examples #' -#' ## Path to the demo pedigree file is located in this package +#' ## Path to the demo vcf files in this package #' dataDir <- system.file("extdata", package="RAIDS") -#' -#' ## TODO +#' pathGeno <- file.path(dataDir, "demoGenoChr") +#' +#' ## Path where the output vcf file will be created +#' pathOut <- getwd() +#' +#' ## The current directory must be writable +#' if (file.access(pathOut) == 0 && +#' !file.exists(file.path(getwd(), "NA12003.csv.bz2")) && +#' !file.exists(file.path(getwd(), "NA12004.csv.bz2")) && +#' !file.exists(file.path(getwd(), "NA12005.csv.bz2"))) { +#' +#' ## Return 0 when successful +#' ## The files "NA12003.csv.bz2", "NA12004.csv.bz2" and +#' ## "NA12005.csv.bz2" should not be present in the current directory +#' groupChr1KGSNV(pathGenoChr=pathGeno, pathOut=pathOut) +#' +#' ## Remove temporary VCF file +#' unlink(file.path(getwd(), "NA12003.csv.bz2"), force=TRUE) +#' unlink(file.path(getwd(), "NA12004.csv.bz2"), force=TRUE) +#' unlink(file.path(getwd(), "NA12005.csv.bz2"), force=TRUE) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom utils write.csv2 read.csv2 diff --git a/inst/extdata/demoGenoChr/chr1/NA12003.chr1.vcf.bz2 b/inst/extdata/demoGenoChr/chr1/NA12003.chr1.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..5a9e113810de19334e580365ec025e181925c408 GIT binary patch literal 69 zcmZ>Y%CIzaj8qGb{J2I=kAY!^PXmKM1%m=31B(Jfh>9f;T4*^jL0KkKSzS_OjQ{|cOn?9obO0a$00bZaa6f literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr1/NA12005.chr1.vcf.bz2 b/inst/extdata/demoGenoChr/chr1/NA12005.chr1.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..09d7ec7534134ae459194b24659bdc3717a0e7ce GIT binary patch literal 80 zcmV-W0I&Z-T4*^jL0KkKS>2*a4FCX`On?9oasVI!00bZaa6YT literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr10/NA12003.chr10.vcf.bz2 b/inst/extdata/demoGenoChr/chr10/NA12003.chr10.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9559377f6710765ffd26bfe949aa666a92d00630 GIT binary patch literal 73 zcmV-P0Ji@^T4*^jL0KkKSxG%zF#rIVOn?9ocmN;)00bZaP=*8uQ4>iVgjz$8WE8$t fPUk^WL+oDj+q$brQUxf|#rV6DDZ+$;N$Tl{280^O literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr10/NA12004.chr10.vcf.bz2 b/inst/extdata/demoGenoChr/chr10/NA12004.chr10.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9d57ad3073ba252e7c4f328476b61cb0061f2e0c GIT binary patch literal 75 zcmV-R0JQ%?T4*^jL0KkKS-<#`ZU6w7On?9obO0a$00bZaP=*8uQZ+Qp4$GA&6-rS` h(iEN%P0bNbA@(7?_b^c8pv4d3?ntK!5*PmxZNPY%CIzaj8qGbl%FIV&A>3jr-4DBh(UpofklBKppAti$kgOaz?(LY0Fy>Y%CIzaj8qGbTvRya2m`|mp9Thj3I+v61{MW|fHoG6AXAgWa)(m10z?>H^&5kW dLxa1&v3Uzr$C+Fldgh=iY|{eI{++J7_k5V literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr11/NA12004.chr11.vcf.bz2 b/inst/extdata/demoGenoChr/chr11/NA12004.chr11.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..5a88d80958f1618b8d595be2bfe7c13e8374708d GIT binary patch literal 81 zcmZ>Y%CIzaj8qGb{H8tcG6Ta5p9Thj5(WiE1{MW|BB`obJR(zieJu~=%zNB3JM6-( lX!R@0D{loK{N23o?{oGZ-bJ^zNqaC&5ifGJ2$%pe0sz0}A)WvL literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr11/NA12005.chr11.vcf.bz2 b/inst/extdata/demoGenoChr/chr11/NA12005.chr11.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..6055efe7dedad2e472568eff91e757ba3215649b GIT binary patch literal 69 zcmZ>Y%CIzaj8qGbG%XIf%D^zgr-4DBh(UpofklBK#H@pn%ONcwsFmyT4sivWt~uwl ZmNh3u)&@9eN!RH;=_**Lko9ckDgd+27YhIY literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr12/NA12003.chr12.vcf.bz2 b/inst/extdata/demoGenoChr/chr12/NA12003.chr12.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..57cf24de4e2223a95bf0c15d1819d26400d975a2 GIT binary patch literal 61 zcmZ>Y%CIzaj8qGbTx)mKk%3``PXmKM1%m=31B(KKArA*vsNu>v7q)+L57->(bpPkM QXDi~wi(D-NCV-R!07ZKh-T(jq literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr12/NA12004.chr12.vcf.bz2 b/inst/extdata/demoGenoChr/chr12/NA12004.chr12.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..6fdeed51dbb452c70e6cf581a440fabdf0127139 GIT binary patch literal 66 zcmV-I0KNZ0T4*^jL0KkKS>Z%McmM#HOn?9obO0a$00bZaR5qZ<3Q9n8k(!N&*jpX% YrB6BK3#BIWut^>+~+5i9m literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr12/NA12005.chr12.vcf.bz2 b/inst/extdata/demoGenoChr/chr12/NA12005.chr12.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..418994f9c096793d4a2f7b16d827a14ff486f95c GIT binary patch literal 65 zcmZ>Y%CIzaj8qGbJS2Chgn?m(PXmKM5rYCF1B(JfKpP83SBh?tYL^hh39iaevsVot VtarX$#r&~cCAgK7NAZoi0|0h)6!!oC literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr13/NA12003.chr13.vcf.bz2 b/inst/extdata/demoGenoChr/chr13/NA12003.chr13.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..f0ff41dd323a335decb81dfe41db387ba443b317 GIT binary patch literal 73 zcmV-P0Ji@^T4*^jL0KkKSz{m+(EtFLOn?9ocmN;)00bZaP=*8uQZ+Qp5`?7+QKUO$ f1p(kx+|&W${f774#Yd6>NPaHlig2MI#y}~eAL|+1 literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr13/NA12004.chr13.vcf.bz2 b/inst/extdata/demoGenoChr/chr13/NA12004.chr13.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..0d5fc433f26196d3afe6433d10f070197f0c359b GIT binary patch literal 74 zcmV-Q0JZ-@T4*^jL0KkKSv#c2pa1}vOn?9obO0a$00bZaR5sO6&=D!=G(`}|1LXnl gF;O-Hx7O4oLQS?TRBT0}FjwO4NT&)C2XvVf0Cd|J`~Uy| literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr13/NA12005.chr13.vcf.bz2 b/inst/extdata/demoGenoChr/chr13/NA12005.chr13.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..474e86cb55275409e8819fef97e3b7cf340f6f5d GIT binary patch literal 72 zcmZ>Y%CIzaj8qGbR9bN1F9X92p9ThjA_fIU1{MW|fHoG6kjudyA#WO<{BS6r)im=v b%e~*mY*Q9;u`bc%P_P#-aY%CIzaj8qGbv<;cJih*H literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr14/NA12004.chr14.vcf.bz2 b/inst/extdata/demoGenoChr/chr14/NA12004.chr14.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..c19eee1968b4a3feefd352063e1590a0de980ec4 GIT binary patch literal 61 zcmZ>Y%CIzaj8qGbeD7eM#=tPcr-4DBgh7FkfklDAkcUGsSZd}JuIUdiGENm?`){18 R!Oy)@X^w_R`2y+93;_LT5o`be literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr14/NA12005.chr14.vcf.bz2 b/inst/extdata/demoGenoChr/chr14/NA12005.chr14.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..509cb2d287b439986803041e874d5ed59de20696 GIT binary patch literal 61 zcmZ>Y%CIzaj8qGb?C7y|XJDA&)4(85#Gt^)z@orl$ipERe4@=EWRE-t-&q0an>$~# Ru>FZWDe}Y%CIzaj8qGb+@#~}$G|Ydr-4DBgh7FkfklBKppAv2(?pj+MI@zC`~dTI2X?vZ Vd%guQ9)I-CV>y?Qm}_U|0RT9_6W;&; literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr15/NA12005.chr15.vcf.bz2 b/inst/extdata/demoGenoChr/chr15/NA12005.chr15.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..f48cd254721a3d20ae0bbb2e22ff7a8923671bf2 GIT binary patch literal 68 zcmZ>Y%CIzaj8qGbJhhP}ih*Hy+1d7&Tl-a8h3 Y&-?k^Oy<;L`R<)cb2L0sBbsy>0Mfq~Z2$lO literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr16/NA12003.chr16.vcf.bz2 b/inst/extdata/demoGenoChr/chr16/NA12003.chr16.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..aca1b7a8763b55eae5eaa9badb352c55b5b4654c GIT binary patch literal 64 zcmZ>Y%CIzaj8qGb6ueN_%fK+hr-4DBfY%CIzaj8qGbw7zJN$iOher-4DBgh7FkfklBKppAtih}ke~itnj;4sz*&!R`gs a`?JM^E-<<>OcDK9t`gkJ$-GyXO#lF)8xyYp literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr16/NA12005.chr16.vcf.bz2 b/inst/extdata/demoGenoChr/chr16/NA12005.chr16.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9a94357479918d368949f05dd4ed46bbf919c277 GIT binary patch literal 62 zcmZ>Y%CIzaj8qGb{AJO>$-pqfr-4DBh(UpofklDAkcUIi*GHu@L}9v95yO+Cj30N` SPIRc#d(u^~Q1MHlfDiy1=o6a& literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr17/NA12003.chr17.vcf.bz2 b/inst/extdata/demoGenoChr/chr17/NA12003.chr17.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..5491587438a9b77ea1ec3174c21bfc8bc23f1a3e GIT binary patch literal 60 zcmV-C0K@-6T4*^jL0KkKSzcJzO8@|vOn?9ocmN;)00bZaF$@R_l)@QH;3tqxtwArf Sx$C47{x0N-aG@Z)v96XGv=w;( literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr17/NA12004.chr17.vcf.bz2 b/inst/extdata/demoGenoChr/chr17/NA12004.chr17.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..7040e9d70815f4c4d99550ed0911b29f2d032fc9 GIT binary patch literal 64 zcmZ>Y%CIzaj8qGbTxP+>%)l_ir-4DBgh7FkfklBK#F>dDY%CIzaj8qGbe0eV^n1Nx2PXmKM5rYCF1B(JfKpP83r-`mg2%iJDioe#fyP`gP YSMF77EJ|TwKYC}PpNNW8`HU$C0G=EbX8-^I literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr18/NA12003.chr18.vcf.bz2 b/inst/extdata/demoGenoChr/chr18/NA12003.chr18.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..7069651ccca44b73369f772179a4836f6c97bdca GIT binary patch literal 60 zcmV-C0K@-6T4*^jL0KkKSs03~`Tzi!On?9ocmN;)00bZaF$@S1Q`EsC0N1oYZd!o< SGPdG?@Vk;J!i0dtRd3KZ;}(?w literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr18/NA12004.chr18.vcf.bz2 b/inst/extdata/demoGenoChr/chr18/NA12004.chr18.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..719c31374402d15473af9f6aa9e1f05ec728040e GIT binary patch literal 62 zcmZ>Y%CIzaj8qGb6rK>4&A>3jr-4DBgh7FkfklDAkcUIi*GHveZD5H)5yO+Cj30N` SPIRc#d(u^~P(fW`%{2fF!V|*) literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr18/NA12005.chr18.vcf.bz2 b/inst/extdata/demoGenoChr/chr18/NA12005.chr18.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..2928cf343b3de3cfc9b02ab5591bbbe5f0565bd3 GIT binary patch literal 61 zcmZ>Y%CIzaj8qGbTt8`52m`|mp9ThjA_fIU1{MVdLmm!6&ljpp;$G`D_^OVuXQz9z Rus?d|v7Adt^i!x;0{{W<5v2eC literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr19/NA12003.chr19.vcf.bz2 b/inst/extdata/demoGenoChr/chr19/NA12003.chr19.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9733612b48f20530a35a146725c79fd65f8576f0 GIT binary patch literal 74 zcmZ>Y%CIzaj8qGbl%A+t%D^zgr-4DBfY%CIzaj8qGb+`QxGUj~L5J`D^4B@7CT3@i!^hCCdCo-b6nrhD{j@KqgQ&rbJb RVSn__V>y?QSh>9Y0sugv5|jV{ literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr19/NA12005.chr19.vcf.bz2 b/inst/extdata/demoGenoChr/chr19/NA12005.chr19.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..eaf2103ed782a850bd94b12be9fba925b24cb20f GIT binary patch literal 63 zcmV-F0Kor3T4*^jL0KkKS@9Cx?f?LoOn?9oasVI!00bZaF$@S1Q`Fj;NT`{_oJ~L* VDuDF$&9Oj!F64@Ep&{ZWyWF4h7?A(~ literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr2/NA12003.chr2.vcf.bz2 b/inst/extdata/demoGenoChr/chr2/NA12003.chr2.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..68b8d8cb510a5cc5f076d3cb620430d19b27abb9 GIT binary patch literal 61 zcmV-D0K)%5T4*^jL0KkKS&8v8tpEU+On?9ocmN;)00bZaF$@R_l4Q|9%8)%Eo#r5$ TTYkH=6XNbjrwS4gJ|=abL&Fqt literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr2/NA12004.chr2.vcf.bz2 b/inst/extdata/demoGenoChr/chr2/NA12004.chr2.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..29710f3b9dbcd8e721954cda2aecc34e3a1c25d0 GIT binary patch literal 61 zcmZ>Y%CIzaj8qGbY};qHje%i?PXmKM34;P71B(KKArFUO@Rfr~TH%vj*q*N7|E!&- R!Oy)@X^w`6bG&pk0{|6a5nliR literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr2/NA12005.chr2.vcf.bz2 b/inst/extdata/demoGenoChr/chr2/NA12005.chr2.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..e7207c85e5ae7ccf39b0f6997580201d6cf7e7dd GIT binary patch literal 61 zcmZ>Y%CIzaj8qGb4E!|Dn}K15PXmKM5rYCF1B(KKArFUO@CB95I#)jdnHdVEoAXz3 R@Yckh6nW_6=zgkF2LKA55;Fh* literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr20/NA12003.chr20.vcf.bz2 b/inst/extdata/demoGenoChr/chr20/NA12003.chr20.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..e46f8375224e977e022627265b2af5636c076dcb GIT binary patch literal 64 zcmV-G0Kfl2T4*^jL0KkKS$xmVaR30AOn?9ocmN;)00bZaP=*8rDNjkGAm$+Yh3}k# W?mNG3?MpEy;_gVN3K9>Q`OYAx#~0fG literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr20/NA12004.chr20.vcf.bz2 b/inst/extdata/demoGenoChr/chr20/NA12004.chr20.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..901c941be7eb200a88420fd5ee654bceb4c3f04f GIT binary patch literal 65 zcmV-H0KWf1T4*^jL0KkKSq5#D*#H2TOn?9obO0a$00bZaP=*8ul=PY+ra(~gfcKaH XI~~5ZqLL#Zq49SlQ-uitX4zeko39qb literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr20/NA12005.chr20.vcf.bz2 b/inst/extdata/demoGenoChr/chr20/NA12005.chr20.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..0286e12e82e9153a5bff204ccff9efcf587e8631 GIT binary patch literal 60 zcmZ>Y%CIzaj8qGbd~n8R4+Fytp9ThjA_fIU1{MVdLmm#n;45E^A{JOJu$$^oY`sl` Q|LC2Gej+Ls#=`mx04{_QLjV8( literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr21/NA12003.chr21.vcf.bz2 b/inst/extdata/demoGenoChr/chr21/NA12003.chr21.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..1b8e8a4b8d568c1d8b4e0fd2f85e6be982ba1426 GIT binary patch literal 72 zcmV-O0Jr}_T4*^jL0KkKS!&mNHvj;bOn?9ocmN;)00bZaR5npG!3scTBSNJExX4-x eJc^voDyD<=CVOt61+WE*@Vk;J!i0lXyVuTcBp=*j7=RI*7|;L! literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr21/NA12005.chr21.vcf.bz2 b/inst/extdata/demoGenoChr/chr21/NA12005.chr21.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..175df8b9f9efeaa9b17855e14c551876a3ba54ad GIT binary patch literal 65 zcmZ>Y%CIzaj8qGboEggy!@w}Zr-4DBh(UpofklBKppAvqtIF3`SK+;i_wfb3yP1+- V-TSS>*?;uTL_ZM~wQvV<1^`+#6ej=x literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr22/NA12003.chr22.vcf.bz2 b/inst/extdata/demoGenoChr/chr22/NA12003.chr22.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..df8ed4e019624a1f61ceece31539d9ab6a9891b1 GIT binary patch literal 77 zcmV-T0J8r=T4*^jL0KkKS#5?nnE(KoOn?9ocmN;)00bZaP=*8uQZ+Qp0)~`mM!OC{ jLiiOoG(|YSVjJIc1mqz|r7c91#rV6DDZ+$Y%CIzaj8qGbREg%vW?-1%)4(85!l1y&z@orl$ipERd_kpSWu2dZ%nSw7&H1Z1 Rcxz%$iad03n3!X@1_0N85rqH% literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr22/NA12005.chr22.vcf.bz2 b/inst/extdata/demoGenoChr/chr22/NA12005.chr22.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..45979aa6b045b5726b6e9cf33838efbf1f1c79b9 GIT binary patch literal 79 zcmV-V0I>f;T4*^jL0KkKS=~j3P5=OyOn?9oasVI!00bZaY7%;>03t-wIm;Nf#84I6 la%iv+WMc?uC}m&(+NbHyZPRf8B&sWZF64@Ep&`1944mv%9E1P> literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr3/NA12003.chr3.vcf.bz2 b/inst/extdata/demoGenoChr/chr3/NA12003.chr3.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..e1d4d9c329f447a3e1aa3aadfbc8e8c579211565 GIT binary patch literal 74 zcmZ>Y%CIzaj8qGbRDLk~4g35KE14bprqvq!wfV literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr3/NA12004.chr3.vcf.bz2 b/inst/extdata/demoGenoChr/chr3/NA12004.chr3.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..b14a26a07fd993ef67ce204c524308107f1f8166 GIT binary patch literal 71 zcmZ>Y%CIzaj8qGb{M%b-!oV=Yr-4DBgh7FkfklBKppAti$kgPFwVuihSg7~PVY%q!9vB~QjanK1)~^p literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr3/NA12005.chr3.vcf.bz2 b/inst/extdata/demoGenoChr/chr3/NA12005.chr3.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..ae85583170d06015e9ee70ef602924e594efb7b2 GIT binary patch literal 76 zcmV-S0JHx>T4*^jL0KkKSz^wpWdHz}On?9oasVI!00bZaP=*8uQZ+QpS_SNx3Q*M| iQQ%bE)fD3WfNy=wK;(l;lmkQ`i@744C`d79R5F0KjvGAy literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr4/NA12003.chr4.vcf.bz2 b/inst/extdata/demoGenoChr/chr4/NA12003.chr4.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..c01c61b9054eb33400ed878443d08e14fb757018 GIT binary patch literal 64 zcmZ>Y%CIzaj8qGb><&4U!oV=Yr-4DBfdDIG9tRJA^x&a!2uK)m;On?9obO0a$00bZaR3$XfVG&G)pfU*{p$Mi$ aJSv-XKzNzRzCH$rxt< literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr4/NA12005.chr4.vcf.bz2 b/inst/extdata/demoGenoChr/chr4/NA12005.chr4.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..bfa295fde0b375b71d628bf7e0d1cb991c664347 GIT binary patch literal 69 zcmZ>Y%CIzaj8qGbJn&gy3j@Opp9ThjA_fIU1{MW|fHoG6Kp#(Wg(#MNNBJ4}jk{K^ XFR=c;y+k8)sg%8Vk*h_(1duiWy($(p literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr5/NA12003.chr5.vcf.bz2 b/inst/extdata/demoGenoChr/chr5/NA12003.chr5.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..e812d8fbd60b98fd1b6c8cb4065875624542c75e GIT binary patch literal 71 zcmV-N0J#4`T4*^jL0KkKS(ZyFmjD2mOn?9ocmN;)00bZaP=*8uQkzpV1DS~u6aqvP dAxx3fMBLQ@_+R&(+)y72xgwk>NJ}M@%Ye$@7Ulo| literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr5/NA12004.chr5.vcf.bz2 b/inst/extdata/demoGenoChr/chr5/NA12004.chr5.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..b978498b0bc2b086501a8b42a35cf3682723d844 GIT binary patch literal 69 zcmV-L0J{G|T4*^jL0KkKStq(3IRF5dOn?9obO0a$00bZaP=*8uQkzpV7MGEd(ya?Y bK%E6m%}^hg{pWWS2g2@1rwS4T_d};3syP;C literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr5/NA12005.chr5.vcf.bz2 b/inst/extdata/demoGenoChr/chr5/NA12005.chr5.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..f60e08d41baf52c399a488ffebd55846de5446e6 GIT binary patch literal 71 zcmZ>Y%CIzaj8qGbY@K=9k%3``PXmKM5rYCF1B(JfKpP83kg3U;sJLU^UR!ionJPrh bO++pBC%vyd!|JF1=$*%ME+K)i=AZa-cLZ^TS exztqG>>l&mx*3jARN2^ literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr6/NA12004.chr6.vcf.bz2 b/inst/extdata/demoGenoChr/chr6/NA12004.chr6.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..1c94aff643f6c77595e5a5ca61015f277eb52048 GIT binary patch literal 70 zcmZ>Y%CIzaj8qGbY%CIzaj8qGbT++PXmKM5rYCF1B(JfKpP83(ClDiQOziaiJ$)O%dY%CIzaj8qGblt^((XJDA&)4(85!l1y&z@oqq(8j_M#BAWOB)sqmY%CIzaj8qGbT=&1pkbz-_PXmKM5rYCF1B(JfKpP83ps=UF$t6w=mNP0tt>?P> c@^7d&y03I_J^Z)<= literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr8/NA12003.chr8.vcf.bz2 b/inst/extdata/demoGenoChr/chr8/NA12003.chr8.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..1e1a1581bf5d7434bca805f6833156cbc6d9812e GIT binary patch literal 77 zcmV-T0J8r=T4*^jL0KkKS-SQL?*IUpOn?9ocmN;)00bZaP=*8uQZ+QpDM|>Ej>_Z> jC=?zMP0ayLA@(V~_c2$JEe#?=N8;{CrwS4mUcp`9k$@SB literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr8/NA12004.chr8.vcf.bz2 b/inst/extdata/demoGenoChr/chr8/NA12004.chr8.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9fe74e90bad2a10aab6fd1e26b8aa6b133bb0851 GIT binary patch literal 75 zcmV-R0JQ%?T4*^jL0KkKS+e%$S^xl;On?9obO0a$00bZaP=*8uQZ+QpDM|>Em$GCn h2|~~m2Y^#^Lp*Pn84&;g literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr8/NA12005.chr8.vcf.bz2 b/inst/extdata/demoGenoChr/chr8/NA12005.chr8.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..2831fedcc1f292179f383b10502155bb331cf47d GIT binary patch literal 78 zcmZ>Y%CIzaj8qGbtTy_@$-pqfr-4DBh(UpofklC#NU@Pgq}SJ&E2ybymQ(ZQNg^Bp im8|9_tQP7wmVLi-)X#yJ!P&oir_vk^58IiQEDZoY%CIzaj8qGb%*>v!gn?m(PXmKM1%m=31B(KKArFV3=1UVt#*_1r)ogc<4p literal 0 HcmV?d00001 diff --git a/inst/extdata/demoGenoChr/chr9/NA12005.chr9.vcf.bz2 b/inst/extdata/demoGenoChr/chr9/NA12005.chr9.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..64b3334102c94adbd7fbd23f4862ef4624def35a GIT binary patch literal 67 zcmV-J0KES~T4*^jL0KkKS>@Wq2><|?On?9oasVI!00bZaR3wcw1StUnlBu}^AZVoW Zs&hCXIu7K{ZHNWp?ntK!5*)i&fgrR`79{`x literal 0 HcmV?d00001 diff --git a/man/generateGDSSNPinfo.Rd b/man/generateGDSSNPinfo.Rd index e41fad72f..685676f84 100644 --- a/man/generateGDSSNPinfo.Rd +++ b/man/generateGDSSNPinfo.Rd @@ -3,7 +3,7 @@ \encoding{UTF-8} \name{generateGDSSNPinfo} \alias{generateGDSSNPinfo} -\title{Add information related to SNVs into a Reference GDS file} +\title{Add information related to SNVs into a Population Reference GDS file} \usage{ generateGDSSNPinfo(gdsReference, fileFreq, verbose) } @@ -21,18 +21,16 @@ to show how the different steps in the function.} The integer \code{0L} when successful. } \description{ -the function adds the SNV information into a Reference -GDS file. +The function adds the SNV information into a Population +Reference GDS file. } \examples{ ## Required package library(gdsfmt) -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", package="RAIDS") - ## The RDS file containing the filtered SNP information +dataDir <- system.file("extdata", package="RAIDS") fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") ## Different code depending of the withr package availability diff --git a/man/groupChr1KGSNV.Rd b/man/groupChr1KGSNV.Rd index a31cf95df..35fc9082f 100644 --- a/man/groupChr1KGSNV.Rd +++ b/man/groupChr1KGSNV.Rd @@ -30,10 +30,29 @@ files for all samples present in the input directory. } \examples{ -## Path to the demo pedigree file is located in this package +## Path to the demo vcf files in this package dataDir <- system.file("extdata", package="RAIDS") +pathGeno <- file.path(dataDir, "demoGenoChr") -## TODO +## Path where the output vcf file will be created +pathOut <- getwd() + +## The current directory must be writable +if (file.access(pathOut) == 0 && + !file.exists(file.path(getwd(), "NA12003.csv.bz2")) && + !file.exists(file.path(getwd(), "NA12004.csv.bz2")) && + !file.exists(file.path(getwd(), "NA12005.csv.bz2"))) { + + ## Return 0 when successful + ## The files "NA12003.csv.bz2", "NA12004.csv.bz2" and + ## "NA12005.csv.bz2" should not be present in the current directory + groupChr1KGSNV(pathGenoChr=pathGeno, pathOut=pathOut) + + ## Remove temporary VCF file + unlink(file.path(getwd(), "NA12003.csv.bz2"), force=TRUE) + unlink(file.path(getwd(), "NA12004.csv.bz2"), force=TRUE) + unlink(file.path(getwd(), "NA12005.csv.bz2"), force=TRUE) +} } \author{ diff --git a/man/validatePepSynthetic.Rd b/man/validatePepSynthetic.Rd index 7549cce7d..9a98d95c5 100644 --- a/man/validatePepSynthetic.Rd +++ b/man/validatePepSynthetic.Rd @@ -51,7 +51,7 @@ to show how the different steps in the function.} } \description{ This function validates the input parameters for the -\code{\link{prepSynthetic}} function. +\code{\link[=prepSynthetic]{prepSynthetic()}} function. } \examples{ diff --git a/man/validateSyntheticGeno.Rd b/man/validateSyntheticGeno.Rd index d7cb1163c..6d7aba4b9 100644 --- a/man/validateSyntheticGeno.Rd +++ b/man/validateSyntheticGeno.Rd @@ -55,7 +55,7 @@ The integer \code{0L} when the function is successful. } \description{ This function validates the input parameters for the -\code{\link{syntheticGeno}} function. +\code{\link[=syntheticGeno]{syntheticGeno()}} function. } \examples{ diff --git a/tests/testthat/fixtures/demoGenoChr/chr1/NA12003.chr1.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr1/NA12003.chr1.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..5a9e113810de19334e580365ec025e181925c408 GIT binary patch literal 69 zcmZ>Y%CIzaj8qGb{J2I=kAY!^PXmKM1%m=31B(Jfh>9f;T4*^jL0KkKSzS_OjQ{|cOn?9obO0a$00bZaa6f literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr1/NA12005.chr1.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr1/NA12005.chr1.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..09d7ec7534134ae459194b24659bdc3717a0e7ce GIT binary patch literal 80 zcmV-W0I&Z-T4*^jL0KkKS>2*a4FCX`On?9oasVI!00bZaa6YT literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr1/NA12006.chr1.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr1/NA12006.chr1.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..d099218ab66135d32b77455f59c21bc2a57d25c0 GIT binary patch literal 69 zcmV-L0J{G|T4*^jL0KkKS>MU*I{*NfOn?9oaR49z00bZaR5qqS3Q9n8lG$u6q<4oJ beJXj+5V{)j`Y`~d3&q@#P81|J@_P=z7T6fo literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr10/NA12003.chr10.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr10/NA12003.chr10.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9559377f6710765ffd26bfe949aa666a92d00630 GIT binary patch literal 73 zcmV-P0Ji@^T4*^jL0KkKSxG%zF#rIVOn?9ocmN;)00bZaP=*8uQ4>iVgjz$8WE8$t fPUk^WL+oDj+q$brQUxf|#rV6DDZ+$;N$Tl{280^O literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr10/NA12004.chr10.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr10/NA12004.chr10.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9d57ad3073ba252e7c4f328476b61cb0061f2e0c GIT binary patch literal 75 zcmV-R0JQ%?T4*^jL0KkKS-<#`ZU6w7On?9obO0a$00bZaP=*8uQZ+Qp4$GA&6-rS` h(iEN%P0bNbA@(7?_b^c8pv4d3?ntK!5*PmxZNPY%CIzaj8qGbl%FIV&A>3jr-4DBh(UpofklBKppAti$kgOaz?(LY0Fy>Y%CIzaj8qGb469B|Wnh@$)4(85$e_T;z@oqq(8j_MDD17k(COznVPB}Y%CIzaj8qGbTvRya2m`|mp9Thj3I+v61{MW|fHoG6AXAgWa)(m10z?>H^&5kW dLxa1&v3Uzr$C+Fldgh=iY|{eI{++J7_k5V literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr11/NA12004.chr11.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr11/NA12004.chr11.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..5a88d80958f1618b8d595be2bfe7c13e8374708d GIT binary patch literal 81 zcmZ>Y%CIzaj8qGb{H8tcG6Ta5p9Thj5(WiE1{MW|BB`obJR(zieJu~=%zNB3JM6-( lX!R@0D{loK{N23o?{oGZ-bJ^zNqaC&5ifGJ2$%pe0sz0}A)WvL literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr11/NA12005.chr11.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr11/NA12005.chr11.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..6055efe7dedad2e472568eff91e757ba3215649b GIT binary patch literal 69 zcmZ>Y%CIzaj8qGbG%XIf%D^zgr-4DBh(UpofklBK#H@pn%ONcwsFmyT4sivWt~uwl ZmNh3u)&@9eN!RH;=_**Lko9ckDgd+27YhIY literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr11/NA12006.chr11.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr11/NA12006.chr11.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..e1364900b76ab95d814fce1bddb3d6668bfbdd1c GIT binary patch literal 74 zcmV-Q0JZ-@T4*^jL0KkKSxp`1ng9TpOn?9oaR49z00bZaP=*8uQZ+Qg9>QcQQcx6y g6wr7@H#Jo_hu9n6a{yD36$j$(NT&)C38TF8Kp9{c)c^nh literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr12/NA12003.chr12.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr12/NA12003.chr12.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..57cf24de4e2223a95bf0c15d1819d26400d975a2 GIT binary patch literal 61 zcmZ>Y%CIzaj8qGbTx)mKk%3``PXmKM1%m=31B(KKArA*vsNu>v7q)+L57->(bpPkM QXDi~wi(D-NCV-R!07ZKh-T(jq literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr12/NA12004.chr12.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr12/NA12004.chr12.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..6fdeed51dbb452c70e6cf581a440fabdf0127139 GIT binary patch literal 66 zcmV-I0KNZ0T4*^jL0KkKS>Z%McmM#HOn?9obO0a$00bZaR5qZ<3Q9n8k(!N&*jpX% YrB6BK3#BIWut^>+~+5i9m literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr12/NA12005.chr12.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr12/NA12005.chr12.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..418994f9c096793d4a2f7b16d827a14ff486f95c GIT binary patch literal 65 zcmZ>Y%CIzaj8qGbJS2Chgn?m(PXmKM5rYCF1B(JfKpP83SBh?tYL^hh39iaevsVot VtarX$#r&~cCAgK7NAZoi0|0h)6!!oC literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr12/NA12006.chr12.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr12/NA12006.chr12.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..978907920add53d41aef6674b2d794f3709555cc GIT binary patch literal 63 zcmZ>Y%CIzaj8qGbT%}^nz`!uWr-4DBkU@cwfklDAkcWdSNLby}=_~i!BJLgU{_f@6 TqjS>#=$(mvA}U&)JO>y66X6qL literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr13/NA12003.chr13.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr13/NA12003.chr13.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..f0ff41dd323a335decb81dfe41db387ba443b317 GIT binary patch literal 73 zcmV-P0Ji@^T4*^jL0KkKSz{m+(EtFLOn?9ocmN;)00bZaP=*8uQZ+Qp5`?7+QKUO$ f1p(kx+|&W${f774#Yd6>NPaHlig2MI#y}~eAL|+1 literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr13/NA12004.chr13.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr13/NA12004.chr13.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..0d5fc433f26196d3afe6433d10f070197f0c359b GIT binary patch literal 74 zcmV-Q0JZ-@T4*^jL0KkKSv#c2pa1}vOn?9obO0a$00bZaR5sO6&=D!=G(`}|1LXnl gF;O-Hx7O4oLQS?TRBT0}FjwO4NT&)C2XvVf0Cd|J`~Uy| literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr13/NA12005.chr13.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr13/NA12005.chr13.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..474e86cb55275409e8819fef97e3b7cf340f6f5d GIT binary patch literal 72 zcmZ>Y%CIzaj8qGbR9bN1F9X92p9ThjA_fIU1{MW|fHoG6kjudyA#WO<{BS6r)im=v b%e~*mY*Q9;u`bc%P_P#-aY%CIzaj8qGb6ycp4%fK+hr-4DBkU@cwfklBKppAtiXm+qM+tdYIPb9f6To%<2 a2rdp`e`tTNywIUW?@3p|LIn+Jt6cz~M-{&S literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr14/NA12003.chr14.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr14/NA12003.chr14.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..a2b975c4d16f5bb6384cd2fdf8388e5d84866001 GIT binary patch literal 61 zcmZ>Y%CIzaj8qGbv<;cJih*H literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr14/NA12004.chr14.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr14/NA12004.chr14.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..c19eee1968b4a3feefd352063e1590a0de980ec4 GIT binary patch literal 61 zcmZ>Y%CIzaj8qGbeD7eM#=tPcr-4DBgh7FkfklDAkcUGsSZd}JuIUdiGENm?`){18 R!Oy)@X^w_R`2y+93;_LT5o`be literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr14/NA12005.chr14.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr14/NA12005.chr14.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..509cb2d287b439986803041e874d5ed59de20696 GIT binary patch literal 61 zcmZ>Y%CIzaj8qGb?C7y|XJDA&)4(85#Gt^)z@orl$ipERe4@=EWRE-t-&q0an>$~# Ru>FZWDe}uM_^fj%zeig2MIobSHijMx{l literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr15/NA12003.chr15.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr15/NA12003.chr15.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..b08b9656638f4710f2e13fe5bf35f16a8b55779b GIT binary patch literal 73 zcmV-P0Ji@^T4*^jL0KkKS#-y-LjVAnOn?9ocmN;)00bZaP=*8uRMS&QQ?d?9lq2K; f-e`(p_YmIuGZ0D!kt!yEkHy@PP81{^G3-#lOoJJ4 literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr15/NA12004.chr15.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr15/NA12004.chr15.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..8a68edc988a0d9eac52d0b2f38990c2ad6c5dca0 GIT binary patch literal 65 zcmZ>Y%CIzaj8qGb+@#~}$G|Ydr-4DBgh7FkfklBKppAv2(?pj+MI@zC`~dTI2X?vZ Vd%guQ9)I-CV>y?Qm}_U|0RT9_6W;&; literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr15/NA12005.chr15.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr15/NA12005.chr15.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..f48cd254721a3d20ae0bbb2e22ff7a8923671bf2 GIT binary patch literal 68 zcmZ>Y%CIzaj8qGbJhhP}ih*Hy+1d7&Tl-a8h3 Y&-?k^Oy<;L`R<)cb2L0sBbsy>0Mfq~Z2$lO literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr15/NA12006.chr15.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr15/NA12006.chr15.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..dcc06d2d4b4c2572e9efa57521ead508ea0a3a2e GIT binary patch literal 64 zcmZ>Y%CIzaj8qGb{21?%$-pqfr-4DBkU@cwfklBKppAvq!^@MF13a4RRj=$Ez$0A0ToZ~y=R literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr16/NA12003.chr16.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr16/NA12003.chr16.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..aca1b7a8763b55eae5eaa9badb352c55b5b4654c GIT binary patch literal 64 zcmZ>Y%CIzaj8qGb6ueN_%fK+hr-4DBfY%CIzaj8qGbw7zJN$iOher-4DBgh7FkfklBKppAtih}ke~itnj;4sz*&!R`gs a`?JM^E-<<>OcDK9t`gkJ$-GyXO#lF)8xyYp literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr16/NA12005.chr16.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr16/NA12005.chr16.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9a94357479918d368949f05dd4ed46bbf919c277 GIT binary patch literal 62 zcmZ>Y%CIzaj8qGb{AJO>$-pqfr-4DBh(UpofklDAkcUIi*GHu@L}9v95yO+Cj30N` SPIRc#d(u^~Q1MHlfDiy1=o6a& literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr16/NA12006.chr16.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr16/NA12006.chr16.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..fe8357bf0db58e85362ab9af6fa3d92aed752700 GIT binary patch literal 69 zcmZ>Y%CIzaj8qGbY~WlS&cHCkr-4DBkU@cwfklBKppAtiXm+qMpHrL1C6R!og0_La ZX9MIL{#V{T%J^aTB+WxDEeyUWq7cc+- literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr17/NA12003.chr17.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr17/NA12003.chr17.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..5491587438a9b77ea1ec3174c21bfc8bc23f1a3e GIT binary patch literal 60 zcmV-C0K@-6T4*^jL0KkKSzcJzO8@|vOn?9ocmN;)00bZaF$@R_l)@QH;3tqxtwArf Sx$C47{x0N-aG@Z)v96XGv=w;( literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr17/NA12004.chr17.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr17/NA12004.chr17.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..7040e9d70815f4c4d99550ed0911b29f2d032fc9 GIT binary patch literal 64 zcmZ>Y%CIzaj8qGbTxP+>%)l_ir-4DBgh7FkfklBK#F>dDY%CIzaj8qGbe0eV^n1Nx2PXmKM5rYCF1B(JfKpP83r-`mg2%iJDioe#fyP`gP YSMF77EJ|TwKYC}PpNNW8`HU$C0G=EbX8-^I literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr17/NA12006.chr17.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr17/NA12006.chr17.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..936e42bb6649a7b8dc371b06b93c7dfc5890f5b1 GIT binary patch literal 71 zcmV-N0J#4`T4*^jL0KkKSu#VKF#rIVOn?9oaR49z00bZaR3cN+0SZ7!FkaDJ) dJc^vo01k(|cRg(sWI-hOyOJrwgn^PA(TK*87kvN# literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr18/NA12003.chr18.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr18/NA12003.chr18.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..7069651ccca44b73369f772179a4836f6c97bdca GIT binary patch literal 60 zcmV-C0K@-6T4*^jL0KkKSs03~`Tzi!On?9ocmN;)00bZaF$@S1Q`EsC0N1oYZd!o< SGPdG?@Vk;J!i0dtRd3KZ;}(?w literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr18/NA12004.chr18.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr18/NA12004.chr18.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..719c31374402d15473af9f6aa9e1f05ec728040e GIT binary patch literal 62 zcmZ>Y%CIzaj8qGb6rK>4&A>3jr-4DBgh7FkfklDAkcUIi*GHveZD5H)5yO+Cj30N` SPIRc#d(u^~P(fW`%{2fF!V|*) literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr18/NA12005.chr18.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr18/NA12005.chr18.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..2928cf343b3de3cfc9b02ab5591bbbe5f0565bd3 GIT binary patch literal 61 zcmZ>Y%CIzaj8qGbTt8`52m`|mp9ThjA_fIU1{MVdLmm!6&ljpp;$G`D_^OVuXQz9z Rus?d|v7Adt^i!x;0{{W<5v2eC literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr18/NA12006.chr18.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr18/NA12006.chr18.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..d24b326dbf9d1ce8653bfb875c7ad6090de1178e GIT binary patch literal 76 zcmV-S0JHx>T4*^jL0KkKS(@_M@c;mrOn?9oaR49z00bZaP=*8uQA|j3T0)kZ1)`Rg if_}yFqH{Q^nh$V0_qTR|8UdjX#oUoj6eK3RwtPVMFC4J| literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr19/NA12003.chr19.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr19/NA12003.chr19.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9733612b48f20530a35a146725c79fd65f8576f0 GIT binary patch literal 74 zcmZ>Y%CIzaj8qGbl%A+t%D^zgr-4DBfY%CIzaj8qGb+`QxGUj~L5J`D^4B@7CT3@i!^hCCdCo-b6nrhD{j@KqgQ&rbJb RVSn__V>y?QSh>9Y0sugv5|jV{ literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr19/NA12005.chr19.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr19/NA12005.chr19.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..eaf2103ed782a850bd94b12be9fba925b24cb20f GIT binary patch literal 63 zcmV-F0Kor3T4*^jL0KkKS@9Cx?f?LoOn?9oasVI!00bZaF$@S1Q`Fj;NT`{_oJ~L* VDuDF$&9Oj!F64@Ep&{ZWyWF4h7?A(~ literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr19/NA12006.chr19.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr19/NA12006.chr19.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..0519557fb38306c13ebe532374e5bce0b216e1a0 GIT binary patch literal 60 zcmZ>Y%CIzaj8qGbv~ZX_k%3``PXmKMA%g-V1B(KKArFUO@RhGd5euvq*iCgPw%(?} QfAr2oKM@r^0hK2X0Qj5{;{X5v literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr2/NA12003.chr2.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr2/NA12003.chr2.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..68b8d8cb510a5cc5f076d3cb620430d19b27abb9 GIT binary patch literal 61 zcmV-D0K)%5T4*^jL0KkKS&8v8tpEU+On?9ocmN;)00bZaF$@R_l4Q|9%8)%Eo#r5$ TTYkH=6XNbjrwS4gJ|=abL&Fqt literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr2/NA12004.chr2.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr2/NA12004.chr2.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..29710f3b9dbcd8e721954cda2aecc34e3a1c25d0 GIT binary patch literal 61 zcmZ>Y%CIzaj8qGbY};qHje%i?PXmKM34;P71B(KKArFUO@Rfr~TH%vj*q*N7|E!&- R!Oy)@X^w`6bG&pk0{|6a5nliR literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr2/NA12005.chr2.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr2/NA12005.chr2.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..e7207c85e5ae7ccf39b0f6997580201d6cf7e7dd GIT binary patch literal 61 zcmZ>Y%CIzaj8qGb4E!|Dn}K15PXmKM5rYCF1B(KKArFUO@CB95I#)jdnHdVEoAXz3 R@Yckh6nW_6=zgkF2LKA55;Fh* literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr2/NA12006.chr2.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr2/NA12006.chr2.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..1e82c82003153e7dcd2a4e6f0f13b535ce5ec3fa GIT binary patch literal 60 zcmV-C0K@-6T4*^jL0KkKS^lHpr~m+%On?9oaR49z00bZaF$@S1N$4dF(kgO*=d3_> Swsep{elFySaG@dnN5fE0a}~S* literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr20/NA12003.chr20.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr20/NA12003.chr20.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..e46f8375224e977e022627265b2af5636c076dcb GIT binary patch literal 64 zcmV-G0Kfl2T4*^jL0KkKS$xmVaR30AOn?9ocmN;)00bZaP=*8rDNjkGAm$+Yh3}k# W?mNG3?MpEy;_gVN3K9>Q`OYAx#~0fG literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr20/NA12004.chr20.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr20/NA12004.chr20.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..901c941be7eb200a88420fd5ee654bceb4c3f04f GIT binary patch literal 65 zcmV-H0KWf1T4*^jL0KkKSq5#D*#H2TOn?9obO0a$00bZaP=*8ul=PY+ra(~gfcKaH XI~~5ZqLL#Zq49SlQ-uitX4zeko39qb literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr20/NA12005.chr20.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr20/NA12005.chr20.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..0286e12e82e9153a5bff204ccff9efcf587e8631 GIT binary patch literal 60 zcmZ>Y%CIzaj8qGbd~n8R4+Fytp9ThjA_fIU1{MVdLmm#n;45E^A{JOJu$$^oY`sl` Q|LC2Gej+Ls#=`mx04{_QLjV8( literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr20/NA12006.chr20.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr20/NA12006.chr20.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..0519557fb38306c13ebe532374e5bce0b216e1a0 GIT binary patch literal 60 zcmZ>Y%CIzaj8qGbv~ZX_k%3``PXmKMA%g-V1B(KKArFUO@RhGd5euvq*iCgPw%(?} QfAr2oKM@r^0hK2X0Qj5{;{X5v literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr21/NA12003.chr21.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr21/NA12003.chr21.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..1b8e8a4b8d568c1d8b4e0fd2f85e6be982ba1426 GIT binary patch literal 72 zcmV-O0Jr}_T4*^jL0KkKS!&mNHvj;bOn?9ocmN;)00bZaR5npG!3scTBSNJExX4-x eJc^voDyD<=CVOt61+WE*@Vk;J!i0lXyVuTcBp=*j7=RI*7|;L! literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr21/NA12005.chr21.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr21/NA12005.chr21.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..175df8b9f9efeaa9b17855e14c551876a3ba54ad GIT binary patch literal 65 zcmZ>Y%CIzaj8qGboEggy!@w}Zr-4DBh(UpofklBKppAvqtIF3`SK+;i_wfb3yP1+- V-TSS>*?;uTL_ZM~wQvV<1^`+#6ej=x literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr21/NA12006.chr21.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr21/NA12006.chr21.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..d000d6bf1bd26904815d346e43e5d8c6fc81b3b2 GIT binary patch literal 64 zcmZ>Y%CIzaj8qGb<{9 literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr22/NA12003.chr22.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr22/NA12003.chr22.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..df8ed4e019624a1f61ceece31539d9ab6a9891b1 GIT binary patch literal 77 zcmV-T0J8r=T4*^jL0KkKS#5?nnE(KoOn?9ocmN;)00bZaP=*8uQZ+Qp0)~`mM!OC{ jLiiOoG(|YSVjJIc1mqz|r7c91#rV6DDZ+$Y%CIzaj8qGbREg%vW?-1%)4(85!l1y&z@orl$ipERd_kpSWu2dZ%nSw7&H1Z1 Rcxz%$iad03n3!X@1_0N85rqH% literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr22/NA12005.chr22.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr22/NA12005.chr22.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..45979aa6b045b5726b6e9cf33838efbf1f1c79b9 GIT binary patch literal 79 zcmV-V0I>f;T4*^jL0KkKS=~j3P5=OyOn?9oasVI!00bZaY7%;>03t-wIm;Nf#84I6 la%iv+WMc?uC}m&(+NbHyZPRf8B&sWZF64@Ep&`1944mv%9E1P> literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr22/NA12006.chr22.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr22/NA12006.chr22.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..5e9a8cf72cef1b64f03a475a876819d436c5715a GIT binary patch literal 79 zcmV-V0I>f;T4*^jL0KkKS!XG1;{X7dOn?9oaR49z00bZabqPIHGytfS+L>8kIa4f_ lhe0uTcBpJ$EIKbY@9A^Lk literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr3/NA12003.chr3.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr3/NA12003.chr3.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..e1d4d9c329f447a3e1aa3aadfbc8e8c579211565 GIT binary patch literal 74 zcmZ>Y%CIzaj8qGbRDLk~4g35KE14bprqvq!wfV literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr3/NA12004.chr3.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr3/NA12004.chr3.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..b14a26a07fd993ef67ce204c524308107f1f8166 GIT binary patch literal 71 zcmZ>Y%CIzaj8qGb{M%b-!oV=Yr-4DBgh7FkfklBKppAti$kgPFwVuihSg7~PVY%q!9vB~QjanK1)~^p literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr3/NA12005.chr3.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr3/NA12005.chr3.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..ae85583170d06015e9ee70ef602924e594efb7b2 GIT binary patch literal 76 zcmV-S0JHx>T4*^jL0KkKSz^wpWdHz}On?9oasVI!00bZaP=*8uQZ+QpS_SNx3Q*M| iQQ%bE)fD3WfNy=wK;(l;lmkQ`i@744C`d79R5F0KjvGAy literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr3/NA12006.chr3.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr3/NA12006.chr3.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..8ca1d4febb8613a35a6f8e34f9858c84b0e856ef GIT binary patch literal 76 zcmZ>Y%CIzaj8qGbbelcJoq=J7PXmKMA%g-V1B(JfKpP83kg3TTE^A3mr(lmM6HS`k g8-j}+gS%?G_kK5IpRn3dY%CIzaj8qGb><&4U!oV=Yr-4DBfdDIG9tRJA^x&a!2uK)m;On?9obO0a$00bZaR3$XfVG&G)pfU*{p$Mi$ aJSv-XKzNzRzCH$rxt< literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr4/NA12005.chr4.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr4/NA12005.chr4.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..bfa295fde0b375b71d628bf7e0d1cb991c664347 GIT binary patch literal 69 zcmZ>Y%CIzaj8qGbJn&gy3j@Opp9ThjA_fIU1{MW|fHoG6Kp#(Wg(#MNNBJ4}jk{K^ XFR=c;y+k8)sg%8Vk*h_(1duiWy($(p literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr4/NA12006.chr4.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr4/NA12006.chr4.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..4f169969ba206abfb84019c4cfe17ff575f8ea76 GIT binary patch literal 64 zcmZ>Y%CIzaj8qGbG&=3KiGg8;PXmKMA%g-V1B(Jfh%*z@R4KJt?51H^-6vx2Cv1MZ U`+Qo8z{hfx;8sp%oh`2w0AxB9RsaA1 literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr5/NA12003.chr5.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr5/NA12003.chr5.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..e812d8fbd60b98fd1b6c8cb4065875624542c75e GIT binary patch literal 71 zcmV-N0J#4`T4*^jL0KkKS(ZyFmjD2mOn?9ocmN;)00bZaP=*8uQkzpV1DS~u6aqvP dAxx3fMBLQ@_+R&(+)y72xgwk>NJ}M@%Ye$@7Ulo| literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr5/NA12004.chr5.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr5/NA12004.chr5.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..b978498b0bc2b086501a8b42a35cf3682723d844 GIT binary patch literal 69 zcmV-L0J{G|T4*^jL0KkKStq(3IRF5dOn?9obO0a$00bZaP=*8uQkzpV7MGEd(ya?Y bK%E6m%}^hg{pWWS2g2@1rwS4T_d};3syP;C literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr5/NA12005.chr5.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr5/NA12005.chr5.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..f60e08d41baf52c399a488ffebd55846de5446e6 GIT binary patch literal 71 zcmZ>Y%CIzaj8qGbY@K=9k%3``PXmKM5rYCF1B(JfKpP83kg3U;sJLU^UR!ionJPrh bO++pBC%vyd!|JF1=$*%ME+K)i=AZa-cLZ^TS exztqG>>l&mx*3jARN2^ literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr6/NA12004.chr6.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr6/NA12004.chr6.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..1c94aff643f6c77595e5a5ca61015f277eb52048 GIT binary patch literal 70 zcmZ>Y%CIzaj8qGbY%CIzaj8qGbT++PXmKM5rYCF1B(JfKpP83(ClDiQOzia%B) c6!I!<)KtOk9p|#5rVqv3kxmpOF_SEy!0&z-RR910 literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr7/NA12003.chr7.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr7/NA12003.chr7.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..8d0eb4604c697de5803bdb9a93ceb81874155558 GIT binary patch literal 70 zcmV-M0J;A{T4*^jL0KkKS-#0n{r~`&On?9ocmN;)00bZaP=*8uQ4>iJ$)O%dY%CIzaj8qGblt^((XJDA&)4(85!l1y&z@oqq(8j_M#BAWOB)sqmY%CIzaj8qGbT=&1pkbz-_PXmKM5rYCF1B(JfKpP83ps=UF$t6w=mNP0tt>?P> c@^7d&y03I_J^Z)<= literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr7/NA12006.chr7.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr7/NA12006.chr7.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..dcc289f341fd36e2d50fcd48c7f581b0c573802c GIT binary patch literal 74 zcmZ>Y%CIzaj8qGblEj>_Z> jC=?zMP0ayLA@(V~_c2$JEe#?=N8;{CrwS4mUcp`9k$@SB literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr8/NA12004.chr8.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr8/NA12004.chr8.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9fe74e90bad2a10aab6fd1e26b8aa6b133bb0851 GIT binary patch literal 75 zcmV-R0JQ%?T4*^jL0KkKS+e%$S^xl;On?9obO0a$00bZaP=*8uQZ+QpDM|>Em$GCn h2|~~m2Y^#^Lp*Pn84&;g literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr8/NA12005.chr8.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr8/NA12005.chr8.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..2831fedcc1f292179f383b10502155bb331cf47d GIT binary patch literal 78 zcmZ>Y%CIzaj8qGbtTy_@$-pqfr-4DBh(UpofklC#NU@Pgq}SJ&E2ybymQ(ZQNg^Bp im8|9_tQP7wmVLi-)X#yJ!P&oir_vk^58IiQEDZoY%CIzaj8qGbba}fboPlA6PXmKMA%g-V1B(JfKpP835VK+6okbN6m2(7r%LU&3 XT_bu?;lc%$13~fPMXnYB6F}Mk;tdz> literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr9/NA12003.chr9.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr9/NA12003.chr9.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9cf34b914dbb3d5f8c3124357853e888c6e15d68 GIT binary patch literal 62 zcmZ>Y%CIzaj8qGb%*>v!gn?m(PXmKM1%m=31B(KKArFV3=1UVt#*_1r)ogc<4p literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr9/NA12005.chr9.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr9/NA12005.chr9.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..64b3334102c94adbd7fbd23f4862ef4624def35a GIT binary patch literal 67 zcmV-J0KES~T4*^jL0KkKS>@Wq2><|?On?9oasVI!00bZaR3wcw1StUnlBu}^AZVoW Zs&hCXIu7K{ZHNWp?ntK!5*)i&fgrR`79{`x literal 0 HcmV?d00001 diff --git a/tests/testthat/fixtures/demoGenoChr/chr9/NA12006.chr9.vcf.bz2 b/tests/testthat/fixtures/demoGenoChr/chr9/NA12006.chr9.vcf.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..47d31ea3cf35c82104a49fb8c593e0eea0ae5777 GIT binary patch literal 62 zcmZ>Y%CIzaj8qGblrG Date: Fri, 18 Aug 2023 21:46:42 -0400 Subject: [PATCH 142/385] Update doc for prepSynthetic() function --- R/synthetic.R | 2 +- man/prepSynthetic.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/synthetic.R b/R/synthetic.R index 5fec8f602..9b5eee0f6 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -195,7 +195,7 @@ splitSelectByPop <- function(dataRef) { #' "Sample.Type" entries are always set to 'Synthetic'. #' #' The synthetic profiles are assigned unique names by combining: -#' [prefix].[data.id.profile].[listSampleRef].[simulation number(1 to nbSim)] +#' \code{prefix}.\code{data.id.profile}.\code{listSampleRef}.\code{simulation number(1 to nbSim)} #' #' @param fileProfileGDS a \code{character} string representing the file name #' of the Profile GDS file containing the information about the reference diff --git a/man/prepSynthetic.Rd b/man/prepSynthetic.Rd index 3e879485e..f4a8b1b38 100644 --- a/man/prepSynthetic.Rd +++ b/man/prepSynthetic.Rd @@ -63,7 +63,7 @@ the Profile GDS file "study.annot" node. Both the "Source" and the "Sample.Type" entries are always set to 'Synthetic'. The synthetic profiles are assigned unique names by combining: -\link{prefix}.\link{data.id.profile}.\link{listSampleRef}.\link{simulation number(1 to nbSim)} +\code{prefix}.\code{data.id.profile}.\code{listSampleRef}.\code{simulation number(1 to nbSim)} } \examples{ From cb57375b03d088b14b23bc13f027e9869f5a7483 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 18 Aug 2023 21:48:24 -0400 Subject: [PATCH 143/385] Update doc for validateComputeSyntheticRoc() function --- R/synthetic_internal.R | 3 +-- man/validateComputeSyntheticRoc.Rd | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/R/synthetic_internal.R b/R/synthetic_internal.R index 393ef80f6..46eeb526b 100644 --- a/R/synthetic_internal.R +++ b/R/synthetic_internal.R @@ -235,8 +235,7 @@ validatePepSynthetic <- function(fileProfileGDS, #' @title Validate input parameters for computeSyntheticROC() function #' #' @description This function validates the input parameters for the -#' \code{\link{computeSyntheticROC}} function. -#' +#' [computeSyntheticROC()] function. #' #' @param matKNN a \code{data.frame} containing the inferred ancestry results #' for fixed values of _D_ and _K_. On of the column names of the diff --git a/man/validateComputeSyntheticRoc.Rd b/man/validateComputeSyntheticRoc.Rd index b2924f4e4..6e13bcd97 100644 --- a/man/validateComputeSyntheticRoc.Rd +++ b/man/validateComputeSyntheticRoc.Rd @@ -43,7 +43,7 @@ the list of all possible ancestry assignations.} } \description{ This function validates the input parameters for the -\code{\link{computeSyntheticROC}} function. +\code{\link[=computeSyntheticROC]{computeSyntheticROC()}} function. } \examples{ From 9ed8a317470f69bd0c39f5c02354ca62a8f87bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Fri, 18 Aug 2023 22:00:55 -0400 Subject: [PATCH 144/385] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b9aa5f80b..88b658e4a 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ alterations, such as those caused by cancer. ## Authors ## [Pascal Belleau](http://ca.linkedin.com/in/pascalbelleau "Pascal Belleau"), -[Astrid Deschênes](http://ca.linkedin.com/in/astriddeschenes "Astrid Deschênes"), +[Astrid Deschênes](https://www.linkedin.com/in/astriddeschenes "Astrid Deschênes"), David A. Tuveson and [Alexander Krasnitz](https://www.cshl.edu/research/faculty-staff/alexander-krasnitz/ "Alexander Krasnitz") From a6d479464d2b7f312fdb4d5aeaeb4103e15af603 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 18 Aug 2023 22:22:10 -0400 Subject: [PATCH 145/385] Removed loop testEmptyBox --- R/allelicFraction_internal.R | 30 +++++++++++++----------------- man/generateGDSSNPinfo.Rd | 6 +++--- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 25150df1b..a16fb931e 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -1313,27 +1313,23 @@ testEmptyBox <- function(matCov, pCutOff=-3) { vMean <- 0.5 matCov$pWin <- rep(1, nrow(matCov)) - for (i in seq_len(nrow(matCov))) { + matTmp <- apply(matCov[, c("cnt.alt", "cnt.ref")], 1, + FUN=function(x){ + vCur1 <- ifelse(x[1] <= x[2], + x[1], x[2]) - ## Always use the small count as input - vCur1 <- ifelse(matCov$cnt.alt[i] <= matCov$cnt.ref[i], - matCov$cnt.alt[i], matCov$cnt.ref[i]) - - ## Calculate the probability with assumption 0f 0.5 ratio - pCur <- pbinom(q=vCur1, size=matCov$cnt.ref[i] + matCov$cnt.alt[i], - prob=vMean) + pCur <- pbinom(q=vCur1, size=x[2] + x[1], + prob=vMean) - ## Ensure value is not below 0.01 - pCurO <- max(1 - max(2 * pCur, 0.01), 0.01) + pCurO <- max(1 - max(2 * pCur, 0.01), 0.01) - ## Twice the probability (2 tails) - matCov$pWin[i] <- pCur * 2 + return(c(vCur1, pCur, pCurO)) + }) + matCov$pWin <- matTmp[2, ] * 2 + tmp <- which(matTmp[2,] > 0.01) + p <- sum(log10(matTmp[2,tmp])) + (ncol(matTmp) - length(tmp)) * log10(0.01) + p0 <- sum(log10(matTmp[3,])) - ## Similar to likelihood for imbalance - p <- p + log10(max(pCur, 0.01)) - ## Similar to likelihood for not imbalance ( 1- probability) - pO <- pO + log10(pCurO) - } ## Calculate a global statistic using all SNVs ## The region is imbalance or not diff --git a/man/generateGDSSNPinfo.Rd b/man/generateGDSSNPinfo.Rd index e41fad72f..6cd746ef2 100644 --- a/man/generateGDSSNPinfo.Rd +++ b/man/generateGDSSNPinfo.Rd @@ -3,7 +3,7 @@ \encoding{UTF-8} \name{generateGDSSNPinfo} \alias{generateGDSSNPinfo} -\title{Add information related to SNVs into a Reference GDS file} +\title{Add information related to SNVs into a Population Reference GDS file} \usage{ generateGDSSNPinfo(gdsReference, fileFreq, verbose) } @@ -21,8 +21,8 @@ to show how the different steps in the function.} The integer \code{0L} when successful. } \description{ -the function adds the SNV information into a Reference -GDS file. +The function adds the SNV information into a Population +Reference GDS file. } \examples{ From 33570c7ad8a70d556bf732446ba6b4b09adf742f Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 18 Aug 2023 22:31:53 -0400 Subject: [PATCH 146/385] Remove documents in doc directory --- doc/README_1KG_GDS.md | 152 ----------------------- doc/README_GDS.struct.md | 106 ---------------- doc/README_StudyInit.md | 257 --------------------------------------- 3 files changed, 515 deletions(-) delete mode 100644 doc/README_1KG_GDS.md delete mode 100644 doc/README_GDS.struct.md delete mode 100644 doc/README_StudyInit.md diff --git a/doc/README_1KG_GDS.md b/doc/README_1KG_GDS.md deleted file mode 100644 index 0b5999f0e..000000000 --- a/doc/README_1KG_GDS.md +++ /dev/null @@ -1,152 +0,0 @@ -# Generate the 1000 genomes GDS file # - -Preparation of the 1000 genomes (1KG) GDS file for RAIDS - -## Authors ## - -[Pascal Belleau](http://ca.linkedin.com/in/pascalbelleau "Pascal Belleau"), -[Astrid Deschênes](http://ca.linkedin.com/in/astriddeschenes "Astrid Deschênes") and -[Alexander Krasnitz](https://www.cshl.edu/research/faculty-staff/alexander-krasnitz/ "Alexander Krasnitz") - -## Download needs ## - -you need to download the vcf files from GRCh38 -The files used are (add ref): - - ftp.1000genomes.ebi.ac.uk/vol1/ftp/data_collections/1000_genomes_project/release/20181203_biallelic_SNV/ALL.chr*.shapeit2_integrated_v1a.GRCh38.20181129.phased.vcf.gz* - - -You need a pedigree file for the description of the samples - - ftp://ftp.1000genomes.ebi.ac.uk/vol1/ftp/technical/working/20130606_sample_info/20130606_g1k.ped - -## Prepare a rds file in R from the pedigree file ## - -In R: - - library(RAIDS) - ## pedigree file from 1KG with the path - ## If the file is in the current directory - filePED1KGOri <- "20130606_g1k.ped" - ped <- prepPed1KG(filePED1KGOri) - ## save the RDS file here we - ##save the file in data/metadata/ped1KG.rds - filePED1KG <- file.path("data", "metadata","ped1KG.rds") - saveRDS(ped, filePED1KG) - - - -## Prepare intermediate files based on 1KG vcf for GDS - -We generate some intermediate files to prepare the data to be import in R GDS file (Bioconductor gdsfmt) - -Generate a file with the SNP position and the frequence in each super population. - -PATHVCF is the path to the vcf files from 1KG -The script generates the matFreq.${chr}.txt -We will change extract1000gFreq.py soon. - - - for i in `ls PATHVCF/*shapeit2_integrated_v1a.GRCh38.20181129.phased.vcf.gz` - do - chr=$(echo $FILECUR|perl -n -e '/ALL\.(chr[^\.]+)/;print $1') - python PATH2SCRIPT/extract1000gFreq.py ${FILECUR} matFreq.${chr} - done - for i in `seq 1 22` - do - cat matFreq.chr${i}.txt >matFreqSNV.txt - bzip2 matFreqSNV.txt - done - - -Generate a list of SNP with frequency higher then a cutoff (here 0.01) for at least 1 super population. - -The file is mapSNVSel.rds - -In R: - - library(RAIDS) - - fileSNV.v <- file.path(PATHGENO, "matFreqSNV.txt.bz2") - fileLSNP.v <- file.path(PATHSEL, "listSNP.rds") - fileFREQ.v <- file.path(PATHSEL, "mapSNVSel.rds") - generateMapSnvSel(cutOff = 0.01, - fileSNV = fileSNV.v, - fileLSNP = fileLSNP.v, - fileFREQ = fileFREQ.v) - - - -## Split the VCF by sample - -NOTE: Should be implemented - -## Generate the base GDS file with 1KG - - library(RAIDS) - - filePED1KG <- file.path(PATHMETA,"ped1KG.rds") - fileSNV.v <- file.path(PATHGENO, "matFreqSNV.txt.bz2") - fileLSNP.v <- file.path(PATHSEL, "listSNP.rds") - fileFREQ.v <- file.path(PATHSEL, "mapSNVSel.rds") - - fileNameGDS <- "matGeno1000g.gds" - fileGDS <- file.path(PATHGDS, fileNameGDS) - fileIBD <- file.path(PATHMETA,"ibd.All.0.05.rds") - filePart <- file.path(PATHMETA,"part.All.0.05.rds") - - # Generate the base structure of the gds file - generateGDS1KG(PATHGENO = file.path("data", "sampleGeno"), - fileNamePED = filePED1KG, - fileSNPSel = fileFREQ.v, - fileListSNP = fileLSNP.v, - fileNameGDS = fileGDS) - - # Identify the individual related - gds <- snpgdsOpen(fileGDS) - identifyRelative(gds, - maf = 0.05, - thresh = 2^(-11/2), - fileIBD = fileIBD, - filePart = filePart) - closefn.gds(gds) - - # create the ref sample list which correspond - # to the list of sample unrelated - - addRef2GDS1KG(fileGDS, - filePart) - - -## The base GDS for 1KG - - File: fileGDS (15.4G) - + [ ] * - # The id for the genotype - |--+ sample.id { Str8 2548, 19.9K } - # data.frame for the annotation of sample - # for all genotype good for the reference - # samples but sn other data.frame will be - # define to describe the samples - # in the studies - |--+ sample.annot [ data.frame ] * - | |--+ sex { Str8 2548, 5.0K } - # population - | |--+ pop.group { Str8 2548, 10.0K } - # The 5 super populations in - | |--+ superPop { Str8 2548, 10.0K } - | \--+ batch { Float64 2548, 19.9K } - |--+ snp.id { Str8 24542710, 223.5M } - |--+ snp.chromosome { UInt16 24542710, 46.8M } - |--+ snp.position { Int32 24542710, 93.6M } - |--+ snp.allele { Str8 24542710, 93.6M } - |--+ snp.AF { PackedReal24 24542710, 70.2M } - |--+ snp.EAS_AF { PackedReal24 24542710, 70.2M } - |--+ snp.EUR_AF { PackedReal24 24542710, 70.2M } - |--+ snp.AFR_AF { PackedReal24 24542710, 70.2M } - |--+ snp.AMR_AF { PackedReal24 24542710, 70.2M } - |--+ snp.SAS_AF { PackedReal24 24542710, 70.2M } - |--+ genotype { Bit2 24542710x2548, 14.6G } - \--+ sample.ref { Bit1 2548, 319B } - - diff --git a/doc/README_GDS.struct.md b/doc/README_GDS.struct.md deleted file mode 100644 index 63d8ef406..000000000 --- a/doc/README_GDS.struct.md +++ /dev/null @@ -1,106 +0,0 @@ -# GDS file structure - - -## The base for 1KG - - File: /mnt/wigclust5/data/unsafe/belleau/process1000G/samples1000gUnrelated/data/genoGDS1KG.2022.03.22/matGeno1000g.gds (15.4G) - + [ ] * - |--+ sample.id { Str8 2548, 19.9K } - |--+ sample.annot [ data.frame ] * - | |--+ sex { Str8 2548, 5.0K } - | |--+ pop.group { Str8 2548, 10.0K } - | |--+ superPop { Str8 2548, 10.0K } - | \--+ batch { Float64 2548, 19.9K } - |--+ snp.id { Str8 24542710, 223.5M } - |--+ snp.chromosome { UInt16 24542710, 46.8M } - |--+ snp.position { Int32 24542710, 93.6M } - |--+ snp.allele { Str8 24542710, 93.6M } - |--+ snp.AF { PackedReal24 24542710, 70.2M } - |--+ snp.EAS_AF { PackedReal24 24542710, 70.2M } - |--+ snp.EUR_AF { PackedReal24 24542710, 70.2M } - |--+ snp.AFR_AF { PackedReal24 24542710, 70.2M } - |--+ snp.AMR_AF { PackedReal24 24542710, 70.2M } - |--+ snp.SAS_AF { PackedReal24 24542710, 70.2M } - |--+ genotype { Bit2 24542710x2548, 14.6G } - \--+ sample.ref { Bit1 2548, 319B } - -If we add the information relative to specific studies we want to -infer the ancestry. - - File: /mnt/wigclust15/data/unsafe/belleau/TCGA-OV-WXS/data/genoGDS1KG.TCGA-OV.2022.03.30/matGeno1000g.gds (15.5G) - + [ ] * - |--+ sample.id { Str8 2558, 20.2K } - |--+ sample.annot [ data.frame ] * - | |--+ sex { Str8 2558, 5.0K } - | |--+ pop.group { Str8 2558, 10.2K } - | |--+ superPop { Str8 2558, 10.0K } - | \--+ batch { Float64 2558, 20.0K } - |--+ snp.id { Str8 24516859, 223.2M } - |--+ snp.chromosome { UInt16 24516859, 46.8M } - |--+ snp.position { Int32 24516859, 93.5M } - |--+ snp.allele { Str8 24516859, 93.5M } - |--+ snp.AF { PackedReal24 24516859, 70.1M } - |--+ snp.EAS_AF { PackedReal24 24516859, 70.1M } - |--+ snp.EUR_AF { PackedReal24 24516859, 70.1M } - |--+ snp.AFR_AF { PackedReal24 24516859, 70.1M } - |--+ snp.AMR_AF { PackedReal24 24516859, 70.1M } - |--+ snp.SAS_AF { PackedReal24 24516859, 70.1M } - |--+ genotype { Bit2 24516859x2558, 14.6G } - |--+ sample.ref { Bit1 2548, 319B } - |--+ study.offset { Int32 1, 4B } - |--+ study.list [ data.frame ] * - | |--+ study.id { Str8 1, 14B } - | |--+ study.desc { Str8 1, 16B } - | \--+ study.platform { Str8 1, 4B } - \--+ study.annot [ data.frame ] * - |--+ data.id { Str8 10, 170B } - |--+ case.id { Str8 10, 130B } - |--+ sample.type { Str8 10, 140B } - |--+ diagnosis { Str8 10, 20B } - |--+ source { Str8 10, 60B } - \--+ study.id { Str8 10, 140B } - - -## The phase GDS for 1KG - -It includes the linkage disequilibrium and the gene info -for the allelic of the RNA seq (Not show yet) - - File: /mnt/wigclust6/data/unsafe/belleau/process1000G/samples1000gUnrelated/data/genoGDS1KG.2022.04.03/matPhase1000g.gds (5.1G) - + [ ] - \--+ phase { Bit2 24516859x2548 LZ4_ra(35.0%), 5.1G } - - -## A group of GDS specific to each sample we want to infor - -Principaly use for the simulation - - File: /mnt/wigclust15/data/unsafe/belleau/TCGA-OV-WXS/data/genoGDS1KG.TCGA-OV.samples/TCGA-25-2404-01A-01W-0799-08.gds (164.1M) - + [ ] - |--+ Ref.count { SparseInt16 24516859x1, 7.2M } - |--+ Alt.count { SparseInt16 24516859x1, 1.0M } - |--+ Total.count { SparseInt16 24516859x1, 7.6M } - |--+ pruned.study { Str8 237908, 2.2M } - |--+ sampleStudy { Str8 1, 29B } - |--+ sample.id { Str8 2470, 19.3K } - |--+ snp.id { Str8 237908, 2.2M } - |--+ snp.chromosome { Int32 237908, 929.3K } - |--+ snp.position { Int32 237908, 929.3K } - |--+ snp.index { Int32 237908, 929.3K } - |--+ genotype { Bit2 237908x2470, 140.1M } - |--+ SamplePos { Float64 1, 8B } - |--+ lap { PackedReal8 237908, 232.3K } - \--+ segment { UInt32 237908, 929.3K } - - -## A GDS phase specific for a study with with a smaller number of SNV - -The snp.id are the union the snp.id of GDSSample - -File: /mnt/wigclust15/data/unsafe/belleau/TCGA-OV-WXS/data/genoGDS1KG.TCGA-OV.samples/phase1KG.gds (434.6M) -+ [ ] -|--+ snp.id { Str8 722473, 6.6M } -|--+ snp.index { Int32 722473, 2.8M } -\--+ phase { Bit2 722473x2469, 425.3M } - - diff --git a/doc/README_StudyInit.md b/doc/README_StudyInit.md deleted file mode 100644 index 5fb7b77fd..000000000 --- a/doc/README_StudyInit.md +++ /dev/null @@ -1,257 +0,0 @@ -# Initialize a study - -You need a mapped BAM with the same genome than the -reference here (hg38 for 1KG) -for each sample. - -## Extract the read at each in the GDS - -We used here snp-pileup from Facet - -First you a vcf file with the SNV you want to keep - -## Create a VCF file with the SNV you want tokeep -In R - library(RAIDS) - - gds <- snpgdsOpen(fileGDS1kg) - snvListVCF(gds, fileOUT, offset = 1) - closefn.gds(gds) - -You should compress and indexing the vcf file -You need to install [HTSlib](http://www.htslib.org/download/) - -in a terminal - - bgzip fileOUT - tabix -p vcf fileOUT.gz - - - -You need a ped file with the column: - -"sample.id"* Id of the sample but the sample can be genotyped more than one -"sex"* -"pop.group"* can be self declare or something else but must be there -"superPop"* can be self declare or something else but must be there -"Sample.Type"* Ex Primary Tumor or Blood Derived Normal -"Diagnosis"* C or N (cancer normal) this is for the sample not the patient -"Source"* The tissue ex Ovary -"Recurrent" -"Case.ID" Patient identifiant -"Name.ID"* This the unique id of the table -"batch" Number - -You need the extra code in the package Facet to extract the SNV -[snp-pileup](https://github.com/mskcc/facets/tree/master/inst/extcode) - -The output from snp-pileup should be Name.ID.txt -(snp-pileup add .gz to the filename) - - - snp-pileup -g -d5000 -q15 -Q20 -r0 VCFGenerateAbove snvSel0.01.vcf.gz OUTPUT.txt FILEBAM.bam - - - -NOTE: change the path to something generic - -You add the genotype call from the SNP-pileup to -the gds 1KG and create a GDS file for each sample. -with the covereage information - -in R: - - library(RAIDS) - - PATHGENO <- file.path("data", "snpCancer") - PATHMETA <- file.path("data", "metadata") - PATHGDS <- file.path("data", "genoGDS1000gAF.All.TCGA_OV.WXS") - - fileNamePED <- "pedTCGA_OV_WXS_C.rds" - fileNameGDS <- "matGeno1000g.gds" - - filePED <- file.path(PATHMETA, fileNamePED) - fileNameGDS <- file.path(PATHGDS, fileNameGDS) - - ped <- readRDS(filePED) - - studyDF <- data.frame(study.id = "TCGA-OV.WXS.C", - study.desc = "Ovarian example", - study.platform = "WXS", - stringsAsFactors = FALSE) - - listSamples <- ped[, "Name.ID"] - appendStudy2GDS1KG(PATHGENO = PATHGENO, - fileNamePED = filePED, - fileNameGDS = fileNameGDS, - listSamples = listSamples, - studyDesc = studyDF, - batch = 1) - - - - - -The gds per sample at this step - + [ ] - |--+ Ref.count { SparseInt16 24516859x1, 7.2M } - |--+ Alt.count { SparseInt16 24516859x1, 1.0M } - |--+ Total.count { SparseInt16 24516859x1, 7.6M } - |--+ sampleStudy { Str8 1, 29B } - -It the coverage it define at each position in the GDS 1KG - -We select a subset of SNV pruned SNV - -I include a R script with the possibility to run it in parallele -on mutliple instance. - - Rscript ${PATHRSCRIPT}/runPruningStudy1KG.R ${PATHPKG} ${PATHGDS} matGeno1000g.gds $SGE_TASK_ID $PATHOUT $FILEPREF $STUDYNAME - -or in R - - library(RAIDS) - - # fileNameGDS with the sample and 1KG genotype - # listSamples list of sample.id from the study - # PATHSAMPLEGDS is the path where the gds specific - # to the sample is created - - gds <- snpgdsOpen(fileNameGDS) - - for(i in seq_len(length(listSamples))){ - print(system.time(pruned <- pruningSample(gds=gds, - method="corr", - sampleCurrent = listSamples[i], - listSNP = NULL, - slide.max.bp.v = 5e5, - ld.threshold.v=sqrt(0.1), - np = 1, - verbose.v=FALSE, - chr = NULL, - minAF.SuperPop = NULL, - keepGDSpruned = TRUE, - PATHSAMPLEGDS = PATHSAMPLEGDS, - keepFile = FALSE))) - } - - Sys.time() - closefn.gds(gds) - -The function pruningSample add the snp.id of the snp selected -in the pruning process to the gds Sample - - + [ ] - |--+ Ref.count { SparseInt16 24516859x1, 7.2M } - |--+ Alt.count { SparseInt16 24516859x1, 1.0M } - |--+ Total.count { SparseInt16 24516859x1, 7.6M } - |--+ sampleStudy { Str8 1, 29B } - |--+ pruned.study { Str8 237908, 2.2M } - - -NOTE -Add genotype only for the snp selected in pruning to gdsSample - - library(RAIDS) - - # fileNameGDS1KG the file to the gds1KG - # PATHSAMPLEGDS the path where the files gdsSample - - gds <- snpgdsOpen(fileNameGDS1KG) - listGDSSample <- dir(PATHSAMPLEGDS, pattern = ".+.gds") - - for(gdsSampleFile in listGDSSample){ - print(system.time(add1KG2SampleGDS(gds, file.path(PATHSAMPLEGDS, gdsSampleFile) ))) - } - - -see GDSSample - - + [ ] - # Ref.count, Alt.count, Total.count are - # all the snv from 1KG - |--+ Ref.count { SparseInt16 24516859x1, 7.2M } - |--+ Alt.count { SparseInt16 24516859x1, 1.0M } - |--+ Total.count { SparseInt16 24516859x1, 7.6M } - # Genotype from pruning - |--+ sampleStudy { Str8 1, 29B } - |--+ pruned.study { Str8 237908, 2.2M } - |--+ sample.id { Str8 2470, 19.3K } - |--+ snp.id { Str8 237908, 2.2M } - |--+ snp.chromosome { Int32 237908, 929.3K } - |--+ snp.position { Int32 237908, 929.3K } - |--+ snp.index { Int32 237908, 929.3K } - |--+ genotype { Bit2 237908x2470, 140.1M } - |--+ SamplePos { Float64 1, 8B } - |--+ lap { PackedReal8 237908, 232.3K } - \--+ segment { UInt32 237908, 929.3K } # not sure I keep it - - -Section annotation study - |--+ study.list [ data.frame ] * - | |--+ study.id { Str8 1, 9B } - | |--+ study.desc { Str8 1, 13B } - | \--+ study.platform { Str8 1, 4B } - \--+ study.annot [ data.frame ] * - |--+ data.id { Str8 188, 1.1K } - |--+ case.id { Str8 188, 1.1K } - |--+ sample.type { Str8 188, 376B } - |--+ diagnosis { Str8 188, 376B } - |--+ source { Str8 188, 1.7K } - \--+ study.id { Str8 188, 1.7K } -Not yet the good struct for option 1 and 2 - -option 1 all the hetero from ex varscan - - |--+ Ref.count.o { SparseInt16 24516859x1, 7.2M } - |--+ Alt.count.o { SparseInt16 24516859x1, 1.0M } - |--+ Total.count.o { SparseInt16 24516859x1, 7.6M } - |--+ snp.id.o { Str8 237908, 2.2M } - |--+ snp.allele.o { Str8 237908, 2.2M } - |--+ snp.chromosome.o { Int32 237908, 929.3K } - |--+ snp.position.o { Int32 237908, 929.3K } - |--+ normal.geno { Bit2 237908x2470, 140.1M } - |--+ cancer.geno { Bit2 237908x2470, 140.1M } - -option 2 all the hetero in normal from ex varscan we extract -the coverage in cancer at the position where the hetero -are (no overlap with anp.id) - - |--+ Ref.count.N { SparseInt16 24516859x1, 7.2M } - |--+ Alt.count.N { SparseInt16 24516859x1, 1.0M } - |--+ Total.count.N { SparseInt16 24516859x1, 7.6M } - |--+ snp.id.N { Str8 237908, 2.2M } - |--+ snp.chromosome.N { Int32 237908, 929.3K } - |--+ snp.position.N { Int32 237908, 929.3K } - -Block - - File: /mnt/wigclust5/data/unsafe/belleau/process1000G/samples1000gUnrelated/data/genoGDS1KG.2022.04.18/testBlock.gds (69.2M) - + [ ] - |--+ block.annot [ data.frame ] * - | |--+ block.id { Str8 2, 28B } - | \--+ block.desc { Str8 2, 108B } - \--+ block { Int32 9076010x2 LZ4_ra(3.75%), 2.6M } - - -We create another GDS with the snp.id, -snp.index the index in GDS of the snp in at least one sample -phase information for the snp.id of the 1KG -in R - - - fileGDS1KG <- file.path(PATH1KG, PATHGDS, "matGeno1000g.gds") - gds <- openfn.gds(fileGDS1KG) - fileGDSPhase <- file.path(PATH1KG, PATHGDS, "matPhase1000g.gds") - gdsPhase <- openfn.gds(fileGDSPhase) - - PATHSAMPLEGDS <- file.path("data", "genoGDS1KG.TCGA-OV.samples") - - - addPhase1KG2SampleGDSFromGDS(gds, - gdsPhase, - PATHSAMPLEGDS) - closefn.gds(gdsPhase) - closefn.gds(gds) - - From ecd543841cd4cff2ae5986872d6b82030e6fe230 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 18 Aug 2023 23:27:13 -0400 Subject: [PATCH 147/385] Change variable names in addGeneBlockGDSRefAnnot() to fit camel cases --- R/process1KG.R | 46 +++++++++++++++++-------------- R/synthetic.R | 2 +- R/tools.R | 47 +++++++++++++++++++++++--------- man/addGeneBlockGDSRefAnnot.Rd | 24 +++++++++------- man/groupChr1KGSNV.Rd | 2 +- tests/testthat/test-process1KG.R | 14 +++++----- 6 files changed, 83 insertions(+), 52 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index d4789d53e..d1a0010bf 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -954,16 +954,18 @@ getRef1KGPop <- function(gdsReference, popName="superPop") { } -#' @title Generate two indexes based on gene annotation for gdsAnnot1KG -#' block and add the indexes into the -#' gdsAnnot1KG +#' @title Append information associated to blocks, as indexes, into the +#' Population Reference SNV Annotation GDS file #' -#' @description TODO +#' @description The function appends the information about the blocks into +#' the Population Reference SNV Annotation GDS file. The information is +#' extracted from the Population Reference GDS file. #' #' @param gdsReference an object of class #' \link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file. #' -#' @param file.gdsRefAnnot the filename corresponding the Reference SNV +#' @param gdsRefAnnotFile a \code{character} string representing the +#' file name corresponding the Reference SNV #' Annotation GDS file. The function will #' open it in write mode and close it after. The file must exist. #' @@ -971,10 +973,12 @@ getRef1KGPop <- function(gdsReference, popName="superPop") { #' size of the window to use to group the SNVs when the SNVs are in a #' non-coding region. Default: \code{10000L}. #' -#' @param EnsDb An object with the ensembl genome annotation +#' @param ensDb An object with the ensembl genome annotation #' Default: \code{EnsDb.Hsapiens.v86}. #' -#' @param suffixe.blockName TODO ex Ensembl.Hsapiens.v86 +#' @param suffixBlockName a \code{character} string that identify the source +#' of the block and that will be added to the block description into +#' the Reference SNV Annotation GDS file, as example: Ensembl.Hsapiens.v86. #' #' @return The integer \code{OL} when the function is successful. #' @@ -990,17 +994,17 @@ getRef1KGPop <- function(gdsReference, popName="superPop") { #' @importFrom S4Vectors isSingleNumber #' @encoding UTF-8 #' @export -addGeneBlockGDSRefAnnot <- function(gdsReference, file.gdsRefAnnot, - winSize=10000, EnsDb, suffixe.blockName) { +addGeneBlockGDSRefAnnot <- function(gdsReference, gdsRefAnnotFile, + winSize=10000, ensDb, suffixBlockName) { ## The gdsReference must be an object of class "gds.class" if (!inherits(gdsReference, "gds.class")) { stop("The \'gdsReference\' must be an object of class \'gds.class\'") } - ## Validate that the file.gdsRefAnnot GDS file exists - if (! file.exists(file.gdsRefAnnot)) { - stop("The file \'", file.gdsRefAnnot, "\' does not exist.") + ## Validate that the Reference Annotation GDS file exists + if (! file.exists(gdsRefAnnotFile)) { + stop("The file \'", gdsRefAnnotFile, "\' does not exist.") } ## The winSize must be a positive single number @@ -1008,18 +1012,20 @@ addGeneBlockGDSRefAnnot <- function(gdsReference, file.gdsRefAnnot, stop("The \'winSize\' parameter must be a single numeric value." ) } - ## Generate two indexes based on gene annotation for gdsAnnot1KG block - dfGeneBlock <- generateGeneBlock(gdsReference, winSize, EnsDb) + ## Generate two indexes based on gene annotation for + ## the Reference GDS Annotation block + dfGeneBlock <- generateGeneBlock(gdsReference=gdsReference, + winSize=winSize, EnsDb=ensDb) - ## Open GDS Reference Annotation file in writting mode - gdsRefAnnot <- openfn.gds(file.gdsRefAnnot, readonly=FALSE) + ## Open GDS Reference Annotation file in writing mode + gdsRefAnnot <- openfn.gds(gdsRefAnnotFile, readonly=FALSE) - blockName <- paste0("Gene.", suffixe.blockName) + blockName <- paste0("Gene.", suffixBlockName) blockDesc <- paste0("List of blocks including overlapping genes ", - suffixe.blockName) + suffixBlockName) addBlockInGDSAnnot(gdsRefAnnot, dfGeneBlock$Gene, blockName, blockDesc) - blockName <- paste0("GeneS.", suffixe.blockName) - blockDesc <- paste0("List of blocks of split by genes ", suffixe.blockName) + blockName <- paste0("GeneS.", suffixBlockName) + blockDesc <- paste0("List of blocks of split by genes ", suffixBlockName) addBlockInGDSAnnot(gdsRefAnnot, dfGeneBlock$GeneS, blockName, blockDesc) ## Close GDS Reference annotation file diff --git a/R/synthetic.R b/R/synthetic.R index 9b5eee0f6..6063f4f4d 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -78,7 +78,7 @@ select1KGPop <- function(gdsReference, nbProfiles) { sample.id <- read.gdsn(index.gdsn(gdsReference, "sample.id"))[listKeep] listPop <- unique(sample.annot$pop.group) - ## FOR_LOOP modification to be validated by Pascal + ## FOR_LOOP modification to be validated by Pascal TOREVIEW ## Remove commented code and this text after validation ## For each subcontinental population, randomly select a fixed number of diff --git a/R/tools.R b/R/tools.R index 85e2e0bba..c8794a844 100644 --- a/R/tools.R +++ b/R/tools.R @@ -157,7 +157,7 @@ snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { #' the merged genotyping files for each sample will be created. #' The path must exists. #' -#' @return The integer \code{0L} when successful. +#' @return The integer \code{0L} when successful or \code{FALSE} if not. #' #' @examples #' @@ -205,25 +205,46 @@ groupChr1KGSNV <- function(pathGenoChr, pathOut) { listFiles <- dir(file.path(pathGenoChr, "chr1"), ".+\\.chr1\\.vcf\\.bz2") listSamples <- gsub("\\.chr1\\.vcf\\.bz2", "", listFiles) + ## TOREVIEW FOR_LOOP REMOVAL ## Merge files associated to each samples into one csv file - for(sampleId in listSamples) { - listGeno <- list() - + # for(sampleId in listSamples) { + # + # ## TOREVIEW FOR_LOOOP REMOVAL ## Read each genotyping file and append the information - for(chr in seq_len(22)) { - geno <- read.csv2(file.path(pathGenoChr, paste0("chr", chr), - paste0(sampleId, ".chr", chr,".vcf.bz2")), - sep="\t", row.names=NULL) + # listGeno <- list() + # for(chr in seq_len(22)) { + # geno <- read.csv2(file.path(pathGenoChr, paste0("chr", chr), + # paste0(sampleId, ".chr", chr,".vcf.bz2")), + # sep="\t", row.names=NULL) + # + # listGeno[[paste0("chr", chr)]] <- geno + # } + # genoAll <- do.call(rbind, listGeno) +# +# ## Save the genotyping information into one file +# write.csv2(genoAll, file=bzfile(file.path(pathOut, +# paste0(sampleId, ".csv.bz2"))), row.names=FALSE) +# } + + + ## Merge files associated to each samples into one csv file + results <- lapply(X=listSamples, FUN=function(sampleId, pathOut) { - listGeno[[paste0("chr", chr)]] <- geno - } + ## For each chromosome, read genotyping file and append the information + listGeno <- lapply(seq_len(22), function(chr, sampleId) { + geno <- read.csv2(file.path(pathGenoChr, paste0("chr", chr), + paste0(sampleId, ".chr", chr,".vcf.bz2")), + sep="\t", row.names=NULL) + return(geno)}, sampleId=sampleId) genoAll <- do.call(rbind, listGeno) ## Save the genotyping information into one file write.csv2(genoAll, file=bzfile(file.path(pathOut, - paste0(sampleId, ".csv.bz2"))), row.names=FALSE) - } + paste0(sampleId, ".csv.bz2"))), row.names=FALSE) - return(0L) + return(TRUE)}, pathOut=pathOut) + + ## Successful or not + return(ifelse(all(unlist(results)), 0L, FALSE)) } diff --git a/man/addGeneBlockGDSRefAnnot.Rd b/man/addGeneBlockGDSRefAnnot.Rd index 5728790a2..cba0fe466 100644 --- a/man/addGeneBlockGDSRefAnnot.Rd +++ b/man/addGeneBlockGDSRefAnnot.Rd @@ -3,23 +3,23 @@ \encoding{UTF-8} \name{addGeneBlockGDSRefAnnot} \alias{addGeneBlockGDSRefAnnot} -\title{Generate two indexes based on gene annotation for gdsAnnot1KG -block and add the indexes into the -gdsAnnot1KG} +\title{Append information associated to blocks, as indexes, into the +Population Reference SNV Annotation GDS file} \usage{ addGeneBlockGDSRefAnnot( gdsReference, - file.gdsRefAnnot, + gdsRefAnnotFile, winSize = 10000, - EnsDb, - suffixe.blockName + ensDb, + suffixBlockName ) } \arguments{ \item{gdsReference}{an object of class \link[gdsfmt]{gds.class} (a GDS file), the opened Reference GDS file.} -\item{file.gdsRefAnnot}{the filename corresponding the Reference SNV +\item{gdsRefAnnotFile}{a \code{character} string representing the +file name corresponding the Reference SNV Annotation GDS file. The function will open it in write mode and close it after. The file must exist.} @@ -27,16 +27,20 @@ open it in write mode and close it after. The file must exist.} size of the window to use to group the SNVs when the SNVs are in a non-coding region. Default: \code{10000L}.} -\item{EnsDb}{An object with the ensembl genome annotation +\item{ensDb}{An object with the ensembl genome annotation Default: \code{EnsDb.Hsapiens.v86}.} -\item{suffixe.blockName}{TODO ex Ensembl.Hsapiens.v86} +\item{suffixBlockName}{a \code{character} string that identify the source +of the block and that will be added to the block description into +the Reference SNV Annotation GDS file, as example: Ensembl.Hsapiens.v86.} } \value{ The integer \code{OL} when the function is successful. } \description{ -TODO +The function appends the information about the blocks into +the Population Reference SNV Annotation GDS file. The information is +extracted from the Population Reference GDS file. } \examples{ diff --git a/man/groupChr1KGSNV.Rd b/man/groupChr1KGSNV.Rd index 35fc9082f..f5db6ae09 100644 --- a/man/groupChr1KGSNV.Rd +++ b/man/groupChr1KGSNV.Rd @@ -19,7 +19,7 @@ the merged genotyping files for each sample will be created. The path must exists.} } \value{ -The integer \code{0L} when successful. +The integer \code{0L} when successful or \code{FALSE} if not. } \description{ This function merge all the genotyping files associated to one diff --git a/tests/testthat/test-process1KG.R b/tests/testthat/test-process1KG.R index cde421236..62a2b9179 100644 --- a/tests/testthat/test-process1KG.R +++ b/tests/testthat/test-process1KG.R @@ -562,8 +562,8 @@ test_that("addGeneBlockGDSRefAnnot() must return error when gds is a character s error_message <- "The \'gdsReference\' must be an object of class \'gds.class\'" expect_error(addGeneBlockGDSRefAnnot(gdsReference="test.gds", - file.gdsRefAnnot="toto.gds", winSize=10000, EnsDb="human", - suffixe.blockName="test"), error_message) + gdsRefAnnotFile="toto.gds", winSize=10000, ensDb="human", + suffixBlockName="test"), error_message) }) test_that("addGeneBlockGDSRefAnnot() must return error when file.gdsRefAnnot does not exist", { @@ -576,8 +576,8 @@ test_that("addGeneBlockGDSRefAnnot() must return error when file.gdsRefAnnot doe error_message <- "The file \'fixtures/titi.gds\' does not exist." expect_error(addGeneBlockGDSRefAnnot(gdsReference=gds_1KG, - file.gdsRefAnnot=test_path("fixtures", "titi.gds"), - winSize=1000, EnsDb="human", suffixe.blockName="test"), error_message) + gdsRefAnnotFile=test_path("fixtures", "titi.gds"), + winSize=1000, ensDb="human", suffixBlockName="test"), error_message) }) test_that("addGeneBlockGDSRefAnnot() must return error when winSize is a character string", { @@ -590,9 +590,9 @@ test_that("addGeneBlockGDSRefAnnot() must return error when winSize is a charact error_message <- "The \'winSize\' parameter must be a single numeric value." expect_error(addGeneBlockGDSRefAnnot(gdsReference=gds_1KG, - file.gdsRefAnnot=test_path("fixtures", - "ex1_good_small_1KG_Annot_GDS.gds"), winSize="10", EnsDb="human", - suffixe.blockName="test"), error_message) + gdsRefAnnotFile=test_path("fixtures", + "ex1_good_small_1KG_Annot_GDS.gds"), winSize="10", ensDb="human", + suffixBlockName="test"), error_message) }) From 4884c768b8a98e9006d3df2ab7b0de3d6a6d229a Mon Sep 17 00:00:00 2001 From: belleau Date: Sat, 19 Aug 2023 09:59:23 -0400 Subject: [PATCH 148/385] Example and manual page in allelicFraction_internal --- R/allelicFraction_internal.R | 21 +++++++++++------- .../extdata/demoAllelicFraction/demSnpPos.rds | Bin 0 -> 3008 bytes man/computeLOHBlocksDNAChr.Rd | 6 ++--- man/tableBlockAF.Rd | 15 ++++++++----- 4 files changed, 26 insertions(+), 16 deletions(-) create mode 100644 inst/extdata/demoAllelicFraction/demSnpPos.rds diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index a16fb931e..3b2b17589 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -270,8 +270,8 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' \code{chrInfo} parameter must contain the value for the specified #' chromosome. #' -#' @param genoN a single \code{numeric} between 0 and 1 representing TODO. -#' Default: \code{0.0001}. +#' @param genoN a single \code{numeric} between 0 and 1 representing the +#' probability of sequencing error. Default: \code{0.0001}. #' #' @return a \code{data.frame} with the informations about LOH on a specific #' chromosome. The \code{data.frame} contains those columns: @@ -283,7 +283,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' \item{end} {a \code{integer} representing the end position on the #' box containing only homozygote SNVs (or not SNV). The last box ends at the #' length of the chromosome.} -#' \item{logLHR} {TODO} +#' \item{logLHR} {score for LOH} #' \item{LH1} {TODO} #' \item{LM1} {TODO} #' \item{homoScore} {a \code{numeric} representing \code{LH1} - \code{LM1}} @@ -1453,9 +1453,10 @@ calcAFMLRNA <- function(snpPosHetero) { #' the alternative allele.} #' \item{nPhase} {a single \code{integer} representin the number of SNV #' phases.} -#' \item{sumAlleleLow} {a single \code{integer} sum of the allele with -#' the minimum coverage.} -#' \item{sumAlleleHigh} {a single \code{integer} TODO.} +#' \item{sumAlleleLow} {a single \code{integer} TOREVIEW sum of the allele with +#' the less coverage.} +#' \item{sumAlleleHigh} {a single \code{integer} TOREVIEW sum of the allele +#' with more coverage.} #' \item{lH} {a single \code{numeric} for the homozygotes log10 of the product #' frequencies of the allele not found in the profile (not a probability).} #' \item{lM} {a single \code{numeric} log10 product frequency allele @@ -1471,8 +1472,12 @@ calcAFMLRNA <- function(snpPosHetero) { #' #' @examples #' -#' # TODO -#' gds <- "Demo GDS TODO" +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' snpPos <- readRDS(file.path(dataDir, "demoAllelicFraction", "demSnpPos.rds")) +#' +#' result <- RAIDS:::tableBlockAF(snpPos[which(snpPos$snp.chr == 1),]) +#' head(result) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom S4Vectors aggregate diff --git a/inst/extdata/demoAllelicFraction/demSnpPos.rds b/inst/extdata/demoAllelicFraction/demSnpPos.rds new file mode 100644 index 0000000000000000000000000000000000000000..25b35631376fd509552b5100724d843b24d63661 GIT binary patch literal 3008 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 Date: Sat, 19 Aug 2023 11:10:14 -0400 Subject: [PATCH 149/385] Update manual page and corrected a condition for normal in computeLOHBlocksDNAChr --- R/allelicFraction_internal.R | 51 ++++++++++++++++++++--------------- man/computeLOHBlocksDNAChr.Rd | 20 +++++++++----- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 3b2b17589..cac7d9c0d 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -283,16 +283,24 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' \item{end} {a \code{integer} representing the end position on the #' box containing only homozygote SNVs (or not SNV). The last box ends at the #' length of the chromosome.} -#' \item{logLHR} {score for LOH} -#' \item{LH1} {TODO} -#' \item{LM1} {TODO} +#' \item{logLHR} {TOREVIEW Score for LOH base on frequencies in population. Sum of +#' the log10 of the frequencies of the observe gegenotype minus the +#' the sum of the log10 of the higher frequent genotype. +#' (-100 when normal genotype are present)} +#' \item{LH1} {TOREVIEW If normal genotype present and heterozygot the probability to be heterozygote +#' base on the coverage of each allele} +#' \item{LM1} {TOREVIEW If normal genotype present and heterozygot the max probability the max probability +#' for the read coverage at the position} #' \item{homoScore} {a \code{numeric} representing \code{LH1} - \code{LM1}} #' \item{nbSNV} {a \code{integer} representing th number of SNVs in #' the box} -#' \item{nbPruned} {a \code{integer} representing th number of pruned SNVs in +#' \item{nbPruned} {a \code{integer} representing the number of pruned SNVs in #' the box} -#' \item{nbNorm} {TODO} -#' \item{LOH} {TODO} +#' \item{nbNorm} {TOREVIEW a \code{integer} representing of genotype +#' heterozygote for the normal in the block} +#' \item{LOH} {TOREVIEW a \code{integer} representing a flag if 1 it mean +#' the block is satisfy the criteria to be LOH. The value is not assign +#' in this function they are all 0} #' } #' #' @examples @@ -396,21 +404,22 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, if (length(which(snvH$normal.geno != 3)) > 0) { listCount <- snvH$cnt.tot[which(snvH$normal.geno == 1)] homoBlock$nbNorm[i] <- length(listCount) - - lH1 <-sum(log10(apply(snvH[which(snvH$normal.geno == 1), - c("cnt.ref", "cnt.tot"), drop=FALSE], - 1, FUN=function(x){ - return(dbinom(x[1], x[2], 0.5)) - # genoN1 * dbinom(x[1], x[2], 0.5) + genoN - }))) - - lM1 <- sum(log10(apply(snvH[which(snvH$normal.geno == 1), - c("cnt.ref", "cnt.tot"), drop=FALSE], - 1, FUN=function(x){ - return(dbinom((x[2] + x[2]%%2)/2, x[2], 0.5)) - #genoN1 *dbinom((x[2] + x[2]%%2)/2, x[2], 0.5) + genoN - }))) - logLHR <- -100 + if(homoBlock$nbNorm[i] > 0){ + lH1 <-sum(log10(apply(snvH[which(snvH$normal.geno == 1), + c("cnt.ref", "cnt.tot"), drop=FALSE], + 1, FUN=function(x){ + return(dbinom(x[1], x[2], 0.5)) + # genoN1 * dbinom(x[1], x[2], 0.5) + genoN + }))) + + lM1 <- sum(log10(apply(snvH[which(snvH$normal.geno == 1), + c("cnt.ref", "cnt.tot"), drop=FALSE], + 1, FUN=function(x){ + return(dbinom((x[2] + x[2]%%2)/2, x[2], 0.5)) + #genoN1 *dbinom((x[2] + x[2]%%2)/2, x[2], 0.5) + genoN + }))) + logLHR <- -100 + } } else if (length(which(snvH$pruned)) > 2) { afSNV <- listAF[snvH$snp.index[which(snvH$pruned)]] diff --git a/man/computeLOHBlocksDNAChr.Rd b/man/computeLOHBlocksDNAChr.Rd index 6325c5eb4..2c8a05851 100644 --- a/man/computeLOHBlocksDNAChr.Rd +++ b/man/computeLOHBlocksDNAChr.Rd @@ -59,16 +59,24 @@ position 1.} \item{end} {a \code{integer} representing the end position on the box containing only homozygote SNVs (or not SNV). The last box ends at the length of the chromosome.} -\item{logLHR} {score for LOH} -\item{LH1} {TODO} -\item{LM1} {TODO} +\item{logLHR} {TOREVIEW Score for LOH base on frequencies in population. Sum of +the log10 of the frequencies of the observe gegenotype minus the +the sum of the log10 of the higher frequent genotype. +(-100 when normal genotype are present)} +\item{LH1} {TOREVIEW If normal genotype present and heterozygot the probability to be heterozygote +base on the coverage of each allele} +\item{LM1} {TOREVIEW If normal genotype present and heterozygot the max probability the max probability +for the read coverage at the position} \item{homoScore} {a \code{numeric} representing \code{LH1} - \code{LM1}} \item{nbSNV} {a \code{integer} representing th number of SNVs in the box} -\item{nbPruned} {a \code{integer} representing th number of pruned SNVs in +\item{nbPruned} {a \code{integer} representing the number of pruned SNVs in the box} -\item{nbNorm} {TODO} -\item{LOH} {TODO} +\item{nbNorm} {TOREVIEW a \code{integer} representing of genotype +heterozygote for the normal in the block} +\item{LOH} {TOREVIEW a \code{integer} representing a flag if 1 it mean +the block is satisfy the criteria to be LOH. The value is not assign +in this function they are all 0} } } \description{ From f69f3ae4c81bb1119a30cd2364a3e0273af10bea Mon Sep 17 00:00:00 2001 From: belleau Date: Sat, 19 Aug 2023 13:06:32 -0400 Subject: [PATCH 150/385] Removed loop of testAlleleFractionChange and manual page in allelicFraction_internal --- R/allelicFraction_internal.R | 80 +++++++++++++++++++++++++----------- man/calcAFMLRNA.Rd | 8 +++- 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index cac7d9c0d..af79e4fac 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -1233,30 +1233,56 @@ testAlleleFractionChange <- function(matCov, pCutOff=-3, vMean) { pO <- 0 matCov$pWin <- rep(1, nrow(matCov)) + # FORLOOP remove to test + # and remove the code in comments + matTmp <- apply(matCov[, c("cnt.alt", "cnt.ref")], 1, + FUN=function(x, vMean){ + vCur <- ifelse(x[1] <= x[2], + x[1], x[2]) + + diff2Mean <- abs(vMean * (x[1] + + x[2]) - vCur) + pCur1 <- pbinom(round(vMean * (x[1] + + x[2]) - diff2Mean), + size=x[2] + x[1], vMean) + pCur2 <- 1 - pbinom(round(vMean * (x[1] + + x[2]) + diff2Mean), + size=x[2] + x[1], vMean) + + pCur <- pCur1 + pCur2 + + pCurO <- max(1 - max(pCur, 0.01), 0.01) + pCurMax <- max(pCur, 0.01) + return(c(pCur, pCurMax, pCurO)) + }, vMean=vMean) + matCov$pWin <- matTmp[1, ] + + p <- sum(log10(matTmp[2,])) + p0 <- sum(log10(matTmp[3,])) - for(i in seq_len(nrow(matCov))) { - - vCur <- ifelse(matCov$cnt.alt[i] <= matCov$cnt.ref[i], - matCov$cnt.alt[i], matCov$cnt.ref[i]) - - diff2Mean <- abs(vMean * (matCov$cnt.alt[i] + - matCov$cnt.ref[i]) - vCur) - pCur1 <- pbinom(round(vMean * (matCov$cnt.alt[i] + - matCov$cnt.ref[i]) - diff2Mean), - size=matCov$cnt.ref[i] + matCov$cnt.alt[i], vMean) - pCur2 <- 1 - pbinom(round(vMean * (matCov$cnt.alt[i] + - matCov$cnt.ref[i]) + diff2Mean), - size=matCov$cnt.ref[i] + matCov$cnt.alt[i], vMean) - - pCur <- pCur1 + pCur2 - - matCov$pWin[i] <- pCur - - pCurO <- max(1 - max(pCur, 0.01), 0.01) - - p <- p + log10(max(pCur, 0.01)) - pO <- pO + log10(pCurO) - } + # for(i in seq_len(nrow(matCov))) { + # + # vCur <- ifelse(matCov$cnt.alt[i] <= matCov$cnt.ref[i], + # matCov$cnt.alt[i], matCov$cnt.ref[i]) + # + # diff2Mean <- abs(vMean * (matCov$cnt.alt[i] + + # matCov$cnt.ref[i]) - vCur) + # pCur1 <- pbinom(round(vMean * (matCov$cnt.alt[i] + + # matCov$cnt.ref[i]) - diff2Mean), + # size=matCov$cnt.ref[i] + matCov$cnt.alt[i], vMean) + # pCur2 <- 1 - pbinom(round(vMean * (matCov$cnt.alt[i] + + # matCov$cnt.ref[i]) + diff2Mean), + # size=matCov$cnt.ref[i] + matCov$cnt.alt[i], vMean) + # + # pCur <- pCur1 + pCur2 + # + # matCov$pWin[i] <- pCur + # + # pCurO <- max(1 - max(pCur, 0.01), 0.01) + # + # p <- p + log10(max(pCur, 0.01)) + # pO <- pO + log10(pCurO) + # } pCut1 <- as.integer((sum(matCov$pWin < 0.5) >= nrow(matCov)-1) & matCov$pWin[1] < 0.5 & (matCov$pWin[nrow(matCov)] < 0.5) & @@ -1359,9 +1385,13 @@ testEmptyBox <- function(matCov, pCutOff=-3) { ############################################### -#' @title TODO +#' @title TOREVIEW Compute the log likelihood ratio base on the coverage (read depth) +#' of each allele in block (gene in the case of RNA-seq) #' -#' @description TODO +#' @description TOREVIEW For each hetero sum the log of read depth of the lowest depth +#' divide by the total depth of the position minus of likelhood of the allelic +#' fraction of 0.5. If the phase is known, the variant varaint in the same +#' haplotype are group. #' #' @param snpPosHetero For a specific gene (block) a \code{data.frame} with #' lap for the SNV heterozygote dataset with diff --git a/man/calcAFMLRNA.Rd b/man/calcAFMLRNA.Rd index c40f66477..4075065fb 100644 --- a/man/calcAFMLRNA.Rd +++ b/man/calcAFMLRNA.Rd @@ -3,7 +3,8 @@ \encoding{UTF-8} \name{calcAFMLRNA} \alias{calcAFMLRNA} -\title{TODO} +\title{TOREVIEW Compute the log likelihood ratio base on the coverage (read depth) +of each allele in block (gene in the case of RNA-seq)} \usage{ calcAFMLRNA(snpPosHetero) } @@ -21,7 +22,10 @@ sumAlleleLow number of read overlapping the allele low sumAlleleHigh number of read overlapping the allele high TODO } \description{ -TODO +TOREVIEW For each hetero sum the log of read depth of the lowest depth +divide by the total depth of the position minus of likelhood of the allelic +fraction of 0.5. If the phase is known, the variant varaint in the same +haplotype are group. } \examples{ From 26f379f731f4c73f8773d15de4a81fa095fe680b Mon Sep 17 00:00:00 2001 From: belleau Date: Sat, 19 Aug 2023 13:12:25 -0400 Subject: [PATCH 151/385] Removed loop of testAlleleFractionChange part 2 --- R/allelicFraction_internal.R | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index af79e4fac..f5d659b7e 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -1233,8 +1233,7 @@ testAlleleFractionChange <- function(matCov, pCutOff=-3, vMean) { pO <- 0 matCov$pWin <- rep(1, nrow(matCov)) - # FORLOOP remove to test - # and remove the code in comments + matTmp <- apply(matCov[, c("cnt.alt", "cnt.ref")], 1, FUN=function(x, vMean){ vCur <- ifelse(x[1] <= x[2], @@ -1260,29 +1259,7 @@ testAlleleFractionChange <- function(matCov, pCutOff=-3, vMean) { p <- sum(log10(matTmp[2,])) p0 <- sum(log10(matTmp[3,])) - # for(i in seq_len(nrow(matCov))) { - # - # vCur <- ifelse(matCov$cnt.alt[i] <= matCov$cnt.ref[i], - # matCov$cnt.alt[i], matCov$cnt.ref[i]) - # - # diff2Mean <- abs(vMean * (matCov$cnt.alt[i] + - # matCov$cnt.ref[i]) - vCur) - # pCur1 <- pbinom(round(vMean * (matCov$cnt.alt[i] + - # matCov$cnt.ref[i]) - diff2Mean), - # size=matCov$cnt.ref[i] + matCov$cnt.alt[i], vMean) - # pCur2 <- 1 - pbinom(round(vMean * (matCov$cnt.alt[i] + - # matCov$cnt.ref[i]) + diff2Mean), - # size=matCov$cnt.ref[i] + matCov$cnt.alt[i], vMean) - # - # pCur <- pCur1 + pCur2 - # - # matCov$pWin[i] <- pCur - # - # pCurO <- max(1 - max(pCur, 0.01), 0.01) - # - # p <- p + log10(max(pCur, 0.01)) - # pO <- pO + log10(pCurO) - # } + pCut1 <- as.integer((sum(matCov$pWin < 0.5) >= nrow(matCov)-1) & matCov$pWin[1] < 0.5 & (matCov$pWin[nrow(matCov)] < 0.5) & From 8d53b8955849d6829e7d4b000be986339aac6f75 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sat, 19 Aug 2023 17:18:47 -0400 Subject: [PATCH 152/385] Update variable names in generateGeneBlock() function to fit camel cases --- R/process1KG.R | 2 +- R/process1KG_internal.R | 26 +++++++++++++------------- man/generateGeneBlock.Rd | 18 +++++++++--------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index d1a0010bf..871b4240a 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -1015,7 +1015,7 @@ addGeneBlockGDSRefAnnot <- function(gdsReference, gdsRefAnnotFile, ## Generate two indexes based on gene annotation for ## the Reference GDS Annotation block dfGeneBlock <- generateGeneBlock(gdsReference=gdsReference, - winSize=winSize, EnsDb=ensDb) + winSize=winSize, ensDb=ensDb) ## Open GDS Reference Annotation file in writing mode gdsRefAnnot <- openfn.gds(gdsRefAnnotFile, readonly=FALSE) diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index 0247e87ef..1516cf9a5 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -144,18 +144,18 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, #' size of the window to use to group the SNVs when the SNVs are in a #' non-coding region. Default: \code{10000}. #' -#' @param EnsDb An object of class \code{EnsDb} with the Ensembl genome +#' @param ensBd An object of class \code{EnsDb} with the Ensembl genome #' annotation. By default, the \code{EnsDb.Hsapiens.v86} class has been used. #' #' @return a \code{data.frame} with those columns: #' \itemize{ -#' \item{chr} {} -#' \item{pos} {} -#' \item{snp.allele} {} -#' \item{Exon} {} -#' \item{GName} {} -#' \item{Gene} {} -#' \item{GeneS} {} +#' \item{chr} {TODO} +#' \item{pos} {TODO} +#' \item{snp.allele} {TODO} +#' \item{Exon} {TODO} +#' \item{GName} {TODO} +#' \item{Gene} {TODO} +#' \item{GeneS} {TODO} #' } #' "chr", "pos", "snp.allele", "Exon", "GName", "Gene", "GeneS" #' Example for GName and the two indexes "Gene", "GeneS" @@ -186,9 +186,9 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, #' @importFrom AnnotationFilter GeneIdFilter #' @encoding UTF-8 #' @keywords internal -generateGeneBlock <- function(gdsReference, winSize=10000, EnsDb) { +generateGeneBlock <- function(gdsReference, winSize=10000, ensBd) { - edb <- EnsDb + edb <- ensBd listEnsId <- unique(names(genes(edb))) cols <- c("GENEID", "SYMBOL", "GENENAME", "GENESEQSTART", @@ -230,7 +230,7 @@ generateGeneBlock <- function(gdsReference, winSize=10000, EnsDb) { stringsAsFactors=FALSE) offsetGene <- 0 offsetGeneS <- 0 - offsetGene.O <- 0 + offsetGeneO <- 0 for(chr in seq_len(22)) { @@ -372,7 +372,7 @@ generateGeneBlock <- function(gdsReference, winSize=10000, EnsDb) { matFreq$GeneS[matFreq$Gene < 0] <- 0 listOrph <- which(matFreq$GeneS == 0) flag <- TRUE - v <- offsetGene.O - 1 + v <- offsetGeneO - 1 i <- 1 curZone <- "GeneS" curZone1 <- "Gene" @@ -407,7 +407,7 @@ generateGeneBlock <- function(gdsReference, winSize=10000, EnsDb) { i <- which(listOrph == j) + 1 flag <- ifelse(i <= length(listOrph), TRUE, FALSE) } - offsetGene.O <- min(offsetGene.O, min(matFreq$Gene)) + offsetGeneO <- min(offsetGeneO, min(matFreq$Gene)) } listMat[[chr]] <- matFreq diff --git a/man/generateGeneBlock.Rd b/man/generateGeneBlock.Rd index 4f53b12f5..b60fb0b75 100644 --- a/man/generateGeneBlock.Rd +++ b/man/generateGeneBlock.Rd @@ -5,7 +5,7 @@ \alias{generateGeneBlock} \title{Generate two indexes based on gene annotation for gdsAnnot1KG block} \usage{ -generateGeneBlock(gdsReference, winSize = 10000, EnsDb) +generateGeneBlock(gdsReference, winSize = 10000, ensBd) } \arguments{ \item{gdsReference}{an object of class @@ -15,19 +15,19 @@ generateGeneBlock(gdsReference, winSize = 10000, EnsDb) size of the window to use to group the SNVs when the SNVs are in a non-coding region. Default: \code{10000}.} -\item{EnsDb}{An object of class \code{EnsDb} with the Ensembl genome +\item{ensBd}{An object of class \code{EnsDb} with the Ensembl genome annotation. By default, the \code{EnsDb.Hsapiens.v86} class has been used.} } \value{ a \code{data.frame} with those columns: \itemize{ -\item{chr} {} -\item{pos} {} -\item{snp.allele} {} -\item{Exon} {} -\item{GName} {} -\item{Gene} {} -\item{GeneS} {} +\item{chr} {TODO} +\item{pos} {TODO} +\item{snp.allele} {TODO} +\item{Exon} {TODO} +\item{GName} {TODO} +\item{Gene} {TODO} +\item{GeneS} {TODO} } "chr", "pos", "snp.allele", "Exon", "GName", "Gene", "GeneS" Example for GName and the two indexes "Gene", "GeneS" From cb26af1da9b9b6e0cb3338bd3deab19263690f62 Mon Sep 17 00:00:00 2001 From: belleau Date: Sat, 19 Aug 2023 17:39:53 -0400 Subject: [PATCH 153/385] Update manual pages and exemple for calcAFMLRNA.Rd computeAllelicFractionRNA --- R/allelicFraction_internal.R | 51 ++++++++++++++++++++++++-------- man/calcAFMLRNA.Rd | 49 ++++++++++++++++++++++-------- man/computeAllelicFractionRNA.Rd | 2 +- 3 files changed, 76 insertions(+), 26 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index f5d659b7e..15caf34f2 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -901,7 +901,7 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' \item{homo} {a \code{logical} indicating if the SNV is homozygote} #' \item{block.id} {TOREVIEW a \code{integer} indicating the block.id in gdsRefAnnot the #' vairant is in} -#' \item{phase} {TOREVIEW a \code{integer} indicating the phase of the vairant +#' \item{phase} {TOREVIEW a \code{integer} indicating the phase of the variant #' if known, 3 if not known} #' \item{lap} {a \code{numeric} indicating lower allelic fraction} #' \item{LOH} {a \code{integer} indicating if the SNV is in an LOH region @@ -1365,26 +1365,51 @@ testEmptyBox <- function(matCov, pCutOff=-3) { #' @title TOREVIEW Compute the log likelihood ratio base on the coverage (read depth) #' of each allele in block (gene in the case of RNA-seq) #' -#' @description TOREVIEW For each hetero sum the log of read depth of the lowest depth +#' @description TOREVIEW For the block sum the log of read depth of the lowest depth #' divide by the total depth of the position minus of likelhood of the allelic #' fraction of 0.5. If the phase is known, the variant varaint in the same #' haplotype are group. #' -#' @param snpPosHetero For a specific gene (block) a \code{data.frame} with -#' lap for the SNV heterozygote dataset with -#' coverage > \code{minCov}. The \code{data.frame} must contain those columns: -#' 'phase', 'cnt.ref', 'cnt.alt'. TODO +#' @param snpPosHetero For a specific gene (block) a \code{data.frame} +#' containing the SNV information. +#' The \code{data.frame} must contain those columns: +#' \itemize{ +#' \item{cnt.ref} {a single \code{integer} representing the coverage for +#' the reference allele.} +#' \item{cnt.alt} {a single \code{integer} representing the coverage for +#' the alternative allele.} +#' \item{phase} {TOREVIEW a \code{integer} indicating the phase of the variant +#' if known, 3 if not known} +#' } #' -#' @return TODO a \code{list} of \code{numeric} for the gene lR the score -#' for aFraction different than 0.5 -#' aFraction allele estimation, nPhase number of SNV phase, -#' sumAlleleLow number of read overlapping the allele low -#' sumAlleleHigh number of read overlapping the allele high TODO +#' @return TOREVIEW a \code{list} for the block with the information of +#' relative to the heterozygotes. +#' The \code{list} contains: +#' \itemize{ +#' \item{lR} {TOREVIEW a single \code{numeric} representing sum the log of read depth of the lowest depth +#' divide by the total depth of the position minus of likelhood of the allelic +#' fraction of 0.5.} +#' \item{aFraction} {TOREVIEW a single \code{numeric} representing the allele +#' fraction estimation.} +#' \item{sumAlleleLow} {TOREVIEW a \code{integer} representing the +#' sum of the allele read depth +#' of the lowest read alelle depth} +#' \item{sumAlleleHigh} {TOREVIEW a \code{integer} representing the +#' sum of the allele read depth +#' of the highsest read alelle depth} +#' } #' #' @examples #' -#' # TODO -#' gds <- "Demo GDS TODO" +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' snpPos <- readRDS(file.path(dataDir, "demoAllelicFraction", "demSnpPos.rds")) +#' +#' result <- RAIDS:::calcAFMLRNA(snpPos[which( +#' snpPos$block.id == 2750 & +#' snpPos$hetero), c("cnt.ref", +#' "cnt.alt", "phase")]) +#' head(result) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @encoding UTF-8 diff --git a/man/calcAFMLRNA.Rd b/man/calcAFMLRNA.Rd index 4075065fb..37c8f7dd9 100644 --- a/man/calcAFMLRNA.Rd +++ b/man/calcAFMLRNA.Rd @@ -9,28 +9,53 @@ of each allele in block (gene in the case of RNA-seq)} calcAFMLRNA(snpPosHetero) } \arguments{ -\item{snpPosHetero}{For a specific gene (block) a \code{data.frame} with -lap for the SNV heterozygote dataset with -coverage > \code{minCov}. The \code{data.frame} must contain those columns: -'phase', 'cnt.ref', 'cnt.alt'. TODO} +\item{snpPosHetero}{For a specific gene (block) a \code{data.frame} +containing the SNV information. +The \code{data.frame} must contain those columns: +\itemize{ +\item{cnt.ref} {a single \code{integer} representing the coverage for +the reference allele.} +\item{cnt.alt} {a single \code{integer} representing the coverage for +the alternative allele.} +\item{phase} {TOREVIEW a \code{integer} indicating the phase of the variant +if known, 3 if not known} +}} } \value{ -TODO a \code{list} of \code{numeric} for the gene lR the score -for aFraction different than 0.5 -aFraction allele estimation, nPhase number of SNV phase, -sumAlleleLow number of read overlapping the allele low -sumAlleleHigh number of read overlapping the allele high TODO +TOREVIEW a \code{list} for the block with the information of +relative to the heterozygotes. +The \code{list} contains: +\itemize{ +\item{lR} {TOREVIEW a single \code{numeric} representing sum the log of read depth of the lowest depth +divide by the total depth of the position minus of likelhood of the allelic +fraction of 0.5.} +\item{aFraction} {TOREVIEW a single \code{numeric} representing the allele +fraction estimation.} +\item{sumAlleleLow} {TOREVIEW a \code{integer} representing the +sum of the allele read depth +of the lowest read alelle depth} +\item{sumAlleleHigh} {TOREVIEW a \code{integer} representing the +sum of the allele read depth +of the highsest read alelle depth} +} } \description{ -TOREVIEW For each hetero sum the log of read depth of the lowest depth +TOREVIEW For the block sum the log of read depth of the lowest depth divide by the total depth of the position minus of likelhood of the allelic fraction of 0.5. If the phase is known, the variant varaint in the same haplotype are group. } \examples{ -# TODO -gds <- "Demo GDS TODO" +dataDir <- system.file("extdata", package="RAIDS") + +snpPos <- readRDS(file.path(dataDir, "demoAllelicFraction", "demSnpPos.rds")) + +result <- RAIDS:::calcAFMLRNA(snpPos[which( + snpPos$block.id == 2750 & + snpPos$hetero), c("cnt.ref", + "cnt.alt", "phase")]) +head(result) } \author{ diff --git a/man/computeAllelicFractionRNA.Rd b/man/computeAllelicFractionRNA.Rd index 62951a4e1..a520939b4 100644 --- a/man/computeAllelicFractionRNA.Rd +++ b/man/computeAllelicFractionRNA.Rd @@ -87,7 +87,7 @@ SNV in the Reference GDS file that contains all SNVs} \item{homo} {a \code{logical} indicating if the SNV is homozygote} \item{block.id} {TOREVIEW a \code{integer} indicating the block.id in gdsRefAnnot the vairant is in} -\item{phase} {TOREVIEW a \code{integer} indicating the phase of the vairant +\item{phase} {TOREVIEW a \code{integer} indicating the phase of the variant if known, 3 if not known} \item{lap} {a \code{numeric} indicating lower allelic fraction} \item{LOH} {a \code{integer} indicating if the SNV is in an LOH region From c80e7f311f81e937a3ee45b518ec24d608b8069a Mon Sep 17 00:00:00 2001 From: belleau Date: Sat, 19 Aug 2023 17:48:42 -0400 Subject: [PATCH 154/385] Update manual pages and exemple for computeAlleleFraction --- R/allelicFraction_internal.R | 5 ++++- man/computeAlleleFraction.Rd | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 15caf34f2..43b49edc1 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -468,7 +468,10 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, #' window to compute the allelic fraction. #' Default: \code{10}. #' -#' @param cutOff a single \code{numeric} representing TODO. Default: \code{-3}. +#' @param cutOff a \code{numeric} representing the cut-off for considering +#' a region imbalanced when comparing likelihood to gave allelic fraction +#' change and likelihood not to have allelic fraction change. +#' Default: \code{-3}. #' #' @return a \code{matrix} of \code{numeric} with 3 columns where each #' row represent a segment diff --git a/man/computeAlleleFraction.Rd b/man/computeAlleleFraction.Rd index b77a894a2..c21b6c485 100644 --- a/man/computeAlleleFraction.Rd +++ b/man/computeAlleleFraction.Rd @@ -15,7 +15,10 @@ a SNV dataset.} window to compute the allelic fraction. Default: \code{10}.} -\item{cutOff}{a single \code{numeric} representing TODO. Default: \code{-3}.} +\item{cutOff}{a \code{numeric} representing the cut-off for considering +a region imbalanced when comparing likelihood to gave allelic fraction +change and likelihood not to have allelic fraction change. +Default: \code{-3}.} } \value{ a \code{matrix} of \code{numeric} with 3 columns where each From 8e39cbfbe914c0b8f04c036ed96561a2f35ddc10 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sat, 19 Aug 2023 23:08:53 -0400 Subject: [PATCH 155/385] Update GDS Reference vignette --- vignettes/Create_Reference_GDS_File.Rmd | 46 +++++++++++++++---------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index a6f8bb1e8..edffb584a 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -98,24 +98,25 @@ size, compressed or not + compression ratio. The mandatory fields are: -* *sample.id*: a unique identifier for each sample. -* *snp.id*: a unique identifier for each SNV. -* *sample.annot*: a *data.frame* where each row correspond to a sample and containing those columns: - * *sex*: a identifier of the sex of the sample - * *pop.Group*: TODO - * *superPop*: a identifier of the super-population ancestry of the sample - * *batch*: a unique number representing the batch of provenance of the sample -* *snp.chromosome*: an integer or character mapping for each chromosome. Integer: numeric values 1-26, mapped in order from 1-22, 23=X, 24=XY (the pseudoautosomal region), 25=Y, 26=M (the mitochondrial probes), and 0 for probes with unknown positions; it does not allow NA. Character: “X”, “XY”, “Y” and “M” can be used here, and a blank string indicating unknown position. -* *snp.position*: the base position of each SNV on the chromosome, and 0 for unknown position; it does not allow NA. -* *snp.allele*: TODO -* *snp.AF*: TODO -* *snp.[Population_ID]_AF*: TODO -* *snp.EUR_AF*: TODO -* *snp.AFR_AF*: TODO -* *snp.AMR_AF*: TODO -* *snp.SAS_AF*: TODO -* *genotype*: a SNV genotypic matrix (i.e., the number of A alleles) in individual-major mode nsnp×nsample -* *sample.ref*: TODO +* **sample.id**: a unique identifier for each sample +* **snp.id**: a unique identifier for each SNV. +* **sample.annot**: a *data.frame* where each row correspond to a sample and containing those columns: + * **sex**: a identifier of the sex of the sample + * **pop.Group**: a *character* string representing the sub-population ancestry of the sample (ex:GBR, etc) + * **superPop**: a *character* string representing the super-population ancestry of the sample (ex:EUR, AFR, EAS, SAS, AMR) + * **batch**: an *integer* representing the batch of provenance of the sample +* **snp.chromosome**: an integer or character mapping for each chromosome. Integer: numeric values 1-26, mapped in order from 1-22, 23=X, 24=XY (the pseudoautosomal region), 25=Y, 26=M (the mitochondrial probes), and 0 for probes with unknown positions; it does not allow NA. Character: “X”, “XY”, “Y” and “M” can be used here, and a blank string indicating unknown position +* **snp.position**: a *integer* representing the base position of each SNV on the chromosome, and 0 for unknown position; it does not allow NA. +* **snp.allele**: a *character* string representing the reference allele and alternative allele for each of the SNVs present in the *snp.id* field +* **snp.AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the general population for each of the SNVs present in the *snp.id* field +* **snp.EAS_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the East Asian population for each of the SNVs present in the *snp.id* field +* **snp.EUR_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the European population for each of the SNVs present in the *snp.id* field +* **snp.AFR_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the African population for each of the SNVs present in the *snp.id* field +* **snp.AMR_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the American population for each of the SNVs present in the *snp.id* field +* **snp.SAS_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the South Asian population for each of the SNVs present in the *snp.id* field +* **genotype**: a SNV genotypic *integer* *matrix* (i.e., the number of A alleles) in SNVs-major mode (number of Samples × number of SNvs) +* **sample.ref**: an *integer* indicating if the sample is retained to be used as reference (=1) or removed (=0) as related samples have to be discarded +

@@ -146,6 +147,15 @@ closefn.gds(gdsRefAnnot) ``` + +The mandatory fields are: + +* **phase**: TODO +* **block.annot**: a data.frame containing those columns: + * **block.id**: TODO + * **block.desc**: TODO +* **bloc**: TODO +

From c22b478ab39f8beba943361d51835f2c7a3cfbc5 Mon Sep 17 00:00:00 2001 From: belleau Date: Sun, 20 Aug 2023 11:25:51 -0400 Subject: [PATCH 156/385] Removed loop of add1KG2SampleGDS --- R/processStudy.R | 52 ++++++++++++++++++++++++----------------- man/add1KG2SampleGDS.Rd | 1 - 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 20d5e64f4..561cb4156 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -610,7 +610,6 @@ pruningSample <- function(gdsReference, #' @examples #' #' ## Required library for GDS -#' library(gdsfmt) #' library(SNPRelate) #' #' ## Path to the demo 1KG GDS file is located in this package @@ -701,26 +700,33 @@ add1KG2SampleGDS <- function(gdsReference, fileProfileGDS, currentProfile, var.geno <- NULL - j <- 1 - for(i in listRef) { - g <- read.gdsn(index.gdsn(gdsReference, "genotype"), start=c(1,i), - count = c(-1,1))[listSNP] - - if(! ("genotype" %in% ls.gdsn(gdsSample))){ - var.geno <- add.gdsn(gdsSample, "genotype", - valdim=c(length(listSNP), 1), g, storage="bit2") - - }else { - if(is.null(var.geno)) { - var.geno <- index.gdsn(gdsSample, "genotype") - } - append.gdsn(var.geno, g) - } - if(j %% 5 == 0) { - sync.gds(gdsSample) - } - j <- j + 1 - } + j <- apply(matrix(c(seq_len(length(listRef)), listRef), ncol=2), 1, + FUN=function(x, gdsReference, + gdsSample, listSNP){ + i <- x[2] + j <- x[1] + + g <- read.gdsn(index.gdsn(gdsReference, "genotype"), start=c(1,i), + count = c(-1,1))[listSNP] + + if(! ("genotype" %in% ls.gdsn(gdsSample))){ + var.geno <- add.gdsn(gdsSample, "genotype", + valdim=c(length(listSNP), 1), g, storage="bit2") + + }else { + if(is.null(var.geno)) { + var.geno <- index.gdsn(gdsSample, "genotype") + } + append.gdsn(var.geno, g) + } + if(j %% 5 == 0) { + sync.gds(gdsSample) + } + return(NULL) + }, + gdsReference=gdsReference, + gdsSample=gdsSample, + listSNP=listSNP) # add.gdsn(gdsSample, "SamplePos", objdesp.gdsn(index.gdsn(gdsSample, # "genotype"))$dim[2] + 1, @@ -729,7 +735,9 @@ add1KG2SampleGDS <- function(gdsReference, fileProfileGDS, currentProfile, posCur <- which(study.annot$data.id == currentProfile & study.annot$study.id == studyID) - + if(is.null(var.geno)) { + var.geno <- index.gdsn(gdsSample, "genotype") + } g <- read.gdsn(index.gdsn(gdsSample, "geno.ref"), start=c(1, posCur), count=c(-1, 1))[listSNP] append.gdsn(var.geno, g) diff --git a/man/add1KG2SampleGDS.Rd b/man/add1KG2SampleGDS.Rd index 15d039fc8..5a270f8eb 100644 --- a/man/add1KG2SampleGDS.Rd +++ b/man/add1KG2SampleGDS.Rd @@ -34,7 +34,6 @@ the Profile GDS file. The nodes are added to the Profile GDS file: \examples{ ## Required library for GDS -library(gdsfmt) library(SNPRelate) ## Path to the demo 1KG GDS file is located in this package From 034c237ba6e310054e16bfd8193bbfc6786d4093 Mon Sep 17 00:00:00 2001 From: belleau Date: Sun, 20 Aug 2023 12:13:59 -0400 Subject: [PATCH 157/385] Remove unused functions in processStudy --- NAMESPACE | 5 - R/processStudy.R | 466 -------------------- R/processStudy_internal.R | 119 ----- man/addPhase1KG2SampleGDSFromFile.Rd | 48 -- man/addPhase1KG2SampleGDSFromGDS.Rd | 44 -- man/appendStudy2GDS1KG.Rd | 103 ----- man/computePrunedPCARef.Rd | 49 -- man/projectSample2PCA.Rd | 66 --- man/validateAppendStudy2GDS1KG.Rd | 90 ---- tests/testthat/test-processStudy.R | 334 -------------- tests/testthat/test-processStudy_internal.R | 26 -- 11 files changed, 1350 deletions(-) delete mode 100644 man/addPhase1KG2SampleGDSFromFile.Rd delete mode 100644 man/addPhase1KG2SampleGDSFromGDS.Rd delete mode 100644 man/appendStudy2GDS1KG.Rd delete mode 100644 man/computePrunedPCARef.Rd delete mode 100644 man/projectSample2PCA.Rd delete mode 100644 man/validateAppendStudy2GDS1KG.Rd diff --git a/NAMESPACE b/NAMESPACE index 0ab3f8b45..4126b7894 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,11 +3,8 @@ export(add1KG2SampleGDS) export(addBlockFromPlink2GDS) export(addGeneBlockGDSRefAnnot) -export(addPhase1KG2SampleGDSFromFile) -export(addPhase1KG2SampleGDSFromGDS) export(addRef2GDS1KG) export(addStudy1Kg) -export(appendStudy2GDS1KG) export(basePCASample) export(computeAncestryFromSyntheticFile) export(computeKNNRefSample) @@ -15,7 +12,6 @@ export(computeKNNRefSynthetic) export(computePCAMultiSynthetic) export(computePCARefSample) export(computePoolSyntheticAncestryGr) -export(computePrunedPCARef) export(computeSyntheticROC) export(createStudy2GDS1KG) export(estimateAllelicFraction) @@ -27,7 +23,6 @@ export(groupChr1KGSNV) export(identifyRelative) export(prepPed1KG) export(prepSynthetic) -export(projectSample2PCA) export(pruningSample) export(runExomeAncestry) export(runRNAAncestry) diff --git a/R/processStudy.R b/R/processStudy.R index 561cb4156..135b484f0 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -187,140 +187,6 @@ createStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), return(0L) } -#' @title Create the GDS Sample file(s) for one or multiple specific samples -#' using the information from a RDS Sample description file and the 1KG -#' GDS file -#' -#' @description The function uses the information for the 1KG GDS file and the -#' RDS Sample Description file to create the GDS Sample file. One GDS Sample -#' file is created per sample. One GDS Sample file will be created for each -#' entry present in the \code{listSamples} parameter. -#' -#' @param pathGeno a \code{character} string representing the path to the -#' directory containing the output of SNP-pileup, a VCF Sample file, for -#' each sample. The -#' SNP-pileup files must be compressed (gz files) and have the name identifiers -#' of the samples. A sample with "Name.ID" identifier would have an -#' associated SNP-pileup file called "Name.ID.txt.gz". -#' -#' @param filePedRDS a \code{character} string representing the path to the -#' RDS file that contains the information about the sample to analyse. -#' The RDS file must -#' include a \code{data.frame} with those mandatory columns: "Name.ID", -#' "Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in -#' \code{character} strings. The \code{data.frame} -#' must contain the information for all the samples passed in the -#' \code{listSamples} parameter. -#' -#' @param fileNameGDS a \code{character} string representing the file name of -#' the 1KG GDS file. The file must exist. -#' -#' @param batch a single positive \code{integer} representing the current -#' identifier for the batch. Beware, this field is not stored anymore. -#' Default: \code{1}. -#' -#' @param studyDF a \code{data.frame} containing the information about the -#' study associated to the analysed sample(s). The \code{data.frame} must have -#' those 3 columns: "study.id", "study.desc", "study.platform". All columns -#' must be in \code{character} strings. -#' -#' @param listSamples a \code{vector} of \code{character} string corresponding -#' to the sample identifiers that will have a GDS Sample file created. The -#' sample identifiers must be present in the "Name.ID" column of the RDS file -#' passed to the \code{filePedRDS} parameter. -#' If \code{NULL}, all samples in the \code{filePedRDS} are selected. -#' Default: \code{NULL}. -#' -#' @param pathProfileGDS a \code{character} string representing the path to -#' the directory where the GDS Sample files will be created. -#' Default: \code{NULL}. -#' -#' @param genoSource a \code{character} string with two possible values: -#' 'snp-pileup' or 'generic'. It specifies if the genotype files -#' are generated by snp-pileup (Facets) or are a generic format CSV file -#' with at least those columns: -#' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. -#' The 'Count' is the depth at the specified position; -#' 'FileR' is the depth of the reference allele and -#' 'File1A' is the depth of the specific alternative allele. -#' -#' @param verbose a \code{logical} indicating if message information should be -#' printed. Default: \code{TRUE}. -#' -#' @return The function returns \code{0L} when successful. -#' -#' @examples -#' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") -#' -#' ## The data.frame containing the information about the study -#' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" -#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) -#' studyInfo <- data.frame(study.id="Pancreatic.WES", -#' study.desc="Pancreatic study", -#' study.platform="WES", -#' stringsAsFactors=FALSE) -#' -#' ## TODO -#' filePedRDS <- "TODO" -#' -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt createfn.gds put.attr.gdsn closefn.gds read.gdsn -#' @importFrom rlang arg_match -#' @encoding UTF-8 -#' @export -appendStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), - filePedRDS, fileNameGDS, batch=1, studyDF, - listSamples=NULL, pathProfileGDS=NULL, - genoSource=c("snp-pileup", "generic"), verbose=TRUE) { - - ## Validate inputs - validateAppendStudy2GDS1KG(pathGeno=pathGeno, filePedRDS=filePedRDS, - fileNameGDS=fileNameGDS, batch=batch, studyDF=studyDF, - listSamples=listSamples, pathProfileGDS=pathProfileGDS, - genoSource=genoSource, verbose=verbose) - - genoSource <- arg_match(genoSource) - - ## Open the RDS Sample information file - pedStudy <- readRDS(file=filePedRDS) - - ## Read the Reference GDS file - gdsReference <- snpgdsOpen(filename=fileNameGDS) - - ## Extract the chromosome and position information for all SNPs - ## in Reference GDS - ## Create a data.frame containing the information - snpCHR <- index.gdsn(node=gdsReference, "snp.chromosome") - snpPOS <- index.gdsn(node=gdsReference, "snp.position") - - listPos <- data.frame(snp.chromosome=read.gdsn(snpCHR), - snp.position=read.gdsn(snpPOS)) - - if (verbose) { - message("Start ", Sys.time()) - message("Sample info DONE ", Sys.time()) - } - - generateGDS1KGgenotypeFromSNPPileup(pathGeno=pathGeno, - listSamples=listSamples, listPos=listPos, offset=-1, - minCov=10, minProb=0.999, seqError=0.001, dfPedProfile=pedStudy, - batch=batch, studyDF=studyDF, pathProfileGDS=pathProfileGDS, - genoSource=genoSource, verbose=verbose) - - if (verbose) { - message("Genotype DONE ", Sys.time()) - } - - ## Close Reference GDS file - closefn.gds(gdsReference) - - ## Return successful code - return(0L) -} - #' @title Compute the list of pruned SNVs for a specific profile using the #' information from the Reference GDS file and a linkage disequilibrium @@ -752,338 +618,6 @@ add1KG2SampleGDS <- function(gdsReference, fileProfileGDS, currentProfile, return(0L) } -#' @title TODO -#' -#' @description TODO -#' -#' @param gdsReference an object of class -#' \link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file. -#' -#' @param pathProfileGDS a \code{character} string representing the path to -#' the directory that contains the Profile GDS files. The directory must -#' exist. -#' -#' @param pathGeno a \code{character} string representing the path to -#' the directory that contains TODO -#' -#' @param fileSNPsRDS TODO -#' -#' @param verbose a \code{logical} indicating if message information should be -#' printed. Default: \code{FALSE}. -#' -#' @return The integer \code{0L} when successful. -#' -#' @examples -#' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", 'RAIDS') -#' -#' ## TODO -#' -#' @author Pascal Belleau, Astrid Deschênes and Alex Krasnitz -#' @importFrom gdsfmt index.gdsn read.gdsn -#' @encoding UTF-8 -#' @export -addPhase1KG2SampleGDSFromFile <- function(gdsReference, pathProfileGDS, - pathGeno, fileSNPsRDS, verbose=FALSE) { - - ## The gdsReference must be an object of class "gds.class" - validateGDSClass(gds=gdsReference, name="gdsReference") - - ## Verbose must be a logical - if (!is.logical(verbose)) { - stop("The \'verbose\' parameter must be a logical (TRUE or FALSE).") - } - - listGDSSample <- dir(pathProfileGDS, pattern = ".+.gds") - - ## Each index is very big and there is a lot of overlapping between - ## the samples - ## The for loop limits the memory usage - indexAll <- NULL - for(fileProfileGDS in listGDSSample) { - gdsSample <- openfn.gds(filename=file.path(pathProfileGDS, - fileProfileGDS)) - - snp.index <- read.gdsn(node=index.gdsn(node=gdsSample, "snp.index")) - - indexAll <- union(indexAll, snp.index) - closefn.gds(gdsfile=gdsSample) - } - - gdsSample <- createfn.gds(file.path(pathProfileGDS, "phase1KG.gds")) - indexAll <- indexAll[order(indexAll)] - snp.id <- read.gdsn(index.gdsn(gdsReference,"snp.id"))[indexAll] - add.gdsn(gdsSample, "snp.id", snp.id) - add.gdsn(gdsSample, "snp.index", indexAll) - listRef <- which(read.gdsn(index.gdsn(gdsReference, "sample.ref"))==1) - listSample <- read.gdsn(index.gdsn(gdsReference, "sample.id"))[listRef] - listSNP <- readRDS(file=fileSNPsRDS) - i<-1 - for(sample1KG in listSample){ - if(verbose) { message("P ", i, " ", Sys.time()) } - i <- i + 1 - file1KG <- file.path(pathGeno, paste0(sample1KG,".csv.bz2")) - matSample <- read.csv2(file=file1KG, row.names=NULL) - matSample <- matSample[listSNP[indexAll],, drop=FALSE] - matSample <- matrix(as.numeric(unlist(strsplit(matSample[,1], - "\\|"))), nrow=2)[1,] - var.phase <- NULL - if (!("phase" %in% ls.gdsn(gdsSample))) { - var.phase <- add.gdsn(gdsSample, "phase", - valdim=c(length(indexAll), 1), - matSample, storage="bit2") - } else { - if (is.null(var.phase)) { - var.phase <- index.gdsn(node=gdsSample, "phase") - } - append.gdsn(node=var.phase, val=matSample) - } - } - - closefn.gds(gdsfile=gdsSample) - - ## Success - return(0L) -} - - -#' @title TODO -#' -#' @description TODO -#' -#' @param gdsReference an object of class -#' \code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, a SNP -#' GDS file. -#' -#' @param gdsPhase TODO -#' -#' @param pathProfileGDS the path of an object of class \code{gds} related to -#' the sample -#' -#' @param verbose a \code{logical} indicating if message information should be -#' printed. Default: \code{TRUE}. -#' -#' @return The integer \code{0} when successful. -#' -#' @examples -#' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", "RAIDS") -#' -#' ## TODO -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt index.gdsn read.gdsn -#' @encoding UTF-8 -#' @export -addPhase1KG2SampleGDSFromGDS <- function(gdsReference, gdsPhase, pathProfileGDS, - verbose=FALSE) { - - listGDSSample <- dir(pathProfileGDS, pattern = ".+.gds") - - indexAll <- NULL - for(fileProfileGDS in listGDSSample){ - gdsSample <- openfn.gds(file.path(pathProfileGDS, fileProfileGDS)) - - snp.index <- read.gdsn(index.gdsn(gdsSample,"snp.index")) - - indexAll <- union(indexAll, snp.index) - closefn.gds(gdsSample) - } - - gdsSample <- createfn.gds(file.path(pathProfileGDS, "phase1KG.gds")) - indexAll <- indexAll[order(indexAll)] - snp.id <- read.gdsn(index.gdsn(gdsReference,"snp.id"))[indexAll] - add.gdsn(gdsSample, "snp.id", snp.id) - add.gdsn(gdsSample, "snp.index", indexAll) - listRef <- which(read.gdsn(index.gdsn(gdsReference, "sample.ref"))==1) - listSample <- read.gdsn(index.gdsn(gdsReference, "sample.id"))[listRef] - #listSNP <- readRDS(fileSNPsRDS) - i<-1 - for(sample1KG in listSample){ - if(verbose) { message("P ", i, " ", Sys.time()) } - - matSample <- read.gdsn(index.gdsn(gdsPhase, "phase"), - start=c(1, listRef[i]), count=c(-1,1))[indexAll] - i<-i+1 - - var.phase <- NULL - if (! ("phase" %in% ls.gdsn(gdsSample))) { - var.phase <- add.gdsn(gdsSample, "phase", - valdim=c(length(indexAll), 1), - matSample, storage="bit2") - - } else { - if (is.null(var.phase)) { - var.phase <- index.gdsn(gdsSample, "phase") - } - append.gdsn(var.phase, matSample) - } - } - - closefn.gds(gdsSample) - - ## Successful - return(0L) -} - - -#' @title Compute principal component axes (PCA) on pruned SNV with the -#' reference samples -#' -#' @description This function compute the PCA on pruned SNV with the -#' reference samples -#' -#' @param gdsProfile an object of class -#' \code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, a SNP -#' GDS file. -#' -#' @param listRef a \code{vector} of string representing the -#' identifier of the profiles in the reference (unrelated). -#' -#' @param np a single positive \code{integer} representing the number of -#' threads. Default: \code{1L}. -#' -#' @param verbose a \code{logical} indicating if the PCA functions should be -#' verbose. Default: \code{FALSE}. -#' -#' @return listPCA a \code{list} containing two objects -#' pca.unrel -> \code{snpgdsPCAClass} -#' and a snp.load -> \code{snpgdsPCASNPLoading} -#' -#' @details -#' -#' More information about the method used to calculate the patient eigenvectors -#' can be found at the Bioconductor SNPRelate website: -#' https://bioconductor.org/packages/SNPRelate/ -#' -#' @examples -#' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", "RAIDS") -#' -#' ## TODO -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom SNPRelate snpgdsPCA snpgdsPCASNPLoading -#' @importFrom gdsfmt index.gdsn read.gdsn -#' @importFrom S4Vectors isSingleNumber -#' @encoding UTF-8 -#' @export -computePrunedPCARef <- function(gdsProfile, listRef, np=1L, verbose=FALSE) { - - ## The gdsReference must be an object of class "gds.class" - validateGDSClass(gds=gdsProfile, name="gdsProfile") - - ## Validate that np is a single positive integer - if(! (isSingleNumber(np) && np > 0)) { - stop("The \'np\' parameter must be a single positive integer.") - } - - if(! is.logical(verbose)) { - stop("The \'verbose\' parameter must be logical (TRUE or FALSE).") - } - - listPCA <- list() - - listPruned <- read.gdsn(index.gdsn(gdsProfile, "pruned.study")) - - ## Calculate the eigenvectors using the specified SNP loadings for - ## the reference profiles - listPCA[["pca.unrel"]] <- snpgdsPCA(gdsobj=gdsProfile, - sample.id=listRef, - snp.id=listPruned, - num.thread=np, - verbose=verbose) - - listPCA[["snp.load"]] <- snpgdsPCASNPLoading(pcaobj=listPCA[["pca.unrel"]], - gdsobj=gdsProfile, - num.thread=np, - verbose=verbose) - return(listPCA) -} - - - -#' @title Project profile onto existing principal component axes (PCA) -#' -#' @description This function calculates the profile eigenvectors using -#' the specified SNP loadings. -#' -#' @param gdsProfile an object of class -#' \code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, an -#' opened Profile GDS file. -#' -#' @param listPCA a \code{list} containing two entries: -#' \itemize{ -#' \item{pca.unrel} {\code{snpgdsPCAClass} object} -#' \item{snp.load} {\code{snpgdsPCASNPLoading} object} -#' } -#' -#' @param currentProfile a \code{character} string representing the -#' identifiant of the profile to be projected in the PCA. -#' -#' @param np a single positive \code{integer} representing the number of -#' threads. Default: \code{1L}. -#' -#' @param verbose a \code{logical} passed to the PCA function. -#' Default: \code{FALSE}. -#' -#' @return a \code{snpgdsPCAClass} object, a \code{list} that contains: -#' \itemize{ -#' \item{sample.id} {the sample ids used in the analysis} -#' \item{snp.id} {the SNP ids used in the analysis} -#' \item{eigenvalues} {eigenvalues} -#' \item{eigenvect} {eigenvactors, “# of samples” x “eigen.cnt”} -#' \item{TraceXTX} {the trace of the genetic covariance matrix} -#' \item{Bayesian} {whether use bayerisan normalization} -#'} -#' -#' @details -#' -#' More information about the method used to calculate the patient eigenvectors -#' can be found at the Bioconductor SNPRelate website: -#' https://bioconductor.org/packages/SNPRelate/ -#' -#' @examples -#' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", "RAIDS") -#' -#' ## TODO -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom SNPRelate snpgdsPCASampLoading -#' @importFrom S4Vectors isSingleNumber -#' @encoding UTF-8 -#' @export -projectSample2PCA <- function(gdsProfile, listPCA, currentProfile, np=1L, - verbose=FALSE) { - - - ## Validate that currentProfile is a character string - if(! is.character(currentProfile)) { - stop("The \'currentProfile\' parameter must be a character string.") - } - - ## Validate that np is a single positive integer - if(! (isSingleNumber(np) && np > 0)) { - stop("The \'np\' parameter must be a single positive integer.") - } - - if(! is.logical(verbose)) { - stop("The \'verbose\' parameter must be logical (TRUE or FALSE).") - } - - ## Calculate the sample eigenvectors using the specified SNP loadings - samplePCA <- snpgdsPCASampLoading(listPCA[["snp.load"]], - gdsobj=gdsProfile, sample.id=currentProfile, - num.thread=1, verbose=verbose) - - return(samplePCA) -} - #' @title Append information about the 1KG samples into #' the Profile GDS file diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 717c81787..56d3945d0 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -861,125 +861,6 @@ validateComputePCARefSample <- function(gdsProfile, currentProfile, studyIDRef, } -#' @title Validate input parameters for appendStudy2GDS1KG() function -#' -#' @description This function validates the input parameters for the -#' \code{\link{appendStudy2GDS1KG}} function. -#' -#' @param pathGeno a \code{character} string representing the path to the -#' directory containing the output of SNP-pileup, a VCF Sample file, for -#' each sample. -#' -#' @param filePedRDS a \code{character} string representing the path to the -#' RDS file that contains the information about the sample to analyse. -#' -#' @param fileNameGDS a \code{character} string representing the file name of -#' the Population Reference GDS file. The file must exist. -#' -#' @param batch a single positive \code{integer} representing the current -#' identifier for the batch. Beware, this field is not stored anymore. -#' -#' @param studyDF a \code{data.frame} containing the information about the -#' study associated to the analysed sample(s). The \code{data.frame} must have -#' those 3 columns: "studyID", "study.desc", "study.platform". All columns -#' must be in \code{character} strings. -#' -#' @param listSamples a \code{vector} of \code{character} string corresponding -#' to the sample identifiers that will have a GDS Sample file created. The -#' sample identifiers must be present in the "Name.ID" column of the RDS file -#' passed to the \code{filePedRDS} parameter. -#' If \code{NULL}, all samples in the \code{filePedRDS} are selected. -#' -#' @param pathProfileGDS a \code{character} string representing the path to -#' the directory where the GDS Sample files will be created. -#' -#' @param genoSource a \code{character} string with two possible values: -#' 'snp-pileup' or 'generic'. It specifies if the genotype files -#' are generate by snp-pileup (Facets) or generic format csv. -#' -#' @param verbose a \code{logical} indicating if message information should be -#' printed. -#' -#' @return The function returns \code{0L} when successful. -#' -#' @examples -#' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") -#' -#' ## Demo 1KG Population reference GDS file -#' gds1KG <- file.path(dataDir, "1KG_Demo.gds") -#' ped <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") -#' -#' ## The data.frame containing the information about the study -#' ## The 3 mandatory columns: "studyID", "study.desc", "study.platform" -#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) -#' studyInfo <- data.frame(study.id="Pancreatic.WES", -#' study.desc="Pancreatic study", -#' study.platform="WES", -#' stringsAsFactors=FALSE) -#' -#' ## The validatiion should be successful -#' RAIDS:::validateAppendStudy2GDS1KG(pathGeno=dataDir, -#' filePedRDS=ped, fileNameGDS=gds1KG, -#' batch=1L, studyDF=studyInfo, listSamples=c("HC01", "HC02"), -#' pathProfileGDS=dataDir, genoSource="snp-pileup", verbose=TRUE) -#' -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom S4Vectors isSingleNumber -#' @encoding UTF-8 -#' @keywords internal -validateAppendStudy2GDS1KG <- function(pathGeno, filePedRDS, fileNameGDS, - batch, studyDF, listSamples, pathProfileGDS, - genoSource, verbose) { - - ## The pathGeno must be a character string and the path must exists - if (!(is.character(pathGeno) && (dir.exists(pathGeno)))) { - stop("The \'pathGeno\' must be a character string representing ", - "a path. The path must exist.") - } - - ## The filePedRDS must be a character string and the file must exists - if (!(is.character(filePedRDS) && (file.exists(filePedRDS)))) { - stop("The \'filePedRDS\' must be a character string representing ", - "the RDS Sample information file. The file must exist.") - } - - ## The fileNameGDS must be a character string and the file must exists - if (!(is.character(fileNameGDS) && (file.exists(fileNameGDS)))) { - stop("The \'fileNameGDS\' must be a character string representing ", - "the Population Reference GDS file. The file must exist.") - } - - ## The batch must be a single numeric - if (!(isSingleNumber(batch))) { - stop("The \'batch\' must be a single integer.") - } - - if (!(is.data.frame(studyDF) && all(c("study.id", "study.desc", - "study.platform") %in% colnames(studyDF)))) { - stop("The \'studyDF\' must be a data.frame and contain those 3 ", - "columns: \'study.id\', \'study.desc\' and \'study.platform\'.") - } - - ## The listSamples must be a vector of character string - if (!(is.character(listSamples) || is.null(listSamples))) { - stop("The \'listSamples\' must be a vector ", - "of character strings (1 entry or more) or NULL.") - } - - ## The genoSource must be a character string - if (!is.character(genoSource)) { - stop("The \'genoSource\' parameter must be a character string.") - } - - ## The verbose parameter must be a logical - validateLogical(logical=verbose, name="verbose") - - return(0L) -} - #' @title Validate input parameters for add1KG2SampleGDS() function #' #' @description This function validates the input parameters for the diff --git a/man/addPhase1KG2SampleGDSFromFile.Rd b/man/addPhase1KG2SampleGDSFromFile.Rd deleted file mode 100644 index ee339f644..000000000 --- a/man/addPhase1KG2SampleGDSFromFile.Rd +++ /dev/null @@ -1,48 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy.R -\encoding{UTF-8} -\name{addPhase1KG2SampleGDSFromFile} -\alias{addPhase1KG2SampleGDSFromFile} -\title{TODO} -\usage{ -addPhase1KG2SampleGDSFromFile( - gdsReference, - pathProfileGDS, - pathGeno, - fileSNPsRDS, - verbose = FALSE -) -} -\arguments{ -\item{gdsReference}{an object of class -\link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file.} - -\item{pathProfileGDS}{a \code{character} string representing the path to -the directory that contains the Profile GDS files. The directory must -exist.} - -\item{pathGeno}{a \code{character} string representing the path to -the directory that contains TODO} - -\item{fileSNPsRDS}{TODO} - -\item{verbose}{a \code{logical} indicating if message information should be -printed. Default: \code{FALSE}.} -} -\value{ -The integer \code{0L} when successful. -} -\description{ -TODO -} -\examples{ - -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", 'RAIDS') - -## TODO - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alex Krasnitz -} diff --git a/man/addPhase1KG2SampleGDSFromGDS.Rd b/man/addPhase1KG2SampleGDSFromGDS.Rd deleted file mode 100644 index d86163380..000000000 --- a/man/addPhase1KG2SampleGDSFromGDS.Rd +++ /dev/null @@ -1,44 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy.R -\encoding{UTF-8} -\name{addPhase1KG2SampleGDSFromGDS} -\alias{addPhase1KG2SampleGDSFromGDS} -\title{TODO} -\usage{ -addPhase1KG2SampleGDSFromGDS( - gdsReference, - gdsPhase, - pathProfileGDS, - verbose = FALSE -) -} -\arguments{ -\item{gdsReference}{an object of class -\code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, a SNP -GDS file.} - -\item{gdsPhase}{TODO} - -\item{pathProfileGDS}{the path of an object of class \code{gds} related to -the sample} - -\item{verbose}{a \code{logical} indicating if message information should be -printed. Default: \code{TRUE}.} -} -\value{ -The integer \code{0} when successful. -} -\description{ -TODO -} -\examples{ - -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", "RAIDS") - -## TODO - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} diff --git a/man/appendStudy2GDS1KG.Rd b/man/appendStudy2GDS1KG.Rd deleted file mode 100644 index 9dae8e382..000000000 --- a/man/appendStudy2GDS1KG.Rd +++ /dev/null @@ -1,103 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy.R -\encoding{UTF-8} -\name{appendStudy2GDS1KG} -\alias{appendStudy2GDS1KG} -\title{Create the GDS Sample file(s) for one or multiple specific samples -using the information from a RDS Sample description file and the 1KG -GDS file} -\usage{ -appendStudy2GDS1KG( - pathGeno = file.path("data", "sampleGeno"), - filePedRDS, - fileNameGDS, - batch = 1, - studyDF, - listSamples = NULL, - pathProfileGDS = NULL, - genoSource = c("snp-pileup", "generic"), - verbose = TRUE -) -} -\arguments{ -\item{pathGeno}{a \code{character} string representing the path to the -directory containing the output of SNP-pileup, a VCF Sample file, for -each sample. The -SNP-pileup files must be compressed (gz files) and have the name identifiers -of the samples. A sample with "Name.ID" identifier would have an -associated SNP-pileup file called "Name.ID.txt.gz".} - -\item{filePedRDS}{a \code{character} string representing the path to the -RDS file that contains the information about the sample to analyse. -The RDS file must -include a \code{data.frame} with those mandatory columns: "Name.ID", -"Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in -\code{character} strings. The \code{data.frame} -must contain the information for all the samples passed in the -\code{listSamples} parameter.} - -\item{fileNameGDS}{a \code{character} string representing the file name of -the 1KG GDS file. The file must exist.} - -\item{batch}{a single positive \code{integer} representing the current -identifier for the batch. Beware, this field is not stored anymore. -Default: \code{1}.} - -\item{studyDF}{a \code{data.frame} containing the information about the -study associated to the analysed sample(s). The \code{data.frame} must have -those 3 columns: "study.id", "study.desc", "study.platform". All columns -must be in \code{character} strings.} - -\item{listSamples}{a \code{vector} of \code{character} string corresponding -to the sample identifiers that will have a GDS Sample file created. The -sample identifiers must be present in the "Name.ID" column of the RDS file -passed to the \code{filePedRDS} parameter. -If \code{NULL}, all samples in the \code{filePedRDS} are selected. -Default: \code{NULL}.} - -\item{pathProfileGDS}{a \code{character} string representing the path to -the directory where the GDS Sample files will be created. -Default: \code{NULL}.} - -\item{genoSource}{a \code{character} string with two possible values: -'snp-pileup' or 'generic'. It specifies if the genotype files -are generated by snp-pileup (Facets) or are a generic format CSV file -with at least those columns: -'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. -The 'Count' is the depth at the specified position; -'FileR' is the depth of the reference allele and -'File1A' is the depth of the specific alternative allele.} - -\item{verbose}{a \code{logical} indicating if message information should be -printed. Default: \code{TRUE}.} -} -\value{ -The function returns \code{0L} when successful. -} -\description{ -The function uses the information for the 1KG GDS file and the -RDS Sample Description file to create the GDS Sample file. One GDS Sample -file is created per sample. One GDS Sample file will be created for each -entry present in the \code{listSamples} parameter. -} -\examples{ - -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", package="RAIDS") - -## The data.frame containing the information about the study -## The 3 mandatory columns: "study.id", "study.desc", "study.platform" -## The entries should be strings, not factors (stringsAsFactors=FALSE) -studyInfo <- data.frame(study.id="Pancreatic.WES", - study.desc="Pancreatic study", - study.platform="WES", - stringsAsFactors=FALSE) - -## TODO -filePedRDS <- "TODO" - - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} diff --git a/man/computePrunedPCARef.Rd b/man/computePrunedPCARef.Rd deleted file mode 100644 index 03d1a2fe0..000000000 --- a/man/computePrunedPCARef.Rd +++ /dev/null @@ -1,49 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy.R -\encoding{UTF-8} -\name{computePrunedPCARef} -\alias{computePrunedPCARef} -\title{Compute principal component axes (PCA) on pruned SNV with the -reference samples} -\usage{ -computePrunedPCARef(gdsProfile, listRef, np = 1L, verbose = FALSE) -} -\arguments{ -\item{gdsProfile}{an object of class -\code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, a SNP -GDS file.} - -\item{listRef}{a \code{vector} of string representing the -identifier of the profiles in the reference (unrelated).} - -\item{np}{a single positive \code{integer} representing the number of -threads. Default: \code{1L}.} - -\item{verbose}{a \code{logical} indicating if the PCA functions should be -verbose. Default: \code{FALSE}.} -} -\value{ -listPCA a \code{list} containing two objects -pca.unrel -> \code{snpgdsPCAClass} -and a snp.load -> \code{snpgdsPCASNPLoading} -} -\description{ -This function compute the PCA on pruned SNV with the -reference samples -} -\details{ -More information about the method used to calculate the patient eigenvectors -can be found at the Bioconductor SNPRelate website: -https://bioconductor.org/packages/SNPRelate/ -} -\examples{ - -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", "RAIDS") - -## TODO - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} diff --git a/man/projectSample2PCA.Rd b/man/projectSample2PCA.Rd deleted file mode 100644 index 9a789c72d..000000000 --- a/man/projectSample2PCA.Rd +++ /dev/null @@ -1,66 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy.R -\encoding{UTF-8} -\name{projectSample2PCA} -\alias{projectSample2PCA} -\title{Project profile onto existing principal component axes (PCA)} -\usage{ -projectSample2PCA( - gdsProfile, - listPCA, - currentProfile, - np = 1L, - verbose = FALSE -) -} -\arguments{ -\item{gdsProfile}{an object of class -\code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, an -opened Profile GDS file.} - -\item{listPCA}{a \code{list} containing two entries: -\itemize{ -\item{pca.unrel} {\code{snpgdsPCAClass} object} -\item{snp.load} {\code{snpgdsPCASNPLoading} object} -}} - -\item{currentProfile}{a \code{character} string representing the -identifiant of the profile to be projected in the PCA.} - -\item{np}{a single positive \code{integer} representing the number of -threads. Default: \code{1L}.} - -\item{verbose}{a \code{logical} passed to the PCA function. -Default: \code{FALSE}.} -} -\value{ -a \code{snpgdsPCAClass} object, a \code{list} that contains: -\itemize{ -\item{sample.id} {the sample ids used in the analysis} -\item{snp.id} {the SNP ids used in the analysis} -\item{eigenvalues} {eigenvalues} -\item{eigenvect} {eigenvactors, “# of samples” x “eigen.cnt”} -\item{TraceXTX} {the trace of the genetic covariance matrix} -\item{Bayesian} {whether use bayerisan normalization} -} -} -\description{ -This function calculates the profile eigenvectors using -the specified SNP loadings. -} -\details{ -More information about the method used to calculate the patient eigenvectors -can be found at the Bioconductor SNPRelate website: -https://bioconductor.org/packages/SNPRelate/ -} -\examples{ - -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", "RAIDS") - -## TODO - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} diff --git a/man/validateAppendStudy2GDS1KG.Rd b/man/validateAppendStudy2GDS1KG.Rd deleted file mode 100644 index f3c9253ed..000000000 --- a/man/validateAppendStudy2GDS1KG.Rd +++ /dev/null @@ -1,90 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/processStudy_internal.R -\encoding{UTF-8} -\name{validateAppendStudy2GDS1KG} -\alias{validateAppendStudy2GDS1KG} -\title{Validate input parameters for appendStudy2GDS1KG() function} -\usage{ -validateAppendStudy2GDS1KG( - pathGeno, - filePedRDS, - fileNameGDS, - batch, - studyDF, - listSamples, - pathProfileGDS, - genoSource, - verbose -) -} -\arguments{ -\item{pathGeno}{a \code{character} string representing the path to the -directory containing the output of SNP-pileup, a VCF Sample file, for -each sample.} - -\item{filePedRDS}{a \code{character} string representing the path to the -RDS file that contains the information about the sample to analyse.} - -\item{fileNameGDS}{a \code{character} string representing the file name of -the Population Reference GDS file. The file must exist.} - -\item{batch}{a single positive \code{integer} representing the current -identifier for the batch. Beware, this field is not stored anymore.} - -\item{studyDF}{a \code{data.frame} containing the information about the -study associated to the analysed sample(s). The \code{data.frame} must have -those 3 columns: "studyID", "study.desc", "study.platform". All columns -must be in \code{character} strings.} - -\item{listSamples}{a \code{vector} of \code{character} string corresponding -to the sample identifiers that will have a GDS Sample file created. The -sample identifiers must be present in the "Name.ID" column of the RDS file -passed to the \code{filePedRDS} parameter. -If \code{NULL}, all samples in the \code{filePedRDS} are selected.} - -\item{pathProfileGDS}{a \code{character} string representing the path to -the directory where the GDS Sample files will be created.} - -\item{genoSource}{a \code{character} string with two possible values: -'snp-pileup' or 'generic'. It specifies if the genotype files -are generate by snp-pileup (Facets) or generic format csv.} - -\item{verbose}{a \code{logical} indicating if message information should be -printed.} -} -\value{ -The function returns \code{0L} when successful. -} -\description{ -This function validates the input parameters for the -\code{\link{appendStudy2GDS1KG}} function. -} -\examples{ - -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", package="RAIDS") - -## Demo 1KG Population reference GDS file -gds1KG <- file.path(dataDir, "1KG_Demo.gds") -ped <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") - -## The data.frame containing the information about the study -## The 3 mandatory columns: "studyID", "study.desc", "study.platform" -## The entries should be strings, not factors (stringsAsFactors=FALSE) -studyInfo <- data.frame(study.id="Pancreatic.WES", - study.desc="Pancreatic study", - study.platform="WES", - stringsAsFactors=FALSE) - -## The validatiion should be successful -RAIDS:::validateAppendStudy2GDS1KG(pathGeno=dataDir, - filePedRDS=ped, fileNameGDS=gds1KG, - batch=1L, studyDF=studyInfo, listSamples=c("HC01", "HC02"), - pathProfileGDS=dataDir, genoSource="snp-pileup", verbose=TRUE) - - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{internal} diff --git a/tests/testthat/test-processStudy.R b/tests/testthat/test-processStudy.R index 7ea009793..b8774e080 100644 --- a/tests/testthat/test-processStudy.R +++ b/tests/testthat/test-processStudy.R @@ -11,257 +11,7 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 181538259L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) -############################################################################# -### Tests projectSample2PCA() results -############################################################################# - -context("projectSample2PCA() results") - - -test_that("projectSample2PCA() must return error when np is character string", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - - error_message <- "The \'np\' parameter must be a single positive integer." - - expect_error(projectSample2PCA(gdsProfile=fileGDS, listPCA=list(), - currentProfile="sample1", - np="test"), error_message) -}) - -test_that("projectSample2PCA() must return error when np is negative integer", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - - error_message <- "The \'np\' parameter must be a single positive integer." - - expect_error(projectSample2PCA(gdsProfile=fileGDS, listPCA=list(), - currentProfile="sample1", - np=-1L), error_message) -}) - - -test_that("projectSample2PCA() must return error when np is zero", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - - error_message <- "The \'np\' parameter must be a single positive integer." - - expect_error(projectSample2PCA(gdsProfile=fileGDS, listPCA=list(), - currentProfile="sample1", np=0L), error_message) -}) - - -test_that("projectSample2PCA() must return error when currentProfile is number", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - - error_message <- paste0("The \'currentProfile\' ", - "parameter must be a character string.") - - expect_error(projectSample2PCA(gdsProfile=fileGDS, listPCA=list(), - currentProfile=101, np=1L), error_message) -}) - - -test_that("projectSample2PCA() must return error when verbose is number", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - - error_message <- paste0("The \'verbose\' parameter must be logical ", - "(TRUE or FALSE).") - - expect_error(projectSample2PCA(gdsProfile=fileGDS, listPCA=list(), - currentProfile="sample01", np=1L, verbose=33), error_message, - fixed=TRUE) -}) - - -############################################################################# -### Tests appendStudy2GDS1KG() results -############################################################################# - - -context("appendStudy2GDS1KG() results") - -test_that("appendStudy2GDS1KG() must return error when pathGeno is a numeric", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - sampleRDS <- test_path("fixtures", "Sample_Info_Test.RDS") - - studyInfo <- data.frame(study.id="Pancreatic.WES", - study.desc="Pancreatic study", study.platform="WES", - stringsAsFactors=FALSE) - - error_message <- paste0("The \'pathGeno\' must be a character string ", - "representing a path. The path must exist.") - - expect_error(appendStudy2GDS1KG(pathGeno=22, filePedRDS=sampleRDS, - fileNameGDS=fileGDS, batch=2, - studyDF=studyInfo, listSamples=NULL, pathProfileGDS=NULL, - genoSource="snp-pileup", verbose="TRUE"), error_message, fixed=TRUE) -}) - - -test_that("appendStudy2GDS1KG() must return error when filePedRDS is numeric", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - sampleRDS <- test_path("fixtures", "Sample_Info_Test.RDS") - - studyInfo <- data.frame(study.id="Pancreatic.WES", - study.desc="Pancreatic study", study.platform="WES", - stringsAsFactors=FALSE) - - error_message <- paste0("The \'filePedRDS\' must be a character string ", - "representing the RDS Sample information file. The file must exist.") - - expect_error(appendStudy2GDS1KG(pathGeno=test_path("fixtures"), - filePedRDS=21, fileNameGDS=fileGDS, batch=1, - studyDF=studyInfo, listSamples=NULL, pathProfileGDS=NULL, - genoSource="snp-pileup", verbose=TRUE), error_message) -}) - - -test_that("appendStudy2GDS1KG() must return error when fileNameGDS is numeric", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - sampleRDS <- test_path("fixtures", "Sample_Info_Test.RDS") - - studyInfo <- data.frame(study.id="Pancreatic.WES", - study.desc="Pancreatic study", study.platform="WES", - stringsAsFactors=FALSE) - - error_message <- paste0("The \'fileNameGDS\' must be a character string ", - "representing the Population Reference GDS file. The file must exist.") - - expect_error(appendStudy2GDS1KG(pathGeno=test_path("fixtures"), - filePedRDS=sampleRDS, fileNameGDS=33, batch=1, - studyDF=studyInfo, listSamples=NULL, pathProfileGDS=NULL, - genoSource="snp-pileup", verbose=TRUE), error_message) -}) - - -test_that("appendStudy2GDS1KG() must return error when batch is a vector of numerics", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - sampleRDS <- test_path("fixtures", "Sample_Info_Test.RDS") - - studyInfo <- data.frame(study.id="Pancreatic.WES", study.desc="Pancreatic", - study.platform="WES", stringsAsFactors=FALSE) - - error_message <- "The \'batch\' must be a single integer." - - expect_error(appendStudy2GDS1KG(pathGeno=test_path("fixtures"), - filePedRDS=sampleRDS, fileNameGDS=fileGDS, batch=c(1,2), - studyDF=studyInfo, listSamples=NULL, pathProfileGDS=NULL, - genoSource="snp-pileup", verbose=TRUE), error_message) -}) - -test_that("appendStudy2GDS1KG() must return error when batch is a character string", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - sampleRDS <- test_path("fixtures", "Sample_Info_Test.RDS") - - studyInfo <- data.frame(study.id="Pancreatic.WES", - study.desc="Pancreatic study", study.platform="WES", - stringsAsFactors=FALSE) - - error_message <- "The \'batch\' must be a single integer." - - expect_error(appendStudy2GDS1KG(pathGeno=test_path("fixtures"), - filePedRDS=sampleRDS, fileNameGDS=fileGDS, batch="2", - studyDF=studyInfo, listSamples=NULL, pathProfileGDS=NULL, - genoSource="snp-pileup", verbose=TRUE), error_message) -}) - - -test_that("appendStudy2GDS1KG() must return error when studyDF is missing mandatory column", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - sampleRDS <- test_path("fixtures", "Sample_Info_Test.RDS") - - studyInfo <- data.frame(study.id="Pancreatic.WES", - study.descption="Pancreatic study", study.platform="WES", - stringsAsFactors=FALSE) - error_message <- paste0("The \'studyDF\' must be a data.frame and contain ", - "those 3 columns: \'study.id\', \'study.desc\' and \'study.platform\'.") - - expect_error(appendStudy2GDS1KG(pathGeno=test_path("fixtures"), - filePedRDS=sampleRDS, fileNameGDS=fileGDS, batch=1, - studyDF=studyInfo, listSamples=NULL, pathProfileGDS=NULL, - genoSource="snp-pileup", verbose=TRUE), error_message) -}) - - -test_that("appendStudy2GDS1KG() must return error when listSamples is a numeric", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - sampleRDS <- test_path("fixtures", "Sample_Info_Test.RDS") - - studyInfo <- data.frame(study.id="Pancreatic.WES", - study.desc="Pancreatic study", study.platform="WES", - stringsAsFactors=FALSE) - - error_message <- paste0("The \'listSamples\' must be a vector ", - "of character strings (1 entry or more) or NULL.") - - expect_error(appendStudy2GDS1KG(pathGeno=test_path("fixtures"), - filePedRDS=sampleRDS, fileNameGDS=fileGDS, batch=2, - studyDF=studyInfo, listSamples=33, pathProfileGDS=NULL, - genoSource="snp-pileup", verbose=FALSE), error_message, fixed=TRUE) -}) - -test_that("appendStudy2GDS1KG() must return error when genoSource is a numeric", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - sampleRDS <- test_path("fixtures", "Sample_Info_Test.RDS") - - studyInfo <- data.frame(study.id="Pancreatic.WES", - study.desc="Pancreatic study", study.platform="WES", - stringsAsFactors=FALSE) - - error_message <- 'The \'genoSource\' parameter must be a character string.' - - expect_error(appendStudy2GDS1KG(pathGeno=test_path("fixtures"), - filePedRDS=sampleRDS, fileNameGDS=fileGDS, batch=2, - studyDF=studyInfo, listSamples=NULL, pathProfileGDS=NULL, - genoSource=3, verbose=TRUE), error_message, fixed=TRUE) -}) - - -test_that("appendStudy2GDS1KG() must return error when verbose is a character string", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - sampleRDS <- test_path("fixtures", "Sample_Info_Test.RDS") - - studyInfo <- data.frame(study.id="Pancreatic.WES", - study.desc="Pancreatic study", study.platform="WES", - stringsAsFactors=FALSE) - - error_message <- 'The \'verbose\' parameter must be a logical (TRUE or FALSE).' - - expect_error(appendStudy2GDS1KG(pathGeno=test_path("fixtures"), - filePedRDS=sampleRDS, fileNameGDS=fileGDS, batch=2, - studyDF=studyInfo, listSamples=NULL, pathProfileGDS=NULL, - genoSource="snp-pileup", verbose="TRUE"), error_message, fixed=TRUE) -}) - - -test_that("appendStudy2GDS1KG() must return error when genoSource not in list of choices", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - sampleRDS <- test_path("fixtures", "Sample_Info_Test.RDS") - - studyInfo <- data.frame(study.id="Pancreatic.WES", - study.desc="Pancreatic study", study.platform="WES", - stringsAsFactors=FALSE) - - expect_error(appendStudy2GDS1KG(pathGeno=test_path("fixtures"), - filePedRDS=sampleRDS, fileNameGDS=fileGDS, batch=2, - studyDF=studyInfo, listSamples=NULL, pathProfileGDS=NULL, - genoSource="TOP-pileup", verbose=TRUE)) -}) ############################################################################# ### Tests pruningSample() results @@ -2159,90 +1909,6 @@ test_that(paste0("computeAncestryFromSyntheticFile() must return expected result }) - - - -############################################################################# -### Tests addPhase1KG2SampleGDSFromFile() results -############################################################################# - -context("addPhase1KG2SampleGDSFromFile() results") - - -test_that("addPhase1KG2SampleGDSFromFile() must return error when gdsReference is character string", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - - error_message <- "The \'gdsReference\' must be an object of class \'gds.class\'" - - expect_error(addPhase1KG2SampleGDSFromFile(gdsReference=fileGDS, - pathProfileGDS=test_path("fixtures"), pathGenotest_path("fixtures"), - fileSNPsRDS="test", verbose="CANADA"), error_message, fixed=TRUE) -}) - - -test_that("addPhase1KG2SampleGDSFromFile() must return error when verbose is character string", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - gdsF <- openfn.gds(fileGDS) - withr::defer(closefn.gds(gdsF), envir=parent.frame()) - - error_message <- paste0("The \'verbose\' parameter must be a ", - "logical (TRUE or FALSE).") - - expect_error(addPhase1KG2SampleGDSFromFile(gdsReference=gdsF, - pathProfileGDS=test_path("fixtures"), pathGenotest_path("fixtures"), - fileSNPsRDS="test", verbose="CANADA"), error_message, fixed=TRUE) -}) - - -############################################################################# -### Tests computePrunedPCARef() results -############################################################################# - -context("computePrunedPCARef() results") - - -test_that("computePrunedPCARef() must return error when gdsProfile is character string", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - - error_message <- "The \'gdsProfile\' must be an object of class \'gds.class\'" - - expect_error(computePrunedPCARef(gdsProfile=fileGDS, - listRef=c("sample1", "sample2"), np=1L, verbose=FALSE), - error_message, fixed=TRUE) -}) - - -test_that("computePrunedPCARef() must return error when np is character string", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - gdsF <- openfn.gds(fileGDS) - withr::defer(closefn.gds(gdsF), envir=parent.frame()) - - error_message <- "The \'np\' parameter must be a single positive integer." - - expect_error(computePrunedPCARef(gdsProfile=gdsF, - listRef=c("sample1", "sample2"), np="1", verbose=FALSE), - error_message, fixed=TRUE) -}) - - -test_that("computePrunedPCARef() must return error when verbose is character string", { - - fileGDS <- test_path("fixtures", "1KG_Test.gds") - gdsF <- openfn.gds(fileGDS) - withr::defer(closefn.gds(gdsF), envir=parent.frame()) - - error_message <- "The \'verbose\' parameter must be logical (TRUE or FALSE)." - - expect_error(computePrunedPCARef(gdsProfile=gdsF, - listRef=c("sample1", "sample2"), np=1L, verbose="GLUTEN"), - error_message, fixed=TRUE) -}) - - ############################################################################# ### Tests runExomeAncestry() results ############################################################################# diff --git a/tests/testthat/test-processStudy_internal.R b/tests/testthat/test-processStudy_internal.R index 53a97d440..9c3615666 100644 --- a/tests/testthat/test-processStudy_internal.R +++ b/tests/testthat/test-processStudy_internal.R @@ -152,32 +152,6 @@ test_that("validateComputePCARefSample() must return expected results when all i }) -############################################################################# -### Tests validateAppendStudy2GDS1KG() results -############################################################################# - -context("validateAppendStudy2GDS1KG() results") - - -test_that("validateAppendStudy2GDS1KG() must return expected results when all input are valid", { - - dataDir <- test_path("fixtures") - fileGDS <- file.path(dataDir, "GDS_Sample_with_study_demo.gds") - rdsFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") - - studyInfo <- data.frame(study.id="Pancreatic.WES", - study.desc="Pancreatic study", study.platform="WES", - stringsAsFactors=FALSE) - - result1 <- RAIDS:::validateAppendStudy2GDS1KG(pathGeno=test_path("fixtures"), - filePedRDS=rdsFile, fileNameGDS=fileGDS, - batch=1L, studyDF=studyInfo, listSamples=c("HC01", "HC02"), - pathProfileGDS=test_path("fixtures"), genoSource="snp-pileup", - verbose=TRUE) - - expect_identical(result1, 0L) -}) - ############################################################################# ### Tests validateAdd1KG2SampleGDS() results From 26c76b9ebc54b1c7890e671cdd069f59abc9574d Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 20 Aug 2023 15:59:06 -0400 Subject: [PATCH 158/385] Update GDS Reference vignette --- vignettes/Create_Reference_GDS_File.Rmd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index edffb584a..543409122 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -114,7 +114,7 @@ The mandatory fields are: * **snp.AFR_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the African population for each of the SNVs present in the *snp.id* field * **snp.AMR_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the American population for each of the SNVs present in the *snp.id* field * **snp.SAS_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the South Asian population for each of the SNVs present in the *snp.id* field -* **genotype**: a SNV genotypic *integer* *matrix* (i.e., the number of A alleles) in SNVs-major mode (number of Samples × number of SNvs) +* **genotype**: a SNV genotypic *integer* *matrix* (i.e., the number of A alleles) in SNVs-major mode (number of Samples × number of SNvs) TODO validate mode type * **sample.ref**: an *integer* indicating if the sample is retained to be used as reference (=1) or removed (=0) as related samples have to be discarded @@ -151,9 +151,9 @@ closefn.gds(gdsRefAnnot) The mandatory fields are: * **phase**: TODO -* **block.annot**: a data.frame containing those columns: - * **block.id**: TODO - * **block.desc**: TODO +* **block.annot**: a *data.frame* containing those columns: + * **block.id**: a *character* string representing TODO + * **block.desc**: ! *character* string describing the block TODO * **bloc**: TODO
From 8b9e2a25c4335847ef864853357ce0643240560d Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 20 Aug 2023 16:06:56 -0400 Subject: [PATCH 159/385] Update GDS Reference vignette --- vignettes/Create_Reference_GDS_File.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 543409122..a23c341d9 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -114,7 +114,7 @@ The mandatory fields are: * **snp.AFR_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the African population for each of the SNVs present in the *snp.id* field * **snp.AMR_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the American population for each of the SNVs present in the *snp.id* field * **snp.SAS_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the South Asian population for each of the SNVs present in the *snp.id* field -* **genotype**: a SNV genotypic *integer* *matrix* (i.e., the number of A alleles) in SNVs-major mode (number of Samples × number of SNvs) TODO validate mode type +* **genotype**: a SNV genotypic *integer* *matrix* (i.e., the number of A alleles) with SNVs as rows and samples as columns (number of SNVs × number of Samples) * **sample.ref**: an *integer* indicating if the sample is retained to be used as reference (=1) or removed (=0) as related samples have to be discarded @@ -153,7 +153,7 @@ The mandatory fields are: * **phase**: TODO * **block.annot**: a *data.frame* containing those columns: * **block.id**: a *character* string representing TODO - * **block.desc**: ! *character* string describing the block TODO + * **block.desc**: a *character* string describing the block TODO * **bloc**: TODO
From a0729b984a59e76f1e75763be65b08c7732039a4 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 20 Aug 2023 16:07:17 -0400 Subject: [PATCH 160/385] Update docu for processBlockChr() function --- R/tools_internal.R | 2 +- man/processBlockChr.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/tools_internal.R b/R/tools_internal.R index b1fd4f940..5bd863745 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -197,7 +197,7 @@ validatePositiveIntegerVector <- function(value, name) { #' #' @param chr a \code{integer} representing the current chromosome. #' -#' @return the a \code{array} with the sample from pedDF keept +#' @return a \code{array} pf TODO with the sample from pedDF keept #' #' @examples #' diff --git a/man/processBlockChr.Rd b/man/processBlockChr.Rd index f6525c2aa..308751d80 100644 --- a/man/processBlockChr.Rd +++ b/man/processBlockChr.Rd @@ -21,7 +21,7 @@ continental population (ex: EUR, AFR, etc.).} \item{chr}{a \code{integer} representing the current chromosome.} } \value{ -the a \code{array} with the sample from pedDF keept +a \code{array} pf TODO with the sample from pedDF keept } \description{ The function reads the information form the specified block From 0a7911110464726babdd46b4a82f6e18a1f300d2 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 20 Aug 2023 16:18:08 -0400 Subject: [PATCH 161/385] Update doc for generateGeneBlock() function --- R/process1KG_internal.R | 6 +++--- man/generateGeneBlock.Rd | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index 1516cf9a5..feea78521 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -144,7 +144,7 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, #' size of the window to use to group the SNVs when the SNVs are in a #' non-coding region. Default: \code{10000}. #' -#' @param ensBd An object of class \code{EnsDb} with the Ensembl genome +#' @param ensDb An object of class \code{EnsDb} with the Ensembl genome #' annotation. By default, the \code{EnsDb.Hsapiens.v86} class has been used. #' #' @return a \code{data.frame} with those columns: @@ -186,9 +186,9 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, #' @importFrom AnnotationFilter GeneIdFilter #' @encoding UTF-8 #' @keywords internal -generateGeneBlock <- function(gdsReference, winSize=10000, ensBd) { +generateGeneBlock <- function(gdsReference, winSize=10000, ensDb) { - edb <- ensBd + edb <- ensDb listEnsId <- unique(names(genes(edb))) cols <- c("GENEID", "SYMBOL", "GENENAME", "GENESEQSTART", diff --git a/man/generateGeneBlock.Rd b/man/generateGeneBlock.Rd index b60fb0b75..939fede62 100644 --- a/man/generateGeneBlock.Rd +++ b/man/generateGeneBlock.Rd @@ -5,7 +5,7 @@ \alias{generateGeneBlock} \title{Generate two indexes based on gene annotation for gdsAnnot1KG block} \usage{ -generateGeneBlock(gdsReference, winSize = 10000, ensBd) +generateGeneBlock(gdsReference, winSize = 10000, ensDb) } \arguments{ \item{gdsReference}{an object of class @@ -15,7 +15,7 @@ generateGeneBlock(gdsReference, winSize = 10000, ensBd) size of the window to use to group the SNVs when the SNVs are in a non-coding region. Default: \code{10000}.} -\item{ensBd}{An object of class \code{EnsDb} with the Ensembl genome +\item{ensDb}{An object of class \code{EnsDb} with the Ensembl genome annotation. By default, the \code{EnsDb.Hsapiens.v86} class has been used.} } \value{ From 622a16d95bb91f0dfb760bdd186cc510b50809a3 Mon Sep 17 00:00:00 2001 From: belleau Date: Sun, 20 Aug 2023 16:23:34 -0400 Subject: [PATCH 162/385] Remove unused functions in process1KG --- NAMESPACE | 1 - R/process1KG.R | 94 ------------------------------------ R/tools_internal.R | 73 ---------------------------- man/addBlockFromPlink2GDS.Rd | 63 ------------------------ man/processBlockChr.Rd | 39 --------------- 5 files changed, 270 deletions(-) delete mode 100644 man/addBlockFromPlink2GDS.Rd delete mode 100644 man/processBlockChr.Rd diff --git a/NAMESPACE b/NAMESPACE index 4126b7894..0d71d5788 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,7 +1,6 @@ # Generated by roxygen2: do not edit by hand export(add1KG2SampleGDS) -export(addBlockFromPlink2GDS) export(addGeneBlockGDSRefAnnot) export(addRef2GDS1KG) export(addStudy1Kg) diff --git a/R/process1KG.R b/R/process1KG.R index 871b4240a..a89dcd179 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -790,100 +790,6 @@ basePCASample <- function(gds, listSample.Ref=NULL, listSNP=NULL, np=1L) { return(listPCA) } -#' @title Save the information about a specific block in a -#' Population Reference GDS Annotation file -#' -#' @description This function extracts the information for all -#' SNVs related to a specific block from the Population Reference GDS file. It -#' uses this information and the information from the block files associated -#' to a specific super-population to generate the final block information. -#' The block information is then saved in a Population Reference GDS Annotation -#' file. -#' -#' @param gds an object of class -#' \link[gdsfmt]{gds.class} (a GDS file), TODO -#' -#' @param gdsOut an object of class \code{gds} opened in writing mode. -#' -#' @param pathBlock a \code{character} string representing the path where -#' the block files are located. -#' -#' @param superPop a \code{character} string representing the specific -#' continental population. -#' -#' @param blockName a \code{character} string representing the unique -#' block name. -#' -#' @param blockDesc a \code{character} string representing the description of -#' the current block. -#' -#' @param verbose a \code{logical} indicating if message information should be -#' printed. Default: \code{FALSE}. -#' -#' @return \code{OL} when the function is successful. -#' -#' @details -#' -#' More information about GDS file format can be found at the Bioconductor -#' gdsfmt website: -#' https://bioconductor.org/packages/gdsfmt/ -#' -#' @examples -#' -#' # TODO -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' -#' @importFrom gdsfmt createfn.gds put.attr.gdsn closefn.gds -#' @encoding UTF-8 -#' @export -addBlockFromPlink2GDS <- function(gds, gdsOut, pathBlock, - superPop, blockName, - blockDesc, verbose=FALSE) { - ## NOTE - ## add validations - - ## The gds must be an object of class "gds.class" - validateGDSClass(gds=gds, name="gds") - - ## The verbose must be a logical - validateLogical(verbose, "verbose") - - ## Extract the SNP chromosomes and positions - snpChromosome <- read.gdsn(index.gdsn(gds, "snp.chromosome")) - snpPosition <- read.gdsn(index.gdsn(gds, "snp.position")) - - listChr <- unique(snpChromosome) - - listChr <- listChr[order(listChr)] - listChr <- seq_len(22) - listBlock <- list() - for(chr in listChr) { - if(verbose) { message("chr", chr, " ", Sys.time()) } - - snpKeep <- snpPosition[snpChromosome == chr] - - listBlock[[chr]] <- processBlockChr(snpKeep, pathBlock, superPop, chr) - if(chr > 1) { - vMax <- max(listBlock[[chr-1]]) - vMin <- min(listBlock[[chr-1]]) - listBlock[[chr]][listBlock[[chr]] > 0] <- - listBlock[[chr]][listBlock[[chr]] > 0] + vMax - if(vMin < 0) { - listBlock[[chr]][listBlock[[chr]] < 0] <- - listBlock[[chr]][listBlock[[chr]] < 0] + vMin - } - } - } - listBlock <- do.call(c, listBlock) - - ## Save the information into the GDS Annotation file - addBlockInGDSAnnot(gds=gdsOut, listBlock=listBlock, blockName=blockName, - blockDesc=blockDesc) - - ## Success - return(0L) -} #' @title Extract the specified column from the 1KG GDS 'sample.ref' node #' for the reference profiles (real ancestry assignation) diff --git a/R/tools_internal.R b/R/tools_internal.R index b1fd4f940..7e0369cdb 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -178,79 +178,6 @@ validatePositiveIntegerVector <- function(value, name) { } - -#' @title Extract the block information from the block file associated to a -#' specific population and chromosome -#' -#' @description The function reads the information form the specified block -#' file associated to a specified population and a specified chromosome. The -#' the block information for a list of SNV positions is formatted and returned. -#' -#' @param snpKeep a \code{vector} of \code{integer} representing the -#' positions of the retained SNVs for the current chromosome. -#' -#' @param pathBlock a \code{character} string representing the path to the -#' block files. -#' -#' @param superPop a \code{character} string representing the current -#' continental population (ex: EUR, AFR, etc.). -#' -#' @param chr a \code{integer} representing the current chromosome. -#' -#' @return the a \code{array} with the sample from pedDF keept -#' -#' @examples -#' -#' # TODO -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt add.gdsn -#' @importFrom utils read.delim -#' @encoding UTF-8 -#' @keywords internal -processBlockChr <- function(snpKeep, pathBlock, superPop, chr) { - - blockChr <- read.delim(file.path(pathBlock, - paste0("block.sp.", superPop, ".f0.05.chr", chr, - ".blocks.det")), sep="") - - z <- cbind(c(blockChr$BP1, snpKeep, blockChr$BP2+1), - c(seq_len(nrow(blockChr)), - rep(0, length(snpKeep)), -1*seq_len(nrow(blockChr)))) - - z <- z[order(z[,1]),] - blockSnp <- cumsum(z[,2])[z[,2] == 0] - - curStart <- 0 - activeBlock <- 0 - blockState <- 0 - blockInter <- rep(0, length(which(blockSnp == 0))) - k <- 1 - for(i in seq_len(length(blockSnp))){ - if(blockSnp[i] == 0){ - if(activeBlock == 1){ - if(snpKeep[i] - curStart >= 10000) { - blockState <- blockState - 1 - curStart <- snpKeep[i] - } - } else{ - blockState <- blockState - 1 - curStart <- snpKeep[i] - curStart <- snpKeep[i] - activeBlock <- 1 - } - blockInter[k] <- blockState - k <- k + 1 - }else{ - activeBlock <- 0 - } - } - blockSnp[blockSnp == 0] <- blockInter - - return(blockSnp) -} - - #' @title Read a SNP-pileup file #' #' @description The function reads a generic SNP pileup file and diff --git a/man/addBlockFromPlink2GDS.Rd b/man/addBlockFromPlink2GDS.Rd deleted file mode 100644 index c8826d8af..000000000 --- a/man/addBlockFromPlink2GDS.Rd +++ /dev/null @@ -1,63 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/process1KG.R -\encoding{UTF-8} -\name{addBlockFromPlink2GDS} -\alias{addBlockFromPlink2GDS} -\title{Save the information about a specific block in a -Population Reference GDS Annotation file} -\usage{ -addBlockFromPlink2GDS( - gds, - gdsOut, - pathBlock, - superPop, - blockName, - blockDesc, - verbose = FALSE -) -} -\arguments{ -\item{gds}{an object of class -\link[gdsfmt]{gds.class} (a GDS file), TODO} - -\item{gdsOut}{an object of class \code{gds} opened in writing mode.} - -\item{pathBlock}{a \code{character} string representing the path where -the block files are located.} - -\item{superPop}{a \code{character} string representing the specific -continental population.} - -\item{blockName}{a \code{character} string representing the unique -block name.} - -\item{blockDesc}{a \code{character} string representing the description of -the current block.} - -\item{verbose}{a \code{logical} indicating if message information should be -printed. Default: \code{FALSE}.} -} -\value{ -\code{OL} when the function is successful. -} -\description{ -This function extracts the information for all -SNVs related to a specific block from the Population Reference GDS file. It -uses this information and the information from the block files associated -to a specific super-population to generate the final block information. -The block information is then saved in a Population Reference GDS Annotation -file. -} -\details{ -More information about GDS file format can be found at the Bioconductor -gdsfmt website: -https://bioconductor.org/packages/gdsfmt/ -} -\examples{ - -# TODO - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} diff --git a/man/processBlockChr.Rd b/man/processBlockChr.Rd deleted file mode 100644 index f6525c2aa..000000000 --- a/man/processBlockChr.Rd +++ /dev/null @@ -1,39 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/tools_internal.R -\encoding{UTF-8} -\name{processBlockChr} -\alias{processBlockChr} -\title{Extract the block information from the block file associated to a -specific population and chromosome} -\usage{ -processBlockChr(snpKeep, pathBlock, superPop, chr) -} -\arguments{ -\item{snpKeep}{a \code{vector} of \code{integer} representing the -positions of the retained SNVs for the current chromosome.} - -\item{pathBlock}{a \code{character} string representing the path to the -block files.} - -\item{superPop}{a \code{character} string representing the current -continental population (ex: EUR, AFR, etc.).} - -\item{chr}{a \code{integer} representing the current chromosome.} -} -\value{ -the a \code{array} with the sample from pedDF keept -} -\description{ -The function reads the information form the specified block -file associated to a specified population and a specified chromosome. The -the block information for a list of SNV positions is formatted and returned. -} -\examples{ - -# TODO - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} -\keyword{internal} From 7ee88d33e214b79028b88011fcbef439d31291f4 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 20 Aug 2023 17:00:19 -0400 Subject: [PATCH 163/385] Update examle in pruning1KGbyChr() --- R/process1KG_internal.R | 3 +++ man/pruning1KGbyChr.Rd | 3 +++ 2 files changed, 6 insertions(+) diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index feea78521..be77f76bb 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -76,6 +76,9 @@ #' #' prunedSNVs <- readRDS(file.path(getwd(), paste0(outPrefix, ".rds"))) #' prunedSNVs +#' +#' ## Delete temporary file +#' unlink(getwd(), paste0(outPrefix, ".rds"), force=TRUE) #' } #' #' ## Close 1K GDS file diff --git a/man/pruning1KGbyChr.Rd b/man/pruning1KGbyChr.Rd index 0f48c71a3..f3aaac5b6 100644 --- a/man/pruning1KGbyChr.Rd +++ b/man/pruning1KGbyChr.Rd @@ -98,6 +98,9 @@ if (file.access(getwd()) == 0 && prunedSNVs <- readRDS(file.path(getwd(), paste0(outPrefix, ".rds"))) prunedSNVs + + ## Delete temporary file + unlink(getwd(), paste0(outPrefix, ".rds"), force=TRUE) } ## Close 1K GDS file From 59547c0bdacf9c7cc27c0298c79dd0d441183e30 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 20 Aug 2023 17:00:47 -0400 Subject: [PATCH 164/385] Update version to 0.99.7 --- DESCRIPTION | 2 +- inst/NEWS.md | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 946b83cc5..b7d860128 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.6 +Version: 0.99.7 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index 3b3a35918..a3ed93550 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,13 @@ +CHANGES IN VERSION 0.99.7 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o The new runRNAAncestry() function executes most steps leading to the ancestry inference call on a specific RNA profile. + o A vignette describing the content of the Reference GDS files has been created. + o More parameter names have been changed to follow the camelCase style. + + CHANGES IN VERSION 0.99.6 ------------------------ From b739c37e8a84e55ec6f2d36d7b6407e208a4d098 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 20 Aug 2023 17:22:04 -0400 Subject: [PATCH 165/385] Update examle in pruning1KGbyChr() --- R/process1KG_internal.R | 2 +- man/pruning1KGbyChr.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index be77f76bb..579a0f1f2 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -78,7 +78,7 @@ #' prunedSNVs #' #' ## Delete temporary file -#' unlink(getwd(), paste0(outPrefix, ".rds"), force=TRUE) +#' unlink(file.path(getwd(), paste0(outPrefix, ".rds")), force=TRUE) #' } #' #' ## Close 1K GDS file diff --git a/man/pruning1KGbyChr.Rd b/man/pruning1KGbyChr.Rd index f3aaac5b6..86a5e06e9 100644 --- a/man/pruning1KGbyChr.Rd +++ b/man/pruning1KGbyChr.Rd @@ -100,7 +100,7 @@ if (file.access(getwd()) == 0 && prunedSNVs ## Delete temporary file - unlink(getwd(), paste0(outPrefix, ".rds"), force=TRUE) + unlink(file.path(getwd(), paste0(outPrefix, ".rds")), force=TRUE) } ## Close 1K GDS file From 5b5e7f70097a0a76cf17c3de18a511903a4ddc63 Mon Sep 17 00:00:00 2001 From: belleau Date: Sun, 20 Aug 2023 17:42:44 -0400 Subject: [PATCH 166/385] Add runRNAAncestry to the vignette --- .../example/snpPileupRNA/ex1.generic.txt.gz | Bin 0 -> 484 bytes inst/extdata/example/snpPileupRNA/ex1.txt.gz | Bin 0 -> 70424 bytes vignettes/RAIDS.Rmd | 202 ++++++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 inst/extdata/example/snpPileupRNA/ex1.generic.txt.gz create mode 100644 inst/extdata/example/snpPileupRNA/ex1.txt.gz diff --git a/inst/extdata/example/snpPileupRNA/ex1.generic.txt.gz b/inst/extdata/example/snpPileupRNA/ex1.generic.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..48192f0940e5a099580f4a9e0c9375d87f2ef22f GIT binary patch literal 484 zcmVj)c-D@d*gEC78+6LO``>(WN zVtLXT2qy5eog;YBBEb+^kiY{l*Y0z<~FQ0>YoFlAiTde%Z(&C(iL zPfO*%oG}&b*aF*tqa@F(atP-zI2SHm+76pQPwL*eHBJ?~?iLRl?JhRGU2k*Twwy!6 z4V*E1nYLC8j01M}x6=~X?qO?XbG}Q90V8#M9hiYoe_NuNLM*yp6DWmiz2-;P)11Ll_I z`+9&)B>MbP@36)km^AFlHL#9Y>b82^+INNIii%N>jG`u#Yob`oHsBlu=QiL-`o%hu a&iQdAgxm9P%Bd!owfGO&(sHs*1^@uMIr&Hc literal 0 HcmV?d00001 diff --git a/inst/extdata/example/snpPileupRNA/ex1.txt.gz b/inst/extdata/example/snpPileupRNA/ex1.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..4e729bb8a991b979e941809399d5059687260700 GIT binary patch literal 70424 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 literal 0 HcmV?d00001 diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 0e8d973e2..f5ebc1d8d 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -398,6 +398,208 @@ also created. TODO +The wrapper function, called _runRNAAncestry()_, requires 4 files as input: + +- The **population reference GDS file** +- The **population reference SNV Annotation GDS file** +- The **Profile SNP pileup file** (one per sample present in the study) +- The **Profile PED RDS file** (one file with information for all profiles in the study) + +A *data.frame* containing the general information about the study is +also required. The *data.frame* must contain those 3 columns: + +- _study.id_: The study identifier (example: TCGA-BRCA). +- _study.desc_: The description of the study. +- _study.platform_: The type of sequencing (example: RNA-seq). + +The required **population reference GDS file** and +**population reference SNV Annotation GDS file** should be stored in the same +directory. In the example below, this directory is referred to +as **pathReference**. + +The generic **Profile SNP pileup file** format is coma separated and the +mandatory columns are: + +* _Chromosome_: The name of the chromosome +* _Position_: The position on the chromosome +* _Ref_: The reference nucleotide +* _Alt_: The aternative nucleotide +* _Count_: The total count +* _File1R_: The count for the reference nucleotide +* _File1A_: The count for the alternative nucleotide + +Beware that the starting position in the **population reference GDS File** is +zero (like BED files). The **Profile SNP pileup file** should also start +at position zero. + +Note that the name assigned to the **Profile SNP pileup file** has to +correspond to the profile identifier (Name.ID) in the following analysis. +For example, a SNP pileup file called "Sample.01.txt.gz" would be +associated to the "Sample.01" profile. + +The **Profile PED RDS file** must contain a *data.frame* describing all +the profiles to be analyzed. These 5 mandatory columns: + +- _Name.ID_: The unique sample identifier. The profile VCF file +should be called "Name.ID.txt.gz". +- _Case.ID_: The patient identifier associated to the sample. +- _Sample.Type_: The information about the profile tissue source +(primary tumor, metastatic tumor, normal, etc..). +- _Diagnosis_: The donor's diagnosis. +- _Source_: The source of the profile sequence data (example: dbGAP_XYZ). + +Important: The row names of the *data.frame* must be the profiles' **Name.ID**. + +This file is referred to as the **Profile PED RDS file** (PED for pedigree). +Alternatively, the PED information can be saved in another type of +file (CVS, etc..) as long as the *data.frame* information can be regenerated +in R (with _read.csv()_ or else). + +```{r runRNAAncestry, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +############################################################################# +## Load required packages +############################################################################# +library(RAIDS) +library(gdsfmt) + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +############################################################################# +## The path and file name for the PED RDS file +## will the information about the analyzed samples +############################################################################# +filePED <- file.path(dataDir, "example", "pedEx.rds") +ped <- readRDS(filePED) +head(ped) + +############################################################################# +## The population reference GDS file and SNV Annotation GDS file +## need to be located in the same directory. +## Note that the population reference GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +############################################################################# +pathReference <- file.path(dataDir, "example", "gdsRef") + +fileGDS <- file.path(pathReference, "ex1kg.gds") +fileAnnotGDS <- file.path(pathReference, "exAnnot1kg.gds") + +############################################################################# +## A data frame containing general information about the study +## is also required. The data frame must have +## those 3 columns: "study.id", "study.desc", "study.platform" +############################################################################# +studyDF <- data.frame(study.id="MYDATA", + study.desc="Description", + study.platform="PLATFORM", + stringsAsFactors=FALSE) + +############################################################################# +## The Sample SNP pileup files (one per sample) need +## to be all located in the same directory. +############################################################################# +pathGeno <- file.path(dataDir, "example", "snpPileupRNA") + +############################################################################# +## Fix RNG seed to ensure reproducible results +############################################################################# +set.seed(3043) + +############################################################################# +## Select the profiles from the population reference GDS file for +## the synthetic data. +## Here we select 2 profiles from the simplified 1KG GDS for each +## subcontinental-level. +## Normally, we use 30 profile for each +## subcontinental-level but it is too big for the example. +## The 1KG files in this example only have 6 profiles for each +## subcontinental-level (for demo purpose only). +############################################################################# +gds1KG <- snpgdsOpen(fileGDS) +dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +closefn.gds(gds1KG) + +## Chromosome length information for hg38 +## chrInfo[23] is chrX, chrInfo[24] is chrY and chrM is chrInfo[25] +chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, + 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, + 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, + 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, + 156040895L, 57227415L, 16569L) + +############################################################################# +## The path where the Sample GDS files (one per sample) +## will be created needs to be specified. +############################################################################# +pathProfileGDS <- file.path(getwd(), "exampleRNA", "outRNA.tmp") + +############################################################################# +## The path where the result files will be created needs to +## be specified +############################################################################# +pathOut <- file.path(getwd(), "exampleRNA", "resRNA.out") + +## Example can only be run if the current directory is in writing mode +if (file.access(getwd()) == 0 && !dir.exists(file.path(getwd(), "exampleRNA"))) { + + dir.create(file.path(getwd(), "exampleRNA")) + dir.create(pathProfileGDS) + dir.create(pathOut) + + ######################################################################### + ## The wrapper function generates the synthetic dataset and uses it + ## to selected the optimal parameters before calling the genetic + ## ancestry on the current profiles. + ## All important information, for each step, are saved in + ## multiple output files. + ## The 'genoSource' parameter has 2 options depending on how the + ## SNP pileup files have been generated: + ## "snp-pileup" (snp-pileup software) or "generic" (other software) + ######################################################################### + runRNAAncestry(pedStudy=ped, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, + pathGeno=pathGeno, + pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + blockTypeID="GeneS.Ensembl.Hsapiens.v86", + genoSource="snp-pileup") + + list.files(pathOut) + list.files(file.path(pathOut, ped$Name.ID[1])) + + ######################################################################### + ## The file containing the ancestry inference (SuperPop column) and + ## optimal number of PCA component (D column) + ## optimal number of neighbours (K column) + ######################################################################### + resAncestry <- read.csv(file.path(pathOut, + paste0(ped$Name.ID[1], ".Ancestry.csv"))) + resAncestry + + ## Remove temporary files created for this demo + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + unlink(file.path(getwd(), "example"), force=TRUE) +} + +``` + +
+
+ +The *runExomeAncestry()* function generates 3 types of files +in the *pathOut* directory. + +* The ancestry inference CSV file (**".Ancestry.csv"** file) +* The inference information RDS file (**".infoCall.rds"** file) +* The parameter information RDS files from the synthetic inference (**"KNN.synt.*.rds"** files in a sub-directory) + +In addition, a sub-directory (named using the *profile ID*) is +also created. +

From 32d01a58c859570500ffac84fcc28ec059e4aa97 Mon Sep 17 00:00:00 2001 From: belleau Date: Sun, 20 Aug 2023 17:48:18 -0400 Subject: [PATCH 167/385] Add runRNAAncestry to the vignette --- vignettes/RAIDS.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index f5ebc1d8d..2f92596e8 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -560,13 +560,13 @@ if (file.access(getwd()) == 0 && !dir.exists(file.path(getwd(), "exampleRNA"))) pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, - fileReferenceGDS=fileReferenceGDS, + fileReferenceGDS=fileGDS, fileReferenceAnnotGDS=fileAnnotGDS, chrInfo=chrInfo, syntheticRefDF=dataRef, blockTypeID="GeneS.Ensembl.Hsapiens.v86", genoSource="snp-pileup") - + list.files(pathOut) list.files(file.path(pathOut, ped$Name.ID[1])) From 4cca28383a65d9229d9e397d3cb252377152f463 Mon Sep 17 00:00:00 2001 From: belleau Date: Sun, 20 Aug 2023 18:10:37 -0400 Subject: [PATCH 168/385] Update runRNAAncestry to the vignette --- vignettes/RAIDS.Rmd | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 2f92596e8..f765ef951 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -397,8 +397,10 @@ also created. ### RNA data - Wrapper function to run ancestry inference on RNA data -TODO -The wrapper function, called _runRNAAncestry()_, requires 4 files as input: +TOREVIEW +The process is the same as for the DNA but use the wrapper function +called _runRNAAncestry()_. Internally the data is process differently. +It requires 4 files as input: - The **population reference GDS file** - The **population reference SNV Annotation GDS file** From d26143e0366ddd3d79187c9968a3754c9631fd30 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 20 Aug 2023 18:14:54 -0400 Subject: [PATCH 169/385] Update test to remove TODO --- tests/testthat/test-tools_internal.R | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-tools_internal.R b/tests/testthat/test-tools_internal.R index cdc6eb9da..5b0d84b0f 100644 --- a/tests/testthat/test-tools_internal.R +++ b/tests/testthat/test-tools_internal.R @@ -28,9 +28,9 @@ test_that("validateGDSClass() must return expected results when all input are va test_that("validateGDSClass() must return error when input is not valid", { - expected <- "The \'todo_01\' must be an object of class \'gds.class\'." + expected <- "The \'tudo_01\' must be an object of class \'gds.class\'." - expect_error(RAIDS:::validateGDSClass(gds="toto.gds", name="todo_01"), + expect_error(RAIDS:::validateGDSClass(gds="toto.gds", name="tudo_01"), expected, fixed=TRUE) }) @@ -136,7 +136,8 @@ context("validatePositiveIntegerVector() results") test_that("validatePositiveIntegerVector() must return expected results when all input are valid", { - result1 <- RAIDS:::validatePositiveIntegerVector(value=c(1,2,3), name="parameter_01") + result1 <- RAIDS:::validatePositiveIntegerVector(value=c(1,2,3), + name="parameter_01") expect_identical(result1, 0L) }) From 86dc778018fa7f26eabe17bca103f27577271056 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Sun, 20 Aug 2023 18:22:02 -0400 Subject: [PATCH 170/385] Update package version to 0.99.8 --- DESCRIPTION | 2 +- inst/NEWS.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index b7d860128..52912f8cd 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.7 +Version: 0.99.8 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index a3ed93550..826b12dd4 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,11 @@ +CHANGES IN VERSION 0.99.8 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o Some examples have been updated in the documentation. + + CHANGES IN VERSION 0.99.7 ------------------------ From 65afaa4a2078596f0cf961a428fdb5b3a9a01bdb Mon Sep 17 00:00:00 2001 From: belleau Date: Mon, 21 Aug 2023 08:42:51 -0400 Subject: [PATCH 171/385] Remove scripsPy --- scriptsPy/extract1000gFreqAll.py | 72 -------------------------------- 1 file changed, 72 deletions(-) delete mode 100644 scriptsPy/extract1000gFreqAll.py diff --git a/scriptsPy/extract1000gFreqAll.py b/scriptsPy/extract1000gFreqAll.py deleted file mode 100644 index e750bc616..000000000 --- a/scriptsPy/extract1000gFreqAll.py +++ /dev/null @@ -1,72 +0,0 @@ -import vcf -from datetime import date -import os -import sys -import numpy as np - -def main(): - fileVCF = sys.argv[1] - fileBASE = sys.argv[2] - freqCutOff = -1 - today = date.today() - displayLOG(fileBASE, today, fileVCF, freqCutOff) - extractFreq(fileBASE, fileVCF, freqCutOff, today) - -def displayLOG(fileBASE, today, fileVCF, freqCutOff): - try: - fileLOG = "log/" + fileBASE + "_" + str(today) + ".log" - FLOG = open(fileLOG, "w") - FLOG.write("fileVCF " + fileVCF + "\n") - FLOG.write("fileBASE " + fileBASE + "\n") - FLOG.write("FreqCutOff " + str(freqCutOff) + "\n") - FLOG.close() - except (OSError, IOError) as e: - sys.stderr.write( 'Problem with the file: '+ fileLOG + '\n') - sys.stderr.write(e + "\n") - sys.exit(1) - -def extractFreq(fileBASE, fileVCF, freqCutOff, today): - try: - fileName = fileBASE + "_" + str(today) + "_f_All" + ".txt" - - fileOUT = os.path.join("mat1000gFAll", fileName) - sep = ";" - vcf_reader = vcf.Reader(filename=fileVCF) - OUT = open(fileOUT, "w") - - for record in vcf_reader: - # At least the frequency in one super population - # higher or equal to freqCutOff - if (record.INFO['EAS_AF'][0] >= freqCutOff or - record.INFO['EUR_AF'][0] >= freqCutOff or - record.INFO['AFR_AF'][0] >= freqCutOff or - record.INFO['AMR_AF'][0] >= freqCutOff or - record.INFO['SAS_AF'][0] >= freqCutOff): - - OUT.write( record.CHROM +"\t" + str( record.start ) + "\t" + record.REF) - - flag = 0 - for g in record.ALT: - if flag == 1: - OUT.write(sep) - OUT.write("\t" + str(g)) - flag = 1 - OUT.write("\t" + str(record.INFO['AF'][0])) - OUT.write("\t" + str(record.INFO['EAS_AF'][0])) - OUT.write("\t" + str(record.INFO['EUR_AF'][0])) - OUT.write("\t" + str(record.INFO['AFR_AF'][0])) - OUT.write("\t" + str(record.INFO['AMR_AF'][0])) - OUT.write("\t" + str(record.INFO['SAS_AF'][0])) - OUT.write("\n") - - OUT.close - - - except (OSError, IOError) as e: - sys.stderr.write( 'Problem with the file: '+ fileBASE + '_' + fileVCF + '\n') - sys.stderr.write(e + "\n") - sys.exit(1) - -if __name__ == "__main__": - main() - From a91c9e34bde195b21957b4609608ac7ee3730fa1 Mon Sep 17 00:00:00 2001 From: belleau Date: Mon, 21 Aug 2023 09:53:06 -0400 Subject: [PATCH 172/385] Update Create_Reference_GDS_File --- vignettes/Create_Reference_GDS_File.Rmd | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index a23c341d9..776c1531e 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -123,9 +123,10 @@ The mandatory fields are: # Population Reference Annotation GDS file - -The *Population Reference Annotation GDS file* should contain TODO - +TOREVIEW +The *Population Reference Annotation GDS file* should contain phase information +and block group of the variant in *gdsRef*. A block can be a linkage disequelibrium block +relative to a population or gene. ```{r runRefAnnotGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# @@ -149,13 +150,19 @@ closefn.gds(gdsRefAnnot) The mandatory fields are: - -* **phase**: TODO +TOREVIEW +* **phase**: A *2bit* representing the phase of the variant in *gdsRef*. If 0 means +the first allele is a reference and 1 means the first allele +is the alternative and 3 means unknown. The first allele combine with the +genotype of the variant determine the phase for a biallelic variant. +The variant in phase are in the same order as gdsRef * **block.annot**: a *data.frame* containing those columns: - * **block.id**: a *character* string representing TODO - * **block.desc**: a *character* string describing the block TODO -* **bloc**: TODO - + * **block.id**: a *character* string representing an identifiant of block group. + A block can be linkage disequilibrium block relative to a populationn or gene. + * **block.desc**: a *character* string describing the block group. +* **bloc**: A *integer* *matrix* where each row representing a variant in *gdsRef* in the same order. +The column are a block group describe in *block.annot*. Each *integer* in +the *matrix* representing a specific block.

From f5891d20d15dc8b4d2d370133a6ab5499e424491 Mon Sep 17 00:00:00 2001 From: belleau Date: Mon, 21 Aug 2023 11:49:57 -0400 Subject: [PATCH 173/385] Update vignette RNA part of RAIDS --- vignettes/RAIDS.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index f765ef951..44f1bba5f 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -592,7 +592,7 @@ if (file.access(getwd()) == 0 && !dir.exists(file.path(getwd(), "exampleRNA")))

-The *runExomeAncestry()* function generates 3 types of files +The *runRNAAncestry()* function generates 3 types of files in the *pathOut* directory. * The ancestry inference CSV file (**".Ancestry.csv"** file) From 78f60a16530ace279f75ccff9acb9a05e0db01d5 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Aug 2023 11:53:56 -0400 Subject: [PATCH 174/385] Update Reference GDS vignette --- vignettes/Create_Reference_GDS_File.Rmd | 75 +++++++++++++------------ 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 776c1531e..dce3b5e45 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -66,11 +66,10 @@ also used to generate the PCA on which the samples of interest are going to be projected. The *Population Reference GDS file* is a GDS object of class -[SNPGDSFileClass](https://www.bioconductor.org/packages/release/bioc/vignettes/SNPRelate/inst/doc/SNPRelate.html#data-formats-used-in-snprelate) -from [SNPRelate](https://www.bioconductor.org/packages/release/bioc/html/SNPRelate.html) +[SNPGDSFileClass](https://www.bioconductor.org/packages/release/bioc/vignettes/SNPRelate/inst/doc/SNPRelate.html#data-formats-used-in-snprelate) from [SNPRelate](https://www.bioconductor.org/packages/release/bioc/html/SNPRelate.html) package [@Zheng2012]. -Beware that only unrelated samples should be present in the GDS file. +Beware that only unrelated samples should be present in the GDS files. ```{r runRefGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# @@ -91,31 +90,33 @@ print(gdsRef) closefn.gds(gdsRef) ``` -This output lists all variables stored in the *Population Reference GDS file". +
+ +This output lists all variables stored in the *Population Reference GDS file*. At the first level, it stores variables *sample.id*, *snp.id*, etc. The additional information displayed in the braces indicate the data type, size, compressed or not + compression ratio. The mandatory fields are: -* **sample.id**: a unique identifier for each sample -* **snp.id**: a unique identifier for each SNV. +* **sample.id**: a *character* string (saved in *Str8* format) used as unique identifier for each sample +* **snp.id**: a a *character* string (saved in *Str8* format) used as unique identifier for each SNV * **sample.annot**: a *data.frame* where each row correspond to a sample and containing those columns: - * **sex**: a identifier of the sex of the sample - * **pop.Group**: a *character* string representing the sub-population ancestry of the sample (ex:GBR, etc) - * **superPop**: a *character* string representing the super-population ancestry of the sample (ex:EUR, AFR, EAS, SAS, AMR) - * **batch**: an *integer* representing the batch of provenance of the sample -* **snp.chromosome**: an integer or character mapping for each chromosome. Integer: numeric values 1-26, mapped in order from 1-22, 23=X, 24=XY (the pseudoautosomal region), 25=Y, 26=M (the mitochondrial probes), and 0 for probes with unknown positions; it does not allow NA. Character: “X”, “XY”, “Y” and “M” can be used here, and a blank string indicating unknown position -* **snp.position**: a *integer* representing the base position of each SNV on the chromosome, and 0 for unknown position; it does not allow NA. -* **snp.allele**: a *character* string representing the reference allele and alternative allele for each of the SNVs present in the *snp.id* field -* **snp.AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the general population for each of the SNVs present in the *snp.id* field -* **snp.EAS_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the East Asian population for each of the SNVs present in the *snp.id* field -* **snp.EUR_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the European population for each of the SNVs present in the *snp.id* field -* **snp.AFR_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the African population for each of the SNVs present in the *snp.id* field -* **snp.AMR_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the American population for each of the SNVs present in the *snp.id* field -* **snp.SAS_AF**: a *numeric* value between 0 and 1 representing the allelic frequency of the alternative allele in the South Asian population for each of the SNVs present in the *snp.id* field -* **genotype**: a SNV genotypic *integer* *matrix* (i.e., the number of A alleles) with SNVs as rows and samples as columns (number of SNVs × number of Samples) -* **sample.ref**: an *integer* indicating if the sample is retained to be used as reference (=1) or removed (=0) as related samples have to be discarded + * **sex**: a *character* string (saved in *Str8* format) used as identifier of the sex of the sample + * **pop.Group**: a *character* string (saved in *Str8* format) representing the sub-population ancestry of the sample (ex:GBR, etc) + * **superPop**: a *character* string (saved in *Str8* format) representing the super-population ancestry of the sample (ex:EUR, AFR, EAS, SAS, AMR) + * **batch**: an *integer* (saved in *Float64* format) representing the batch of provenance of the sample +* **snp.chromosome**: an *integer* or *character* (saved in *UInt16 * format) mapping for each chromosome. Integer: numeric values 1-26, mapped in order from 1-22, 23=X, 24=XY (the pseudoautosomal region), 25=Y, 26=M (the mitochondrial probes), and 0 for probes with unknown positions; it does not allow NA. Character: “X”, “XY”, “Y” and “M” can be used here, and a blank string indicating unknown position +* **snp.position**: an *integer* (saved in *Int32* format) representing the base position of each SNV on the chromosome, and 0 for unknown position; it does not allow NA. +* **snp.allele**: a *character* string (saved as *Str8* format) representing the reference allele and alternative allele for each of the SNVs present in the *snp.id* field +* **snp.AF**: a *numeric* value between 0 and 1 (saved as *PackedReal24* format) representing the allelic frequency of the alternative allele in the general population for each of the SNVs present in the *snp.id* field +* **snp.EAS_AF**: a *numeric* value between 0 and 1 (saved as *PackedReal24* format) representing the allelic frequency of the alternative allele in the East Asian population for each of the SNVs present in the *snp.id* field +* **snp.EUR_AF**: a *numeric* value between 0 and 1 (saved as *PackedReal24* format) representing the allelic frequency of the alternative allele in the European population for each of the SNVs present in the *snp.id* field +* **snp.AFR_AF**: a *numeric* value between 0 and 1 (saved as *PackedReal24* format) representing the allelic frequency of the alternative allele in the African population for each of the SNVs present in the *snp.id* field +* **snp.AMR_AF**: a *numeric* value between 0 and 1 (saved as *PackedReal24* format) representing the allelic frequency of the alternative allele in the American population for each of the SNVs present in the *snp.id* field +* **snp.SAS_AF**: a *numeric* value between 0 and 1 (saved as *PackedReal24* format) representing the allelic frequency of the alternative allele in the South Asian population for each of the SNVs present in the *snp.id* field +* **genotype**: a SNV genotypic *matrix* of *integer* values (saved in *Bit2* format) (i.e., the number of A alleles) with SNVs as rows and samples as columns (number of SNVs × number of Samples) +* **sample.ref**: an *integer* (saved in *Bit1* format) indicating if the sample is retained to be used as reference (=1) or removed (=0) as related samples have to be discarded
@@ -123,10 +124,10 @@ The mandatory fields are: # Population Reference Annotation GDS file -TOREVIEW -The *Population Reference Annotation GDS file* should contain phase information -and block group of the variant in *gdsRef*. A block can be a linkage disequelibrium block -relative to a population or gene. +The *Population Reference Annotation GDS file* contains phase information +and block group information forl all the SNVs present in +*Population Reference GDS file*. A block can be a linkage disequelibrium block +relative to a population or a gene. ```{r runRefAnnotGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# @@ -147,22 +148,22 @@ print(gdsRefAnnot) closefn.gds(gdsRefAnnot) ``` +
+This output lists all variables stored in +the *Population Reference Annotation GDS file*. +At the first level, it stores variables *phase*, *block.annot*, etc. +The additional information displayed in the braces indicate the data type, +size, compressed or not + compression ratio. The mandatory fields are: -TOREVIEW -* **phase**: A *2bit* representing the phase of the variant in *gdsRef*. If 0 means -the first allele is a reference and 1 means the first allele -is the alternative and 3 means unknown. The first allele combine with the -genotype of the variant determine the phase for a biallelic variant. -The variant in phase are in the same order as gdsRef + +* **phase**: a *integer* (saved in *Bit2* format) representing the phase of the SNVs in the *Population Annotation GDS file*; 0 means the first allele is a reference; 1 means the first allele is the alternative and 3 means unknown. The first allele combine with the genotype of the variant determine the phase for a biallelic variant. The SNVs in phase are in the same order as in the *Population Annotation GDS file*. * **block.annot**: a *data.frame* containing those columns: - * **block.id**: a *character* string representing an identifiant of block group. - A block can be linkage disequilibrium block relative to a populationn or gene. - * **block.desc**: a *character* string describing the block group. -* **bloc**: A *integer* *matrix* where each row representing a variant in *gdsRef* in the same order. -The column are a block group describe in *block.annot*. Each *integer* in -the *matrix* representing a specific block. + * **block.id**: a *character* string (saved in *Str8* format) representing an identifier of block group. A block can be linkage disequilibrium block relative to a population or a gene. + * **block.desc**: a *character* string (saved in *Str8* format) describing the block group. +* **bloc**: a *matrix* of *integer* values (saved in *Int32* format) where each row representing a SNV in the *Population Annotation GDS file* in the same order. The columns are the block groups described in *block.annot*. Each *integer* in the *matrix* representing a specific block. +

From 3b70842cde4dfdbf43f13309a06d314b421a919b Mon Sep 17 00:00:00 2001 From: belleau Date: Mon, 21 Aug 2023 12:05:28 -0400 Subject: [PATCH 175/385] Remove deprecated basePCASample process1KG --- R/process1KG.R | 71 -------------------------------------------------- 1 file changed, 71 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index a89dcd179..b61f85f05 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -719,77 +719,6 @@ addRef2GDS1KG <- function(fileNameGDS, filePart) { } -#' @title Compute principal component axes (PCA) on SNV data using the -#' reference samples -#' -#' @description The function runs a Principal Component Analysis (PCA) on -#' the SNv genotype data. The function also loads SNVs into the PCA to -#' calculate the SNV eigenvectors. Those 2 steps are done with the -#' \code{\link[SNPRelate]{snpgdsPCA}} and -#' \code{\link[SNPRelate]{snpgdsPCASNPLoading}} -#' functions. -#' -#' @param gds an object of class -#' \code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, a SNP -#' GDS file. -#' -#' @param listSample.Ref a \code{vector} of \code{character} strings -#' corresponding to -#' the sample identifiers that will be used for the PCA. -#' -#' @param listSNP a \code{vector} of \code{character} strings representing -#' the SNV identifiers retained for the PCA. -#' -#' @param np a single positive \code{integer} representing the number of -#' threads. Default: \code{1L}. -#' -#' @return a \code{list} with 3 entries: -#' \itemize{ -#' \item{SNP}{ a \code{vector} of \code{character} strings representing the -#' SNV identifiers used in the PCA.} -#' \item{pca.unrel}{ an object of class \code{snpgdsPCAClass} as generated -#' by the -#' \code{\link[SNPRelate:snpgdsPCA]{SNPRelate::snpgdsPCA}} function. } -#' \item{snp.load}{ an object of class \code{snpgdsPCASNPLoading} as generated -#' by the -#' \code{\link[SNPRelate:snpgdsPCASNPLoading]{SNPRelate::snpgdsPCASNPLoading}} -#' function. } -#' } -#' -#' @examples -#' -#' ## Path to the demo pedigree file is located in this package -#' dataDir <- system.file("extdata", package="RAIDS") -#' -#' ## TODO -#' -#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom SNPRelate snpgdsPCA snpgdsPCASNPLoading -#' @encoding UTF-8 -#' @export -basePCASample <- function(gds, listSample.Ref=NULL, listSNP=NULL, np=1L) { - - listPCA <- list() - - ## Save the SNV list - listPCA[["SNP"]] <- listSNP - - ## Calculate the PCA and save the results - listPCA[["pca.unrel"]] <- snpgdsPCA(gds, sample.id=listSample.Ref, - snp.id=listSNP, - num.thread=np, - verbose=TRUE) - - ## Calculate the SNV eigenvectors and save the results - listPCA[["snp.load"]] <- snpgdsPCASNPLoading(listPCA[["pca.unrel"]], - gdsobj=gds, - num.thread=np, - verbose=TRUE) - - ## Return a list with 3 entries - return(listPCA) -} - #' @title Extract the specified column from the 1KG GDS 'sample.ref' node #' for the reference profiles (real ancestry assignation) From 64102c741b077318712fdcf2a545256d26db18f9 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Aug 2023 17:03:12 -0400 Subject: [PATCH 176/385] Update tableBlockAF() doc --- R/allelicFraction_internal.R | 41 ++++++++++++++++++------------------ man/tableBlockAF.Rd | 40 +++++++++++++++++------------------ 2 files changed, 40 insertions(+), 41 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 43b49edc1..b7e573922 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -1470,42 +1470,42 @@ calcAFMLRNA <- function(snpPosHetero) { } -#' @title TOREVIEW Compile the information about the variants -#' for each bloc. +#' @title Compile the information about the SNVs +#' for each block #' -#' @description TOREVIEW For each block, the function evaluates a score -#' about lost of heterizygocity and allelic fration. It generates some -#' information about the variants in the block like number of homozigte or -#' heterozygote. -#' In the case of RNA-seq the blocks are genes. +#' @description The function evaluates a score +#' about loss of heterozygosity and allelic fraction for each block. It +#' generates specific information about the variants in the block, like the +#' number of homozygotes or heterozygotes. +#' In the case of RNA-seq, the blocks are genes. #' -#' @param snpPos For a specific chromosome a \code{data.frame} with lap for -#' the SNV dataset with -#' coverage > \code{minCov}. +#' @param snpPos a \code{data.frame} with lower allelic fraction (lap) for +#' the SNVs with coverage > \code{minCov}, for a specific chromosome. #' -#' @return TOREVIEW resBlock a \code{data.frame} containing only heterozygote +#' @return a \code{data.frame} containing only heterozygote #' SNV information. The #' \code{data.frame} contain those columns: #' \itemize{ #' \item{block} {a single \code{integer} representing the unique identifier #' of the block.} -#' \item{aRF} {a single \code{numeric} representing the final allelic fraction not compute -#' here -1 for all entries.} +#' \item{aRF} {a single \code{numeric} representing the final allelic +#' fraction; not computed yet, \code{-1} value assigned to all entries.} #' \item{aFraction} {a single \code{integer} representing the possible allelic -#' fraction in absence of LOH.} +#' fraction in absence of loss of heterozygosity (LOH).} #' \item{lR} {a single \code{integer} representing the coverage for #' the alternative allele.} -#' \item{nPhase} {a single \code{integer} representin the number of SNV +#' \item{nPhase} {a single \code{integer} representing the number of SNV #' phases.} -#' \item{sumAlleleLow} {a single \code{integer} TOREVIEW sum of the allele with -#' the less coverage.} -#' \item{sumAlleleHigh} {a single \code{integer} TOREVIEW sum of the allele -#' with more coverage.} +#' \item{sumAlleleLow} {a single \code{integer} representing the sum of the +#' alleles with the less coverage.} +#' \item{sumAlleleHigh} {a single \code{integer} representing the sum of +#' the alleles with more coverage.} #' \item{lH} {a single \code{numeric} for the homozygotes log10 of the product #' frequencies of the allele not found in the profile (not a probability).} #' \item{lM} {a single \code{numeric} log10 product frequency allele #' in population.} -#' \item{lRhomo} {a single \code{numeric} score lH - lM.} +#' \item{lRhomo} {a single \code{numeric} representing the score +#' \code{lH} - \code{lM}.} #' \item{nbHomo} {a single \code{integer} representing the number of #' homozygote SNVs per block.} #' \item{nbKeep} {a single \code{integer} representing the number of @@ -1533,7 +1533,6 @@ tableBlockAF <- function(snpPos) { resBlock <- data.frame(block=listBlocks) - # Number of homozygotes per block tmp <- aggregate(snpPos[, c( "homo"), drop=FALSE], by = list(block=snpPos$block.id), sum) diff --git a/man/tableBlockAF.Rd b/man/tableBlockAF.Rd index 3bde4bc23..ea3f5cbc8 100644 --- a/man/tableBlockAF.Rd +++ b/man/tableBlockAF.Rd @@ -3,40 +3,40 @@ \encoding{UTF-8} \name{tableBlockAF} \alias{tableBlockAF} -\title{TOREVIEW Compile the information about the variants -for each bloc.} +\title{Compile the information about the SNVs +for each block} \usage{ tableBlockAF(snpPos) } \arguments{ -\item{snpPos}{For a specific chromosome a \code{data.frame} with lap for -the SNV dataset with -coverage > \code{minCov}.} +\item{snpPos}{a \code{data.frame} with lower allelic fraction (lap) for +the SNVs with coverage > \code{minCov}, for a specific chromosome.} } \value{ -TOREVIEW resBlock a \code{data.frame} containing only heterozygote +a \code{data.frame} containing only heterozygote SNV information. The \code{data.frame} contain those columns: \itemize{ \item{block} {a single \code{integer} representing the unique identifier of the block.} -\item{aRF} {a single \code{numeric} representing the final allelic fraction not compute -here -1 for all entries.} +\item{aRF} {a single \code{numeric} representing the final allelic +fraction; not computed yet, \code{-1} value assigned to all entries.} \item{aFraction} {a single \code{integer} representing the possible allelic -fraction in absence of LOH.} +fraction in absence of loss of heterozygosity (LOH).} \item{lR} {a single \code{integer} representing the coverage for the alternative allele.} -\item{nPhase} {a single \code{integer} representin the number of SNV +\item{nPhase} {a single \code{integer} representing the number of SNV phases.} -\item{sumAlleleLow} {a single \code{integer} TOREVIEW sum of the allele with -the less coverage.} -\item{sumAlleleHigh} {a single \code{integer} TOREVIEW sum of the allele -with more coverage.} +\item{sumAlleleLow} {a single \code{integer} representing the sum of the +alleles with the less coverage.} +\item{sumAlleleHigh} {a single \code{integer} representing the sum of +the alleles with more coverage.} \item{lH} {a single \code{numeric} for the homozygotes log10 of the product frequencies of the allele not found in the profile (not a probability).} \item{lM} {a single \code{numeric} log10 product frequency allele in population.} -\item{lRhomo} {a single \code{numeric} score lH - lM.} +\item{lRhomo} {a single \code{numeric} representing the score +\code{lH} - \code{lM}.} \item{nbHomo} {a single \code{integer} representing the number of homozygote SNVs per block.} \item{nbKeep} {a single \code{integer} representing the number of @@ -46,11 +46,11 @@ heterozygote SNVs per block.} } } \description{ -TOREVIEW For each block, the function evaluates a score -about lost of heterizygocity and allelic fration. It generates some -information about the variants in the block like number of homozigte or -heterozygote. -In the case of RNA-seq the blocks are genes. +The function evaluates a score +about loss of heterozygosity and allelic fraction for each block. It +generates specific information about the variants in the block, like the +number of homozygotes or heterozygotes. +In the case of RNA-seq, the blocks are genes. } \examples{ From 97446df890155064a40db5e3d0e296f68c2f7032 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Aug 2023 17:14:18 -0400 Subject: [PATCH 177/385] Update calcalcAFMLRNA() function --- R/allelicFraction_internal.R | 46 +++++++++++++++++------------------- man/calcAFMLRNA.Rd | 46 +++++++++++++++++------------------- 2 files changed, 44 insertions(+), 48 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index b7e573922..56de3742c 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -1365,41 +1365,40 @@ testEmptyBox <- function(matCov, pCutOff=-3) { ############################################### -#' @title TOREVIEW Compute the log likelihood ratio base on the coverage (read depth) -#' of each allele in block (gene in the case of RNA-seq) +#' @title Compute the log likelihood ratio based on the coverage of +#' each allele in a specific block (gene in the case of RNA-seq) #' -#' @description TOREVIEW For the block sum the log of read depth of the lowest depth -#' divide by the total depth of the position minus of likelhood of the allelic -#' fraction of 0.5. If the phase is known, the variant varaint in the same -#' haplotype are group. +#' @description This function sums the log of read depth of the lowest depth +#' divide by the total depth of the position minus of likelihood of the allelic +#' fraction of 0.5 for a block. If the phase is known, the SNVs in the same +#' haplotype are grouped together. #' -#' @param snpPosHetero For a specific gene (block) a \code{data.frame} -#' containing the SNV information. +#' @param snpPosHetero a \code{data.frame} +#' containing the SNV information for a specific block (gene if RNA-seq). #' The \code{data.frame} must contain those columns: #' \itemize{ #' \item{cnt.ref} {a single \code{integer} representing the coverage for #' the reference allele.} #' \item{cnt.alt} {a single \code{integer} representing the coverage for #' the alternative allele.} -#' \item{phase} {TOREVIEW a \code{integer} indicating the phase of the variant -#' if known, 3 if not known} +#' \item{phase} { a single \code{integer} indicating the phase of the variant +#' if known, \code{3} if not known} #' } #' -#' @return TOREVIEW a \code{list} for the block with the information of +#' @return a \code{list} for the block with the information #' relative to the heterozygotes. #' The \code{list} contains: #' \itemize{ -#' \item{lR} {TOREVIEW a single \code{numeric} representing sum the log of read depth of the lowest depth -#' divide by the total depth of the position minus of likelhood of the allelic -#' fraction of 0.5.} -#' \item{aFraction} {TOREVIEW a single \code{numeric} representing the allele +#' \item{lR} { a single \code{numeric} representing the sum of the log of +#' read depth of the lowest depth divide by the total depth of the position +#' minus of likelihood of the allelic fraction of 0.5.} +#' \item{aFraction} { a single \code{numeric} representing the allele #' fraction estimation.} -#' \item{sumAlleleLow} {TOREVIEW a \code{integer} representing the -#' sum of the allele read depth -#' of the lowest read alelle depth} -#' \item{sumAlleleHigh} {TOREVIEW a \code{integer} representing the +#' \item{sumAlleleLow} { a \code{integer} representing the +#' sum of the allele read depth of the lowest read allele depth} +#' \item{sumAlleleHigh} { a \code{integer} representing the #' sum of the allele read depth -#' of the highsest read alelle depth} +#' of the highest read allele depth} #' } #' #' @examples @@ -1408,10 +1407,9 @@ testEmptyBox <- function(matCov, pCutOff=-3) { #' #' snpPos <- readRDS(file.path(dataDir, "demoAllelicFraction", "demSnpPos.rds")) #' -#' result <- RAIDS:::calcAFMLRNA(snpPos[which( -#' snpPos$block.id == 2750 & -#' snpPos$hetero), c("cnt.ref", -#' "cnt.alt", "phase")]) +#' result <- RAIDS:::calcAFMLRNA(snpPos[which(snpPos$block.id == 2750 & +#' snpPos$hetero), +#' c("cnt.ref", "cnt.alt", "phase")]) #' head(result) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/man/calcAFMLRNA.Rd b/man/calcAFMLRNA.Rd index 37c8f7dd9..4260beb80 100644 --- a/man/calcAFMLRNA.Rd +++ b/man/calcAFMLRNA.Rd @@ -3,47 +3,46 @@ \encoding{UTF-8} \name{calcAFMLRNA} \alias{calcAFMLRNA} -\title{TOREVIEW Compute the log likelihood ratio base on the coverage (read depth) -of each allele in block (gene in the case of RNA-seq)} +\title{Compute the log likelihood ratio based on the coverage of +each allele in a specific block (gene in the case of RNA-seq)} \usage{ calcAFMLRNA(snpPosHetero) } \arguments{ -\item{snpPosHetero}{For a specific gene (block) a \code{data.frame} -containing the SNV information. +\item{snpPosHetero}{a \code{data.frame} +containing the SNV information for a specific block (gene if RNA-seq). The \code{data.frame} must contain those columns: \itemize{ \item{cnt.ref} {a single \code{integer} representing the coverage for the reference allele.} \item{cnt.alt} {a single \code{integer} representing the coverage for the alternative allele.} -\item{phase} {TOREVIEW a \code{integer} indicating the phase of the variant -if known, 3 if not known} +\item{phase} { a single \code{integer} indicating the phase of the variant +if known, \code{3} if not known} }} } \value{ -TOREVIEW a \code{list} for the block with the information of +a \code{list} for the block with the information relative to the heterozygotes. The \code{list} contains: \itemize{ -\item{lR} {TOREVIEW a single \code{numeric} representing sum the log of read depth of the lowest depth -divide by the total depth of the position minus of likelhood of the allelic -fraction of 0.5.} -\item{aFraction} {TOREVIEW a single \code{numeric} representing the allele +\item{lR} { a single \code{numeric} representing the sum of the log of +read depth of the lowest depth divide by the total depth of the position +minus of likelihood of the allelic fraction of 0.5.} +\item{aFraction} { a single \code{numeric} representing the allele fraction estimation.} -\item{sumAlleleLow} {TOREVIEW a \code{integer} representing the +\item{sumAlleleLow} { a \code{integer} representing the +sum of the allele read depth of the lowest read allele depth} +\item{sumAlleleHigh} { a \code{integer} representing the sum of the allele read depth -of the lowest read alelle depth} -\item{sumAlleleHigh} {TOREVIEW a \code{integer} representing the -sum of the allele read depth -of the highsest read alelle depth} +of the highest read allele depth} } } \description{ -TOREVIEW For the block sum the log of read depth of the lowest depth -divide by the total depth of the position minus of likelhood of the allelic -fraction of 0.5. If the phase is known, the variant varaint in the same -haplotype are group. +This function sums the log of read depth of the lowest depth +divide by the total depth of the position minus of likelihood of the allelic +fraction of 0.5 for a block. If the phase is known, the SNVs in the same +haplotype are grouped together. } \examples{ @@ -51,10 +50,9 @@ dataDir <- system.file("extdata", package="RAIDS") snpPos <- readRDS(file.path(dataDir, "demoAllelicFraction", "demSnpPos.rds")) -result <- RAIDS:::calcAFMLRNA(snpPos[which( - snpPos$block.id == 2750 & - snpPos$hetero), c("cnt.ref", - "cnt.alt", "phase")]) +result <- RAIDS:::calcAFMLRNA(snpPos[which(snpPos$block.id == 2750 & + snpPos$hetero), + c("cnt.ref", "cnt.alt", "phase")]) head(result) } From 9255dc2be04d9f4a4d031be966bc8fc7556f037c Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Aug 2023 17:36:54 -0400 Subject: [PATCH 178/385] UPdate runProfileAncestry() doc --- R/processStudy_internal.R | 22 ++++++++++------------ man/runProfileAncestry.Rd | 22 ++++++++++------------ 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 56d3945d0..fa9c17176 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -1923,19 +1923,19 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, return(res) } -#' @title TOREVIEW Run most steps leading to the ancestry inference call on a -#' specific profile +#' @title Run most steps leading to the ancestry inference call on a +#' specific profile (RNA or DNA) #' #' @description This function runs most steps leading to the ancestry inference #' call on a specific profile. First, the function creates the Profile GDS file #' for the specific profile using the information from a RDS Sample -#' description file and the 1KG reference GDS file. +#' description file and the Population reference GDS file. #' #' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), the opened Reference GDS file. +#' (a GDS file), the opened Population Reference GDS file. #' #' @param gdsRefAnnot an object of class \code{\link[gdsfmt]{gds.class}} -#' (a GDS file), the opened Reference SNV Annotation GDS file. +#' (a GDS file), the opened Population Reference SNV Annotation GDS file. #' This parameter is RNA specific. #' #' @param studyDF a \code{data.frame} containing the information about the @@ -1998,7 +1998,7 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' @details #' #' The runWrapperAncestry() function generates 3 types of files -#' in the OUTPUT directory. +#' in the \code{pathOut} directory: #' \itemize{ #' \item{Ancestry Inference}{The ancestry inference CSV file #' (".Ancestry.csv" file)} @@ -2056,9 +2056,9 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' ## will be created need to be specified. #' ################################################################# #' -#' pathProfileGDS <- file.path(getwd(), "out.tmp") +#' pathProfileGDS <- file.path(getwd(), "outTest.tmp") #' -#' pathOut <- file.path(getwd(), "res.out") +#' pathOut <- file.path(getwd(), "resTest.out") #' #' ################################################################# #' ## A data frame containing general information about the study @@ -2100,7 +2100,7 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' profileFile <- file.path(pathProfileGDS, "ex1.gds") #' #' \dontrun{ -#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && +#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && #' !file.exists(pathOut)) { #' #' dir.create(pathProfileGDS) @@ -2124,13 +2124,11 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' closefn.gds(gdsReference) #' closefn.gds(gdsRefAnnot) #' -#' #' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) #' unlink(pathOut, recursive=TRUE, force=TRUE) -#' } +#' } #' } #' -#' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom utils write.csv #' @importFrom rlang arg_match diff --git a/man/runProfileAncestry.Rd b/man/runProfileAncestry.Rd index d80cacff1..e14e1cc88 100644 --- a/man/runProfileAncestry.Rd +++ b/man/runProfileAncestry.Rd @@ -3,8 +3,8 @@ \encoding{UTF-8} \name{runProfileAncestry} \alias{runProfileAncestry} -\title{TOREVIEW Run most steps leading to the ancestry inference call on a -specific profile} +\title{Run most steps leading to the ancestry inference call on a +specific profile (RNA or DNA)} \usage{ runProfileAncestry( gdsReference, @@ -25,10 +25,10 @@ runProfileAncestry( } \arguments{ \item{gdsReference}{an object of class \code{\link[gdsfmt]{gds.class}} -(a GDS file), the opened Reference GDS file.} +(a GDS file), the opened Population Reference GDS file.} \item{gdsRefAnnot}{an object of class \code{\link[gdsfmt]{gds.class}} -(a GDS file), the opened Reference SNV Annotation GDS file. +(a GDS file), the opened Population Reference SNV Annotation GDS file. This parameter is RNA specific.} \item{studyDF}{a \code{data.frame} containing the information about the @@ -93,11 +93,11 @@ more information about the generated output files. This function runs most steps leading to the ancestry inference call on a specific profile. First, the function creates the Profile GDS file for the specific profile using the information from a RDS Sample -description file and the 1KG reference GDS file. +description file and the Population reference GDS file. } \details{ The runWrapperAncestry() function generates 3 types of files -in the OUTPUT directory. +in the \code{pathOut} directory: \itemize{ \item{Ancestry Inference}{The ancestry inference CSV file (".Ancestry.csv" file)} @@ -148,9 +148,9 @@ pathGeno <- file.path(dataDir, "example", "snpPileup") ## will be created need to be specified. ################################################################# -pathProfileGDS <- file.path(getwd(), "out.tmp") +pathProfileGDS <- file.path(getwd(), "outTest.tmp") -pathOut <- file.path(getwd(), "res.out") +pathOut <- file.path(getwd(), "resTest.out") ################################################################# ## A data frame containing general information about the study @@ -192,7 +192,7 @@ listProfileRef <- dataRef$sample.id profileFile <- file.path(pathProfileGDS, "ex1.gds") \dontrun{ - if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && + if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && !file.exists(pathOut)) { dir.create(pathProfileGDS) @@ -216,13 +216,11 @@ profileFile <- file.path(pathProfileGDS, "ex1.gds") closefn.gds(gdsReference) closefn.gds(gdsRefAnnot) - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) unlink(pathOut, recursive=TRUE, force=TRUE) - } + } } - } \references{ Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, From 08adeb585dce1e1c1d511c3a7a36bd415f0cca94 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Aug 2023 17:54:25 -0400 Subject: [PATCH 179/385] Update runWrapperAncestry() doc --- R/processStudy_internal.R | 10 +++++----- man/runWrapperAncestry.Rd | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index fa9c17176..413873877 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2229,7 +2229,7 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, } -#' @title TOREVIEW Run most steps leading to the ancestry inference call +#' @title Run most steps leading to the ancestry inference call #' on a specific profile (RNA or DNA) #' #' @description This function runs most steps leading to the ancestry inference @@ -2288,9 +2288,9 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' way the estimation of the allelic fraction is done. Default: \code{"DNA"}. #' #' @param genoSource a \code{stirng} with two possible values: -#' snp-pileup and generic. It specify if the genotype files -#' are generate by snp-pileup(Facets) or generic format csv -#' with the column at least the columns: +#' snp-pileup and generic. It specifies if the genotype files +#' have been generated by snp-pileup (Facets) or are in a generic format csv +#' with at least the columns: #' Chromosome,Position,Ref,Alt,Count,File1R,File1A #' where Count is the deep at the position, #' FileR is the deep of the reference allele, and @@ -2312,7 +2312,7 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' @details #' #' The runWrapperAncestry() function generates 3 types of files -#' in the OUTPUT directory. +#' in the \code{pathOut} directory. #' \itemize{ #' \item{Ancestry Inference}{The ancestry inference CSV file #' (".Ancestry.csv" file)} diff --git a/man/runWrapperAncestry.Rd b/man/runWrapperAncestry.Rd index e073de9eb..36b2c861f 100644 --- a/man/runWrapperAncestry.Rd +++ b/man/runWrapperAncestry.Rd @@ -3,7 +3,7 @@ \encoding{UTF-8} \name{runWrapperAncestry} \alias{runWrapperAncestry} -\title{TOREVIEW Run most steps leading to the ancestry inference call +\title{Run most steps leading to the ancestry inference call on a specific profile (RNA or DNA)} \usage{ runWrapperAncestry( @@ -71,9 +71,9 @@ super-population assigned to the sample. } }} \item{genoSource}{a \code{stirng} with two possible values: -snp-pileup and generic. It specify if the genotype files -are generate by snp-pileup(Facets) or generic format csv -with the column at least the columns: +snp-pileup and generic. It specifies if the genotype files +have been generated by snp-pileup (Facets) or are in a generic format csv +with at least the columns: Chromosome,Position,Ref,Alt,Count,File1R,File1A where Count is the deep at the position, FileR is the deep of the reference allele, and @@ -105,7 +105,7 @@ description file and the Population reference GDS file. } \details{ The runWrapperAncestry() function generates 3 types of files -in the OUTPUT directory. +in the \code{pathOut} directory. \itemize{ \item{Ancestry Inference}{The ancestry inference CSV file (".Ancestry.csv" file)} From 094d84741c43aee5af920562c89d9c6198e9c76a Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Aug 2023 18:07:08 -0400 Subject: [PATCH 180/385] Update doc for computeAlleleFraction() --- R/allelicFraction_internal.R | 7 ++++--- man/computeAlleleFraction.Rd | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 56de3742c..3dd96dc57 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -455,10 +455,11 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, return(homoBlock) } -#' @title TOREVIEW For each imbalance segments compute the allelic fraction +#' @title Compute the allelic fraction for +#' each imbalanced segment #' -#' @description TOREVIEW Compute the allelic fraction for each segment different -#' than 0.5. The allelic fraction of the segment can be decomposed in +#' @description This function computes the allelic fraction for each segment +#' different than 0.5. The allelic fraction of the segment can be decomposed in #' sub-segments. #' #' @param snpPos a \code{data.frame} containing the genotype information for diff --git a/man/computeAlleleFraction.Rd b/man/computeAlleleFraction.Rd index c21b6c485..a8726a577 100644 --- a/man/computeAlleleFraction.Rd +++ b/man/computeAlleleFraction.Rd @@ -3,7 +3,8 @@ \encoding{UTF-8} \name{computeAlleleFraction} \alias{computeAlleleFraction} -\title{TOREVIEW For each imbalance segments compute the allelic fraction} +\title{Compute the allelic fraction for +each imbalanced segment} \usage{ computeAlleleFraction(snpPos, w = 10, cutOff = -3) } @@ -33,8 +34,8 @@ returned when none of the SNVs tested positive for the imbalance. } \description{ -TOREVIEW Compute the allelic fraction for each segment different -than 0.5. The allelic fraction of the segment can be decomposed in +This function computes the allelic fraction for each segment +different than 0.5. The allelic fraction of the segment can be decomposed in sub-segments. } \examples{ From a89539b3ecc61a7fd57cf1e567fdf82070f36b53 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Aug 2023 18:11:30 -0400 Subject: [PATCH 181/385] Update computeAllelicFractionRNA() doc --- R/allelicFraction_internal.R | 9 +++++---- man/computeAllelicFractionRNA.Rd | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 3dd96dc57..7b2b1777b 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -903,10 +903,11 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} #' \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} #' \item{homo} {a \code{logical} indicating if the SNV is homozygote} -#' \item{block.id} {TOREVIEW a \code{integer} indicating the block.id in gdsRefAnnot the -#' vairant is in} -#' \item{phase} {TOREVIEW a \code{integer} indicating the phase of the variant -#' if known, 3 if not known} +#' \item{block.id} { a \code{integer} indicating the unique identifier of the +#' block in the Population Reference Annotation +#' GDS file that contains the current SNV} +#' \item{phase} { a \code{integer} indicating the phase of the variant +#' if known, \code{3} if not known} #' \item{lap} {a \code{numeric} indicating lower allelic fraction} #' \item{LOH} {a \code{integer} indicating if the SNV is in an LOH region #' (0=not LOH, 1=in LOH)} diff --git a/man/computeAllelicFractionRNA.Rd b/man/computeAllelicFractionRNA.Rd index a520939b4..44920ea75 100644 --- a/man/computeAllelicFractionRNA.Rd +++ b/man/computeAllelicFractionRNA.Rd @@ -85,10 +85,11 @@ SNV in the Reference GDS file that contains all SNVs} \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} \item{homo} {a \code{logical} indicating if the SNV is homozygote} -\item{block.id} {TOREVIEW a \code{integer} indicating the block.id in gdsRefAnnot the -vairant is in} -\item{phase} {TOREVIEW a \code{integer} indicating the phase of the variant -if known, 3 if not known} +\item{block.id} { a \code{integer} indicating the unique identifier of the +block in the Population Reference Annotation +GDS file that contains the current SNV} +\item{phase} { a \code{integer} indicating the phase of the variant +if known, \code{3} if not known} \item{lap} {a \code{numeric} indicating lower allelic fraction} \item{LOH} {a \code{integer} indicating if the SNV is in an LOH region (0=not LOH, 1=in LOH)} From 315e2f3fb4657161240fa7513bb1cb2dbf1e24cb Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Aug 2023 18:21:53 -0400 Subject: [PATCH 182/385] Update computLOHBlocksDNAChr() doc --- R/allelicFraction_internal.R | 24 +++++++++++++----------- man/computeLOHBlocksDNAChr.Rd | 24 +++++++++++++----------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 7b2b1777b..4e53fd613 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -279,28 +279,30 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' \item{chr} {a \code{integer} representing the current chromosome} #' \item{start} {a \code{integer} representing the starting position on the #' box containing only homozygote SNVs (or not SNV). The first box starts at -#' position 1.} +#' position \code{1}.} #' \item{end} {a \code{integer} representing the end position on the #' box containing only homozygote SNVs (or not SNV). The last box ends at the #' length of the chromosome.} -#' \item{logLHR} {TOREVIEW Score for LOH base on frequencies in population. Sum of -#' the log10 of the frequencies of the observe gegenotype minus the +#' \item{logLHR} {a \code{numeric} representing the LOH score basde on +#' population frequencies. It is the sum of +#' the log10 of the frequencies of the observed gegenotype minus the #' the sum of the log10 of the higher frequent genotype. #' (-100 when normal genotype are present)} -#' \item{LH1} {TOREVIEW If normal genotype present and heterozygot the probability to be heterozygote -#' base on the coverage of each allele} -#' \item{LM1} {TOREVIEW If normal genotype present and heterozygot the max probability the max probability +#' \item{LH1} { a \code{numeric} representing the probability to be +#' heterozygote based on the coverage of each allele when normal +#' genotype is present} +#' \item{LM1} {a \code{numeric} representing the max probability #' for the read coverage at the position} #' \item{homoScore} {a \code{numeric} representing \code{LH1} - \code{LM1}} #' \item{nbSNV} {a \code{integer} representing th number of SNVs in #' the box} #' \item{nbPruned} {a \code{integer} representing the number of pruned SNVs in #' the box} -#' \item{nbNorm} {TOREVIEW a \code{integer} representing of genotype -#' heterozygote for the normal in the block} -#' \item{LOH} {TOREVIEW a \code{integer} representing a flag if 1 it mean -#' the block is satisfy the criteria to be LOH. The value is not assign -#' in this function they are all 0} +#' \item{nbNorm} { a \code{integer} representing of the number of +#' heterozygote genotypes for the normal SNVs in the block} +#' \item{LOH} { a \code{integer} representing a flag, if \code{1} it means +#' the block is satisfying the criteria to be LOH. The value is not assigned +#' in this function; the value \code{0} is assigned} #' } #' #' @examples diff --git a/man/computeLOHBlocksDNAChr.Rd b/man/computeLOHBlocksDNAChr.Rd index 2c8a05851..fedef2266 100644 --- a/man/computeLOHBlocksDNAChr.Rd +++ b/man/computeLOHBlocksDNAChr.Rd @@ -55,28 +55,30 @@ chromosome. The \code{data.frame} contains those columns: \item{chr} {a \code{integer} representing the current chromosome} \item{start} {a \code{integer} representing the starting position on the box containing only homozygote SNVs (or not SNV). The first box starts at -position 1.} +position \code{1}.} \item{end} {a \code{integer} representing the end position on the box containing only homozygote SNVs (or not SNV). The last box ends at the length of the chromosome.} -\item{logLHR} {TOREVIEW Score for LOH base on frequencies in population. Sum of -the log10 of the frequencies of the observe gegenotype minus the +\item{logLHR} {a \code{numeric} representing the LOH score basde on +population frequencies. It is the sum of +the log10 of the frequencies of the observed gegenotype minus the the sum of the log10 of the higher frequent genotype. (-100 when normal genotype are present)} -\item{LH1} {TOREVIEW If normal genotype present and heterozygot the probability to be heterozygote -base on the coverage of each allele} -\item{LM1} {TOREVIEW If normal genotype present and heterozygot the max probability the max probability +\item{LH1} { a \code{numeric} representing the probability to be +heterozygote based on the coverage of each allele when normal +genotype is present} +\item{LM1} {a \code{numeric} representing the max probability for the read coverage at the position} \item{homoScore} {a \code{numeric} representing \code{LH1} - \code{LM1}} \item{nbSNV} {a \code{integer} representing th number of SNVs in the box} \item{nbPruned} {a \code{integer} representing the number of pruned SNVs in the box} -\item{nbNorm} {TOREVIEW a \code{integer} representing of genotype -heterozygote for the normal in the block} -\item{LOH} {TOREVIEW a \code{integer} representing a flag if 1 it mean -the block is satisfy the criteria to be LOH. The value is not assign -in this function they are all 0} +\item{nbNorm} { a \code{integer} representing of the number of +heterozygote genotypes for the normal SNVs in the block} +\item{LOH} { a \code{integer} representing a flag, if \code{1} it means +the block is satisfying the criteria to be LOH. The value is not assigned +in this function; the value \code{0} is assigned} } } \description{ From e510f4e2a36f54dcd4b46c113ba9cfa5eb872e8b Mon Sep 17 00:00:00 2001 From: belleau Date: Mon, 21 Aug 2023 18:27:17 -0400 Subject: [PATCH 183/385] Add examples and update manual page of addGeneBlockGDSRefAnnot generateGeneBlock --- DESCRIPTION | 3 +- NAMESPACE | 1 - R/process1KG.R | 40 +++- R/process1KG_internal.R | 195 ++++++++++-------- .../tests/ex1_NoBlockGene.1KG_Annot_GDS.gds | Bin 0 -> 155202 bytes man/addGeneBlockGDSRefAnnot.Rd | 38 +++- man/basePCASample.Rd | 58 ------ man/generateGeneBlock.Rd | 45 +++- 8 files changed, 223 insertions(+), 157 deletions(-) create mode 100644 inst/extdata/tests/ex1_NoBlockGene.1KG_Annot_GDS.gds delete mode 100644 man/basePCASample.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 52912f8cd..66f78bd8c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -43,7 +43,8 @@ Suggests: testthat, BiocStyle, withr, GenomeInfoDb, - BSgenome.Hsapiens.UCSC.hg38 + BSgenome.Hsapiens.UCSC.hg38, + EnsDb.Hsapiens.v86 BugReports: https://github.com/KrasnitzLab/RAIDS/issues URL: https://krasnitzlab.github.io/RAIDS/ biocViews: Genetics, Software, Sequencing, WholeGenome, PrincipalComponent, diff --git a/NAMESPACE b/NAMESPACE index 0d71d5788..2acbf2897 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,7 +4,6 @@ export(add1KG2SampleGDS) export(addGeneBlockGDSRefAnnot) export(addRef2GDS1KG) export(addStudy1Kg) -export(basePCASample) export(computeAncestryFromSyntheticFile) export(computeKNNRefSample) export(computeKNNRefSynthetic) diff --git a/R/process1KG.R b/R/process1KG.R index b61f85f05..13914982e 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -718,8 +718,6 @@ addRef2GDS1KG <- function(fileNameGDS, filePart) { return(0L) } - - #' @title Extract the specified column from the 1KG GDS 'sample.ref' node #' for the reference profiles (real ancestry assignation) #' @@ -819,10 +817,46 @@ getRef1KGPop <- function(gdsReference, popName="superPop") { #' #' @examples #' +#' ## Required library +#' library(SNPRelate) +#' #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' -#' ## TODO +#' +#' fileAnnotGDS <- file.path(getwd(), "ex1_good_small_1KG_Annot_GDS.gds") +#' ## Required library +#' if (file.access(getwd()) == 0 && !file.exists(fileAnnotGDS)) { +#' +#' if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { +#' +#' file.copy(file.path(dataDir, "tests", "ex1_NoBlockGene.1KG_Annot_GDS.gds"), +#' fileAnnotGDS) +#' ## Making a "short cut" on the ensDb object +#' edb <- EnsDb.Hsapiens.v86::EnsDb.Hsapiens.v86 +#' +#' +#' ## Temporary Profile GDS file for one profile +#' fileReferenceGDS <- file.path(dataDir, "tests", +#' "ex1_good_small_1KG_GDS.gds") +#' +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileReferenceGDS) +#' +#' +#' ## The function +#' addGeneBlockGDSRefAnnot(gdsReference=gds1KG, +#' gdsRefAnnotFile=fileAnnotGDS, +#' ensDb=edb, +#' suffixBlockName="EnsDb.Hsapiens.v86") +#' gdsAnnot1KG <- openfn.gds(fileAnnotGDS) +#' print(gdsAnnot1KG) +#' print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) +#' closefn.gds(gds1KG) +#' closefn.gds(gdsAnnot1KG) +#' unlink(fileAnnotGDS, force=TRUE) +#' } +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt openfn.gds closefn.gds diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index 579a0f1f2..f64aebcd1 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -138,7 +138,8 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, #' @title Generate two indexes based on gene annotation for gdsAnnot1KG block #' -#' @description TODO +#' @description Generate two indexes based on gene annotation for +#' gdsAnnot1KG block #' #' @param gdsReference an object of class #' \link[gdsfmt]{gds.class} (a GDS file), the opened 1KG GDS file (reference). @@ -152,13 +153,18 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, #' #' @return a \code{data.frame} with those columns: #' \itemize{ -#' \item{chr} {TODO} -#' \item{pos} {TODO} -#' \item{snp.allele} {TODO} -#' \item{Exon} {TODO} -#' \item{GName} {TODO} -#' \item{Gene} {TODO} -#' \item{GeneS} {TODO} +#' \item{chr} {a single \code{integer} representing the SNV chromosome.} +#' \item{pos} {a single \code{integer} representing the SNV position.} +#' \item{snp.allele} {a \code{character} string representing the reference allele +#' and alternative allele for each of the SNV} +#' \item{Exon} {a \code{character} with the ensembl GeneId(s) if the SNV is in +#' one exon. If more than one GeneId they are separted by ':'} +#' \item{GName} {a \code{character} with the ensembl GeneId(s) if the SNV is in +#' the gene. If more than one GeneId they are separted by ':'} +#' \item{Gene} {A single \code{integer} specific to the SNVs that share +#' at least one genes} +#' \item{GeneS} {A single \code{integer} specific to the SNVs that share +#' a unique combination of genes} #' } #' "chr", "pos", "snp.allele", "Exon", "GName", "Gene", "GeneS" #' Example for GName and the two indexes "Gene", "GeneS" @@ -174,10 +180,31 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, #' 493 ENSG00000230021:ENSG00000228794 17 3825 #' @examples #' +#' ## Required library +#' library(SNPRelate) +#' #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' -#' # TODO +#' ## Required library +#' if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { +#' +#' ## Making a "short cut" on the ensDb object +#' edb <- EnsDb.Hsapiens.v86::EnsDb.Hsapiens.v86 +#' +#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' +#' ## Temporary Profile GDS file for one profile +#' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") +#' +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileReferenceGDS) +#' +#' ## The function returns a data frame containing gene block information +#' matGeneBlock <- RAIDS:::generateGeneBlock(gdsReference=gds1KG, ensDb=edb) +#' print(head(matGeneBlock[grep("ENSG00000157152", matGeneBlock$GName),])) +#' closefn.gds(gds1KG) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alex Krasnitz #' @importFrom S4Vectors Rle @@ -243,84 +270,84 @@ generateGeneBlock <- function(gdsReference, winSize=10000, ensDb) { # colnames(matFreq) <- c("chr", "pos", "ref", "alt", "af", "EAS_AF", # "EUR_AF","AFR_AF", "AMR_AF", "SAS_AF") - message(system.time({ - # SNV in the GDS - matFreq <- matFreqAll[which(matFreqAll$chr == chr),] - # create two vector (one for the exon and one for the gene) of char - # with 1 entry for each SNV in the GDS - # I will keep the name of the gene and exon at this position - listSNVExons <- character(nrow(matFreq)) - listSNVGenes <- character(nrow(matFreq)) - - listPos <- seq_len(nrow(matFreq)) - listPos <- listPos[order(matFreq$pos)] - # Create an index to accelerate the process - startIndex <- seq(1, nrow(matFreq), 1000) - # Add if the last entry is not the last position - # is not the nb row of matFreq add the the last - #position - if(startIndex[length(startIndex)] < nrow(matFreq)){ - startIndex <- c(startIndex, nrow(matFreq)) - } - # For gene in the chr - # slow but acceptable - # user system elapsed - # 26.116 0.074 26.201 - # see blockAnnotation.R for slower alternatives - for (genePos in seq_len(nrow(dfGenneAllChr))) { - # the gene is where SNV exists - if (dfGenneAllChr$end[genePos] >= matFreq$pos[listPos[1]] & - dfGenneAllChr$start[genePos] <= matFreq$pos[nrow(matFreq)]) { - # In which partitions from the index the gene is located - vStart <- max(c(which(matFreq$pos[startIndex] <= - dfGenneAllChr$start[genePos]), 1)) - vEnd <- min(c(which(matFreq$pos[startIndex] >= - dfGenneAllChr$end[genePos]), - length(startIndex))) - # List of SNV in the gene - listP <- which(matFreq$pos[listPos[startIndex[vStart]:startIndex[vEnd]]] >= dfGenneAllChr$start[genePos] & - matFreq$pos[listPos[startIndex[vStart]:startIndex[vEnd]]] <= dfGenneAllChr$end[genePos]) - - # if SNV in the gene - if (length(listP) > 0) { - # listPos in the gene - listP <- - listPos[startIndex[vStart]:startIndex[vEnd]][listP] - - # Add the name of the gene of SNVs - listSNVGenes[listP] <- paste0(listSNVGenes[listP], ":", - dfGenneAllChr$mcols.GENEID[genePos]) - - # Allow run on all without check if the SNV have - # already gene name - listSNVGenes[listP] <- gsub("^:", "", - listSNVGenes[listP]) - - # Exon of the gene - dfExon <- dfExonChr[which(dfExonChr$GeneID == - dfGenneAllChr$mcols.GENEID[genePos]),] - k <- 1 - - listE <- list() - for (pos in listP) { - if(length(which(dfExon$Start <= matFreq$pos[pos] & - dfExon$End >= matFreq$pos[pos])) > 0) { - listE[[k]] <- pos - k <- k + 1 - } - } - if (length(listE) > 0) { - listE <- do.call(c, listE) - listSNVExons[listE] <- paste0(listSNVExons[listE], - ":", dfGenneAllChr$mcols.GENEID[genePos]) - listSNVExons[listE] <- gsub("^:", "", - listSNVExons[listE]) + # SNV in the GDS + matFreq <- matFreqAll[which(matFreqAll$chr == chr),] + # create two vector (one for the exon and one for the gene) of char + # with 1 entry for each SNV in the GDS + # I will keep the name of the gene and exon at this position + listSNVExons <- character(nrow(matFreq)) + listSNVGenes <- character(nrow(matFreq)) + + listPos <- seq_len(nrow(matFreq)) + listPos <- listPos[order(matFreq$pos)] + # Create an index to accelerate the process + startIndex <- seq(1, nrow(matFreq), 1000) + # Add if the last entry is not the last position + # is not the nb row of matFreq add the the last + #position + if(startIndex[length(startIndex)] < nrow(matFreq)){ + startIndex <- c(startIndex, nrow(matFreq)) + } + # For gene in the chr + # slow but acceptable + # user system elapsed + # 26.116 0.074 26.201 + # see blockAnnotation.R for slower alternatives + for (genePos in seq_len(nrow(dfGenneAllChr))) { + # the gene is where SNV exists + if (dfGenneAllChr$end[genePos] >= matFreq$pos[listPos[1]] & + dfGenneAllChr$start[genePos] <= matFreq$pos[nrow(matFreq)]) { + # In which partitions from the index the gene is located + vStart <- max(c(which(matFreq$pos[startIndex] <= + dfGenneAllChr$start[genePos]), 1)) + vEnd <- min(c(which(matFreq$pos[startIndex] >= + dfGenneAllChr$end[genePos]), + length(startIndex))) + # List of SNV in the gene + listP <- which(matFreq$pos[listPos[startIndex[vStart]:startIndex[vEnd]]] >= dfGenneAllChr$start[genePos] & + matFreq$pos[listPos[startIndex[vStart]:startIndex[vEnd]]] <= dfGenneAllChr$end[genePos]) + + # if SNV in the gene + if (length(listP) > 0) { + # listPos in the gene + listP <- + listPos[startIndex[vStart]:startIndex[vEnd]][listP] + + # Add the name of the gene of SNVs + listSNVGenes[listP] <- paste0(listSNVGenes[listP], ":", + dfGenneAllChr$mcols.GENEID[genePos]) + + # Allow run on all without check if the SNV have + # already gene name + listSNVGenes[listP] <- gsub("^:", "", + listSNVGenes[listP]) + + # Exon of the gene + dfExon <- dfExonChr[which(dfExonChr$GeneID == + dfGenneAllChr$mcols.GENEID[genePos]),] + k <- 1 + + listE <- list() + for (pos in listP) { + if(length(which(dfExon$Start <= matFreq$pos[pos] & + dfExon$End >= matFreq$pos[pos])) > 0) { + listE[[k]] <- pos + k <- k + 1 } } + + if (length(listE) > 0) { + listE <- do.call(c, listE) + listSNVExons[listE] <- paste0(listSNVExons[listE], + ":", dfGenneAllChr$mcols.GENEID[genePos]) + listSNVExons[listE] <- gsub("^:", "", + listSNVExons[listE]) + } } } - })) + } + # add the column Exon with the list of gene with an exon with the SNV @@ -419,9 +446,9 @@ generateGeneBlock <- function(gdsReference, winSize=10000, ensDb) { # create the space at the begining } - matGene.Block <- do.call(rbind, listMat) + matGeneBlock <- do.call(rbind, listMat) rm(listMat) - return(matGene.Block) + return(matGeneBlock) } diff --git a/inst/extdata/tests/ex1_NoBlockGene.1KG_Annot_GDS.gds b/inst/extdata/tests/ex1_NoBlockGene.1KG_Annot_GDS.gds new file mode 100644 index 0000000000000000000000000000000000000000..1f8a29af63d13ffddf827097eb3e65dd11a697a5 GIT binary patch literal 155202 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
;^I_z8wK85lB2P? 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

DUjA7$kXKkmPyo{D%ddUn}U6 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 BOELfe literal 0 HcmV?d00001 diff --git a/man/addGeneBlockGDSRefAnnot.Rd b/man/addGeneBlockGDSRefAnnot.Rd index cba0fe466..829c60ba7 100644 --- a/man/addGeneBlockGDSRefAnnot.Rd +++ b/man/addGeneBlockGDSRefAnnot.Rd @@ -44,10 +44,46 @@ extracted from the Population Reference GDS file. } \examples{ +## Required library +library(SNPRelate) + ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") -## TODO + +fileAnnotGDS <- file.path(getwd(), "ex1_good_small_1KG_Annot_GDS.gds") +## Required library +if (file.access(getwd()) == 0 && !file.exists(fileAnnotGDS)) { + + if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { + + file.copy(file.path(dataDir, "tests", "ex1_NoBlockGene.1KG_Annot_GDS.gds"), + fileAnnotGDS) + ## Making a "short cut" on the ensDb object + edb <- EnsDb.Hsapiens.v86::EnsDb.Hsapiens.v86 + + + ## Temporary Profile GDS file for one profile + fileReferenceGDS <- file.path(dataDir, "tests", + "ex1_good_small_1KG_GDS.gds") + + ## Open the reference GDS file (demo version) + gds1KG <- snpgdsOpen(fileReferenceGDS) + + + ## The function + addGeneBlockGDSRefAnnot(gdsReference=gds1KG, + gdsRefAnnotFile=fileAnnotGDS, + ensDb=edb, + suffixBlockName="EnsDb.Hsapiens.v86") + gdsAnnot1KG <- openfn.gds(fileAnnotGDS) + print(gdsAnnot1KG) + print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) + closefn.gds(gds1KG) + closefn.gds(gdsAnnot1KG) + unlink(fileAnnotGDS, force=TRUE) + } +} } \author{ diff --git a/man/basePCASample.Rd b/man/basePCASample.Rd deleted file mode 100644 index ed0c535d2..000000000 --- a/man/basePCASample.Rd +++ /dev/null @@ -1,58 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/process1KG.R -\encoding{UTF-8} -\name{basePCASample} -\alias{basePCASample} -\title{Compute principal component axes (PCA) on SNV data using the -reference samples} -\usage{ -basePCASample(gds, listSample.Ref = NULL, listSNP = NULL, np = 1L) -} -\arguments{ -\item{gds}{an object of class -\code{\link[SNPRelate:SNPGDSFileClass]{SNPRelate::SNPGDSFileClass}}, a SNP -GDS file.} - -\item{listSample.Ref}{a \code{vector} of \code{character} strings -corresponding to -the sample identifiers that will be used for the PCA.} - -\item{listSNP}{a \code{vector} of \code{character} strings representing -the SNV identifiers retained for the PCA.} - -\item{np}{a single positive \code{integer} representing the number of -threads. Default: \code{1L}.} -} -\value{ -a \code{list} with 3 entries: -\itemize{ -\item{SNP}{ a \code{vector} of \code{character} strings representing the -SNV identifiers used in the PCA.} -\item{pca.unrel}{ an object of class \code{snpgdsPCAClass} as generated -by the -\code{\link[SNPRelate:snpgdsPCA]{SNPRelate::snpgdsPCA}} function. } -\item{snp.load}{ an object of class \code{snpgdsPCASNPLoading} as generated -by the -\code{\link[SNPRelate:snpgdsPCASNPLoading]{SNPRelate::snpgdsPCASNPLoading}} -function. } -} -} -\description{ -The function runs a Principal Component Analysis (PCA) on -the SNv genotype data. The function also loads SNVs into the PCA to -calculate the SNV eigenvectors. Those 2 steps are done with the -\code{\link[SNPRelate]{snpgdsPCA}} and -\code{\link[SNPRelate]{snpgdsPCASNPLoading}} -functions. -} -\examples{ - -## Path to the demo pedigree file is located in this package -dataDir <- system.file("extdata", package="RAIDS") - -## TODO - -} -\author{ -Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -} diff --git a/man/generateGeneBlock.Rd b/man/generateGeneBlock.Rd index 939fede62..e9c1e5342 100644 --- a/man/generateGeneBlock.Rd +++ b/man/generateGeneBlock.Rd @@ -21,13 +21,18 @@ annotation. By default, the \code{EnsDb.Hsapiens.v86} class has been used.} \value{ a \code{data.frame} with those columns: \itemize{ -\item{chr} {TODO} -\item{pos} {TODO} -\item{snp.allele} {TODO} -\item{Exon} {TODO} -\item{GName} {TODO} -\item{Gene} {TODO} -\item{GeneS} {TODO} +\item{chr} {a single \code{integer} representing the SNV chromosome.} +\item{pos} {a single \code{integer} representing the SNV position.} +\item{snp.allele} {a \code{character} string representing the reference allele +and alternative allele for each of the SNV} +\item{Exon} {a \code{character} with the ensembl GeneId(s) if the SNV is in +one exon. If more than one GeneId they are separted by ':'} +\item{GName} {a \code{character} with the ensembl GeneId(s) if the SNV is in +the gene. If more than one GeneId they are separted by ':'} +\item{Gene} {A single \code{integer} specific to the SNVs that share +at least one genes} +\item{GeneS} {A single \code{integer} specific to the SNVs that share +a unique combination of genes} } "chr", "pos", "snp.allele", "Exon", "GName", "Gene", "GeneS" Example for GName and the two indexes "Gene", "GeneS" @@ -43,14 +48,36 @@ GName Gene GeneS 493 ENSG00000230021:ENSG00000228794 17 3825 } \description{ -TODO +Generate two indexes based on gene annotation for +gdsAnnot1KG block } \examples{ +## Required library +library(SNPRelate) + ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") -# TODO +## Required library +if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { + + ## Making a "short cut" on the ensDb object + edb <- EnsDb.Hsapiens.v86::EnsDb.Hsapiens.v86 + + path1KG <- file.path(dataDir, "example", "gdsRef") + + ## Temporary Profile GDS file for one profile + fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") + + ## Open the reference GDS file (demo version) + gds1KG <- snpgdsOpen(fileReferenceGDS) + + ## The function returns a data frame containing gene block information + matGeneBlock <- RAIDS:::generateGeneBlock(gdsReference=gds1KG, ensDb=edb) + print(head(matGeneBlock[grep("ENSG00000157152", matGeneBlock$GName),])) + closefn.gds(gds1KG) +} } \author{ From 2a9bc94e41f7dc04bb0d25ff3dd200204630a789 Mon Sep 17 00:00:00 2001 From: belleau Date: Mon, 21 Aug 2023 18:47:15 -0400 Subject: [PATCH 184/385] Remove TOREVIEW LOOP_REMOVE --- R/synthetic.R | 14 -------------- R/tools.R | 21 --------------------- 2 files changed, 35 deletions(-) diff --git a/R/synthetic.R b/R/synthetic.R index 6063f4f4d..1aa879e27 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -78,20 +78,6 @@ select1KGPop <- function(gdsReference, nbProfiles) { sample.id <- read.gdsn(index.gdsn(gdsReference, "sample.id"))[listKeep] listPop <- unique(sample.annot$pop.group) - ## FOR_LOOP modification to be validated by Pascal TOREVIEW - ## Remove commented code and this text after validation - - ## For each subcontinental population, randomly select a fixed number of - ## samples - # listSel <- list() - # for(i in seq_len(length(listPop))) { - # listGroup <- which(sample.annot$pop.group == listPop[i]) - # tmp <- sample(listGroup, min(nbProfiles, length(listGroup))) - # listSel[[i]] <- data.frame(sample.id=sample.id[tmp], - # pop.group=sample.annot$pop.group[tmp], - # superPop=sample.annot$superPop[tmp], - # stringsAsFactors=FALSE) - # } ## For each subcontinental population, randomly select a fixed number of ## samples diff --git a/R/tools.R b/R/tools.R index c8794a844..a19d4dd4f 100644 --- a/R/tools.R +++ b/R/tools.R @@ -205,27 +205,6 @@ groupChr1KGSNV <- function(pathGenoChr, pathOut) { listFiles <- dir(file.path(pathGenoChr, "chr1"), ".+\\.chr1\\.vcf\\.bz2") listSamples <- gsub("\\.chr1\\.vcf\\.bz2", "", listFiles) - ## TOREVIEW FOR_LOOP REMOVAL - ## Merge files associated to each samples into one csv file - # for(sampleId in listSamples) { - # - # ## TOREVIEW FOR_LOOOP REMOVAL - ## Read each genotyping file and append the information - # listGeno <- list() - # for(chr in seq_len(22)) { - # geno <- read.csv2(file.path(pathGenoChr, paste0("chr", chr), - # paste0(sampleId, ".chr", chr,".vcf.bz2")), - # sep="\t", row.names=NULL) - # - # listGeno[[paste0("chr", chr)]] <- geno - # } - # genoAll <- do.call(rbind, listGeno) -# -# ## Save the genotyping information into one file -# write.csv2(genoAll, file=bzfile(file.path(pathOut, -# paste0(sampleId, ".csv.bz2"))), row.names=FALSE) -# } - ## Merge files associated to each samples into one csv file results <- lapply(X=listSamples, FUN=function(sampleId, pathOut) { From 36aaedb04176642c0680d069841abebc41d34611 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Aug 2023 18:52:21 -0400 Subject: [PATCH 185/385] Update version to 0.99.9 --- DESCRIPTION | 2 +- inst/NEWS.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 66f78bd8c..3ba441e08 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.8 +Version: 0.99.9 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index 826b12dd4..11bcb38e6 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,11 @@ +CHANGES IN VERSION 0.99.9 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o Better documentation for the runRNAAncestry() function. + + CHANGES IN VERSION 0.99.8 ------------------------ From 55f024c3cebc36d3ef36a95f710d89ebb23d71fd Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Aug 2023 18:54:06 -0400 Subject: [PATCH 186/385] Update RAIDS vignette --- vignettes/RAIDS.Rmd | 2 -- 1 file changed, 2 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 44f1bba5f..5a51ffe89 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -396,8 +396,6 @@ also created. ### RNA data - Wrapper function to run ancestry inference on RNA data - -TOREVIEW The process is the same as for the DNA but use the wrapper function called _runRNAAncestry()_. Internally the data is process differently. It requires 4 files as input: From 4caac8daaac0ba335b349a775e461836c57f6617 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Aug 2023 18:55:13 -0400 Subject: [PATCH 187/385] Update package version to 0.99.10 --- DESCRIPTION | 2 +- inst/NEWS.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 3ba441e08..ab7129050 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.9 +Version: 0.99.10 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index 11bcb38e6..2e3395876 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,10 @@ +CHANGES IN VERSION 0.99.10 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o Update main vignette. + CHANGES IN VERSION 0.99.9 ------------------------ From db13effe47c03cef3ccf54f136c5d752ff0381ca Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 29 Aug 2023 14:38:52 -0400 Subject: [PATCH 188/385] Changing getwd() to tempdir() in some examples. --- R/allelicFraction_internal.R | 127 ++++++++++++++----------------- R/gdsWrapper.R | 80 +++++++------------ man/computeAllelicFractionDNA.Rd | 43 +++++------ man/computeAllelicFractionRNA.Rd | 48 ++++++------ man/generateGDSSNPinfo.Rd | 42 +++------- man/generateGDSgenotype.Rd | 38 +++++---- man/getTableSNV.Rd | 36 ++++----- 7 files changed, 166 insertions(+), 248 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 4e53fd613..4e2e55892 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -62,36 +62,32 @@ #' dataDir <- system.file("extdata/tests", package="RAIDS") #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' -#' ## Temporary Profile GDS file for one profile -#' fileProfile <- file.path(getwd(), "ex1.gds") +#' ## Temporary Profile GDS file for one profile in temporary directory +#' fileProfile <- file.path(tempdir(), "ex1.gds") #' -#' ## Example can only be run if the current directory is in writing mode -#' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { -#' -#' ## Copy the Profile GDS file demo that has been pruned and annotated -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), #' fileProfile) #' -#' ## Open the reference GDS file (demo version) -#' gds1KG <- snpgdsOpen(fileGDS) +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Open Profile GDS file for one profile -#' profileGDS <- openfn.gds(fileProfile) +#' ## Open Profile GDS file for one profile +#' profileGDS <- openfn.gds(fileProfile) #' -#' ## The function returns a data frame containing the SNVs information -#' result <- RAIDS:::getTableSNV(gdsReference=gds1KG, gdsSample=profileGDS, +#' ## The function returns a data frame containing the SNVs information +#' result <- RAIDS:::getTableSNV(gdsReference=gds1KG, gdsSample=profileGDS, #' currentProfile="ex1", studyID="MYDATA", minCov=10L, minProb=0.999, #' eProb=0.001, verbose=FALSE) -#' head(result) +#' head(result) #' -#' ## Close both GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) +#' ## Close both GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(fileProfile, force=TRUE) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn @@ -710,46 +706,41 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { #' dataDir <- system.file("extdata/tests", package="RAIDS") #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' -#' ## Temporary Profile GDS file for one profile -#' fileProfile <- file.path(getwd(), "ex1.gds") -#' -#' ## Example can only be run if the current directory is in writing mode -#' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { +#' ## Temporary Profile GDS file for one profile in temporary directory +#' fileProfile <- file.path(tempdir(), "ex1.gds") #' -#' ## Copy the Profile GDS file demo that has been pruned and annotated -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), #' fileProfile) #' -#' ## Open the reference GDS file (demo version) -#' gds1KG <- snpgdsOpen(fileGDS) +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Open Profile GDS file for one profile -#' profileGDS <- openfn.gds(fileProfile) +#' ## Open Profile GDS file for one profile +#' profileGDS <- openfn.gds(fileProfile) #' -#' ## Chromosome length information -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, #' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, #' 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, #' 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, #' 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) #' -#' ## The function returns a data frame containing the allelic fraction info -#' result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, +#' ## The function returns a data frame containing the allelic fraction info +#' result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, #' gdsSample=profileGDS, #' currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, minCov=10L, #' minProb=0.999, eProb=0.001, cutOffLOH=-5, #' cutOffHomoScore=-3, wAR=9L, verbose=FALSE) -#' head(result) -#' -#' ## Close both GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) +#' head(result) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(fileProfile, force=TRUE) +#' ## Close both GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) #' -#' } +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn @@ -930,49 +921,45 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' fileAnnotGDS <- file.path(dataDir, "ex1_good_small_1KG_Annot_GDS.gds") #' -#' ## Temporary Profile GDS file for one profile -#' fileProfile <- file.path(getwd(), "ex1.gds") +#' ## Temporary Profile GDS file for one profile in temporary directory +#' fileProfile <- file.path(tempdir(), "ex1.gds") #' -#' ## Example can only be run if the current directory is in writing mode -#' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { -#' -#' ## Copy the Profile GDS file demo that has been pruned and annotated -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), #' fileProfile) #' -#' ## Open the reference GDS file (demo version) -#' gds1KG <- snpgdsOpen(fileGDS) -#' gdsRefAnnot <- openfn.gds(fileAnnotGDS) -#' ## Open Profile GDS file for one profile -#' profileGDS <- openfn.gds(fileProfile) +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileGDS) +#' gdsRefAnnot <- openfn.gds(fileAnnotGDS) +#' +#' ## Open Profile GDS file for one profile +#' profileGDS <- openfn.gds(fileProfile) #' -#' ## Chromosome length information -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, #' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, #' 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, #' 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, #' 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) #' -#' ## The function returns a data frame containing the allelic fraction info -#' result <- RAIDS:::computeAllelicFractionRNA(gdsReference=gds1KG, +#' ## The function returns a data frame containing the allelic fraction info +#' result <- RAIDS:::computeAllelicFractionRNA(gdsReference=gds1KG, #' gdsSample=profileGDS, gdsRefAnnot=gdsRefAnnot, #' currentProfile="ex1", studyID="MYDATA", #' blockID="GeneS.Ensembl.Hsapiens.v86", #' chrInfo=chrInfo, minCov=10L, #' minProb=0.999, eProb=0.001, cutOffLOH=-5, #' cutOffAR=3, verbose=FALSE) -#' head(result) -#' -#' ## Close both GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) -#' closefn.gds(gdsRefAnnot) +#' head(result) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(fileProfile, force=TRUE) +#' ## Close both GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) +#' closefn.gds(gdsRefAnnot) #' -#' } +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn ls.gdsn diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 9c88fe089..a54859d8b 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -23,43 +23,19 @@ #' dataDir <- system.file("extdata", package="RAIDS") #' fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' -#' ## Different code depending of the withr package availability -#' ## The current directory must be writable -#' if (file.access(getwd()) == 0) { -#' if (requireNamespace("withr", quietly=TRUE)) { +#' ## Temporary Reference GDS file in temporary directory +#' file1KG <- file.path(tempdir(), "1KG_TEMP_002.gds") +#' filenewGDS <- createfn.gds(file1KG) #' -#' ## Temporary Reference GDS file -#' file1KG <- withr::local_file("1KG_TEMP_002.gds") -#' filenewGDS <- createfn.gds(file1KG) -#' -#' ## Add SNV information to Reference GDS -#' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, -#' fileFreq=fileFilerterSNVs, verbose=TRUE) -#' -#' ## Close GDS file (important) -#' closefn.gds(filenewGDS) -#' -#' ## Remove temporary 1KG_TEMP_002.gds file -#' withr::deferred_run() -#' -#' } else { -#' -#' ## Temporary Reference GDS file -#' file1KG <- file.path("1KG_TEMP_002.gds") -#' filenewGDS <- createfn.gds(file1KG) -#' -#' ## Add SNV information to Reference GDS -#' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, +#' ## Add SNV information to Reference GDS +#' RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, #' fileFreq=fileFilerterSNVs, verbose=TRUE) #' -#' ## Close GDS file (important) -#' closefn.gds(filenewGDS) +#' ## Close GDS file (important) +#' closefn.gds(filenewGDS) #' -#' ## Remove temporary 1KG_TEMP_002.gds file -#' unlink(file1KG, force=TRUE) -#' -#' } -#' } +#' ## Remove temporary 1KG_TEMP_002.gds file +#' unlink(file1KG, force=TRUE) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn @@ -158,37 +134,33 @@ generateGDSSNPinfo <- function(gdsReference, fileFreq, verbose) { #' ## The RDS file containing the filtered SNP information #' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' -#' ## Temporary Reference GDS file -#' tempRefGDS <- file.path(getwd(), "Ref_TEMP01.gds") +#' ## Temporary Reference GDS file in temporary directory +#' tempRefGDS <- file.path(tempdir(), "Ref_TEMP01.gds") #' -#' ## Only run example if the directory is writable -#' if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { -#' -#' ## Create temporary Reference GDS file -#' newGDS <- createfn.gds(tempRefGDS) -#' put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") +#' ## Create temporary Reference GDS file +#' newGDS <- createfn.gds(tempRefGDS) +#' put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") #' -#' ## Read the pedigree file -#' ped1KG <- readRDS(pedigreeFile) +#' ## Read the pedigree file +#' ped1KG <- readRDS(pedigreeFile) #' -#' ## Add information about samples to the Reference GDS file -#' listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, +#' ## Add information about samples to the Reference GDS file +#' listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, #' dfPedReference=ped1KG, listSamples=NULL) #' -#' ## Add SNV information to the Reference GDS -#' RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, +#' ## Add SNV information to the Reference GDS +#' RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, #' verbose=FALSE) #' -#' ## Add genotype information to the Reference GDS -#' RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, +#' ## Add genotype information to the Reference GDS +#' RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, #' fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS, verbose=FALSE) #' -#' ## Close file -#' closefn.gds(newGDS) +#' ## Close file +#' closefn.gds(newGDS) #' -#' ## Remove temporary files -#' unlink(tempRefGDS, force=TRUE) -#' } +#' ## Remove temporary files +#' unlink(tempRefGDS, force=TRUE) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn write.gdsn diff --git a/man/computeAllelicFractionDNA.Rd b/man/computeAllelicFractionDNA.Rd index 6cb4048e3..e0310af66 100644 --- a/man/computeAllelicFractionDNA.Rd +++ b/man/computeAllelicFractionDNA.Rd @@ -102,46 +102,41 @@ library(SNPRelate) dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") -## Temporary Profile GDS file for one profile -fileProfile <- file.path(getwd(), "ex1.gds") +## Temporary Profile GDS file for one profile in temporary directory +fileProfile <- file.path(tempdir(), "ex1.gds") -## Example can only be run if the current directory is in writing mode -if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { - - ## Copy the Profile GDS file demo that has been pruned and annotated - file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +## Copy the Profile GDS file demo that has been pruned and annotated +file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), fileProfile) - ## Open the reference GDS file (demo version) - gds1KG <- snpgdsOpen(fileGDS) +## Open the reference GDS file (demo version) +gds1KG <- snpgdsOpen(fileGDS) - ## Open Profile GDS file for one profile - profileGDS <- openfn.gds(fileProfile) +## Open Profile GDS file for one profile +profileGDS <- openfn.gds(fileProfile) - ## Chromosome length information - ## chr23 is chrX, chr24 is chrY and chrM is 25 - chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +## Chromosome length information +## chr23 is chrX, chr24 is chrY and chrM is 25 +chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) - ## The function returns a data frame containing the allelic fraction info - result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, +## The function returns a data frame containing the allelic fraction info +result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, gdsSample=profileGDS, currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, minCov=10L, minProb=0.999, eProb=0.001, cutOffLOH=-5, cutOffHomoScore=-3, wAR=9L, verbose=FALSE) - head(result) - - ## Close both GDS files (important) - closefn.gds(profileGDS) - closefn.gds(gds1KG) +head(result) - ## Remove Profile GDS file (created for demo purpose) - unlink(fileProfile, force=TRUE) +## Close both GDS files (important) +closefn.gds(profileGDS) +closefn.gds(gds1KG) -} +## Remove Profile GDS file (created for demo purpose) +unlink(fileProfile, force=TRUE) } \author{ diff --git a/man/computeAllelicFractionRNA.Rd b/man/computeAllelicFractionRNA.Rd index 44920ea75..9582ff61b 100644 --- a/man/computeAllelicFractionRNA.Rd +++ b/man/computeAllelicFractionRNA.Rd @@ -114,49 +114,45 @@ dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") fileAnnotGDS <- file.path(dataDir, "ex1_good_small_1KG_Annot_GDS.gds") -## Temporary Profile GDS file for one profile -fileProfile <- file.path(getwd(), "ex1.gds") +## Temporary Profile GDS file for one profile in temporary directory +fileProfile <- file.path(tempdir(), "ex1.gds") -## Example can only be run if the current directory is in writing mode -if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { - - ## Copy the Profile GDS file demo that has been pruned and annotated - file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +## Copy the Profile GDS file demo that has been pruned and annotated +file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), fileProfile) - ## Open the reference GDS file (demo version) - gds1KG <- snpgdsOpen(fileGDS) - gdsRefAnnot <- openfn.gds(fileAnnotGDS) - ## Open Profile GDS file for one profile - profileGDS <- openfn.gds(fileProfile) +## Open the reference GDS file (demo version) +gds1KG <- snpgdsOpen(fileGDS) +gdsRefAnnot <- openfn.gds(fileAnnotGDS) + +## Open Profile GDS file for one profile +profileGDS <- openfn.gds(fileProfile) - ## Chromosome length information - ## chr23 is chrX, chr24 is chrY and chrM is 25 - chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +## Chromosome length information +## chr23 is chrX, chr24 is chrY and chrM is 25 +chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) - ## The function returns a data frame containing the allelic fraction info - result <- RAIDS:::computeAllelicFractionRNA(gdsReference=gds1KG, +## The function returns a data frame containing the allelic fraction info +result <- RAIDS:::computeAllelicFractionRNA(gdsReference=gds1KG, gdsSample=profileGDS, gdsRefAnnot=gdsRefAnnot, currentProfile="ex1", studyID="MYDATA", blockID="GeneS.Ensembl.Hsapiens.v86", chrInfo=chrInfo, minCov=10L, minProb=0.999, eProb=0.001, cutOffLOH=-5, cutOffAR=3, verbose=FALSE) - head(result) +head(result) - ## Close both GDS files (important) - closefn.gds(profileGDS) - closefn.gds(gds1KG) - closefn.gds(gdsRefAnnot) +## Close both GDS files (important) +closefn.gds(profileGDS) +closefn.gds(gds1KG) +closefn.gds(gdsRefAnnot) - ## Remove Profile GDS file (created for demo purpose) - unlink(fileProfile, force=TRUE) - -} +## Remove Profile GDS file (created for demo purpose) +unlink(fileProfile, force=TRUE) } \author{ diff --git a/man/generateGDSSNPinfo.Rd b/man/generateGDSSNPinfo.Rd index 685676f84..31bfe77d9 100644 --- a/man/generateGDSSNPinfo.Rd +++ b/man/generateGDSSNPinfo.Rd @@ -33,43 +33,19 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") fileFilerterSNVs <- file.path(dataDir, "mapSNVSelected_Demo.rds") -## Different code depending of the withr package availability -## The current directory must be writable -if (file.access(getwd()) == 0) { - if (requireNamespace("withr", quietly=TRUE)) { +## Temporary Reference GDS file in temporary directory +file1KG <- file.path(tempdir(), "1KG_TEMP_002.gds") +filenewGDS <- createfn.gds(file1KG) - ## Temporary Reference GDS file - file1KG <- withr::local_file("1KG_TEMP_002.gds") - filenewGDS <- createfn.gds(file1KG) - - ## Add SNV information to Reference GDS - RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, +## Add SNV information to Reference GDS +RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, fileFreq=fileFilerterSNVs, verbose=TRUE) - ## Close GDS file (important) - closefn.gds(filenewGDS) - - ## Remove temporary 1KG_TEMP_002.gds file - withr::deferred_run() - - } else { +## Close GDS file (important) +closefn.gds(filenewGDS) - ## Temporary Reference GDS file - file1KG <- file.path("1KG_TEMP_002.gds") - filenewGDS <- createfn.gds(file1KG) - - ## Add SNV information to Reference GDS - RAIDS:::generateGDSSNPinfo(gdsReference=filenewGDS, - fileFreq=fileFilerterSNVs, verbose=TRUE) - - ## Close GDS file (important) - closefn.gds(filenewGDS) - - ## Remove temporary 1KG_TEMP_002.gds file - unlink(file1KG, force=TRUE) - - } -} +## Remove temporary 1KG_TEMP_002.gds file +unlink(file1KG, force=TRUE) } \author{ diff --git a/man/generateGDSgenotype.Rd b/man/generateGDSgenotype.Rd index 2a0650672..4999dce2a 100644 --- a/man/generateGDSgenotype.Rd +++ b/man/generateGDSgenotype.Rd @@ -54,37 +54,33 @@ snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") ## The RDS file containing the filtered SNP information filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") -## Temporary Reference GDS file -tempRefGDS <- file.path(getwd(), "Ref_TEMP01.gds") +## Temporary Reference GDS file in temporary directory +tempRefGDS <- file.path(tempdir(), "Ref_TEMP01.gds") -## Only run example if the directory is writable -if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { +## Create temporary Reference GDS file +newGDS <- createfn.gds(tempRefGDS) +put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") - ## Create temporary Reference GDS file - newGDS <- createfn.gds(tempRefGDS) - put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") +## Read the pedigree file +ped1KG <- readRDS(pedigreeFile) - ## Read the pedigree file - ped1KG <- readRDS(pedigreeFile) - - ## Add information about samples to the Reference GDS file - listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, +## Add information about samples to the Reference GDS file +listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, dfPedReference=ped1KG, listSamples=NULL) - ## Add SNV information to the Reference GDS - RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, +## Add SNV information to the Reference GDS +RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, verbose=FALSE) - ## Add genotype information to the Reference GDS - RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, +## Add genotype information to the Reference GDS +RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS, verbose=FALSE) - ## Close file - closefn.gds(newGDS) +## Close file +closefn.gds(newGDS) - ## Remove temporary files - unlink(tempRefGDS, force=TRUE) -} +## Remove temporary files +unlink(tempRefGDS, force=TRUE) } \author{ diff --git a/man/getTableSNV.Rd b/man/getTableSNV.Rd index 77f3d9f06..377082078 100644 --- a/man/getTableSNV.Rd +++ b/man/getTableSNV.Rd @@ -81,36 +81,32 @@ library(gdsfmt) dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") -## Temporary Profile GDS file for one profile -fileProfile <- file.path(getwd(), "ex1.gds") +## Temporary Profile GDS file for one profile in temporary directory +fileProfile <- file.path(tempdir(), "ex1.gds") -## Example can only be run if the current directory is in writing mode -if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { - - ## Copy the Profile GDS file demo that has been pruned and annotated - file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +## Copy the Profile GDS file demo that has been pruned and annotated +file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), fileProfile) - ## Open the reference GDS file (demo version) - gds1KG <- snpgdsOpen(fileGDS) +## Open the reference GDS file (demo version) +gds1KG <- snpgdsOpen(fileGDS) - ## Open Profile GDS file for one profile - profileGDS <- openfn.gds(fileProfile) +## Open Profile GDS file for one profile +profileGDS <- openfn.gds(fileProfile) - ## The function returns a data frame containing the SNVs information - result <- RAIDS:::getTableSNV(gdsReference=gds1KG, gdsSample=profileGDS, +## The function returns a data frame containing the SNVs information +result <- RAIDS:::getTableSNV(gdsReference=gds1KG, gdsSample=profileGDS, currentProfile="ex1", studyID="MYDATA", minCov=10L, minProb=0.999, eProb=0.001, verbose=FALSE) - head(result) +head(result) - ## Close both GDS files (important) - closefn.gds(profileGDS) - closefn.gds(gds1KG) +## Close both GDS files (important) +closefn.gds(profileGDS) +closefn.gds(gds1KG) - ## Remove Profile GDS file (created for demo purpose) - unlink(fileProfile, force=TRUE) +## Remove Profile GDS file (created for demo purpose) +unlink(fileProfile, force=TRUE) -} } \author{ From 045e8817817546e1feaf2a1bfedb384210d998d5 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 29 Aug 2023 16:33:43 -0400 Subject: [PATCH 189/385] Changing getwd() to tempdir() in some examples. --- R/gdsWrapper.R | 42 ++++++++++------------ R/gdsWrapper_internal.R | 70 ++++++++++++++++--------------------- man/addBlockInGDSAnnot.Rd | 42 ++++++++++------------ man/addGDSRef.Rd | 32 ++++++++--------- man/generateGDSRefSample.Rd | 38 +++++++++----------- 5 files changed, 100 insertions(+), 124 deletions(-) diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index a54859d8b..c30fdedde 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -375,39 +375,35 @@ appendGDSgenotype <- function(gds, listSample, pathGeno, fileSNPsRDS, #' library(gdsfmt) #' #' ## Temporary GDS Annotation file in current directory -#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_Annot_14.gds") +#' gdsFilePath <- file.path(tempdir(), "GDS_TEMP_Annot_14.gds") #' -#' ## Run only if directory in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +#' ## Create and open the GDS file +#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) #' -#' ## Create and open the GDS file -#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) +#' ## One block +#' blockType <- "EAS.0.05.500k" #' -#' ## One block -#' blockType <- "EAS.0.05.500k" +#' ## The description of the block +#' blockDescription <- "EAS population blocks based on 500k windows" #' -#' ## The description of the block -#' blockDescription <- "EAS population blocks based on 500k windows" +#' ## The values for each entry related to the block (integers) +#' blockEntries <- c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3) #' -#' ## The values for each entry related to the block (integers) -#' blockEntries <- c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3) +#' RAIDS:::addBlockInGDSAnnot(gds=GDS_file_tmp, listBlock=blockEntries, +#' blockName=blockType, blockDesc=blockDescription) #' -#' RAIDS:::addBlockInGDSAnnot(gds=GDS_file_tmp, listBlock=blockEntries, -#' blockName=blockType, blockDesc=blockDescription) +#' ## Read 'block.annot' node +#' read.gdsn(index.gdsn(GDS_file_tmp, "block.annot")) #' -#' ## Read 'block.annot' node -#' read.gdsn(index.gdsn(GDS_file_tmp, "block.annot")) +#' ## Read 'block' node +#' read.gdsn(index.gdsn(GDS_file_tmp, "block")) #' -#' ## Read 'block' node -#' read.gdsn(index.gdsn(GDS_file_tmp, "block")) +#' ## Close GDS file +#' closefn.gds(gdsfile=GDS_file_tmp) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=GDS_file_tmp) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) -#' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn index.gdsn ls.gdsn compression.gdsn diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index b51b8eda5..3f7632ce8 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -32,16 +32,13 @@ #' library(gdsfmt) #' #' ## Temporary GDS file in current directory -#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_10.gds") +#' gdsFilePath <- file.path(tempdir(), "GDS_TEMP_10.gds") #' -#' ## Run only if directory in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -#' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) #' -#' ## Create "sample.annot" node (the node must be present) -#' pedInformation <- data.frame(sample.id=c("sample_01", "sample_02"), +#' ## Create "sample.annot" node (the node must be present) +#' pedInformation <- data.frame(sample.id=c("sample_01", "sample_02"), #' Name.ID=c("sample_01", "sample_02"), #' sex=c(1,1), # 1:Male 2: Female #' pop.group=c("ACB", "ACB"), @@ -49,26 +46,25 @@ #' batch=c(1, 1), #' stringsAsFactors=FALSE) #' -#' ## The row names must be the sample identifiers -#' rownames(pedInformation) <- pedInformation$Name.ID +#' ## The row names must be the sample identifiers +#' rownames(pedInformation) <- pedInformation$Name.ID #' -#' ## Add information about 2 samples to the GDS file -#' RAIDS:::generateGDSRefSample(gdsReference=tmpGDS, +#' ## Add information about 2 samples to the GDS file +#' RAIDS:::generateGDSRefSample(gdsReference=tmpGDS, #' dfPedReference=pedInformation, listSamples=NULL) #' -#' ## Read sample identifier list -#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) +#' ## Read sample identifier list +#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) #' -#' ## Read sample information from GDS file -#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) +#' ## Read sample information from GDS file +#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn @@ -128,31 +124,27 @@ generateGDSRefSample <- function(gdsReference, dfPedReference, #' rdsFilePath <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") #' #' ## Temporary GDS file -#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") +#' gdsFilePath <- file.path(tempdir(), "GDS_TEMP_11.gds") #' -#' ## Run only if directory in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -#' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) # -#' ## Create "sample.id" node (the node must be present) -#' sampleIDs <- c("HG00104", "HG00109", "HG00110") -#' add.gdsn(node=tmpGDS, name="sample.id", val=sampleIDs) +#' ## Create "sample.id" node (the node must be present) +#' sampleIDs <- c("HG00104", "HG00109", "HG00110") +#' add.gdsn(node=tmpGDS, name="sample.id", val=sampleIDs) #' -#' ## Create "sample.ref" node in GDS file using RDS information -#' RAIDS:::addGDSRef(gdsReference=tmpGDS, filePart=rdsFilePath) +#' ## Create "sample.ref" node in GDS file using RDS information +#' RAIDS:::addGDSRef(gdsReference=tmpGDS, filePart=rdsFilePath) #' -#' ## Read sample reference data.frame -#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.ref")) +#' ## Read sample reference data.frame +#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.ref")) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn diff --git a/man/addBlockInGDSAnnot.Rd b/man/addBlockInGDSAnnot.Rd index 89ff0ecf8..36479545a 100644 --- a/man/addBlockInGDSAnnot.Rd +++ b/man/addBlockInGDSAnnot.Rd @@ -39,39 +39,35 @@ single column that corresponds to the row number in the 'block.annot' node. library(gdsfmt) ## Temporary GDS Annotation file in current directory -gdsFilePath <- file.path(getwd(), "GDS_TEMP_Annot_14.gds") +gdsFilePath <- file.path(tempdir(), "GDS_TEMP_Annot_14.gds") -## Run only if directory in writing mode -if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +## Create and open the GDS file +GDS_file_tmp <- createfn.gds(filename=gdsFilePath) - ## Create and open the GDS file - GDS_file_tmp <- createfn.gds(filename=gdsFilePath) +## One block +blockType <- "EAS.0.05.500k" - ## One block - blockType <- "EAS.0.05.500k" +## The description of the block +blockDescription <- "EAS population blocks based on 500k windows" - ## The description of the block - blockDescription <- "EAS population blocks based on 500k windows" +## The values for each entry related to the block (integers) +blockEntries <- c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3) - ## The values for each entry related to the block (integers) - blockEntries <- c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3) +RAIDS:::addBlockInGDSAnnot(gds=GDS_file_tmp, listBlock=blockEntries, + blockName=blockType, blockDesc=blockDescription) - RAIDS:::addBlockInGDSAnnot(gds=GDS_file_tmp, listBlock=blockEntries, - blockName=blockType, blockDesc=blockDescription) +## Read 'block.annot' node +read.gdsn(index.gdsn(GDS_file_tmp, "block.annot")) - ## Read 'block.annot' node - read.gdsn(index.gdsn(GDS_file_tmp, "block.annot")) +## Read 'block' node +read.gdsn(index.gdsn(GDS_file_tmp, "block")) - ## Read 'block' node - read.gdsn(index.gdsn(GDS_file_tmp, "block")) +## Close GDS file +closefn.gds(gdsfile=GDS_file_tmp) - ## Close GDS file - closefn.gds(gdsfile=GDS_file_tmp) +## Delete the temporary GDS file +unlink(x=gdsFilePath, force=TRUE) - ## Delete the temporary GDS file - unlink(x=gdsFilePath, force=TRUE) - -} } \author{ diff --git a/man/addGDSRef.Rd b/man/addGDSRef.Rd index e242e7b49..71a905324 100644 --- a/man/addGDSRef.Rd +++ b/man/addGDSRef.Rd @@ -38,30 +38,26 @@ dataDir <- system.file("extdata", package="RAIDS") rdsFilePath <- file.path(dataDir, "unrelatedPatientsInfo_Demo.rds") ## Temporary GDS file -gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") +gdsFilePath <- file.path(tempdir(), "GDS_TEMP_11.gds") -## Run only if directory in writing mode -if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +## Create and open the GDS file +tmpGDS <- createfn.gds(filename=gdsFilePath) +## Create "sample.id" node (the node must be present) +sampleIDs <- c("HG00104", "HG00109", "HG00110") +add.gdsn(node=tmpGDS, name="sample.id", val=sampleIDs) - ## Create and open the GDS file - tmpGDS <- createfn.gds(filename=gdsFilePath) - ## Create "sample.id" node (the node must be present) - sampleIDs <- c("HG00104", "HG00109", "HG00110") - add.gdsn(node=tmpGDS, name="sample.id", val=sampleIDs) +## Create "sample.ref" node in GDS file using RDS information +RAIDS:::addGDSRef(gdsReference=tmpGDS, filePart=rdsFilePath) - ## Create "sample.ref" node in GDS file using RDS information - RAIDS:::addGDSRef(gdsReference=tmpGDS, filePart=rdsFilePath) +## Read sample reference data.frame +read.gdsn(index.gdsn(node=tmpGDS, path="sample.ref")) - ## Read sample reference data.frame - read.gdsn(index.gdsn(node=tmpGDS, path="sample.ref")) +## Close GDS file +closefn.gds(gdsfile=tmpGDS) - ## Close GDS file - closefn.gds(gdsfile=tmpGDS) +## Delete the temporary GDS file +unlink(x=gdsFilePath, force=TRUE) - ## Delete the temporary GDS file - unlink(x=gdsFilePath, force=TRUE) - - } } \author{ diff --git a/man/generateGDSRefSample.Rd b/man/generateGDSRefSample.Rd index 1560c3737..9955c2c90 100644 --- a/man/generateGDSRefSample.Rd +++ b/man/generateGDSRefSample.Rd @@ -42,16 +42,13 @@ the \code{data.frame} passed to the function. The nodes "sample.id" and library(gdsfmt) ## Temporary GDS file in current directory -gdsFilePath <- file.path(getwd(), "GDS_TEMP_10.gds") +gdsFilePath <- file.path(tempdir(), "GDS_TEMP_10.gds") -## Run only if directory in writing mode -if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +## Create and open the GDS file +tmpGDS <- createfn.gds(filename=gdsFilePath) - ## Create and open the GDS file - tmpGDS <- createfn.gds(filename=gdsFilePath) - - ## Create "sample.annot" node (the node must be present) - pedInformation <- data.frame(sample.id=c("sample_01", "sample_02"), +## Create "sample.annot" node (the node must be present) +pedInformation <- data.frame(sample.id=c("sample_01", "sample_02"), Name.ID=c("sample_01", "sample_02"), sex=c(1,1), # 1:Male 2: Female pop.group=c("ACB", "ACB"), @@ -59,26 +56,25 @@ if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { batch=c(1, 1), stringsAsFactors=FALSE) - ## The row names must be the sample identifiers - rownames(pedInformation) <- pedInformation$Name.ID +## The row names must be the sample identifiers +rownames(pedInformation) <- pedInformation$Name.ID - ## Add information about 2 samples to the GDS file - RAIDS:::generateGDSRefSample(gdsReference=tmpGDS, +## Add information about 2 samples to the GDS file +RAIDS:::generateGDSRefSample(gdsReference=tmpGDS, dfPedReference=pedInformation, listSamples=NULL) - ## Read sample identifier list - read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) +## Read sample identifier list +read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) - ## Read sample information from GDS file - read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) +## Read sample information from GDS file +read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) - ## Close GDS file - closefn.gds(gdsfile=tmpGDS) +## Close GDS file +closefn.gds(gdsfile=tmpGDS) - ## Delete the temporary GDS file - unlink(x=gdsFilePath, force=TRUE) +## Delete the temporary GDS file +unlink(x=gdsFilePath, force=TRUE) -} } \author{ From 7b0f46dd290619ffe0d8437cf1ac1033dab4b0be Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 29 Aug 2023 23:00:29 -0400 Subject: [PATCH 190/385] Changing getwd() to tempdir() in some examples. --- R/allelicFraction.R | 54 ++++++++++++++++------------------ R/gdsWrapper.R | 40 ++++++++++++------------- man/appendGDSgenotype.Rd | 40 ++++++++++++------------- man/estimateAllelicFraction.Rd | 54 ++++++++++++++++------------------ 4 files changed, 86 insertions(+), 102 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index bc230c4ea..f7c259a7d 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -93,54 +93,50 @@ #' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") #' #' ## Profile GDS file for one profile -#' fileProfile <- file.path("ex1.gds") +#' fileProfile <- file.path(tempdir(), "ex1.gds") #' -#' ## Example can only be run if the current directory is in writing mode -#' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { -#' -#' ## Copy the Profile GDS file demo that has been pruned and annotated -#' ## into current directory -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' ## into current directory +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), #' fileProfile) #' -#' ## Open the reference GDS file (demo version) -#' gds1KG <- snpgdsOpen(fileGDS) +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Profile GDS file for one profile -#' profileGDS <- openfn.gds(fileProfile, readonly=FALSE) +#' ## Profile GDS file for one profile +#' profileGDS <- openfn.gds(fileProfile, readonly=FALSE) #' -#' ## Chromosome length information -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, #' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, #' 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, #' 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, #' 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) #' -#' ## A formal way to get the chormosome length information -#' ## library(GenomeInfoDb) -#' ## library(BSgenome.Hsapiens.UCSC.hg38) -#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] +#' ## A formal way to get the chormosome length information +#' ## library(GenomeInfoDb) +#' ## library(BSgenome.Hsapiens.UCSC.hg38) +#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' -#' ## Estimate the allelic fraction of the pruned SNVs -#' estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, +#' ## Estimate the allelic fraction of the pruned SNVs +#' estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, #' currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, #' studyType="DNA", minCov=10L, minProb=0.999, eProb=0.001, #' cutOffLOH=-5, cutOffHomoScore=-3, wAR=9, cutOffAR=3, #' gdsRefAnnot=NULL, blockID=NULL) #' -#' ## The allelic fraction is saved in the 'lap' node of Profile GDS file -#' ## The 'lap' entry should be present -#' profileGDS +#' ## The allelic fraction is saved in the 'lap' node of Profile GDS file +#' ## The 'lap' entry should be present +#' profileGDS #' -#' ## Close both GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) +#' ## Close both GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(fileProfile, force=TRUE) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom rlang arg_match diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index c30fdedde..56ac637c4 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -259,43 +259,39 @@ generateGDSgenotype <- function(gds, pathGeno, fileSNPsRDS, listSamples, #' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' #' ## Temporary Reference GDS file -#' tempRefGDS <- file.path(getwd(), "Ref_TEMP02.gds") +#' tempRefGDS <- file.path(tempdir(), "Ref_TEMP02.gds") #' -#' ## Only run example if the directory is writable -#' if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { -#' -#' ## Create temporary Reference GDS file -#' newGDS <- createfn.gds(tempRefGDS) -#' put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") +#' ## Create temporary Reference GDS file +#' newGDS <- createfn.gds(tempRefGDS) +#' put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") #' -#' ## Read the pedigree file -#' ped1KG <- readRDS(pedigreeFile) +#' ## Read the pedigree file +#' ped1KG <- readRDS(pedigreeFile) #' -#' ## Add information about samples to the Reference GDS file -#' listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, +#' ## Add information about samples to the Reference GDS file +#' listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, #' dfPedReference=ped1KG, listSamples=NULL) #' -#' ## Add SNV information to the Reference GDS -#' RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, +#' ## Add SNV information to the Reference GDS +#' RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, #' verbose=FALSE) #' -#' ## Add genotype information to the Reference GDS for the 3 first samples -#' RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, +#' ## Add genotype information to the Reference GDS for the 3 first samples +#' RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, #' fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS[1:3], #' verbose=FALSE) #' -#' ## Append genotype information to the Reference GDS for the other samples -#' RAIDS:::appendGDSgenotype(gds=newGDS, pathGeno=dataDir, +#' ## Append genotype information to the Reference GDS for the other samples +#' RAIDS:::appendGDSgenotype(gds=newGDS, pathGeno=dataDir, #' fileSNPsRDS=snpIndexFile, #' listSample=listSampleGDS[4:length(listSampleGDS)], #' verbose=FALSE) #' -#' ## Close file -#' closefn.gds(newGDS) +#' ## Close file +#' closefn.gds(newGDS) #' -#' ## Remove temporary files -#' unlink(tempRefGDS, force=TRUE) -#' } +#' ## Remove temporary files +#' unlink(tempRefGDS, force=TRUE) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn diff --git a/man/appendGDSgenotype.Rd b/man/appendGDSgenotype.Rd index bef183169..6a6f1d22b 100644 --- a/man/appendGDSgenotype.Rd +++ b/man/appendGDSgenotype.Rd @@ -55,43 +55,39 @@ snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") ## Temporary Reference GDS file -tempRefGDS <- file.path(getwd(), "Ref_TEMP02.gds") +tempRefGDS <- file.path(tempdir(), "Ref_TEMP02.gds") -## Only run example if the directory is writable -if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { +## Create temporary Reference GDS file +newGDS <- createfn.gds(tempRefGDS) +put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") - ## Create temporary Reference GDS file - newGDS <- createfn.gds(tempRefGDS) - put.attr.gdsn(newGDS$root, "FileFormat", "SNP_ARRAY") +## Read the pedigree file +ped1KG <- readRDS(pedigreeFile) - ## Read the pedigree file - ped1KG <- readRDS(pedigreeFile) - - ## Add information about samples to the Reference GDS file - listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, +## Add information about samples to the Reference GDS file +listSampleGDS <- RAIDS:::generateGDSRefSample(gdsReference=newGDS, dfPedReference=ped1KG, listSamples=NULL) - ## Add SNV information to the Reference GDS - RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, +## Add SNV information to the Reference GDS +RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, verbose=FALSE) - ## Add genotype information to the Reference GDS for the 3 first samples - RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, +## Add genotype information to the Reference GDS for the 3 first samples +RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS[1:3], verbose=FALSE) - ## Append genotype information to the Reference GDS for the other samples - RAIDS:::appendGDSgenotype(gds=newGDS, pathGeno=dataDir, +## Append genotype information to the Reference GDS for the other samples +RAIDS:::appendGDSgenotype(gds=newGDS, pathGeno=dataDir, fileSNPsRDS=snpIndexFile, listSample=listSampleGDS[4:length(listSampleGDS)], verbose=FALSE) - ## Close file - closefn.gds(newGDS) +## Close file +closefn.gds(newGDS) - ## Remove temporary files - unlink(tempRefGDS, force=TRUE) -} +## Remove temporary files +unlink(tempRefGDS, force=TRUE) } \author{ diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index fc05dbb3e..16f2e09aa 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -118,54 +118,50 @@ dataDir <- system.file("extdata/tests", package="RAIDS") fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") ## Profile GDS file for one profile -fileProfile <- file.path("ex1.gds") +fileProfile <- file.path(tempdir(), "ex1.gds") -## Example can only be run if the current directory is in writing mode -if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { - - ## Copy the Profile GDS file demo that has been pruned and annotated - ## into current directory - file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +## Copy the Profile GDS file demo that has been pruned and annotated +## into current directory +file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), fileProfile) - ## Open the reference GDS file (demo version) - gds1KG <- snpgdsOpen(fileGDS) +## Open the reference GDS file (demo version) +gds1KG <- snpgdsOpen(fileGDS) - ## Profile GDS file for one profile - profileGDS <- openfn.gds(fileProfile, readonly=FALSE) +## Profile GDS file for one profile +profileGDS <- openfn.gds(fileProfile, readonly=FALSE) - ## Chromosome length information - ## chr23 is chrX, chr24 is chrY and chrM is 25 - chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, +## Chromosome length information +## chr23 is chrX, chr24 is chrY and chrM is 25 +chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) - ## A formal way to get the chormosome length information - ## library(GenomeInfoDb) - ## library(BSgenome.Hsapiens.UCSC.hg38) - ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] +## A formal way to get the chormosome length information +## library(GenomeInfoDb) +## library(BSgenome.Hsapiens.UCSC.hg38) +## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] - ## Estimate the allelic fraction of the pruned SNVs - estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, +## Estimate the allelic fraction of the pruned SNVs +estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, studyType="DNA", minCov=10L, minProb=0.999, eProb=0.001, cutOffLOH=-5, cutOffHomoScore=-3, wAR=9, cutOffAR=3, gdsRefAnnot=NULL, blockID=NULL) - ## The allelic fraction is saved in the 'lap' node of Profile GDS file - ## The 'lap' entry should be present - profileGDS +## The allelic fraction is saved in the 'lap' node of Profile GDS file +## The 'lap' entry should be present +profileGDS - ## Close both GDS files (important) - closefn.gds(profileGDS) - closefn.gds(gds1KG) +## Close both GDS files (important) +closefn.gds(profileGDS) +closefn.gds(gds1KG) - ## Remove Profile GDS file (created for demo purpose) - unlink(fileProfile, force=TRUE) +## Remove Profile GDS file (created for demo purpose) +unlink(fileProfile, force=TRUE) -} } \author{ From 5f024f9ea2c849c8cac505533299e39c1d9aa449 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 30 Aug 2023 12:58:10 -0400 Subject: [PATCH 191/385] Changing getwd() to tempdir() in some examples. --- R/gdsWrapper_internal.R | 316 +++++++++------------ R/processStudy_internal.R | 45 ++- R/synthetic.R | 40 ++- man/addGDSStudyPruning.Rd | 30 +- man/addStudyGDSSample.Rd | 42 ++- man/addUpdateLap.Rd | 36 ++- man/addUpdateSegment.Rd | 30 +- man/appendGDSRefSample.Rd | 52 ++-- man/appendGDSSampleOnly.Rd | 34 +-- man/appendGDSgenotypeMat.Rd | 42 ++- man/generateGDS1KGgenotypeFromSNPPileup.Rd | 50 ++-- man/prepSynthetic.Rd | 40 ++- man/runProfileAncestry.Rd | 31 +- man/runWrapperAncestry.Rd | 14 +- 14 files changed, 362 insertions(+), 440 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 3f7632ce8..f7c8932af 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -196,38 +196,34 @@ addGDSRef <- function(gdsReference, filePart) { #' library(gdsfmt) #' #' ## Create a temporary GDS file -#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_06.gds") +#' gdsFilePath <- file.path(tempdir(), "GDS_TEMP_06.gds") #' -#' ## Run only if directory in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -#' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) #' -#' ## Create a "genotype" node with initial matrix -#' genoInitial <- matrix(rep(0L, 10), nrow=2) +#' ## Create a "genotype" node with initial matrix +#' genoInitial <- matrix(rep(0L, 10), nrow=2) #' -#' add.gdsn(node=tmpGDS, name="genotype", val=genoInitial) -#' sync.gds(tmpGDS) +#' add.gdsn(node=tmpGDS, name="genotype", val=genoInitial) +#' sync.gds(tmpGDS) #' -#' ## New genotype information to be added -#' newGenotype <- matrix(rep(1L, 6), nrow=2) +#' ## New genotype information to be added +#' newGenotype <- matrix(rep(1L, 6), nrow=2) #' -#' ## Add segments to the GDS file -#' RAIDS:::appendGDSgenotypeMat(gds=tmpGDS, matG=newGenotype) +#' ## Add segments to the GDS file +#' RAIDS:::appendGDSgenotypeMat(gds=tmpGDS, matG=newGenotype) #' -#' ## Read genotype information from GDS file -#' ## The return matrix should be a combination of both initial matrix -#' ## and new matrix (column binded) -#' read.gdsn(index.gdsn(node=tmpGDS, path="genotype")) +#' ## Read genotype information from GDS file +#' ## The return matrix should be a combination of both initial matrix +#' ## and new matrix (column binded) +#' read.gdsn(index.gdsn(node=tmpGDS, path="genotype")) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn @@ -313,57 +309,53 @@ appendGDSgenotypeMat <- function(gds, matG) { #' @examples #' #' ## Current directory -#' dataDir <- file.path(getwd()) +#' dataDir <- file.path(tempdir()) #' -#' ## Run only if directory in writing mode -#' if (file.access(dataDir) == 0) { -#' -#' ## Copy required file into current directory -#' file.copy(from=file.path(system.file("extdata/tests", package="RAIDS"), +#' ## Copy required file into current directory +#' file.copy(from=file.path(system.file("extdata/tests", package="RAIDS"), #' "ex1.txt.gz"), to=dataDir) #' -#' ## The data.frame containing the information about the study -#' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" -#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) -#' studyDF <- data.frame(study.id = "MYDATA", +#' ## The data.frame containing the information about the study +#' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" +#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) +#' studyDF <- data.frame(study.id = "MYDATA", #' study.desc = "Description", #' study.platform = "PLATFORM", #' stringsAsFactors = FALSE) #' -#' ## The data.frame containing the information about the samples -#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) -#' samplePED <- data.frame(Name.ID=c("ex1", "ex2"), +#' ## The data.frame containing the information about the samples +#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) +#' samplePED <- data.frame(Name.ID=c("ex1", "ex2"), #' Case.ID=c("Patient_h11", "Patient_h12"), #' Diagnosis=rep("Cancer", 2), #' Sample.Type=rep("Primary Tumor", 2), #' Source=rep("Databank B", 2), stringsAsFactors=FALSE) -#' rownames(samplePED) <- samplePED$Name.ID +#' rownames(samplePED) <- samplePED$Name.ID #' -#' ## List of SNV positions -#' listPositions <- data.frame(snp.chromosome=c(rep(1, 10)), +#' ## List of SNV positions +#' listPositions <- data.frame(snp.chromosome=c(rep(1, 10)), #' snp.position=c(3467333, 3467428, 3469375, 3469387, 3469502, 3469527, #' 3469737, 3471497, 3471565, 3471618)) #' -#' ## Append genotype information to the Profile GDS file -#' result <- RAIDS:::generateGDS1KGgenotypeFromSNPPileup(pathGeno=dataDir, +#' ## Append genotype information to the Profile GDS file +#' result <- RAIDS:::generateGDS1KGgenotypeFromSNPPileup(pathGeno=dataDir, #' listSamples=c("ex1"), listPos=listPositions, #' offset=-1, minCov=10, minProb=0.999, seqError=0.001, #' dfPedProfile=samplePED, batch=1, studyDF=studyDF, #' pathProfileGDS=dataDir, genoSource="snp-pileup", #' verbose=FALSE) #' -#' ## The function returns OL when successful -#' result +#' ## The function returns OL when successful +#' result #' -#' ## The Profile GDS file 'ex1.gds' has been created in the -#' ## specified directory -#' list.files(dataDir) +#' ## The Profile GDS file 'ex1.gds' has been created in the +#' ## specified directory +#' list.files(dataDir) #' -#' ## Unlink Profile GDS file (created for demo purpose) -#' unlink(file.path(dataDir, "ex1.gds")) -#' unlink(file.path(dataDir, "ex1.txt.gz")) +#' ## Unlink Profile GDS file (created for demo purpose) +#' unlink(file.path(dataDir, "ex1.gds")) +#' unlink(file.path(dataDir, "ex1.txt.gz")) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn write.gdsn openfn.gds @@ -589,45 +581,41 @@ generateGDS1KGgenotypeFromSNPPileup <- function(pathGeno, #' library(gdsfmt) #' #' ## Create a temporary GDS file in an current directory -#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") -#' -#' ## Run only if directory in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +#' gdsFilePath <- file.path(tempdir(), "GDS_TEMP_11.gds") #' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) #' -#' ## Create a PED data frame with sample information -#' ped1KG <- data.frame(Name.ID=c("1KG_sample_01", "1KG_sample_02"), +#' ## Create a PED data frame with sample information +#' ped1KG <- data.frame(Name.ID=c("1KG_sample_01", "1KG_sample_02"), #' Case.ID=c("1KG_sample_01", "1KG_sample_02"), #' Sample.Type=rep("Reference", 2), Diagnosis=rep("Reference", 2), #' Source=rep("IGSR", 2), stringsAsFactors=FALSE) #' -#' ## Create a Study data frame with information about the study -#' ## All samples are associated to the same study -#' studyInfo <- data.frame(study.id="Ref.1KG", +#' ## Create a Study data frame with information about the study +#' ## All samples are associated to the same study +#' studyInfo <- data.frame(study.id="Ref.1KG", #' study.desc="Unrelated samples from 1000 Genomes", #' study.platform="GRCh38 1000 genotypes", #' stringsAsFactors=FALSE) #' -#' ## Add the sample information to the GDS Sample file -#' ## The information for all samples is added (listSamples=NULL) -#' RAIDS:::addStudyGDSSample(gdsProfile=tmpGDS, pedProfile=ped1KG, batch=1, +#' ## Add the sample information to the GDS Sample file +#' ## The information for all samples is added (listSamples=NULL) +#' RAIDS:::addStudyGDSSample(gdsProfile=tmpGDS, pedProfile=ped1KG, batch=1, #' listSamples=NULL, studyDF=studyInfo, verbose=FALSE) #' -#' ## Read study information from GDS Sample file -#' read.gdsn(index.gdsn(node=tmpGDS, path="study.list")) +#' ## Read study information from GDS Sample file +#' read.gdsn(index.gdsn(node=tmpGDS, path="study.list")) #' -#' ## Read sample information from GDS Sample file -#' read.gdsn(index.gdsn(node=tmpGDS, path="study.annot")) +#' ## Read sample information from GDS Sample file +#' read.gdsn(index.gdsn(node=tmpGDS, path="study.annot")) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn append.gdsn @@ -915,20 +903,17 @@ runLDPruning <- function(gds, method, #' library(gdsfmt) #' #' ## Create a temporary GDS file in an test directory -#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_03.gds") -#' -#' ## Only run if directory is in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +#' gdsFilePath <- file.path(tempdir(), "GDS_TEMP_03.gds") #' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) #' -#' ## Create "sample.id" node (the node must be present) -#' add.gdsn(node=tmpGDS, name="sample.id", val=c("sample_01", +#' ## Create "sample.id" node (the node must be present) +#' add.gdsn(node=tmpGDS, name="sample.id", val=c("sample_01", #' "sample_02")) #' -#' ## Create "sample.annot" node (the node must be present) -#' add.gdsn(node=tmpGDS, name="sample.annot", val=data.frame( +#' ## Create "sample.annot" node (the node must be present) +#' add.gdsn(node=tmpGDS, name="sample.annot", val=data.frame( #' Name.ID=c("sample_01", "sample_02"), #' sex=c(1,1), # 1:Male 2: Female #' pop.group=c("ACB", "ACB"), @@ -936,39 +921,38 @@ runLDPruning <- function(gds, method, #' batch=c(1, 1), #' stringsAsFactors=FALSE)) #' -#' sync.gds(gdsfile=tmpGDS) +#' sync.gds(gdsfile=tmpGDS) #' -#' ## Create a data.frame with information about samples -#' sample_info <- data.frame(Name.ID=c("sample_04", "sample_05", +#' ## Create a data.frame with information about samples +#' sample_info <- data.frame(Name.ID=c("sample_04", "sample_05", #' "sample_06"), #' sex=c(1,2,1), # 1:Male 2: Female #' pop.group=c("ACB", "ACB", "ACB"), #' superPop=c("AFR", "AFR", "AFR"), #' stringsAsFactors=FALSE) #' -#' ## The row names must be the sample identifiers -#' rownames(sample_info) <- sample_info$Name.ID +#' ## The row names must be the sample identifiers +#' rownames(sample_info) <- sample_info$Name.ID #' -#' ## Add information about 2 samples to the GDS file -#' RAIDS:::appendGDSRefSample(gdsReference=tmpGDS, +#' ## Add information about 2 samples to the GDS file +#' RAIDS:::appendGDSRefSample(gdsReference=tmpGDS, #' dfPedReference=sample_info, #' batch=2, listSamples=c("sample_04", "sample_06"), verbose=FALSE) #' -#' ## Read sample identifier list -#' ## Only "sample_04" and "sample_06" should have been added -#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) +#' ## Read sample identifier list +#' ## Only "sample_04" and "sample_06" should have been added +#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) #' -#' ## Read sample information from GDS file -#' ## Only "sample_04" and "sample_06" should have been added -#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) +#' ## Read sample information from GDS file +#' ## Only "sample_04" and "sample_06" should have been added +#' read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn append.gdsn @@ -1033,30 +1017,26 @@ appendGDSRefSample <- function(gdsReference, dfPedReference, batch=1, #' library(gdsfmt) #' #' ## Create a temporary GDS file in an test directory -#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_1.gds") +#' gdsFilePath <- file.path(tempdir(), "GDS_TEMP_1.gds") #' -#' ## Only run if directory is in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -#' -#' ## Create and open the GDS file -#' tmpGDS <- createfn.gds(filename=gdsFilePath) +#' ## Create and open the GDS file +#' tmpGDS <- createfn.gds(filename=gdsFilePath) #' -#' ## Vector of low allelic fraction -#' study <- c("s19222", 's19588', 's19988', 's20588', 's23598') +#' ## Vector of low allelic fraction +#' study <- c("s19222", 's19588', 's19988', 's20588', 's23598') #' -#' ## Add segments to the GDS file -#' RAIDS:::addGDSStudyPruning(gdsProfile=tmpGDS, pruned=study) +#' ## Add segments to the GDS file +#' RAIDS:::addGDSStudyPruning(gdsProfile=tmpGDS, pruned=study) #' -#' ## Read lap information from GDS file -#' read.gdsn(index.gdsn(node=tmpGDS, path="pruned.study")) +#' ## Read lap information from GDS file +#' read.gdsn(index.gdsn(node=tmpGDS, path="pruned.study")) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=tmpGDS) +#' ## Close GDS file +#' closefn.gds(gdsfile=tmpGDS) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn index.gdsn delete.gdsn sync.gds ls.gdsn @@ -1105,34 +1085,30 @@ addGDSStudyPruning <- function(gdsProfile, pruned) { #' library(gdsfmt) #' #' ## Create a temporary GDS file -#' gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") +#' gdsFilePath <- file.path(tempdir(), "GDS_TEMP.gds") #' -#' ## Only run if directory is in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -#' -#' ## Create and open the GDS file -#' gdsFile <- createfn.gds(filename=gdsFilePath) +#' ## Create and open the GDS file +#' gdsFile <- createfn.gds(filename=gdsFilePath) #' -#' ## Create a "lap" node -#' add.gdsn(node=gdsFile, name="lap", val=rep(10L, 12)) -#' sync.gds(gdsFile) +#' ## Create a "lap" node +#' add.gdsn(node=gdsFile, name="lap", val=rep(10L, 12)) +#' sync.gds(gdsFile) #' -#' ## Vector of low allelic fraction -#' lap <- c(0.1, 0.23, 0.34, 0.00, 0.12, 0.11, 0.33, 0.55) +#' ## Vector of low allelic fraction +#' lap <- c(0.1, 0.23, 0.34, 0.00, 0.12, 0.11, 0.33, 0.55) #' -#' ## Add segments to the GDS file -#' RAIDS:::addUpdateLap(gdsProfile=gdsFile, snpLap=lap) +#' ## Add segments to the GDS file +#' RAIDS:::addUpdateLap(gdsProfile=gdsFile, snpLap=lap) #' -#' ## Read lap information from GDS file -#' read.gdsn(index.gdsn(node=gdsFile, path="lap")) +#' ## Read lap information from GDS file +#' read.gdsn(index.gdsn(node=gdsFile, path="lap")) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=gdsFile) +#' ## Close GDS file +#' closefn.gds(gdsfile=gdsFile) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn index.gdsn delete.gdsn sync.gds ls.gdsn @@ -1237,30 +1213,26 @@ getBlockIDs <- function(gdsRefAnnot, snpIndex, blockTypeID) { #' library(gdsfmt) #' #' ## Temporary GDS file -#' gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") +#' gdsFilePath <- file.path(tempdir(), "GDS_TEMP.gds") #' -#' ## Only run if directory is in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -#' -#' ## Create and open the GDS file -#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) +#' ## Create and open the GDS file +#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) #' -#' ## Vector of segment identifiers -#' segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L) +#' ## Vector of segment identifiers +#' segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L) #' -#' ## Add segments to the GDS file -#' RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) +#' ## Add segments to the GDS file +#' RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) #' -#' ## Read segments information from GDS file -#' read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) +#' ## Read segments information from GDS file +#' read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=GDS_file_tmp) +#' ## Close GDS file +#' closefn.gds(gdsfile=GDS_file_tmp) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt add.gdsn index.gdsn delete.gdsn sync.gds ls.gdsn @@ -1301,35 +1273,31 @@ addUpdateSegment <- function(gdsProfile, snpSeg) { #' library(gdsfmt) #' #' ## Temporary GDS file in current directory -#' gdsFilePath <- file.path(getwd(), "GDS_TEMP_04.gds") +#' gdsFilePath <- file.path(tempdir(), "GDS_TEMP_04.gds") #' -#' ## Run only if directory in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { -#' -#' ## Create and open the GDS file -#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) +#' ## Create and open the GDS file +#' GDS_file_tmp <- createfn.gds(filename=gdsFilePath) #' -#' ## Create "sample.id" node (the node must be present) -#' add.gdsn(node=GDS_file_tmp, name="sample.id", val=c("sample_01", +#' ## Create "sample.id" node (the node must be present) +#' add.gdsn(node=GDS_file_tmp, name="sample.id", val=c("sample_01", #' "sample_02")) #' -#' sync.gds(gdsfile=GDS_file_tmp) +#' sync.gds(gdsfile=GDS_file_tmp) #' -#' ## Add information about 2 samples to the GDS file -#' RAIDS:::appendGDSSampleOnly(gds=GDS_file_tmp, +#' ## Add information about 2 samples to the GDS file +#' RAIDS:::appendGDSSampleOnly(gds=GDS_file_tmp, #' listSamples=c("sample_03", "sample_04")) #' -#' ## Read sample identifier list -#' ## Only "sample_03" and "sample_04" should have been added -#' read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.id")) +#' ## Read sample identifier list +#' ## Only "sample_03" and "sample_04" should have been added +#' read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.id")) #' -#' ## Close GDS file -#' closefn.gds(gdsfile=GDS_file_tmp) +#' ## Close GDS file +#' closefn.gds(gdsfile=GDS_file_tmp) #' -#' ## Delete the temporary GDS file -#' unlink(x=gdsFilePath, force=TRUE) +#' ## Delete the temporary GDS file +#' unlink(x=gdsFilePath, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn append.gdsn diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 413873877..fe4f72f6f 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2056,9 +2056,9 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' ## will be created need to be specified. #' ################################################################# #' -#' pathProfileGDS <- file.path(getwd(), "outTest.tmp") +#' pathProfileGDS <- file.path(tempdir(), "outTest.tmp") #' -#' pathOut <- file.path(getwd(), "resTest.out") +#' pathOut <- file.path(tempdir(), "resTest.out") #' #' ################################################################# #' ## A data frame containing general information about the study @@ -2092,6 +2092,8 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' ## library(BSgenome.Hsapiens.UCSC.hg38) #' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' +#' +#' #' studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), #' study.desc=paste0(studyDF$study.id, " synthetic data"), #' study.platform=studyDF$study.platform, stringsAsFactors=FALSE) @@ -2100,17 +2102,14 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' profileFile <- file.path(pathProfileGDS, "ex1.gds") #' #' \dontrun{ -#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && -#' !file.exists(pathOut)) { -#' -#' dir.create(pathProfileGDS) -#' dir.create(pathOut) -#' file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) +#' dir.create(pathProfileGDS) +#' dir.create(pathOut) +#' file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) #' -#' gdsReference <- snpgdsOpen(fileReferenceGDS) -#' gdsRefAnnot <- openfn.gds(fileAnnotGDS) +#' gdsReference <- snpgdsOpen(fileReferenceGDS) +#' gdsRefAnnot <- openfn.gds(fileAnnotGDS) #' -#' RAIDS:::runProfileAncestry(gdsReference=gdsReference, +#' RAIDS:::runProfileAncestry(gdsReference=gdsReference, #' gdsRefAnnot=gdsRefAnnot, #' studyDF=studyDF, currentProfile=ped[1,"Name.ID"], #' pathProfileGDS=pathProfileGDS, @@ -2121,12 +2120,12 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' listProfileRef=listProfileRef, #' studyType="DNA") #' -#' closefn.gds(gdsReference) -#' closefn.gds(gdsRefAnnot) +#' closefn.gds(gdsReference) +#' closefn.gds(gdsRefAnnot) +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) #' -#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) -#' } #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz @@ -2369,9 +2368,9 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' ## The path where the Profile GDS Files (one per sample) #' ## will be created need to be specified. #' ################################################################# -#' pathProfileGDS <- file.path(getwd(), "out.tmp") +#' pathProfileGDS <- file.path(tempdir(), "out.tmp") #' -#' pathOut <- file.path(getwd(), "res.out") +#' pathOut <- file.path(tempdir(), "res.out") #' #' ################################################################# #' ## A data frame containing general information about the study @@ -2406,10 +2405,8 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' #' \dontrun{ -#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && -#' !file.exists(pathOut)) { #' -#' RAIDS:::runWrapperAncestry(pedStudy=ped, studyDF=studyDF, +#' RAIDS:::runWrapperAncestry(pedStudy=ped, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, #' pathGeno=pathGeno, #' pathOut=pathOut, @@ -2420,9 +2417,9 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' studyType="DNA", #' genoSource="snp-pileup") #' -#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) -#' } +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/R/synthetic.R b/R/synthetic.R index 1aa879e27..0d8f752e1 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -224,43 +224,39 @@ splitSelectByPop <- function(dataRef) { #' dataDir <- system.file("extdata/tests", package="RAIDS") #' #' ## Temporary Profile GDS file -#' fileNameGDS <- file.path(getwd(), "ex1.gds") -#' -#' ## Only run example if the directory is writable -#' if (file.access(getwd()) == 0 && !file.exists(fileNameGDS)) { +#' fileNameGDS <- file.path(tempdir(), "ex1.gds") #' -#' ## Copy the Profile GDS file demo that has been pruned and annotated -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), #' fileNameGDS) #' -#' ## Information about the synthetic data set -#' syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", +#' ## Information about the synthetic data set +#' syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", #' study.desc="MYDATA synthetic data", study.platform="PLATFORM", #' stringsAsFactors=FALSE) #' -#' ## Add information related to the synthetic profiles into the Profile GDS -#' prepSynthetic(fileProfileGDS=fileNameGDS, +#' ## Add information related to the synthetic profiles into the Profile GDS +#' prepSynthetic(fileProfileGDS=fileNameGDS, #' listSampleRef=c("HG00243", "HG00150"), profileID="ex1", #' studyDF=syntheticStudyDF, nbSim=1L, prefix="synthetic", #' verbose=FALSE) #' -#' ## Open Profile GDS file -#' profileGDS <- openfn.gds(fileNameGDS) +#' ## Open Profile GDS file +#' profileGDS <- openfn.gds(fileNameGDS) #' -#' ## The synthetic profiles should be added in the 'study.annot' entry -#' tail(read.gdsn(index.gdsn(profileGDS, "study.annot"))) +#' ## The synthetic profiles should be added in the 'study.annot' entry +#' tail(read.gdsn(index.gdsn(profileGDS, "study.annot"))) #' -#' ## The synthetic study information should be added to -#' ## the 'study.list' entry -#' tail(read.gdsn(index.gdsn(profileGDS, "study.list"))) +#' ## The synthetic study information should be added to +#' ## the 'study.list' entry +#' tail(read.gdsn(index.gdsn(profileGDS, "study.list"))) #' -#' ## Close GDS file (important) -#' closefn.gds(profileGDS) +#' ## Close GDS file (important) +#' closefn.gds(profileGDS) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(fileNameGDS, force=TRUE) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileNameGDS, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn diff --git a/man/addGDSStudyPruning.Rd b/man/addGDSStudyPruning.Rd index 28a560e3b..e00bd666c 100644 --- a/man/addGDSStudyPruning.Rd +++ b/man/addGDSStudyPruning.Rd @@ -30,30 +30,26 @@ deleted and a new entry is created. library(gdsfmt) ## Create a temporary GDS file in an test directory -gdsFilePath <- file.path(getwd(), "GDS_TEMP_1.gds") +gdsFilePath <- file.path(tempdir(), "GDS_TEMP_1.gds") -## Only run if directory is in writing mode -if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +## Create and open the GDS file +tmpGDS <- createfn.gds(filename=gdsFilePath) - ## Create and open the GDS file - tmpGDS <- createfn.gds(filename=gdsFilePath) +## Vector of low allelic fraction +study <- c("s19222", 's19588', 's19988', 's20588', 's23598') - ## Vector of low allelic fraction - study <- c("s19222", 's19588', 's19988', 's20588', 's23598') +## Add segments to the GDS file +RAIDS:::addGDSStudyPruning(gdsProfile=tmpGDS, pruned=study) - ## Add segments to the GDS file - RAIDS:::addGDSStudyPruning(gdsProfile=tmpGDS, pruned=study) +## Read lap information from GDS file +read.gdsn(index.gdsn(node=tmpGDS, path="pruned.study")) - ## Read lap information from GDS file - read.gdsn(index.gdsn(node=tmpGDS, path="pruned.study")) +## Close GDS file +closefn.gds(gdsfile=tmpGDS) - ## Close GDS file - closefn.gds(gdsfile=tmpGDS) +## Delete the temporary GDS file +unlink(x=gdsFilePath, force=TRUE) - ## Delete the temporary GDS file - unlink(x=gdsFilePath, force=TRUE) - -} } \author{ diff --git a/man/addStudyGDSSample.Rd b/man/addStudyGDSSample.Rd index 69a27c4ff..332227c4e 100644 --- a/man/addStudyGDSSample.Rd +++ b/man/addStudyGDSSample.Rd @@ -55,45 +55,41 @@ created and then, the information is added. library(gdsfmt) ## Create a temporary GDS file in an current directory -gdsFilePath <- file.path(getwd(), "GDS_TEMP_11.gds") +gdsFilePath <- file.path(tempdir(), "GDS_TEMP_11.gds") -## Run only if directory in writing mode -if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +## Create and open the GDS file +tmpGDS <- createfn.gds(filename=gdsFilePath) - ## Create and open the GDS file - tmpGDS <- createfn.gds(filename=gdsFilePath) - - ## Create a PED data frame with sample information - ped1KG <- data.frame(Name.ID=c("1KG_sample_01", "1KG_sample_02"), +## Create a PED data frame with sample information +ped1KG <- data.frame(Name.ID=c("1KG_sample_01", "1KG_sample_02"), Case.ID=c("1KG_sample_01", "1KG_sample_02"), Sample.Type=rep("Reference", 2), Diagnosis=rep("Reference", 2), Source=rep("IGSR", 2), stringsAsFactors=FALSE) - ## Create a Study data frame with information about the study - ## All samples are associated to the same study - studyInfo <- data.frame(study.id="Ref.1KG", +## Create a Study data frame with information about the study +## All samples are associated to the same study +studyInfo <- data.frame(study.id="Ref.1KG", study.desc="Unrelated samples from 1000 Genomes", study.platform="GRCh38 1000 genotypes", stringsAsFactors=FALSE) - ## Add the sample information to the GDS Sample file - ## The information for all samples is added (listSamples=NULL) - RAIDS:::addStudyGDSSample(gdsProfile=tmpGDS, pedProfile=ped1KG, batch=1, +## Add the sample information to the GDS Sample file +## The information for all samples is added (listSamples=NULL) +RAIDS:::addStudyGDSSample(gdsProfile=tmpGDS, pedProfile=ped1KG, batch=1, listSamples=NULL, studyDF=studyInfo, verbose=FALSE) - ## Read study information from GDS Sample file - read.gdsn(index.gdsn(node=tmpGDS, path="study.list")) +## Read study information from GDS Sample file +read.gdsn(index.gdsn(node=tmpGDS, path="study.list")) - ## Read sample information from GDS Sample file - read.gdsn(index.gdsn(node=tmpGDS, path="study.annot")) +## Read sample information from GDS Sample file +read.gdsn(index.gdsn(node=tmpGDS, path="study.annot")) - ## Close GDS file - closefn.gds(gdsfile=tmpGDS) +## Close GDS file +closefn.gds(gdsfile=tmpGDS) - ## Delete the temporary GDS file - unlink(x=gdsFilePath, force=TRUE) +## Delete the temporary GDS file +unlink(x=gdsFilePath, force=TRUE) -} } \author{ diff --git a/man/addUpdateLap.Rd b/man/addUpdateLap.Rd index 470818371..2b1174af8 100644 --- a/man/addUpdateLap.Rd +++ b/man/addUpdateLap.Rd @@ -34,34 +34,30 @@ already be present in the GDS file. library(gdsfmt) ## Create a temporary GDS file -gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") +gdsFilePath <- file.path(tempdir(), "GDS_TEMP.gds") -## Only run if directory is in writing mode -if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +## Create and open the GDS file +gdsFile <- createfn.gds(filename=gdsFilePath) - ## Create and open the GDS file - gdsFile <- createfn.gds(filename=gdsFilePath) +## Create a "lap" node +add.gdsn(node=gdsFile, name="lap", val=rep(10L, 12)) +sync.gds(gdsFile) - ## Create a "lap" node - add.gdsn(node=gdsFile, name="lap", val=rep(10L, 12)) - sync.gds(gdsFile) +## Vector of low allelic fraction +lap <- c(0.1, 0.23, 0.34, 0.00, 0.12, 0.11, 0.33, 0.55) - ## Vector of low allelic fraction - lap <- c(0.1, 0.23, 0.34, 0.00, 0.12, 0.11, 0.33, 0.55) +## Add segments to the GDS file +RAIDS:::addUpdateLap(gdsProfile=gdsFile, snpLap=lap) - ## Add segments to the GDS file - RAIDS:::addUpdateLap(gdsProfile=gdsFile, snpLap=lap) +## Read lap information from GDS file +read.gdsn(index.gdsn(node=gdsFile, path="lap")) - ## Read lap information from GDS file - read.gdsn(index.gdsn(node=gdsFile, path="lap")) +## Close GDS file +closefn.gds(gdsfile=gdsFile) - ## Close GDS file - closefn.gds(gdsfile=gdsFile) +## Delete the temporary GDS file +unlink(x=gdsFilePath, force=TRUE) - ## Delete the temporary GDS file - unlink(x=gdsFilePath, force=TRUE) - -} } \author{ diff --git a/man/addUpdateSegment.Rd b/man/addUpdateSegment.Rd index 35df8d3ed..e9444fa79 100644 --- a/man/addUpdateSegment.Rd +++ b/man/addUpdateSegment.Rd @@ -32,30 +32,26 @@ already exists, the previous information is erased. library(gdsfmt) ## Temporary GDS file -gdsFilePath <- file.path(getwd(), "GDS_TEMP.gds") +gdsFilePath <- file.path(tempdir(), "GDS_TEMP.gds") -## Only run if directory is in writing mode -if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +## Create and open the GDS file +GDS_file_tmp <- createfn.gds(filename=gdsFilePath) - ## Create and open the GDS file - GDS_file_tmp <- createfn.gds(filename=gdsFilePath) +## Vector of segment identifiers +segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L) - ## Vector of segment identifiers - segments <- c(1L, 1L, 1L, 2L, 2L, 3L, 3L) +## Add segments to the GDS file +RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) - ## Add segments to the GDS file - RAIDS:::addUpdateSegment(gdsProfile=GDS_file_tmp, snpSeg=segments) +## Read segments information from GDS file +read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) - ## Read segments information from GDS file - read.gdsn(index.gdsn(node=GDS_file_tmp, path="segment")) +## Close GDS file +closefn.gds(gdsfile=GDS_file_tmp) - ## Close GDS file - closefn.gds(gdsfile=GDS_file_tmp) +## Delete the temporary GDS file +unlink(x=gdsFilePath, force=TRUE) - ## Delete the temporary GDS file - unlink(x=gdsFilePath, force=TRUE) - -} } \author{ diff --git a/man/appendGDSRefSample.Rd b/man/appendGDSRefSample.Rd index 78144dfa4..3791bb95e 100644 --- a/man/appendGDSRefSample.Rd +++ b/man/appendGDSRefSample.Rd @@ -49,20 +49,17 @@ addStudyGDSSample() must be used. library(gdsfmt) ## Create a temporary GDS file in an test directory -gdsFilePath <- file.path(getwd(), "GDS_TEMP_03.gds") +gdsFilePath <- file.path(tempdir(), "GDS_TEMP_03.gds") -## Only run if directory is in writing mode -if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +## Create and open the GDS file +tmpGDS <- createfn.gds(filename=gdsFilePath) - ## Create and open the GDS file - tmpGDS <- createfn.gds(filename=gdsFilePath) - - ## Create "sample.id" node (the node must be present) - add.gdsn(node=tmpGDS, name="sample.id", val=c("sample_01", +## Create "sample.id" node (the node must be present) +add.gdsn(node=tmpGDS, name="sample.id", val=c("sample_01", "sample_02")) - ## Create "sample.annot" node (the node must be present) - add.gdsn(node=tmpGDS, name="sample.annot", val=data.frame( +## Create "sample.annot" node (the node must be present) +add.gdsn(node=tmpGDS, name="sample.annot", val=data.frame( Name.ID=c("sample_01", "sample_02"), sex=c(1,1), # 1:Male 2: Female pop.group=c("ACB", "ACB"), @@ -70,39 +67,38 @@ if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { batch=c(1, 1), stringsAsFactors=FALSE)) - sync.gds(gdsfile=tmpGDS) +sync.gds(gdsfile=tmpGDS) - ## Create a data.frame with information about samples - sample_info <- data.frame(Name.ID=c("sample_04", "sample_05", +## Create a data.frame with information about samples +sample_info <- data.frame(Name.ID=c("sample_04", "sample_05", "sample_06"), sex=c(1,2,1), # 1:Male 2: Female pop.group=c("ACB", "ACB", "ACB"), superPop=c("AFR", "AFR", "AFR"), stringsAsFactors=FALSE) - ## The row names must be the sample identifiers - rownames(sample_info) <- sample_info$Name.ID +## The row names must be the sample identifiers +rownames(sample_info) <- sample_info$Name.ID - ## Add information about 2 samples to the GDS file - RAIDS:::appendGDSRefSample(gdsReference=tmpGDS, +## Add information about 2 samples to the GDS file +RAIDS:::appendGDSRefSample(gdsReference=tmpGDS, dfPedReference=sample_info, batch=2, listSamples=c("sample_04", "sample_06"), verbose=FALSE) - ## Read sample identifier list - ## Only "sample_04" and "sample_06" should have been added - read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) +## Read sample identifier list +## Only "sample_04" and "sample_06" should have been added +read.gdsn(index.gdsn(node=tmpGDS, path="sample.id")) - ## Read sample information from GDS file - ## Only "sample_04" and "sample_06" should have been added - read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) +## Read sample information from GDS file +## Only "sample_04" and "sample_06" should have been added +read.gdsn(index.gdsn(node=tmpGDS, path="sample.annot")) - ## Close GDS file - closefn.gds(gdsfile=tmpGDS) +## Close GDS file +closefn.gds(gdsfile=tmpGDS) - ## Delete the temporary GDS file - unlink(x=gdsFilePath, force=TRUE) +## Delete the temporary GDS file +unlink(x=gdsFilePath, force=TRUE) -} } \author{ diff --git a/man/appendGDSSampleOnly.Rd b/man/appendGDSSampleOnly.Rd index 6b2c0cdf2..34dc5a139 100644 --- a/man/appendGDSSampleOnly.Rd +++ b/man/appendGDSSampleOnly.Rd @@ -27,35 +27,31 @@ This function append the sample identifiers into the library(gdsfmt) ## Temporary GDS file in current directory -gdsFilePath <- file.path(getwd(), "GDS_TEMP_04.gds") +gdsFilePath <- file.path(tempdir(), "GDS_TEMP_04.gds") -## Run only if directory in writing mode -if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +## Create and open the GDS file +GDS_file_tmp <- createfn.gds(filename=gdsFilePath) - ## Create and open the GDS file - GDS_file_tmp <- createfn.gds(filename=gdsFilePath) - - ## Create "sample.id" node (the node must be present) - add.gdsn(node=GDS_file_tmp, name="sample.id", val=c("sample_01", +## Create "sample.id" node (the node must be present) +add.gdsn(node=GDS_file_tmp, name="sample.id", val=c("sample_01", "sample_02")) - sync.gds(gdsfile=GDS_file_tmp) +sync.gds(gdsfile=GDS_file_tmp) - ## Add information about 2 samples to the GDS file - RAIDS:::appendGDSSampleOnly(gds=GDS_file_tmp, +## Add information about 2 samples to the GDS file +RAIDS:::appendGDSSampleOnly(gds=GDS_file_tmp, listSamples=c("sample_03", "sample_04")) - ## Read sample identifier list - ## Only "sample_03" and "sample_04" should have been added - read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.id")) +## Read sample identifier list +## Only "sample_03" and "sample_04" should have been added +read.gdsn(index.gdsn(node=GDS_file_tmp, path="sample.id")) - ## Close GDS file - closefn.gds(gdsfile=GDS_file_tmp) +## Close GDS file +closefn.gds(gdsfile=GDS_file_tmp) - ## Delete the temporary GDS file - unlink(x=gdsFilePath, force=TRUE) +## Delete the temporary GDS file +unlink(x=gdsFilePath, force=TRUE) -} } \author{ diff --git a/man/appendGDSgenotypeMat.Rd b/man/appendGDSgenotypeMat.Rd index bb0265e6f..850edff77 100644 --- a/man/appendGDSgenotypeMat.Rd +++ b/man/appendGDSgenotypeMat.Rd @@ -37,38 +37,34 @@ correspond to the number of rows of the matrix present in the library(gdsfmt) ## Create a temporary GDS file -gdsFilePath <- file.path(getwd(), "GDS_TEMP_06.gds") +gdsFilePath <- file.path(tempdir(), "GDS_TEMP_06.gds") -## Run only if directory in writing mode -if (file.access(getwd()) == 0 && !dir.exists(gdsFilePath)) { +## Create and open the GDS file +tmpGDS <- createfn.gds(filename=gdsFilePath) - ## Create and open the GDS file - tmpGDS <- createfn.gds(filename=gdsFilePath) +## Create a "genotype" node with initial matrix +genoInitial <- matrix(rep(0L, 10), nrow=2) - ## Create a "genotype" node with initial matrix - genoInitial <- matrix(rep(0L, 10), nrow=2) +add.gdsn(node=tmpGDS, name="genotype", val=genoInitial) +sync.gds(tmpGDS) - add.gdsn(node=tmpGDS, name="genotype", val=genoInitial) - sync.gds(tmpGDS) +## New genotype information to be added +newGenotype <- matrix(rep(1L, 6), nrow=2) - ## New genotype information to be added - newGenotype <- matrix(rep(1L, 6), nrow=2) +## Add segments to the GDS file +RAIDS:::appendGDSgenotypeMat(gds=tmpGDS, matG=newGenotype) - ## Add segments to the GDS file - RAIDS:::appendGDSgenotypeMat(gds=tmpGDS, matG=newGenotype) +## Read genotype information from GDS file +## The return matrix should be a combination of both initial matrix +## and new matrix (column binded) +read.gdsn(index.gdsn(node=tmpGDS, path="genotype")) - ## Read genotype information from GDS file - ## The return matrix should be a combination of both initial matrix - ## and new matrix (column binded) - read.gdsn(index.gdsn(node=tmpGDS, path="genotype")) +## Close GDS file +closefn.gds(gdsfile=tmpGDS) - ## Close GDS file - closefn.gds(gdsfile=tmpGDS) +## Delete the temporary GDS file +unlink(x=gdsFilePath, force=TRUE) - ## Delete the temporary GDS file - unlink(x=gdsFilePath, force=TRUE) - -} } \author{ diff --git a/man/generateGDS1KGgenotypeFromSNPPileup.Rd b/man/generateGDS1KGgenotypeFromSNPPileup.Rd index f5c2ebe67..9053724b8 100644 --- a/man/generateGDS1KGgenotypeFromSNPPileup.Rd +++ b/man/generateGDS1KGgenotypeFromSNPPileup.Rd @@ -92,57 +92,53 @@ from a SNV file as generated by SNP-pileup or other tools. \examples{ ## Current directory -dataDir <- file.path(getwd()) +dataDir <- file.path(tempdir()) -## Run only if directory in writing mode -if (file.access(dataDir) == 0) { - - ## Copy required file into current directory - file.copy(from=file.path(system.file("extdata/tests", package="RAIDS"), +## Copy required file into current directory +file.copy(from=file.path(system.file("extdata/tests", package="RAIDS"), "ex1.txt.gz"), to=dataDir) - ## The data.frame containing the information about the study - ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" - ## The entries should be strings, not factors (stringsAsFactors=FALSE) - studyDF <- data.frame(study.id = "MYDATA", +## The data.frame containing the information about the study +## The 3 mandatory columns: "study.id", "study.desc", "study.platform" +## The entries should be strings, not factors (stringsAsFactors=FALSE) +studyDF <- data.frame(study.id = "MYDATA", study.desc = "Description", study.platform = "PLATFORM", stringsAsFactors = FALSE) - ## The data.frame containing the information about the samples - ## The entries should be strings, not factors (stringsAsFactors=FALSE) - samplePED <- data.frame(Name.ID=c("ex1", "ex2"), +## The data.frame containing the information about the samples +## The entries should be strings, not factors (stringsAsFactors=FALSE) +samplePED <- data.frame(Name.ID=c("ex1", "ex2"), Case.ID=c("Patient_h11", "Patient_h12"), Diagnosis=rep("Cancer", 2), Sample.Type=rep("Primary Tumor", 2), Source=rep("Databank B", 2), stringsAsFactors=FALSE) - rownames(samplePED) <- samplePED$Name.ID +rownames(samplePED) <- samplePED$Name.ID - ## List of SNV positions - listPositions <- data.frame(snp.chromosome=c(rep(1, 10)), +## List of SNV positions +listPositions <- data.frame(snp.chromosome=c(rep(1, 10)), snp.position=c(3467333, 3467428, 3469375, 3469387, 3469502, 3469527, 3469737, 3471497, 3471565, 3471618)) - ## Append genotype information to the Profile GDS file - result <- RAIDS:::generateGDS1KGgenotypeFromSNPPileup(pathGeno=dataDir, +## Append genotype information to the Profile GDS file +result <- RAIDS:::generateGDS1KGgenotypeFromSNPPileup(pathGeno=dataDir, listSamples=c("ex1"), listPos=listPositions, offset=-1, minCov=10, minProb=0.999, seqError=0.001, dfPedProfile=samplePED, batch=1, studyDF=studyDF, pathProfileGDS=dataDir, genoSource="snp-pileup", verbose=FALSE) - ## The function returns OL when successful - result +## The function returns OL when successful +result - ## The Profile GDS file 'ex1.gds' has been created in the - ## specified directory - list.files(dataDir) +## The Profile GDS file 'ex1.gds' has been created in the +## specified directory +list.files(dataDir) - ## Unlink Profile GDS file (created for demo purpose) - unlink(file.path(dataDir, "ex1.gds")) - unlink(file.path(dataDir, "ex1.txt.gz")) +## Unlink Profile GDS file (created for demo purpose) +unlink(file.path(dataDir, "ex1.gds")) +unlink(file.path(dataDir, "ex1.txt.gz")) -} } \author{ diff --git a/man/prepSynthetic.Rd b/man/prepSynthetic.Rd index f4a8b1b38..6a78b519e 100644 --- a/man/prepSynthetic.Rd +++ b/man/prepSynthetic.Rd @@ -74,43 +74,39 @@ library(gdsfmt) dataDir <- system.file("extdata/tests", package="RAIDS") ## Temporary Profile GDS file -fileNameGDS <- file.path(getwd(), "ex1.gds") +fileNameGDS <- file.path(tempdir(), "ex1.gds") -## Only run example if the directory is writable -if (file.access(getwd()) == 0 && !file.exists(fileNameGDS)) { - - ## Copy the Profile GDS file demo that has been pruned and annotated - file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +## Copy the Profile GDS file demo that has been pruned and annotated +file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), fileNameGDS) - ## Information about the synthetic data set - syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", +## Information about the synthetic data set +syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", study.desc="MYDATA synthetic data", study.platform="PLATFORM", stringsAsFactors=FALSE) - ## Add information related to the synthetic profiles into the Profile GDS - prepSynthetic(fileProfileGDS=fileNameGDS, +## Add information related to the synthetic profiles into the Profile GDS +prepSynthetic(fileProfileGDS=fileNameGDS, listSampleRef=c("HG00243", "HG00150"), profileID="ex1", studyDF=syntheticStudyDF, nbSim=1L, prefix="synthetic", verbose=FALSE) - ## Open Profile GDS file - profileGDS <- openfn.gds(fileNameGDS) +## Open Profile GDS file +profileGDS <- openfn.gds(fileNameGDS) - ## The synthetic profiles should be added in the 'study.annot' entry - tail(read.gdsn(index.gdsn(profileGDS, "study.annot"))) +## The synthetic profiles should be added in the 'study.annot' entry +tail(read.gdsn(index.gdsn(profileGDS, "study.annot"))) - ## The synthetic study information should be added to - ## the 'study.list' entry - tail(read.gdsn(index.gdsn(profileGDS, "study.list"))) +## The synthetic study information should be added to +## the 'study.list' entry +tail(read.gdsn(index.gdsn(profileGDS, "study.list"))) - ## Close GDS file (important) - closefn.gds(profileGDS) +## Close GDS file (important) +closefn.gds(profileGDS) - ## Remove Profile GDS file (created for demo purpose) - unlink(fileNameGDS, force=TRUE) +## Remove Profile GDS file (created for demo purpose) +unlink(fileNameGDS, force=TRUE) -} } \author{ diff --git a/man/runProfileAncestry.Rd b/man/runProfileAncestry.Rd index e14e1cc88..9735f26ef 100644 --- a/man/runProfileAncestry.Rd +++ b/man/runProfileAncestry.Rd @@ -148,9 +148,9 @@ pathGeno <- file.path(dataDir, "example", "snpPileup") ## will be created need to be specified. ################################################################# -pathProfileGDS <- file.path(getwd(), "outTest.tmp") +pathProfileGDS <- file.path(tempdir(), "outTest.tmp") -pathOut <- file.path(getwd(), "resTest.out") +pathOut <- file.path(tempdir(), "resTest.out") ################################################################# ## A data frame containing general information about the study @@ -184,6 +184,8 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## library(BSgenome.Hsapiens.UCSC.hg38) ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] + + studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), study.desc=paste0(studyDF$study.id, " synthetic data"), study.platform=studyDF$study.platform, stringsAsFactors=FALSE) @@ -192,17 +194,14 @@ listProfileRef <- dataRef$sample.id profileFile <- file.path(pathProfileGDS, "ex1.gds") \dontrun{ - if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && - !file.exists(pathOut)) { + dir.create(pathProfileGDS) + dir.create(pathOut) + file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) - dir.create(pathProfileGDS) - dir.create(pathOut) - file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) + gdsReference <- snpgdsOpen(fileReferenceGDS) + gdsRefAnnot <- openfn.gds(fileAnnotGDS) - gdsReference <- snpgdsOpen(fileReferenceGDS) - gdsRefAnnot <- openfn.gds(fileAnnotGDS) - - RAIDS:::runProfileAncestry(gdsReference=gdsReference, + RAIDS:::runProfileAncestry(gdsReference=gdsReference, gdsRefAnnot=gdsRefAnnot, studyDF=studyDF, currentProfile=ped[1,"Name.ID"], pathProfileGDS=pathProfileGDS, @@ -213,12 +212,12 @@ profileFile <- file.path(pathProfileGDS, "ex1.gds") listProfileRef=listProfileRef, studyType="DNA") - closefn.gds(gdsReference) - closefn.gds(gdsRefAnnot) + closefn.gds(gdsReference) + closefn.gds(gdsRefAnnot) + + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) - } } } diff --git a/man/runWrapperAncestry.Rd b/man/runWrapperAncestry.Rd index 36b2c861f..463465372 100644 --- a/man/runWrapperAncestry.Rd +++ b/man/runWrapperAncestry.Rd @@ -155,9 +155,9 @@ pathGeno <- file.path(dataDir, "example", "snpPileup") ## The path where the Profile GDS Files (one per sample) ## will be created need to be specified. ################################################################# -pathProfileGDS <- file.path(getwd(), "out.tmp") +pathProfileGDS <- file.path(tempdir(), "out.tmp") -pathOut <- file.path(getwd(), "res.out") +pathOut <- file.path(tempdir(), "res.out") ################################################################# ## A data frame containing general information about the study @@ -192,10 +192,8 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] \dontrun{ - if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && - !file.exists(pathOut)) { - RAIDS:::runWrapperAncestry(pedStudy=ped, studyDF=studyDF, + RAIDS:::runWrapperAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, @@ -206,9 +204,9 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, studyType="DNA", genoSource="snp-pileup") - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) - } + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + } } From 9360983b70a562029001843c5a24414a490cd9eb Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 30 Aug 2023 15:52:27 -0400 Subject: [PATCH 192/385] Changing getwd() to tempdir() in some examples. --- R/process1KG.R | 145 +++++++++++++-------------------- R/processStudy.R | 28 +++---- R/synthetic.R | 48 +++++------ man/addGeneBlockGDSRefAnnot.Rd | 46 ++++++----- man/generateGDS1KG.Rd | 32 ++------ man/generateMapSnvSel.Rd | 21 ++--- man/generatePhase1KG2GDS.Rd | 45 +++++----- man/runExomeAncestry.Rd | 14 ++-- man/runRNAAncestry.Rd | 14 ++-- man/syntheticGeno.Rd | 48 +++++------ 10 files changed, 183 insertions(+), 258 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index 13914982e..268fb3701 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -165,22 +165,17 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' ## Temporary output files #' ## The first file contains the indexes of the retained SNPs #' ## The second file contains the filtered SNP information -#' snpIndexFile <- file.path(getwd(), "listSNP_TEMP.rds") -#' filterSNVFile <- file.path(getwd(), "mapSNVSel_TEMP.rds") +#' snpIndexFile <- file.path(tempdir(), "listSNP_TEMP.rds") +#' filterSNVFile <- file.path(tempdir(), "mapSNVSel_TEMP.rds") #' -#' ## Run only if directory in writing mode -#' if (file.access(getwd()) == 0 && !file.exists(snpIndexFile) && -#' !file.exists(filterSNVFile)) { -#' -#' ## Create a data.frame containing the information of the retained -#' ## samples (samples with existing genotyping files) -#' generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, +#' ## Create a data.frame containing the information of the retained +#' ## samples (samples with existing genotyping files) +#' generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, #' fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) #' -#' ## Remove temporary files -#' unlink(snpIndexFile, force=TRUE) -#' unlink(filterSNVFile, force=TRUE) -#' } +#' ## Remove temporary files +#' unlink(snpIndexFile, force=TRUE) +#' unlink(filterSNVFile, force=TRUE) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom S4Vectors isSingleNumber @@ -289,38 +284,16 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { #' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' #' ## Temporary Reference GDS file -#' tempRefGDS <- file.path(getwd(), "1KG_TEMP.gds") -#' -#' ## Only run example if the directory is writable -#' if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { -#' -#' ## Different code depending of the withr package availability -#' if (requireNamespace("withr", quietly=TRUE)) { -#' -#' ## Temporary Reference GDS file -#' gdsFile <- withr::local_file(tempRefGDS) -#' -#' ## Create a temporary Reference GDS file containing -#' ## information from reference file -#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, -#' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, -#' fileNameGDS=gdsFile, listSamples=NULL) -#' -#' ## Remove temporary files -#' withr::deferred_run() -#' -#' } else { +#' tempRefGDS <- file.path(tempdir(), "1KG_TEMP.gds") #' -#' ## Create a temporary Reference GDS file -#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +#' ## Create a temporary Reference GDS file +#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, #' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, #' fileNameGDS=tempRefGDS, listSamples=NULL) #' -#' ## Remove temporary files -#' unlink(tempRefGDS, force=TRUE) +#' ## Remove temporary files +#' unlink(tempRefGDS, force=TRUE) #' -#' } -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @@ -410,44 +383,39 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") #' #' ## Temporary Reference GDS file containing reference information -#' fileReferenceGDS <- "1KG_TEMP_02.gds" -#' -#' ## Only run example if the directory is writable -#' if (file.access(getwd()) == 0 && !file.exists(fileReferenceGDS)) { +#' fileReferenceGDS <- file.path(tempdir(), "1KG_TEMP_02.gds") #' -#' ## Create a temporary Reference GDS file containing information from 1KG -#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +#' ## Create a temporary Reference GDS file containing information from 1KG +#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, #' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, #' fileNameGDS=fileReferenceGDS, listSamples=NULL) #' -#' ## Temporary Phase GDS file that will contain the 1KG Phase information -#' fileRefPhaseGDS <- "1KG_TEMP_Phase_02.gds" +#' ## Temporary Phase GDS file that will contain the 1KG Phase information +#' fileRefPhaseGDS <- file.path(tempdir(), "1KG_TEMP_Phase_02.gds") #' -#' ## Create Reference Phase GDS file -#' gdsPhase <- createfn.gds(fileRefPhaseGDS) +#' ## Create Reference Phase GDS file +#' gdsPhase <- createfn.gds(fileRefPhaseGDS) #' -#' ## Open Reference GDS file -#' gdsRef <- openfn.gds(fileReferenceGDS) +#' ## Open Reference GDS file +#' gdsRef <- openfn.gds(fileReferenceGDS) #' -#' ## Fill temporary Reference Phase GDS file -#' if (FALSE) { -#' generatePhase1KG2GDS(gdsReference=gdsRef, +#' ## Fill temporary Reference Phase GDS file +#' if (FALSE) { +#' generatePhase1KG2GDS(gdsReference=gdsRef, #' gdsReferencePhase=gdsPhase, #' pathGeno=dataDir, fileSNPsRDS=filterSNVFile, #' verbose=FALSE) -#' } -#' -#' ## Close Reference Phase information file -#' closefn.gds(gdsPhase) +#' } #' -#' ## Close Reference information file -#' closefn.gds(gdsRef) +#' ## Close Reference Phase information file +#' closefn.gds(gdsPhase) #' -#' ## Remove temporary files -#' unlink(fileReferenceGDS, force=TRUE) -#' unlink(fileRefPhaseGDS, force=TRUE) +#' ## Close Reference information file +#' closefn.gds(gdsRef) #' -#' } +#' ## Remove temporary files +#' unlink(fileReferenceGDS, force=TRUE) +#' unlink(fileRefPhaseGDS, force=TRUE) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn readmode.gdsn @@ -823,39 +791,42 @@ getRef1KGPop <- function(gdsReference, popName="superPop") { #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' +# ## Temporary file +#' fileAnnotGDS <- file.path(tempdir(), "ex1_good_small_1KG_Ann_GDS.gds") #' -#' fileAnnotGDS <- file.path(getwd(), "ex1_good_small_1KG_Annot_GDS.gds") #' ## Required library -#' if (file.access(getwd()) == 0 && !file.exists(fileAnnotGDS)) { +#' if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { #' -#' if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { +#' file.copy(file.path(dataDir, "tests", +#' "ex1_NoBlockGene.1KG_Annot_GDS.gds"), fileAnnotGDS) #' -#' file.copy(file.path(dataDir, "tests", "ex1_NoBlockGene.1KG_Annot_GDS.gds"), -#' fileAnnotGDS) -#' ## Making a "short cut" on the ensDb object -#' edb <- EnsDb.Hsapiens.v86::EnsDb.Hsapiens.v86 +#' ## Making a "short cut" on the ensDb object +#' edb <- EnsDb.Hsapiens.v86::EnsDb.Hsapiens.v86 #' -#' -#' ## Temporary Profile GDS file for one profile -#' fileReferenceGDS <- file.path(dataDir, "tests", +#' ## GDS Reference file +#' fileReferenceGDS <- file.path(dataDir, "tests", #' "ex1_good_small_1KG_GDS.gds") #' -#' ## Open the reference GDS file (demo version) -#' gds1KG <- snpgdsOpen(fileReferenceGDS) -#' +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileReferenceGDS) #' -#' ## The function -#' addGeneBlockGDSRefAnnot(gdsReference=gds1KG, +#' ## Append information associated to blocks +#' addGeneBlockGDSRefAnnot(gdsReference=gds1KG, #' gdsRefAnnotFile=fileAnnotGDS, #' ensDb=edb, #' suffixBlockName="EnsDb.Hsapiens.v86") -#' gdsAnnot1KG <- openfn.gds(fileAnnotGDS) -#' print(gdsAnnot1KG) -#' print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) -#' closefn.gds(gds1KG) -#' closefn.gds(gdsAnnot1KG) -#' unlink(fileAnnotGDS, force=TRUE) -#' } +#' +#' gdsAnnot1KG <- openfn.gds(fileAnnotGDS) +#' print(gdsAnnot1KG) +#' print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) +#' +#' ## Close GDS files +#' closefn.gds(gds1KG) +#' closefn.gds(gdsAnnot1KG) +#' +#' ## Remove temporary file +#' unlink(fileAnnotGDS, force=TRUE) +#' #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/R/processStudy.R b/R/processStudy.R index 135b484f0..03ff164e6 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -1995,9 +1995,9 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' ## The path where the Profile GDS Files (one per sample) #' ## will be created need to be specified. #' ################################################################# -#' pathProfileGDS <- file.path(getwd(), "out.tmp") +#' pathProfileGDS <- file.path(tempdir(), "out.tmp") #' -#' pathOut <- file.path(getwd(), "res.out") +#' pathOut <- file.path(tempdir(), "res.out") #' #' ################################################################# #' ## A data frame containing general information about the study @@ -2032,10 +2032,8 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' #' \dontrun{ -#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && -#' !file.exists(pathOut)) { #' -#' runExomeAncestry(pedStudy=ped, studyDF=studyDF, +#' runExomeAncestry(pedStudy=ped, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, #' pathGeno=pathGeno, #' pathOut=pathOut, @@ -2045,9 +2043,9 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' syntheticRefDF=dataRef, #' genoSource="snp-pileup") #' -#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) -#' } +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz @@ -2216,9 +2214,9 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ## The path where the Profile GDS Files (one per sample) #' ## will be created need to be specified. #' ################################################################# -#' pathProfileGDS <- file.path(getwd(), "out.tmp") +#' pathProfileGDS <- file.path(tempdir(), "out.tmp") #' -#' pathOut <- file.path(getwd(), "res.out") +#' pathOut <- file.path(tempdir(), "res.out") #' #' ################################################################# #' ## A data frame containing general information about the study @@ -2253,10 +2251,8 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] #' #' \dontrun{ -#' if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && -#' !file.exists(pathOut)) { #' -#' runRNAAncestry(pedStudy=ped, studyDF=studyDF, +#' runRNAAncestry(pedStudy=ped, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, #' pathGeno=pathGeno, #' pathOut=pathOut, @@ -2267,9 +2263,9 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' blockTypeID="GeneS.Ensembl.Hsapiens.v86", #' genoSource="snp-pileup") #' -#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) -#' } +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/R/synthetic.R b/R/synthetic.R index 0d8f752e1..1a2ae1d7b 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -381,54 +381,50 @@ prepSynthetic <- function(fileProfileGDS, listSampleRef, #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") #' -#' ## Profile GDS file -#' fileNameGDS <- file.path(getwd(), "ex1.gds") -#' -#' ## Only run example if the directory is writable -#' if (file.access(getwd()) == 0 && !file.exists(fileNameGDS)) { +#' ## Profile GDS file (temporary) +#' fileNameGDS <- file.path(tempdir(), "ex1.gds") #' -#' ## Copy the Profile GDS file demo that has been pruned and annotated -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +#' ## Copy the Profile GDS file demo that has been pruned and annotated +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), #' fileNameGDS) #' -#' ## Information about the synthetic data set -#' syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", +#' ## Information about the synthetic data set +#' syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", #' study.desc="MYDATA synthetic data", study.platform="PLATFORM", #' stringsAsFactors=FALSE) #' -#' ## Add information related to the synthetic profiles into the Profile GDS -#' prepSynthetic(fileProfileGDS=fileNameGDS, +#' ## Add information related to the synthetic profiles into the Profile GDS +#' prepSynthetic(fileProfileGDS=fileNameGDS, #' listSampleRef=c("HG00243", "HG00150"), profileID="ex1", #' studyDF=syntheticStudyDF, nbSim=1L, prefix="synthTest", #' verbose=FALSE) #' -#' ## The 1KG files -#' gds1KG <- snpgdsOpen(file.path(dataDir, +#' ## The 1KG files +#' gds1KG <- snpgdsOpen(file.path(dataDir, #' "ex1_good_small_1KG_GDS.gds")) -#' gds1KGAnnot <- openfn.gds(file.path(dataDir, +#' gds1KGAnnot <- openfn.gds(file.path(dataDir, #' "ex1_good_small_1KG_Annot_GDS.gds")) #' -#' ## Generate the synthetic profiles and add them into the Profile GDS -#' syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gds1KGAnnot, +#' ## Generate the synthetic profiles and add them into the Profile GDS +#' syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gds1KGAnnot, #' fileProfileGDS=fileNameGDS, profileID="ex1", #' listSampleRef=c("HG00243", "HG00150"), nbSim=1, #' prefix="synthTest", #' pRecomb=0.01, minProb=0.999, seqError=0.001) #' -#' ## Open Profile GDS file -#' profileGDS <- openfn.gds(fileNameGDS) +#' ## Open Profile GDS file +#' profileGDS <- openfn.gds(fileNameGDS) #' -#' tail(read.gdsn(index.gdsn(profileGDS, "sample.id"))) +#' tail(read.gdsn(index.gdsn(profileGDS, "sample.id"))) #' -#' ## Close GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) -#' closefn.gds(gds1KGAnnot) +#' ## Close GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) +#' closefn.gds(gds1KGAnnot) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(fileNameGDS, force=TRUE) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileNameGDS, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn diff --git a/man/addGeneBlockGDSRefAnnot.Rd b/man/addGeneBlockGDSRefAnnot.Rd index 829c60ba7..dcfb8f94a 100644 --- a/man/addGeneBlockGDSRefAnnot.Rd +++ b/man/addGeneBlockGDSRefAnnot.Rd @@ -50,39 +50,41 @@ library(SNPRelate) ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") +fileAnnotGDS <- file.path(tempdir(), "ex1_good_small_1KG_Ann_GDS.gds") -fileAnnotGDS <- file.path(getwd(), "ex1_good_small_1KG_Annot_GDS.gds") ## Required library -if (file.access(getwd()) == 0 && !file.exists(fileAnnotGDS)) { +if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { - if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { + file.copy(file.path(dataDir, "tests", + "ex1_NoBlockGene.1KG_Annot_GDS.gds"), fileAnnotGDS) - file.copy(file.path(dataDir, "tests", "ex1_NoBlockGene.1KG_Annot_GDS.gds"), - fileAnnotGDS) - ## Making a "short cut" on the ensDb object - edb <- EnsDb.Hsapiens.v86::EnsDb.Hsapiens.v86 + ## Making a "short cut" on the ensDb object + edb <- EnsDb.Hsapiens.v86::EnsDb.Hsapiens.v86 - - ## Temporary Profile GDS file for one profile - fileReferenceGDS <- file.path(dataDir, "tests", + ## GDS Reference file + fileReferenceGDS <- file.path(dataDir, "tests", "ex1_good_small_1KG_GDS.gds") - ## Open the reference GDS file (demo version) - gds1KG <- snpgdsOpen(fileReferenceGDS) - + ## Open the reference GDS file (demo version) + gds1KG <- snpgdsOpen(fileReferenceGDS) - ## The function - addGeneBlockGDSRefAnnot(gdsReference=gds1KG, + ## Append information associated to blocks + addGeneBlockGDSRefAnnot(gdsReference=gds1KG, gdsRefAnnotFile=fileAnnotGDS, ensDb=edb, suffixBlockName="EnsDb.Hsapiens.v86") - gdsAnnot1KG <- openfn.gds(fileAnnotGDS) - print(gdsAnnot1KG) - print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) - closefn.gds(gds1KG) - closefn.gds(gdsAnnot1KG) - unlink(fileAnnotGDS, force=TRUE) - } + + gdsAnnot1KG <- openfn.gds(fileAnnotGDS) + print(gdsAnnot1KG) + print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) + + ## Close GDS files + closefn.gds(gds1KG) + closefn.gds(gdsAnnot1KG) + + ## Remove temporary file + unlink(fileAnnotGDS, force=TRUE) + } } diff --git a/man/generateGDS1KG.Rd b/man/generateGDS1KG.Rd index c79a1a221..bae30bc35 100644 --- a/man/generateGDS1KG.Rd +++ b/man/generateGDS1KG.Rd @@ -77,38 +77,16 @@ snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") ## Temporary Reference GDS file -tempRefGDS <- file.path(getwd(), "1KG_TEMP.gds") +tempRefGDS <- file.path(tempdir(), "1KG_TEMP.gds") -## Only run example if the directory is writable -if (file.access(getwd()) == 0 && !file.exists(tempRefGDS)) { - - ## Different code depending of the withr package availability - if (requireNamespace("withr", quietly=TRUE)) { - - ## Temporary Reference GDS file - gdsFile <- withr::local_file(tempRefGDS) - - ## Create a temporary Reference GDS file containing - ## information from reference file - generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, - fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, - fileNameGDS=gdsFile, listSamples=NULL) - - ## Remove temporary files - withr::deferred_run() - - } else { - - ## Create a temporary Reference GDS file - generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +## Create a temporary Reference GDS file +generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, fileNameGDS=tempRefGDS, listSamples=NULL) - ## Remove temporary files - unlink(tempRefGDS, force=TRUE) +## Remove temporary files +unlink(tempRefGDS, force=TRUE) - } -} } \author{ diff --git a/man/generateMapSnvSel.Rd b/man/generateMapSnvSel.Rd index 8af9646d1..f18b05a89 100644 --- a/man/generateMapSnvSel.Rd +++ b/man/generateMapSnvSel.Rd @@ -66,22 +66,17 @@ snvFile <- file.path(dataDir, "matFreqSNV_Demo.txt.bz2") ## Temporary output files ## The first file contains the indexes of the retained SNPs ## The second file contains the filtered SNP information -snpIndexFile <- file.path(getwd(), "listSNP_TEMP.rds") -filterSNVFile <- file.path(getwd(), "mapSNVSel_TEMP.rds") +snpIndexFile <- file.path(tempdir(), "listSNP_TEMP.rds") +filterSNVFile <- file.path(tempdir(), "mapSNVSel_TEMP.rds") -## Run only if directory in writing mode -if (file.access(getwd()) == 0 && !file.exists(snpIndexFile) && - !file.exists(filterSNVFile)) { - - ## Create a data.frame containing the information of the retained - ## samples (samples with existing genotyping files) - generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, +## Create a data.frame containing the information of the retained +## samples (samples with existing genotyping files) +generateMapSnvSel(cutOff=0.01, fileSNV=snvFile, fileSNPsRDS=snpIndexFile, fileFREQ=filterSNVFile) - ## Remove temporary files - unlink(snpIndexFile, force=TRUE) - unlink(filterSNVFile, force=TRUE) -} +## Remove temporary files +unlink(snpIndexFile, force=TRUE) +unlink(filterSNVFile, force=TRUE) } \author{ diff --git a/man/generatePhase1KG2GDS.Rd b/man/generatePhase1KG2GDS.Rd index b6f0b5783..863f687d4 100644 --- a/man/generatePhase1KG2GDS.Rd +++ b/man/generatePhase1KG2GDS.Rd @@ -60,44 +60,39 @@ snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") ## Temporary Reference GDS file containing reference information -fileReferenceGDS <- "1KG_TEMP_02.gds" +fileReferenceGDS <- file.path(tempdir(), "1KG_TEMP_02.gds") -## Only run example if the directory is writable -if (file.access(getwd()) == 0 && !file.exists(fileReferenceGDS)) { - - ## Create a temporary Reference GDS file containing information from 1KG - generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +## Create a temporary Reference GDS file containing information from 1KG +generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, fileNameGDS=fileReferenceGDS, listSamples=NULL) - ## Temporary Phase GDS file that will contain the 1KG Phase information - fileRefPhaseGDS <- "1KG_TEMP_Phase_02.gds" +## Temporary Phase GDS file that will contain the 1KG Phase information +fileRefPhaseGDS <- file.path(tempdir(), "1KG_TEMP_Phase_02.gds") - ## Create Reference Phase GDS file - gdsPhase <- createfn.gds(fileRefPhaseGDS) +## Create Reference Phase GDS file +gdsPhase <- createfn.gds(fileRefPhaseGDS) - ## Open Reference GDS file - gdsRef <- openfn.gds(fileReferenceGDS) +## Open Reference GDS file +gdsRef <- openfn.gds(fileReferenceGDS) - ## Fill temporary Reference Phase GDS file - if (FALSE) { - generatePhase1KG2GDS(gdsReference=gdsRef, +## Fill temporary Reference Phase GDS file +if (FALSE) { + generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, pathGeno=dataDir, fileSNPsRDS=filterSNVFile, verbose=FALSE) - } - - ## Close Reference Phase information file - closefn.gds(gdsPhase) +} - ## Close Reference information file - closefn.gds(gdsRef) +## Close Reference Phase information file +closefn.gds(gdsPhase) - ## Remove temporary files - unlink(fileReferenceGDS, force=TRUE) - unlink(fileRefPhaseGDS, force=TRUE) +## Close Reference information file +closefn.gds(gdsRef) -} +## Remove temporary files +unlink(fileReferenceGDS, force=TRUE) +unlink(fileRefPhaseGDS, force=TRUE) } \author{ diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index 1ce2d91df..49c538dc5 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -146,9 +146,9 @@ pathGeno <- file.path(dataDir, "example", "snpPileup") ## The path where the Profile GDS Files (one per sample) ## will be created need to be specified. ################################################################# -pathProfileGDS <- file.path(getwd(), "out.tmp") +pathProfileGDS <- file.path(tempdir(), "out.tmp") -pathOut <- file.path(getwd(), "res.out") +pathOut <- file.path(tempdir(), "res.out") ################################################################# ## A data frame containing general information about the study @@ -183,10 +183,8 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] \dontrun{ - if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && - !file.exists(pathOut)) { - runExomeAncestry(pedStudy=ped, studyDF=studyDF, + runExomeAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, @@ -196,9 +194,9 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, syntheticRefDF=dataRef, genoSource="snp-pileup") - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) - } + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + } } diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index b760fdf06..85243f71d 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -151,9 +151,9 @@ pathGeno <- file.path(dataDir, "example", "snpPileup") ## The path where the Profile GDS Files (one per sample) ## will be created need to be specified. ################################################################# -pathProfileGDS <- file.path(getwd(), "out.tmp") +pathProfileGDS <- file.path(tempdir(), "out.tmp") -pathOut <- file.path(getwd(), "res.out") +pathOut <- file.path(tempdir(), "res.out") ################################################################# ## A data frame containing general information about the study @@ -188,10 +188,8 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] \dontrun{ - if (file.access(getwd()) == 0 && !file.exists(pathProfileGDS) && - !file.exists(pathOut)) { - runRNAAncestry(pedStudy=ped, studyDF=studyDF, + runRNAAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, @@ -202,9 +200,9 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, blockTypeID="GeneS.Ensembl.Hsapiens.v86", genoSource="snp-pileup") - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) - } + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + } } diff --git a/man/syntheticGeno.Rd b/man/syntheticGeno.Rd index 3e7a5194d..0d02b7311 100644 --- a/man/syntheticGeno.Rd +++ b/man/syntheticGeno.Rd @@ -79,54 +79,50 @@ library(gdsfmt) ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata/tests", package="RAIDS") -## Profile GDS file -fileNameGDS <- file.path(getwd(), "ex1.gds") +## Profile GDS file (temporary) +fileNameGDS <- file.path(tempdir(), "ex1.gds") -## Only run example if the directory is writable -if (file.access(getwd()) == 0 && !file.exists(fileNameGDS)) { - - ## Copy the Profile GDS file demo that has been pruned and annotated - file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), +## Copy the Profile GDS file demo that has been pruned and annotated +file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), fileNameGDS) - ## Information about the synthetic data set - syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", +## Information about the synthetic data set +syntheticStudyDF <- data.frame(study.id="MYDATA.Synthetic", study.desc="MYDATA synthetic data", study.platform="PLATFORM", stringsAsFactors=FALSE) - ## Add information related to the synthetic profiles into the Profile GDS - prepSynthetic(fileProfileGDS=fileNameGDS, +## Add information related to the synthetic profiles into the Profile GDS +prepSynthetic(fileProfileGDS=fileNameGDS, listSampleRef=c("HG00243", "HG00150"), profileID="ex1", studyDF=syntheticStudyDF, nbSim=1L, prefix="synthTest", verbose=FALSE) - ## The 1KG files - gds1KG <- snpgdsOpen(file.path(dataDir, +## The 1KG files +gds1KG <- snpgdsOpen(file.path(dataDir, "ex1_good_small_1KG_GDS.gds")) - gds1KGAnnot <- openfn.gds(file.path(dataDir, +gds1KGAnnot <- openfn.gds(file.path(dataDir, "ex1_good_small_1KG_Annot_GDS.gds")) - ## Generate the synthetic profiles and add them into the Profile GDS - syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gds1KGAnnot, +## Generate the synthetic profiles and add them into the Profile GDS +syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gds1KGAnnot, fileProfileGDS=fileNameGDS, profileID="ex1", listSampleRef=c("HG00243", "HG00150"), nbSim=1, prefix="synthTest", pRecomb=0.01, minProb=0.999, seqError=0.001) - ## Open Profile GDS file - profileGDS <- openfn.gds(fileNameGDS) +## Open Profile GDS file +profileGDS <- openfn.gds(fileNameGDS) - tail(read.gdsn(index.gdsn(profileGDS, "sample.id"))) +tail(read.gdsn(index.gdsn(profileGDS, "sample.id"))) - ## Close GDS files (important) - closefn.gds(profileGDS) - closefn.gds(gds1KG) - closefn.gds(gds1KGAnnot) +## Close GDS files (important) +closefn.gds(profileGDS) +closefn.gds(gds1KG) +closefn.gds(gds1KGAnnot) - ## Remove Profile GDS file (created for demo purpose) - unlink(fileNameGDS, force=TRUE) +## Remove Profile GDS file (created for demo purpose) +unlink(fileNameGDS, force=TRUE) -} } \author{ From 45d3988bea56132fe6914885253ec059abcc20ee Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 30 Aug 2023 18:35:44 -0400 Subject: [PATCH 193/385] Changing getwd() to tempdir() in some examples. --- R/process1KG.R | 3 ++ R/process1KG_internal.R | 25 ++++----- R/processStudy.R | 111 +++++++++++++++++--------------------- R/tools.R | 39 ++++++-------- man/add1KG2SampleGDS.Rd | 40 +++++++------- man/createStudy2GDS1KG.Rd | 29 +++++----- man/getRef1KGPop.Rd | 3 ++ man/groupChr1KGSNV.Rd | 17 +++--- man/pruning1KGbyChr.Rd | 25 ++++----- man/pruningSample.Rd | 42 +++++++-------- man/snvListVCF.Rd | 22 ++++---- 11 files changed, 160 insertions(+), 196 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index 268fb3701..8a9d6b65e 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -710,6 +710,9 @@ addRef2GDS1KG <- function(fileNameGDS, filePart) { #' #' @examples #' +#' ## Required library +#' library(gdsfmt) +#' #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index f64aebcd1..235f918be 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -55,8 +55,9 @@ #' #' @examples #' -#' ## Required library +#' ## Required libraries #' library(SNPRelate) +#' library(gdsfmt) #' #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") @@ -65,25 +66,21 @@ #' gds1KG <- snpgdsOpen(file.path(dataDir, "1KG_Demo.gds")) #' #' ## The prefix of the RDS file to be created and containing the pruned SNVs -#' outPrefix <- "Pruned_Demo_Reference" -#' -#' ## Run only if directory in writing mode -#' if (file.access(getwd()) == 0 && -#' !file.exists(file.path(getwd(), paste0(outPrefix, ".rds")))) { -#' -#' ## Create a RDS file with the pruned SNVs -#' RAIDS:::pruning1KGbyChr(gdsReference=gds1KG, outPrefix=outPrefix) +#' outPrefix <- file.path(tempdir(), "Pruned_Demo_Reference") #' -#' prunedSNVs <- readRDS(file.path(getwd(), paste0(outPrefix, ".rds"))) -#' prunedSNVs +#' ## Create a RDS file with the pruned SNVs +#' RAIDS:::pruning1KGbyChr(gdsReference=gds1KG, outPrefix=outPrefix) #' -#' ## Delete temporary file -#' unlink(file.path(getwd(), paste0(outPrefix, ".rds")), force=TRUE) -#' } +#' prunedSNVs <- readRDS(file.path(paste0(outPrefix, ".rds"))) +#' prunedSNVs #' #' ## Close 1K GDS file #' closefn.gds(gds1KG) #' +#' ## Delete temporary file +#' unlink(paste0(outPrefix, ".rds"), force=TRUE) +#' +#' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn #' @encoding UTF-8 diff --git a/R/processStudy.R b/R/processStudy.R index 03ff164e6..0223cdbf2 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -90,31 +90,26 @@ #' Source=rep("Databank B", 2), stringsAsFactors=FALSE) #' rownames(samplePED) <- samplePED$Name.ID #' -#' ## Run only if directory in writing mode -#' if (file.access(getwd()) == 0 && -#' !file.exists(file.path(file.path(getwd(), "ex1.gds")))) { -#' -#' ## Create the Profile GDS File for samples in 'listSamples' vector -#' ## (in this case, samples "ex1") -#' ## The Profile GDS file is created in the pathProfileGDS directory -#' result <- createStudy2GDS1KG(pathGeno=dataDir, +#' ## Create the Profile GDS File for samples in 'listSamples' vector +#' ## (in this case, samples "ex1") +#' ## The Profile GDS file is created in the pathProfileGDS directory +#' result <- createStudy2GDS1KG(pathGeno=dataDir, #' pedStudy=samplePED, fileNameGDS=fileGDS, #' studyDF=studyDF, listProfiles=c("ex1"), -#' pathProfileGDS=getwd(), +#' pathProfileGDS=tempdir(), #' genoSource="snp-pileup", #' verbose=FALSE) #' -#' ## The function returns OL when successful -#' result +#' ## The function returns OL when successful +#' result #' -#' ## The Profile GDS file 'ex1.gds' has been created in the -#' ## specified directory -#' list.files(getwd()) +#' ## The Profile GDS file 'ex1.gds' has been created in the +#' ## specified directory +#' list.files(tempdir()) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(file.path(getwd(), "ex1.gds")) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(file.path(tempdir(), "ex1.gds"), force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt createfn.gds put.attr.gdsn closefn.gds read.gdsn @@ -296,37 +291,33 @@ createStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' rownames(samplePED) <- samplePED$Name.ID #' #' ## Temporary Profile GDS file -#' profileFile <- file.path(getwd(), "ex1.gds") -#' -#' ## Example can only be run if the current directory is in writing mode -#' if (file.access(getwd()) == 0 && !file.exists(profileFile)) { +#' profileFile <- file.path(tempdir(), "ex1.gds") #' -#' ## Copy the Profile GDS file demo that has not been pruned yet -#' file.copy(file.path(dataDir, "ex1_demo.gds"), profileFile) +#' ## Copy the Profile GDS file demo that has not been pruned yet +#' file.copy(file.path(dataDir, "ex1_demo.gds"), profileFile) #' -#' ## Open 1KG file -#' gds1KG <- snpgdsOpen(fileGDS) +#' ## Open 1KG file +#' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Compute the list of pruned SNVs for a specific profile 'ex1' -#' ## and save it in the Profile GDS file 'ex1.gds' -#' pruningSample(gdsReference=gds1KG, currentProfile=c("ex1"), -#' studyID = studyDF$study.id, pathProfileGDS=getwd()) +#' ## Compute the list of pruned SNVs for a specific profile 'ex1' +#' ## and save it in the Profile GDS file 'ex1.gds' +#' pruningSample(gdsReference=gds1KG, currentProfile=c("ex1"), +#' studyID = studyDF$study.id, pathProfileGDS=tempdir()) #' -#' ## Close the Reference GDS file (important) -#' closefn.gds(gds1KG) +#' ## Close the Reference GDS file (important) +#' closefn.gds(gds1KG) #' -#' ## Check content of Profile GDS file -#' ## The 'pruned.study' entry should be present -#' content <- openfn.gds(profileFile) -#' content +#' ## Check content of Profile GDS file +#' ## The 'pruned.study' entry should be present +#' content <- openfn.gds(profileFile) +#' content #' -#' ## Close the Profile GDS file (important) -#' closefn.gds(content) +#' ## Close the Profile GDS file (important) +#' closefn.gds(content) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(profileFile, force=TRUE) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(profileFile, force=TRUE) #' -#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn @@ -491,39 +482,35 @@ pruningSample <- function(gdsReference, #' stringsAsFactors=FALSE) #' #' ## Temporary Profile file -#' fileProfile <- file.path(getwd(), "ex2.gds") +#' fileProfile <- file.path(tempdir(), "ex2.gds") #' -#' ## Only run example if the directory is writable -#' if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { -#' -#' ## Copy required file -#' file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), +#' ## Copy required file +#' file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), #' fileProfile) #' -#' ## Open 1KG file -#' gds1KG <- snpgdsOpen(fileGDS) +#' ## Open 1KG file +#' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Compute the list of pruned SNVs for a specific profile 'ex1' -#' ## and save it in the Profile GDS file 'ex2.gds' -#' add1KG2SampleGDS(gdsReference=gds1KG, +#' ## Compute the list of pruned SNVs for a specific profile 'ex1' +#' ## and save it in the Profile GDS file 'ex2.gds' +#' add1KG2SampleGDS(gdsReference=gds1KG, #' fileProfileGDS=fileProfile, #' currentProfile=c("ex1"), #' studyID=studyDF$study.id) #' -#' ## Close the 1KG GDS file (important) -#' closefn.gds(gds1KG) +#' ## Close the 1KG GDS file (important) +#' closefn.gds(gds1KG) #' -#' ## Check content of Profile GDS file -#' ## The 'pruned.study' entry should be present -#' content <- openfn.gds(fileProfile) -#' content +#' ## Check content of Profile GDS file +#' ## The 'pruned.study' entry should be present +#' content <- openfn.gds(fileProfile) +#' content #' -#' ## Close the Profile GDS file (important) -#' closefn.gds(content) +#' ## Close the Profile GDS file (important) +#' closefn.gds(content) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(fileProfile, force=TRUE) -#' } +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) #' #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/R/tools.R b/R/tools.R index a19d4dd4f..859ef319e 100644 --- a/R/tools.R +++ b/R/tools.R @@ -33,23 +33,19 @@ #' ## Demo 1KG Reference GDS file #' fileGDS <- openfn.gds(file.path(dataDir, "1KG_Demo.gds")) #' -#' ## Output VCF file that will be created -#' vcfFile <- file.path(getwd(), "Demo_TMP_01.vcf") +#' ## Output VCF file that will be created (temporary) +#' vcfFile <- file.path(tempdir(), "Demo_TMP_01.vcf") #' -#' ## Run only if directory in writing mode -#' if (file.access(getwd()) == 0 && !dir.exists(vcfFile)) { -#' -#' ## Create a VCF file with the SNV dataset present in the GDS file -#' ## No cutoff on frequency, so all SNVs are saved -#' snvListVCF(gdsReference=fileGDS, fileOut=vcfFile, offset=0L, +#' ## Create a VCF file with the SNV dataset present in the GDS file +#' ## No cutoff on frequency, so all SNVs are saved +#' snvListVCF(gdsReference=fileGDS, fileOut=vcfFile, offset=0L, #' freqCutoff=NULL) #' -#' ## Close GDS file (IMPORTANT) -#' closefn.gds(fileGDS) +#' ## Close GDS file (IMPORTANT) +#' closefn.gds(fileGDS) #' -#' ## Remove temporary VCF file -#' unlink(vcfFile, force=TRUE) -#' } +#' ## Remove temporary VCF file +#' unlink(vcfFile, force=TRUE) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt read.gdsn @@ -166,13 +162,12 @@ snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { #' pathGeno <- file.path(dataDir, "demoGenoChr") #' #' ## Path where the output vcf file will be created -#' pathOut <- getwd() +#' pathOut <- tempdir() #' -#' ## The current directory must be writable -#' if (file.access(pathOut) == 0 && -#' !file.exists(file.path(getwd(), "NA12003.csv.bz2")) && -#' !file.exists(file.path(getwd(), "NA12004.csv.bz2")) && -#' !file.exists(file.path(getwd(), "NA12005.csv.bz2"))) { +#' ## The files must not exist +#' if (!file.exists(file.path(tempdir(), "NA12003.csv.bz2")) && +#' !file.exists(file.path(tempdir(), "NA12004.csv.bz2")) && +#' !file.exists(file.path(tempdir(), "NA12005.csv.bz2"))) { #' #' ## Return 0 when successful #' ## The files "NA12003.csv.bz2", "NA12004.csv.bz2" and @@ -180,9 +175,9 @@ snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { #' groupChr1KGSNV(pathGenoChr=pathGeno, pathOut=pathOut) #' #' ## Remove temporary VCF file -#' unlink(file.path(getwd(), "NA12003.csv.bz2"), force=TRUE) -#' unlink(file.path(getwd(), "NA12004.csv.bz2"), force=TRUE) -#' unlink(file.path(getwd(), "NA12005.csv.bz2"), force=TRUE) +#' unlink(file.path(tempdir(), "NA12003.csv.bz2"), force=TRUE) +#' unlink(file.path(tempdir(), "NA12004.csv.bz2"), force=TRUE) +#' unlink(file.path(tempdir(), "NA12005.csv.bz2"), force=TRUE) #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/man/add1KG2SampleGDS.Rd b/man/add1KG2SampleGDS.Rd index 5a270f8eb..06da741e5 100644 --- a/man/add1KG2SampleGDS.Rd +++ b/man/add1KG2SampleGDS.Rd @@ -49,39 +49,35 @@ studyDF <- data.frame(study.id="MYDATA", stringsAsFactors=FALSE) ## Temporary Profile file -fileProfile <- file.path(getwd(), "ex2.gds") +fileProfile <- file.path(tempdir(), "ex2.gds") -## Only run example if the directory is writable -if (file.access(getwd()) == 0 && !file.exists(fileProfile)) { - - ## Copy required file - file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), +## Copy required file +file.copy(file.path(dataDir, "ex1_demo_with_pruning.gds"), fileProfile) - ## Open 1KG file - gds1KG <- snpgdsOpen(fileGDS) +## Open 1KG file +gds1KG <- snpgdsOpen(fileGDS) - ## Compute the list of pruned SNVs for a specific profile 'ex1' - ## and save it in the Profile GDS file 'ex2.gds' - add1KG2SampleGDS(gdsReference=gds1KG, +## Compute the list of pruned SNVs for a specific profile 'ex1' +## and save it in the Profile GDS file 'ex2.gds' +add1KG2SampleGDS(gdsReference=gds1KG, fileProfileGDS=fileProfile, currentProfile=c("ex1"), studyID=studyDF$study.id) - ## Close the 1KG GDS file (important) - closefn.gds(gds1KG) +## Close the 1KG GDS file (important) +closefn.gds(gds1KG) - ## Check content of Profile GDS file - ## The 'pruned.study' entry should be present - content <- openfn.gds(fileProfile) - content +## Check content of Profile GDS file +## The 'pruned.study' entry should be present +content <- openfn.gds(fileProfile) +content - ## Close the Profile GDS file (important) - closefn.gds(content) +## Close the Profile GDS file (important) +closefn.gds(content) - ## Remove Profile GDS file (created for demo purpose) - unlink(fileProfile, force=TRUE) -} +## Remove Profile GDS file (created for demo purpose) +unlink(fileProfile, force=TRUE) } diff --git a/man/createStudy2GDS1KG.Rd b/man/createStudy2GDS1KG.Rd index e70286404..83d9c1f94 100644 --- a/man/createStudy2GDS1KG.Rd +++ b/man/createStudy2GDS1KG.Rd @@ -111,31 +111,26 @@ samplePED <- data.frame(Name.ID=c("ex1", "ex2"), Source=rep("Databank B", 2), stringsAsFactors=FALSE) rownames(samplePED) <- samplePED$Name.ID -## Run only if directory in writing mode -if (file.access(getwd()) == 0 && - !file.exists(file.path(file.path(getwd(), "ex1.gds")))) { - - ## Create the Profile GDS File for samples in 'listSamples' vector - ## (in this case, samples "ex1") - ## The Profile GDS file is created in the pathProfileGDS directory - result <- createStudy2GDS1KG(pathGeno=dataDir, +## Create the Profile GDS File for samples in 'listSamples' vector +## (in this case, samples "ex1") +## The Profile GDS file is created in the pathProfileGDS directory +result <- createStudy2GDS1KG(pathGeno=dataDir, pedStudy=samplePED, fileNameGDS=fileGDS, studyDF=studyDF, listProfiles=c("ex1"), - pathProfileGDS=getwd(), + pathProfileGDS=tempdir(), genoSource="snp-pileup", verbose=FALSE) - ## The function returns OL when successful - result +## The function returns OL when successful +result - ## The Profile GDS file 'ex1.gds' has been created in the - ## specified directory - list.files(getwd()) +## The Profile GDS file 'ex1.gds' has been created in the +## specified directory +list.files(tempdir()) - ## Remove Profile GDS file (created for demo purpose) - unlink(file.path(getwd(), "ex1.gds")) +## Remove Profile GDS file (created for demo purpose) +unlink(file.path(tempdir(), "ex1.gds"), force=TRUE) -} } \author{ diff --git a/man/getRef1KGPop.Rd b/man/getRef1KGPop.Rd index c0f082445..544c37fc2 100644 --- a/man/getRef1KGPop.Rd +++ b/man/getRef1KGPop.Rd @@ -32,6 +32,9 @@ represent the known ancestry assignation. } \examples{ +## Required library +library(gdsfmt) + ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") diff --git a/man/groupChr1KGSNV.Rd b/man/groupChr1KGSNV.Rd index f5db6ae09..dfbf884a6 100644 --- a/man/groupChr1KGSNV.Rd +++ b/man/groupChr1KGSNV.Rd @@ -35,13 +35,12 @@ dataDir <- system.file("extdata", package="RAIDS") pathGeno <- file.path(dataDir, "demoGenoChr") ## Path where the output vcf file will be created -pathOut <- getwd() +pathOut <- tempdir() -## The current directory must be writable -if (file.access(pathOut) == 0 && - !file.exists(file.path(getwd(), "NA12003.csv.bz2")) && - !file.exists(file.path(getwd(), "NA12004.csv.bz2")) && - !file.exists(file.path(getwd(), "NA12005.csv.bz2"))) { +## The files must not exist +if (!file.exists(file.path(tempdir(), "NA12003.csv.bz2")) && + !file.exists(file.path(tempdir(), "NA12004.csv.bz2")) && + !file.exists(file.path(tempdir(), "NA12005.csv.bz2"))) { ## Return 0 when successful ## The files "NA12003.csv.bz2", "NA12004.csv.bz2" and @@ -49,9 +48,9 @@ if (file.access(pathOut) == 0 && groupChr1KGSNV(pathGenoChr=pathGeno, pathOut=pathOut) ## Remove temporary VCF file - unlink(file.path(getwd(), "NA12003.csv.bz2"), force=TRUE) - unlink(file.path(getwd(), "NA12004.csv.bz2"), force=TRUE) - unlink(file.path(getwd(), "NA12005.csv.bz2"), force=TRUE) + unlink(file.path(tempdir(), "NA12003.csv.bz2"), force=TRUE) + unlink(file.path(tempdir(), "NA12004.csv.bz2"), force=TRUE) + unlink(file.path(tempdir(), "NA12005.csv.bz2"), force=TRUE) } } diff --git a/man/pruning1KGbyChr.Rd b/man/pruning1KGbyChr.Rd index 86a5e06e9..7b2a78c50 100644 --- a/man/pruning1KGbyChr.Rd +++ b/man/pruning1KGbyChr.Rd @@ -77,8 +77,9 @@ pruned SNVs are saved in a RDS file. } \examples{ -## Required library +## Required libraries library(SNPRelate) +library(gdsfmt) ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") @@ -87,25 +88,21 @@ dataDir <- system.file("extdata", package="RAIDS") gds1KG <- snpgdsOpen(file.path(dataDir, "1KG_Demo.gds")) ## The prefix of the RDS file to be created and containing the pruned SNVs -outPrefix <- "Pruned_Demo_Reference" +outPrefix <- file.path(tempdir(), "Pruned_Demo_Reference") -## Run only if directory in writing mode -if (file.access(getwd()) == 0 && - !file.exists(file.path(getwd(), paste0(outPrefix, ".rds")))) { +## Create a RDS file with the pruned SNVs +RAIDS:::pruning1KGbyChr(gdsReference=gds1KG, outPrefix=outPrefix) - ## Create a RDS file with the pruned SNVs - RAIDS:::pruning1KGbyChr(gdsReference=gds1KG, outPrefix=outPrefix) - - prunedSNVs <- readRDS(file.path(getwd(), paste0(outPrefix, ".rds"))) - prunedSNVs - - ## Delete temporary file - unlink(file.path(getwd(), paste0(outPrefix, ".rds")), force=TRUE) -} +prunedSNVs <- readRDS(file.path(paste0(outPrefix, ".rds"))) +prunedSNVs ## Close 1K GDS file closefn.gds(gds1KG) +## Delete temporary file +unlink(paste0(outPrefix, ".rds"), force=TRUE) + + } \author{ Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/man/pruningSample.Rd b/man/pruningSample.Rd index 191730234..c174f5f09 100644 --- a/man/pruningSample.Rd +++ b/man/pruningSample.Rd @@ -133,37 +133,33 @@ samplePED <- data.frame(Name.ID = c("ex1", "ex2"), rownames(samplePED) <- samplePED$Name.ID ## Temporary Profile GDS file -profileFile <- file.path(getwd(), "ex1.gds") +profileFile <- file.path(tempdir(), "ex1.gds") -## Example can only be run if the current directory is in writing mode -if (file.access(getwd()) == 0 && !file.exists(profileFile)) { +## Copy the Profile GDS file demo that has not been pruned yet +file.copy(file.path(dataDir, "ex1_demo.gds"), profileFile) - ## Copy the Profile GDS file demo that has not been pruned yet - file.copy(file.path(dataDir, "ex1_demo.gds"), profileFile) +## Open 1KG file +gds1KG <- snpgdsOpen(fileGDS) - ## Open 1KG file - gds1KG <- snpgdsOpen(fileGDS) +## Compute the list of pruned SNVs for a specific profile 'ex1' +## and save it in the Profile GDS file 'ex1.gds' +pruningSample(gdsReference=gds1KG, currentProfile=c("ex1"), + studyID = studyDF$study.id, pathProfileGDS=tempdir()) - ## Compute the list of pruned SNVs for a specific profile 'ex1' - ## and save it in the Profile GDS file 'ex1.gds' - pruningSample(gdsReference=gds1KG, currentProfile=c("ex1"), - studyID = studyDF$study.id, pathProfileGDS=getwd()) +## Close the Reference GDS file (important) +closefn.gds(gds1KG) - ## Close the Reference GDS file (important) - closefn.gds(gds1KG) +## Check content of Profile GDS file +## The 'pruned.study' entry should be present +content <- openfn.gds(profileFile) +content - ## Check content of Profile GDS file - ## The 'pruned.study' entry should be present - content <- openfn.gds(profileFile) - content +## Close the Profile GDS file (important) +closefn.gds(content) - ## Close the Profile GDS file (important) - closefn.gds(content) +## Remove Profile GDS file (created for demo purpose) +unlink(profileFile, force=TRUE) - ## Remove Profile GDS file (created for demo purpose) - unlink(profileFile, force=TRUE) - -} } \author{ diff --git a/man/snvListVCF.Rd b/man/snvListVCF.Rd index 7c1f5b6d0..2b43a6d39 100644 --- a/man/snvListVCF.Rd +++ b/man/snvListVCF.Rd @@ -43,23 +43,19 @@ dataDir <- system.file("extdata", package="RAIDS") ## Demo 1KG Reference GDS file fileGDS <- openfn.gds(file.path(dataDir, "1KG_Demo.gds")) -## Output VCF file that will be created -vcfFile <- file.path(getwd(), "Demo_TMP_01.vcf") +## Output VCF file that will be created (temporary) +vcfFile <- file.path(tempdir(), "Demo_TMP_01.vcf") -## Run only if directory in writing mode -if (file.access(getwd()) == 0 && !dir.exists(vcfFile)) { - - ## Create a VCF file with the SNV dataset present in the GDS file - ## No cutoff on frequency, so all SNVs are saved - snvListVCF(gdsReference=fileGDS, fileOut=vcfFile, offset=0L, +## Create a VCF file with the SNV dataset present in the GDS file +## No cutoff on frequency, so all SNVs are saved +snvListVCF(gdsReference=fileGDS, fileOut=vcfFile, offset=0L, freqCutoff=NULL) - ## Close GDS file (IMPORTANT) - closefn.gds(fileGDS) +## Close GDS file (IMPORTANT) +closefn.gds(fileGDS) - ## Remove temporary VCF file - unlink(vcfFile, force=TRUE) -} +## Remove temporary VCF file +unlink(vcfFile, force=TRUE) } \author{ From 747818aeacc3f583b229826e15c11dceec29d4c7 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 30 Aug 2023 19:26:31 -0400 Subject: [PATCH 194/385] Changing getwd() to tempdir() in main vignette. --- vignettes/RAIDS.Rmd | 46 ++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 5a51ffe89..cc2d7b6a0 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -245,7 +245,7 @@ Alternatively, the PED information can be saved in another type of file (CVS, etc..) as long as the *data.frame* information can be regenerated in R (with _read.csv()_ or else). -```{r runExomeAncestry, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +```{r runExomeAncestry, echo=TRUE, eval=TRUE, collapse=FALSE, warning=FALSE, message=FALSE} ############################################################################# ## Load required packages ############################################################################# @@ -321,18 +321,18 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## The path where the Sample GDS files (one per sample) ## will be created needs to be specified. ############################################################################# -pathProfileGDS <- file.path(getwd(), "example", "out.tmp") +pathProfileGDS <- file.path(tempdir(), "exampleDNA", "out.tmp") ############################################################################# ## The path where the result files will be created needs to ## be specified ############################################################################# -pathOut <- file.path(getwd(), "example", "res.out") +pathOut <- file.path(tempdir(), "exampleDNA", "res.out") ## Example can only be run if the current directory is in writing mode -if (file.access(getwd()) == 0 && !dir.exists(file.path(getwd(), "example"))) { +if (!dir.exists(file.path(tempdir(), "exampleDNA"))) { - dir.create(file.path(getwd(), "example")) + dir.create(file.path(tempdir(), "exampleDNA")) dir.create(pathProfileGDS) dir.create(pathOut) @@ -365,13 +365,14 @@ if (file.access(getwd()) == 0 && !dir.exists(file.path(getwd(), "example"))) { ######################################################################### resAncestry <- read.csv(file.path(pathOut, paste0(ped$Name.ID[1], ".Ancestry.csv"))) - resAncestry + print(resAncestry) ## Remove temporary files created for this demo unlink(pathProfileGDS, recursive=TRUE, force=TRUE) unlink(pathOut, recursive=TRUE, force=TRUE) - unlink(file.path(getwd(), "example"), force=TRUE) + unlink(file.path(tempdir(), "exampleDNA"), recursive=TRUE, force=TRUE) } + ``` @@ -388,6 +389,13 @@ in the *pathOut* directory. In addition, a sub-directory (named using the *profile ID*) is also created. +The inferred ancestry is stored in the ancestry inference CSV +file (**".Ancestry.csv"** file) which also contains those columns: + +* _sample.id_: The unique identifier of the sample +* _D_: The optimal PCA dimension value used to infer the ancestry +* _k_: The optimal number of neighbors value used to infer the ancestry +* _SuperPop_: The inferred ancestry

@@ -455,7 +463,7 @@ Alternatively, the PED information can be saved in another type of file (CVS, etc..) as long as the *data.frame* information can be regenerated in R (with _read.csv()_ or else). -```{r runRNAAncestry, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +```{r runRNAAncestry, echo=TRUE, eval=TRUE, collapse=FALSE, warning=FALSE, message=FALSE} ############################################################################# ## Load required packages ############################################################################# @@ -531,18 +539,18 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, ## The path where the Sample GDS files (one per sample) ## will be created needs to be specified. ############################################################################# -pathProfileGDS <- file.path(getwd(), "exampleRNA", "outRNA.tmp") +pathProfileGDS <- file.path(tempdir(), "exampleRNA", "outRNA.tmp") ############################################################################# ## The path where the result files will be created needs to ## be specified ############################################################################# -pathOut <- file.path(getwd(), "exampleRNA", "resRNA.out") +pathOut <- file.path(tempdir(), "exampleRNA", "resRNA.out") ## Example can only be run if the current directory is in writing mode -if (file.access(getwd()) == 0 && !dir.exists(file.path(getwd(), "exampleRNA"))) { +if (!dir.exists(file.path(tempdir(), "exampleRNA"))) { - dir.create(file.path(getwd(), "exampleRNA")) + dir.create(file.path(tempdir(), "exampleRNA")) dir.create(pathProfileGDS) dir.create(pathOut) @@ -577,14 +585,14 @@ if (file.access(getwd()) == 0 && !dir.exists(file.path(getwd(), "exampleRNA"))) ######################################################################### resAncestry <- read.csv(file.path(pathOut, paste0(ped$Name.ID[1], ".Ancestry.csv"))) - resAncestry + print(resAncestry) ## Remove temporary files created for this demo unlink(pathProfileGDS, recursive=TRUE, force=TRUE) unlink(pathOut, recursive=TRUE, force=TRUE) - unlink(file.path(getwd(), "example"), force=TRUE) + unlink(file.path(tempdir(), "example"), recursive=TRUE, force=TRUE) } - + ```
@@ -600,6 +608,14 @@ in the *pathOut* directory. In addition, a sub-directory (named using the *profile ID*) is also created. +The inferred ancestry is stored in the ancestry inference CSV +file (**".Ancestry.csv"** file) which also contains those columns: + +* _sample.id_: The unique identifier of the sample +* _D_: The optimal PCA dimension value used to infer the ancestry +* _k_: The optimal number of neighbors value used to infer the ancestry +* _SuperPop_: The inferred ancestry +

From edc91db9d361871a1079a141869c5b85241948a2 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 31 Aug 2023 15:37:57 -0400 Subject: [PATCH 195/385] Starting demo creation of a Reference GDS in secondary vignette --- vignettes/Create_Reference_GDS_File.Rmd | 42 ++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index dce3b5e45..a1410a7d6 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -118,6 +118,46 @@ The mandatory fields are: * **genotype**: a SNV genotypic *matrix* of *integer* values (saved in *Bit2* format) (i.e., the number of A alleles) with SNVs as rows and samples as columns (number of SNVs × number of Samples) * **sample.ref**: an *integer* (saved in *Bit1* format) indicating if the sample is retained to be used as reference (=1) or removed (=0) as related samples have to be discarded +
+ +This following example shows how to create a *Population GDS Reference file*. + +```{r createRefGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +############################################################################# +## Load required packages +############################################################################# +library(RAIDS) +library(SNPRelate) +library(gdsfmt) + +## Create a temporary GDS Reference file in the temporary directory +fileNewReferenceGDS <- file.path(tempdir(), "reference_DEMO.gds") + +gdsRefNew <- createfn.gds(fileNewReferenceGDS) + +## The entry 'sample.id' contain the unique identifiers of 10 samples +## that constitute the reference dataset +sample.id <- c("HG00243", "HG00150", "HG00149", "HG00246", "HG00138", + "HG01334", "HG00268", "HG00275", "HG00290", "HG00364") +add.gdsn(node=gdsRefNew, name="sample.id", val=sample.id, + storage="string", check=TRUE) + +## TODO + +## The entry 'sample.ref' is filled with 1 indicating that all 10 +## samples are retained to be used as reference +add.gdsn(node=gdsRefNew, name="sample.ref", val=rep(1L, 10), + storage="bit1", check=TRUE) + + +## Show the file format +print(gdsRefNew) + +closefn.gds(gdsRefNew) + +unlink(fileNewReferenceGDS, force=TRUE) + +```

@@ -125,7 +165,7 @@ The mandatory fields are: # Population Reference Annotation GDS file The *Population Reference Annotation GDS file* contains phase information -and block group information forl all the SNVs present in +and block group information for all the SNVs present in *Population Reference GDS file*. A block can be a linkage disequelibrium block relative to a population or a gene. From 728636e465f3fb6b8f998ea29013b749b8e667c5 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 31 Aug 2023 17:47:27 -0400 Subject: [PATCH 196/385] Change hard-coded chrInfo to use GenomeInfoDb::seqlengths() instead --- R/allelicFraction.R | 43 ++++++++++++++++------------------ man/estimateAllelicFraction.Rd | 43 ++++++++++++++++------------------ 2 files changed, 40 insertions(+), 46 deletions(-) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index f7c259a7d..c4ae67d90 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -106,36 +106,33 @@ #' ## Profile GDS file for one profile #' profileGDS <- openfn.gds(fileProfile, readonly=FALSE) #' -#' ## Chromosome length information -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, -#' 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, -#' 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, -#' 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) -#' -#' ## A formal way to get the chormosome length information -#' ## library(GenomeInfoDb) -#' ## library(BSgenome.Hsapiens.UCSC.hg38) -#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] -#' -#' ## Estimate the allelic fraction of the pruned SNVs -#' estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' ## Estimate the allelic fraction of the pruned SNVs +#' estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, #' currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, #' studyType="DNA", minCov=10L, minProb=0.999, eProb=0.001, #' cutOffLOH=-5, cutOffHomoScore=-3, wAR=9, cutOffAR=3, #' gdsRefAnnot=NULL, blockID=NULL) #' -#' ## The allelic fraction is saved in the 'lap' node of Profile GDS file -#' ## The 'lap' entry should be present -#' profileGDS +#' ## The allelic fraction is saved in the 'lap' node of Profile GDS file +#' ## The 'lap' entry should be present +#' profileGDS +#' +#' ## Close both GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) #' -#' ## Close both GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(fileProfile, force=TRUE) +#' } #' #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/man/estimateAllelicFraction.Rd b/man/estimateAllelicFraction.Rd index 16f2e09aa..6baa2de1a 100644 --- a/man/estimateAllelicFraction.Rd +++ b/man/estimateAllelicFraction.Rd @@ -131,36 +131,33 @@ gds1KG <- snpgdsOpen(fileGDS) ## Profile GDS file for one profile profileGDS <- openfn.gds(fileProfile, readonly=FALSE) -## Chromosome length information -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, - 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, - 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, - 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) - -## A formal way to get the chormosome length information -## library(GenomeInfoDb) -## library(BSgenome.Hsapiens.UCSC.hg38) -## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] - -## Estimate the allelic fraction of the pruned SNVs -estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + ## Estimate the allelic fraction of the pruned SNVs + estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=profileGDS, currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, studyType="DNA", minCov=10L, minProb=0.999, eProb=0.001, cutOffLOH=-5, cutOffHomoScore=-3, wAR=9, cutOffAR=3, gdsRefAnnot=NULL, blockID=NULL) -## The allelic fraction is saved in the 'lap' node of Profile GDS file -## The 'lap' entry should be present -profileGDS + ## The allelic fraction is saved in the 'lap' node of Profile GDS file + ## The 'lap' entry should be present + profileGDS -## Close both GDS files (important) -closefn.gds(profileGDS) -closefn.gds(gds1KG) + ## Close both GDS files (important) + closefn.gds(profileGDS) + closefn.gds(gds1KG) -## Remove Profile GDS file (created for demo purpose) -unlink(fileProfile, force=TRUE) + ## Remove Profile GDS file (created for demo purpose) + unlink(fileProfile, force=TRUE) + +} } From 8976c48975956959fce7b75c7ae281dcb07d2de1 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 31 Aug 2023 18:49:21 -0400 Subject: [PATCH 197/385] Change hard-coded chrInfo to use GenomeInfoDb::seqlengths() instead --- R/allelicFraction_internal.R | 204 ++++++++++++++++--------------- man/computeAllelicFractionDNA.Rd | 38 +++--- man/computeAllelicFractionRNA.Rd | 45 +++---- man/computeAllelicImbDNAChr.Rd | 61 ++++----- man/computeLOHBlocksDNAChr.Rd | 58 ++++----- 5 files changed, 211 insertions(+), 195 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 4e2e55892..0ca3a01aa 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -313,37 +313,39 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' ## Open the Reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Chromosome length information for hg38 -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, -#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, -#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, -#' 156040895L, 57227415L, 16569L) +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' ## Data frame with SNV information for the specified chromosome (chr 1) +#' snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), +#' cnt.ref=c(40, 17, 27, 15, 4, 14, 16, 32), +#' cnt.alt=c(0, 0, 0, 0, 7, 23, 0, 0), +#' snp.pos=c(3722256, 3722328, 3767522, 3868160, 3869467, 4712655, +#' 6085318, 6213145), +#' snp.chr=c(rep(1, 8)), +#' normal.geno=c(rep(3, 8)), pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, +#' TRUE, TRUE, TRUE), +#' pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), +#' snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), +#' keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), +#' homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), +#' stringAsFactor=FALSE) +#' +#' ## The function returns a data frame containing the information about the +#' ## LOH regions in the specified chromosome +#' result <- RAIDS:::computeLOHBlocksDNAChr(gdsReference=gds1KG, +#' chrInfo=chrInfo, snpPos=snpInfo, chr=1L, genoN=0.0001) +#' head(result) +#' +#' ## Close Reference GDS file (important) +#' closefn.gds(gds1KG) #' -#' ## Data frame with SNV information for the specified chromosome (chr 1) -#' snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), -#' cnt.ref=c(40, 17, 27, 15, 4, 14, 16, 32), -#' cnt.alt=c(0, 0, 0, 0, 7, 23, 0, 0), -#' snp.pos=c(3722256, 3722328, 3767522, 3868160, 3869467, 4712655, -#' 6085318, 6213145), -#' snp.chr=c(rep(1, 8)), -#' normal.geno=c(rep(3, 8)), pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, -#' TRUE, TRUE), -#' pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), -#' snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), -#' keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), -#' homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), -#' stringAsFactor=FALSE) -#' -#' ## The function returns a data frame containing the information about the -#' ## LOH regions in the specified chromosome -#' result <- RAIDS:::computeLOHBlocksDNAChr(gdsReference=gds1KG, -#' chrInfo=chrInfo, snpPos=snpInfo, chr=1L, genoN=0.0001) -#' head(result) -#' -#' ## Close Reference GDS file (important) -#' closefn.gds(gds1KG) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn @@ -719,28 +721,30 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { #' ## Open Profile GDS file for one profile #' profileGDS <- openfn.gds(fileProfile) #' -#' ## Chromosome length information -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, -#' 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, -#' 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, -#' 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) -#' -#' ## The function returns a data frame containing the allelic fraction info -#' result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, -#' gdsSample=profileGDS, -#' currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, minCov=10L, +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' ## The function returns a data frame containing the allelic fraction info +#' result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, +#' gdsSample=profileGDS, currentProfile="ex1", studyID="MYDATA", +#' chrInfo=chrInfo, minCov=10L, #' minProb=0.999, eProb=0.001, cutOffLOH=-5, #' cutOffHomoScore=-3, wAR=9L, verbose=FALSE) -#' head(result) +#' head(result) #' -#' ## Close both GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) +#' ## Close both GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(fileProfile, force=TRUE) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn @@ -935,31 +939,32 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' ## Open Profile GDS file for one profile #' profileGDS <- openfn.gds(fileProfile) #' -#' ## Chromosome length information -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, -#' 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, -#' 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, -#' 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] #' -#' ## The function returns a data frame containing the allelic fraction info -#' result <- RAIDS:::computeAllelicFractionRNA(gdsReference=gds1KG, +#' ## The function returns a data frame containing the allelic fraction info +#' result <- RAIDS:::computeAllelicFractionRNA(gdsReference=gds1KG, #' gdsSample=profileGDS, gdsRefAnnot=gdsRefAnnot, #' currentProfile="ex1", studyID="MYDATA", #' blockID="GeneS.Ensembl.Hsapiens.v86", -#' chrInfo=chrInfo, minCov=10L, -#' minProb=0.999, eProb=0.001, cutOffLOH=-5, -#' cutOffAR=3, verbose=FALSE) -#' head(result) +#' chrInfo=chrInfo, minCov=10L, minProb=0.999, eProb=0.001, +#' cutOffLOH=-5, cutOffAR=3, verbose=FALSE) +#' head(result) #' -#' ## Close both GDS files (important) -#' closefn.gds(profileGDS) -#' closefn.gds(gds1KG) -#' closefn.gds(gdsRefAnnot) +#' ## Close both GDS files (important) +#' closefn.gds(profileGDS) +#' closefn.gds(gds1KG) +#' closefn.gds(gdsRefAnnot) #' -#' ## Remove Profile GDS file (created for demo purpose) -#' unlink(fileProfile, force=TRUE) +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(fileProfile, force=TRUE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn ls.gdsn @@ -1096,38 +1101,41 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, #' ## Open the reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileGDS) #' -#' ## Chromosome length information -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, -#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, -#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, -#' 156040895L, 57227415L, 16569L) -#' -#' ## Data frame with SNV information for the specified chromosome (chr 1) -#' snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), -#' cnt.ref=c(40, 17, 27, 15, 4, 14, 16, 32), -#' cnt.alt=c(0, 0, 0, 0, 7, 23, 0, 0), -#' snp.pos=c(3722256, 3722328, 3767522, 3868160, 3869467, 4712655, -#' 6085318, 6213145), -#' snp.chr=c(rep(1, 8)), -#' normal.geno=c(rep(1, 8)), pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, -#' TRUE, TRUE), -#' pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), -#' snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), -#' keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), -#' homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), -#' lap=rep(-1, 8), LOH=rep(0, 8), imbAR=rep(-1, 8), -#' stringAsFactor=FALSE) -#' -#' ## The function returns a data frame containing the information about the -#' ## LOH regions in the specified chromosome -#' result <- RAIDS:::computeAllelicImbDNAChr(snpPos=snpInfo, chr=1, wAR=10, -#' cutOffEmptyBox=-3) -#' head(result) +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' ## Data frame with SNV information for the specified chromosome (chr 1) +#' snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), +#' cnt.ref=c(40, 17, 27, 15, 4, 14, 16, 32), +#' cnt.alt=c(0, 0, 0, 0, 7, 23, 0, 0), +#' snp.pos=c(3722256, 3722328, 3767522, 3868160, 3869467, 4712655, +#' 6085318, 6213145), +#' snp.chr=c(rep(1, 8)), +#' normal.geno=c(rep(1, 8)), pruned=c(TRUE, TRUE, FALSE, TRUE, +#' FALSE, TRUE, TRUE, TRUE), +#' pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), +#' snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), +#' keep=rep(TRUE, 8), +#' hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), +#' homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), +#' lap=rep(-1, 8), LOH=rep(0, 8), imbAR=rep(-1, 8), +#' stringAsFactor=FALSE) +#' +#' ## The function returns a data frame containing the information about the +#' ## LOH regions in the specified chromosome +#' result <- RAIDS:::computeAllelicImbDNAChr(snpPos=snpInfo, chr=1, wAR=10, +#' cutOffEmptyBox=-3) +#' head(result) +#' +#' ## Close GDS file (important) +#' closefn.gds(gds1KG) #' -#' ## Close GDS file (important) -#' closefn.gds(gds1KG) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom gdsfmt index.gdsn read.gdsn diff --git a/man/computeAllelicFractionDNA.Rd b/man/computeAllelicFractionDNA.Rd index e0310af66..a1ece9cab 100644 --- a/man/computeAllelicFractionDNA.Rd +++ b/man/computeAllelicFractionDNA.Rd @@ -115,28 +115,30 @@ gds1KG <- snpgdsOpen(fileGDS) ## Open Profile GDS file for one profile profileGDS <- openfn.gds(fileProfile) -## Chromosome length information -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, - 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, - 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, - 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) - -## The function returns a data frame containing the allelic fraction info -result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, - gdsSample=profileGDS, - currentProfile="ex1", studyID="MYDATA", chrInfo=chrInfo, minCov=10L, +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + ## The function returns a data frame containing the allelic fraction info + result <- RAIDS:::computeAllelicFractionDNA(gdsReference=gds1KG, + gdsSample=profileGDS, currentProfile="ex1", studyID="MYDATA", + chrInfo=chrInfo, minCov=10L, minProb=0.999, eProb=0.001, cutOffLOH=-5, cutOffHomoScore=-3, wAR=9L, verbose=FALSE) -head(result) + head(result) -## Close both GDS files (important) -closefn.gds(profileGDS) -closefn.gds(gds1KG) + ## Close both GDS files (important) + closefn.gds(profileGDS) + closefn.gds(gds1KG) -## Remove Profile GDS file (created for demo purpose) -unlink(fileProfile, force=TRUE) + ## Remove Profile GDS file (created for demo purpose) + unlink(fileProfile, force=TRUE) + +} } \author{ diff --git a/man/computeAllelicFractionRNA.Rd b/man/computeAllelicFractionRNA.Rd index 9582ff61b..e731dc41c 100644 --- a/man/computeAllelicFractionRNA.Rd +++ b/man/computeAllelicFractionRNA.Rd @@ -128,31 +128,32 @@ gdsRefAnnot <- openfn.gds(fileAnnotGDS) ## Open Profile GDS file for one profile profileGDS <- openfn.gds(fileProfile) -## Chromosome length information -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, - 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, - 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, - 64444167L, 46709983L, 50818468L, 156040895L, 57227415L, 16569L) - -## The function returns a data frame containing the allelic fraction info -result <- RAIDS:::computeAllelicFractionRNA(gdsReference=gds1KG, +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + ## The function returns a data frame containing the allelic fraction info + result <- RAIDS:::computeAllelicFractionRNA(gdsReference=gds1KG, gdsSample=profileGDS, gdsRefAnnot=gdsRefAnnot, currentProfile="ex1", studyID="MYDATA", blockID="GeneS.Ensembl.Hsapiens.v86", - chrInfo=chrInfo, minCov=10L, - minProb=0.999, eProb=0.001, cutOffLOH=-5, - cutOffAR=3, verbose=FALSE) -head(result) - -## Close both GDS files (important) -closefn.gds(profileGDS) -closefn.gds(gds1KG) -closefn.gds(gdsRefAnnot) - -## Remove Profile GDS file (created for demo purpose) -unlink(fileProfile, force=TRUE) + chrInfo=chrInfo, minCov=10L, minProb=0.999, eProb=0.001, + cutOffLOH=-5, cutOffAR=3, verbose=FALSE) + head(result) + + ## Close both GDS files (important) + closefn.gds(profileGDS) + closefn.gds(gds1KG) + closefn.gds(gdsRefAnnot) + + ## Remove Profile GDS file (created for demo purpose) + unlink(fileProfile, force=TRUE) + +} } \author{ diff --git a/man/computeAllelicImbDNAChr.Rd b/man/computeAllelicImbDNAChr.Rd index 124097f99..84f498650 100644 --- a/man/computeAllelicImbDNAChr.Rd +++ b/man/computeAllelicImbDNAChr.Rd @@ -68,38 +68,41 @@ fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") ## Open the reference GDS file (demo version) gds1KG <- snpgdsOpen(fileGDS) -## Chromosome length information -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { -## Data frame with SNV information for the specified chromosome (chr 1) -snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), - cnt.ref=c(40, 17, 27, 15, 4, 14, 16, 32), - cnt.alt=c(0, 0, 0, 0, 7, 23, 0, 0), - snp.pos=c(3722256, 3722328, 3767522, 3868160, 3869467, 4712655, - 6085318, 6213145), - snp.chr=c(rep(1, 8)), - normal.geno=c(rep(1, 8)), pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, - TRUE, TRUE), - pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), - snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), - keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), - homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), - lap=rep(-1, 8), LOH=rep(0, 8), imbAR=rep(-1, 8), - stringAsFactor=FALSE) + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] -## The function returns a data frame containing the information about the -## LOH regions in the specified chromosome -result <- RAIDS:::computeAllelicImbDNAChr(snpPos=snpInfo, chr=1, wAR=10, - cutOffEmptyBox=-3) -head(result) + ## Data frame with SNV information for the specified chromosome (chr 1) + snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), + cnt.ref=c(40, 17, 27, 15, 4, 14, 16, 32), + cnt.alt=c(0, 0, 0, 0, 7, 23, 0, 0), + snp.pos=c(3722256, 3722328, 3767522, 3868160, 3869467, 4712655, + 6085318, 6213145), + snp.chr=c(rep(1, 8)), + normal.geno=c(rep(1, 8)), pruned=c(TRUE, TRUE, FALSE, TRUE, + FALSE, TRUE, TRUE, TRUE), + pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), + snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), + keep=rep(TRUE, 8), + hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), + homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), + lap=rep(-1, 8), LOH=rep(0, 8), imbAR=rep(-1, 8), + stringAsFactor=FALSE) -## Close GDS file (important) -closefn.gds(gds1KG) + ## The function returns a data frame containing the information about the + ## LOH regions in the specified chromosome + result <- RAIDS:::computeAllelicImbDNAChr(snpPos=snpInfo, chr=1, wAR=10, + cutOffEmptyBox=-3) + head(result) + + ## Close GDS file (important) + closefn.gds(gds1KG) + +} } \author{ diff --git a/man/computeLOHBlocksDNAChr.Rd b/man/computeLOHBlocksDNAChr.Rd index fedef2266..7ddfddf28 100644 --- a/man/computeLOHBlocksDNAChr.Rd +++ b/man/computeLOHBlocksDNAChr.Rd @@ -97,37 +97,39 @@ fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") ## Open the Reference GDS file (demo version) gds1KG <- snpgdsOpen(fileGDS) -## Chromosome length information for hg38 -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { -## Data frame with SNV information for the specified chromosome (chr 1) -snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), - cnt.ref=c(40, 17, 27, 15, 4, 14, 16, 32), - cnt.alt=c(0, 0, 0, 0, 7, 23, 0, 0), - snp.pos=c(3722256, 3722328, 3767522, 3868160, 3869467, 4712655, - 6085318, 6213145), - snp.chr=c(rep(1, 8)), - normal.geno=c(rep(3, 8)), pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, - TRUE, TRUE), - pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), - snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), - keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), - homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), - stringAsFactor=FALSE) + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] -## The function returns a data frame containing the information about the -## LOH regions in the specified chromosome -result <- RAIDS:::computeLOHBlocksDNAChr(gdsReference=gds1KG, - chrInfo=chrInfo, snpPos=snpInfo, chr=1L, genoN=0.0001) -head(result) + ## Data frame with SNV information for the specified chromosome (chr 1) + snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), + cnt.ref=c(40, 17, 27, 15, 4, 14, 16, 32), + cnt.alt=c(0, 0, 0, 0, 7, 23, 0, 0), + snp.pos=c(3722256, 3722328, 3767522, 3868160, 3869467, 4712655, + 6085318, 6213145), + snp.chr=c(rep(1, 8)), + normal.geno=c(rep(3, 8)), pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, + TRUE, TRUE, TRUE), + pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), + snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), + keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), + homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), + stringAsFactor=FALSE) -## Close Reference GDS file (important) -closefn.gds(gds1KG) + ## The function returns a data frame containing the information about the + ## LOH regions in the specified chromosome + result <- RAIDS:::computeLOHBlocksDNAChr(gdsReference=gds1KG, + chrInfo=chrInfo, snpPos=snpInfo, chr=1L, genoN=0.0001) + head(result) + + ## Close Reference GDS file (important) + closefn.gds(gds1KG) + +} } \author{ From 6175cce6af33bb9d12e5b5c86059b1a2e46818a7 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 31 Aug 2023 19:05:55 -0400 Subject: [PATCH 198/385] Change hard-coded chrInfo to use GenomeInfoDb::seqlengths() instead --- R/processStudy.R | 59 +++++++++++++++++------------------------ man/runExomeAncestry.Rd | 33 ++++++++++------------- man/runRNAAncestry.Rd | 32 ++++++++++------------ 3 files changed, 53 insertions(+), 71 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 0223cdbf2..bedaead18 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2005,22 +2005,17 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' dataRef <- select1KGPop(gds1KG, nbProfiles=2L) #' closefn.gds(gds1KG) #' -#' ## Chromosome length information for hg38 -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, -#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, -#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, -#' 156040895L, 57227415L, 16569L) -#' -#' ## A formal way to get the chromosome length information for hg38 -#' ## library(GenomeInfoDb) -#' ## library(BSgenome.Hsapiens.UCSC.hg38) -#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] -#' -#' \dontrun{ -#' -#' runExomeAncestry(pedStudy=ped, studyDF=studyDF, +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' \dontrun{ +#' +#' runExomeAncestry(pedStudy=ped, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, #' pathGeno=pathGeno, #' pathOut=pathOut, @@ -2030,9 +2025,9 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' syntheticRefDF=dataRef, #' genoSource="snp-pileup") #' -#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) -#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' } #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz @@ -2224,22 +2219,17 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' dataRef <- select1KGPop(gds1KG, nbProfiles=2L) #' closefn.gds(gds1KG) #' -#' ## Chromosome length information for hg38 -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, -#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, -#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, -#' 156040895L, 57227415L, 16569L) +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { #' -#' ## A formal way to get the chromosome length information for hg38 -#' ## library(GenomeInfoDb) -#' ## library(BSgenome.Hsapiens.UCSC.hg38) -#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] #' -#' \dontrun{ +#' \dontrun{ #' -#' runRNAAncestry(pedStudy=ped, studyDF=studyDF, +#' runRNAAncestry(pedStudy=ped, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, #' pathGeno=pathGeno, #' pathOut=pathOut, @@ -2250,9 +2240,10 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' blockTypeID="GeneS.Ensembl.Hsapiens.v86", #' genoSource="snp-pileup") #' -#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) #' +#' } #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index 49c538dc5..d9363540a 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -169,22 +169,17 @@ gds1KG <- snpgdsOpen(fileReferenceGDS) dataRef <- select1KGPop(gds1KG, nbProfiles=2L) closefn.gds(gds1KG) -## Chromosome length information for hg38 -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) - -## A formal way to get the chromosome length information for hg38 -## library(GenomeInfoDb) -## library(BSgenome.Hsapiens.UCSC.hg38) -## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] - -\dontrun{ - - runExomeAncestry(pedStudy=ped, studyDF=studyDF, +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + \dontrun{ + + runExomeAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, @@ -194,9 +189,9 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, syntheticRefDF=dataRef, genoSource="snp-pileup") - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) - + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + } } } diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index 85243f71d..518836e3d 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -174,22 +174,17 @@ gds1KG <- snpgdsOpen(fileReferenceGDS) dataRef <- select1KGPop(gds1KG, nbProfiles=2L) closefn.gds(gds1KG) -## Chromosome length information for hg38 -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) - -## A formal way to get the chromosome length information for hg38 -## library(GenomeInfoDb) -## library(BSgenome.Hsapiens.UCSC.hg38) -## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] - -\dontrun{ - - runRNAAncestry(pedStudy=ped, studyDF=studyDF, +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + \dontrun{ + + runRNAAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, @@ -200,9 +195,10 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, blockTypeID="GeneS.Ensembl.Hsapiens.v86", genoSource="snp-pileup") - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + } } } From 18bd62df55ac91ca7278bcd56f91638b20cb1687 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 31 Aug 2023 20:55:56 -0400 Subject: [PATCH 199/385] Change hard-coded chrInfo to use GenomeInfoDb::seqlengths() instead --- R/processStudy_internal.R | 76 +++++++++++++------------- man/validateEstimateAllelicFraction.Rd | 42 +++++++------- man/validateRunExomeOrRNAAncestry.Rd | 40 +++++++------- 3 files changed, 81 insertions(+), 77 deletions(-) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index fe4f72f6f..66b510696 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -383,27 +383,27 @@ validateComputePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, #' gdsSample <- openfn.gds(file.path(dataDir, #' "GDS_Sample_with_study_demo.gds"), readonly=TRUE) #' -#' ## Get chromosome length information -#' ## Information from BSgenome.Hsapiens.UCSC.hg38 package version 1.4.4 -#' ## Order by chromosomes 1 to 25 -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, -#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, -#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, -#' 156040895L, 57227415L, 16569L) -#' -#' ## The validation should be successful -#' RAIDS:::validateEstimateAllelicFraction(gdsReference=gds1KG, -#' gdsProfile=gdsSample, -#' currentProfile="Sample01", studyID="Synthetic", chrInfo=chrInfo, -#' studyType="DNA", minCov=10L, minProb=0.03, eProb=0.002, cutOffLOH=10, -#' cutOffHomoScore=11, wAR=2, cutOffAR=10, gdsRefAnnot=gds1KG, -#' blockID="1", verbose=FALSE) +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' ## The validation should be successful +#' RAIDS:::validateEstimateAllelicFraction(gdsReference=gds1KG, +#' gdsProfile=gdsSample, +#' currentProfile="Sample01", studyID="Synthetic", chrInfo=chrInfo, +#' studyType="DNA", minCov=10L, minProb=0.03, eProb=0.002, cutOffLOH=10, +#' cutOffHomoScore=11, wAR=2, cutOffAR=10, gdsRefAnnot=gds1KG, +#' blockID="1", verbose=FALSE) +#' +#' ## All GDS file must be closed +#' closefn.gds(gdsfile=gds1KG) +#' closefn.gds(gdsfile=gdsSample) #' -#' ## All GDS file must be closed -#' closefn.gds(gdsfile=gds1KG) -#' closefn.gds(gdsfile=gdsSample) +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom S4Vectors isSingleNumber @@ -1013,25 +1013,27 @@ validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, currentProfil #' Sample.Type=c("DNA", "DNA"), #' Diagnosis=c("Cancer", "Cancer"), Source=c("TCGA", "TCGA")) #' -#' ## Chromosome length information -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, -#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, -#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, -#' 156040895L, 57227415L, 16569L) +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { #' -#' ## Profiles used for synthetic data set -#' syntheticRefDF <- data.frame(sample.id=c("HG00150", "HG00138", "HG00330", -#' "HG00275"), pop.group=c("GBR", "GBR","FIN", "FIN"), -#' superPop=c("EUR", "EUR", "EUR", "EUR"), stringsAsFactors=FALSE) +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] #' -#' ## Returns OL when all parameters are valid -#' RAIDS:::validateRunExomeOrRNAAncestry(pedStudy=ped, studyDF=study, -#' pathProfileGDS=dataDir, pathGeno=dataDir, pathOut=pathOut, -#' fileReferenceGDS=gds1KG, fileReferenceAnnotGDS=gdsAnnot1KG, -#' chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, genoSource="snp-pileup", -#' verbose=FALSE) +#' ## Profiles used for synthetic data set +#' syntheticRefDF <- data.frame(sample.id=c("HG00150", "HG00138", "HG00330", +#' "HG00275"), pop.group=c("GBR", "GBR","FIN", "FIN"), +#' superPop=c("EUR", "EUR", "EUR", "EUR"), stringsAsFactors=FALSE) +#' +#' ## Returns OL when all parameters are valid +#' RAIDS:::validateRunExomeOrRNAAncestry(pedStudy=ped, studyDF=study, +#' pathProfileGDS=dataDir, pathGeno=dataDir, pathOut=pathOut, +#' fileReferenceGDS=gds1KG, fileReferenceAnnotGDS=gdsAnnot1KG, +#' chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, +#' genoSource="snp-pileup", verbose=FALSE) +#' +#' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @encoding UTF-8 diff --git a/man/validateEstimateAllelicFraction.Rd b/man/validateEstimateAllelicFraction.Rd index 06424c570..0764eb59e 100644 --- a/man/validateEstimateAllelicFraction.Rd +++ b/man/validateEstimateAllelicFraction.Rd @@ -99,27 +99,27 @@ gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) gdsSample <- openfn.gds(file.path(dataDir, "GDS_Sample_with_study_demo.gds"), readonly=TRUE) -## Get chromosome length information -## Information from BSgenome.Hsapiens.UCSC.hg38 package version 1.4.4 -## Order by chromosomes 1 to 25 -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) - -## The validation should be successful -RAIDS:::validateEstimateAllelicFraction(gdsReference=gds1KG, - gdsProfile=gdsSample, - currentProfile="Sample01", studyID="Synthetic", chrInfo=chrInfo, - studyType="DNA", minCov=10L, minProb=0.03, eProb=0.002, cutOffLOH=10, - cutOffHomoScore=11, wAR=2, cutOffAR=10, gdsRefAnnot=gds1KG, - blockID="1", verbose=FALSE) - -## All GDS file must be closed -closefn.gds(gdsfile=gds1KG) -closefn.gds(gdsfile=gdsSample) +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + ## The validation should be successful + RAIDS:::validateEstimateAllelicFraction(gdsReference=gds1KG, + gdsProfile=gdsSample, + currentProfile="Sample01", studyID="Synthetic", chrInfo=chrInfo, + studyType="DNA", minCov=10L, minProb=0.03, eProb=0.002, cutOffLOH=10, + cutOffHomoScore=11, wAR=2, cutOffAR=10, gdsRefAnnot=gds1KG, + blockID="1", verbose=FALSE) + + ## All GDS file must be closed + closefn.gds(gdsfile=gds1KG) + closefn.gds(gdsfile=gdsSample) + +} } \author{ diff --git a/man/validateRunExomeOrRNAAncestry.Rd b/man/validateRunExomeOrRNAAncestry.Rd index b6e44ba38..e7a492207 100644 --- a/man/validateRunExomeOrRNAAncestry.Rd +++ b/man/validateRunExomeOrRNAAncestry.Rd @@ -102,25 +102,27 @@ ped <- data.frame(Name.ID=c("Sample_01", "Sample_02"), Sample.Type=c("DNA", "DNA"), Diagnosis=c("Cancer", "Cancer"), Source=c("TCGA", "TCGA")) -## Chromosome length information -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) - -## Profiles used for synthetic data set -syntheticRefDF <- data.frame(sample.id=c("HG00150", "HG00138", "HG00330", - "HG00275"), pop.group=c("GBR", "GBR","FIN", "FIN"), - superPop=c("EUR", "EUR", "EUR", "EUR"), stringsAsFactors=FALSE) - -## Returns OL when all parameters are valid -RAIDS:::validateRunExomeOrRNAAncestry(pedStudy=ped, studyDF=study, - pathProfileGDS=dataDir, pathGeno=dataDir, pathOut=pathOut, - fileReferenceGDS=gds1KG, fileReferenceAnnotGDS=gdsAnnot1KG, - chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, genoSource="snp-pileup", - verbose=FALSE) +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + ## Profiles used for synthetic data set + syntheticRefDF <- data.frame(sample.id=c("HG00150", "HG00138", "HG00330", + "HG00275"), pop.group=c("GBR", "GBR","FIN", "FIN"), + superPop=c("EUR", "EUR", "EUR", "EUR"), stringsAsFactors=FALSE) + + ## Returns OL when all parameters are valid + RAIDS:::validateRunExomeOrRNAAncestry(pedStudy=ped, studyDF=study, + pathProfileGDS=dataDir, pathGeno=dataDir, pathOut=pathOut, + fileReferenceGDS=gds1KG, fileReferenceAnnotGDS=gdsAnnot1KG, + chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, + genoSource="snp-pileup", verbose=FALSE) + +} } \author{ From 8844e8dabfead2574af7fe6dd738cba817ea2803 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 1 Sep 2023 00:46:47 -0400 Subject: [PATCH 200/385] Change hard-coded chrInfo to use GenomeInfoDb::seqlengths() instead --- R/processStudy_internal.R | 77 +++++++++++++++++---------------------- man/runProfileAncestry.Rd | 51 ++++++++++++-------------- man/runWrapperAncestry.Rd | 32 +++++++--------- 3 files changed, 71 insertions(+), 89 deletions(-) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 66b510696..c9e90394b 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2081,37 +2081,31 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' dataRef <- select1KGPop(gdsReference, nbProfiles=2L) #' closefn.gds(gdsReference) #' -#' ## Chromosome length information for hg38 -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, -#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, -#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, -#' 156040895L, 57227415L, 16569L) -#' -#' ## A formal way to get the chromosome length information for hg38 -#' ## library(GenomeInfoDb) -#' ## library(BSgenome.Hsapiens.UCSC.hg38) -#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { #' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] #' +#' studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), +#' study.desc=paste0(studyDF$study.id, " synthetic data"), +#' study.platform=studyDF$study.platform, stringsAsFactors=FALSE) #' -#' studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), -#' study.desc=paste0(studyDF$study.id, " synthetic data"), -#' study.platform=studyDF$study.platform, stringsAsFactors=FALSE) +#' listProfileRef <- dataRef$sample.id +#' profileFile <- file.path(pathProfileGDS, "ex1.gds") #' -#' listProfileRef <- dataRef$sample.id -#' profileFile <- file.path(pathProfileGDS, "ex1.gds") +#' \dontrun{ #' -#' \dontrun{ -#' dir.create(pathProfileGDS) -#' dir.create(pathOut) -#' file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) +#' dir.create(pathProfileGDS) +#' dir.create(pathOut) +#' file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) #' -#' gdsReference <- snpgdsOpen(fileReferenceGDS) -#' gdsRefAnnot <- openfn.gds(fileAnnotGDS) +#' gdsReference <- snpgdsOpen(fileReferenceGDS) +#' gdsRefAnnot <- openfn.gds(fileAnnotGDS) #' -#' RAIDS:::runProfileAncestry(gdsReference=gdsReference, +#' RAIDS:::runProfileAncestry(gdsReference=gdsReference, #' gdsRefAnnot=gdsRefAnnot, #' studyDF=studyDF, currentProfile=ped[1,"Name.ID"], #' pathProfileGDS=pathProfileGDS, @@ -2122,12 +2116,13 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' listProfileRef=listProfileRef, #' studyType="DNA") #' -#' closefn.gds(gdsReference) -#' closefn.gds(gdsRefAnnot) +#' closefn.gds(gdsReference) +#' closefn.gds(gdsRefAnnot) #' -#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) #' +#' } #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz @@ -2393,22 +2388,17 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' dataRef <- select1KGPop(gds1KG, nbProfiles=2L) #' closefn.gds(gds1KG) #' -#' ## Chromosome length information for hg38 -#' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, -#' 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, -#' 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, -#' 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, -#' 156040895L, 57227415L, 16569L) +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { #' -#' ## A formal way to get the chromosome length information for hg38 -#' ## library(GenomeInfoDb) -#' ## library(BSgenome.Hsapiens.UCSC.hg38) -#' ## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] #' -#' \dontrun{ +#' \dontrun{ #' -#' RAIDS:::runWrapperAncestry(pedStudy=ped, studyDF=studyDF, +#' RAIDS:::runWrapperAncestry(pedStudy=ped, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, #' pathGeno=pathGeno, #' pathOut=pathOut, @@ -2419,9 +2409,10 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' studyType="DNA", #' genoSource="snp-pileup") #' -#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) #' +#' } #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/man/runProfileAncestry.Rd b/man/runProfileAncestry.Rd index 9735f26ef..0b4f01045 100644 --- a/man/runProfileAncestry.Rd +++ b/man/runProfileAncestry.Rd @@ -171,37 +171,31 @@ gdsReference <- snpgdsOpen(fileReferenceGDS) dataRef <- select1KGPop(gdsReference, nbProfiles=2L) closefn.gds(gdsReference) -## Chromosome length information for hg38 -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { -## A formal way to get the chromosome length information for hg38 -## library(GenomeInfoDb) -## library(BSgenome.Hsapiens.UCSC.hg38) -## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), + study.desc=paste0(studyDF$study.id, " synthetic data"), + study.platform=studyDF$study.platform, stringsAsFactors=FALSE) + listProfileRef <- dataRef$sample.id + profileFile <- file.path(pathProfileGDS, "ex1.gds") -studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), - study.desc=paste0(studyDF$study.id, " synthetic data"), - study.platform=studyDF$study.platform, stringsAsFactors=FALSE) + \dontrun{ -listProfileRef <- dataRef$sample.id -profileFile <- file.path(pathProfileGDS, "ex1.gds") + dir.create(pathProfileGDS) + dir.create(pathOut) + file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) -\dontrun{ - dir.create(pathProfileGDS) - dir.create(pathOut) - file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) + gdsReference <- snpgdsOpen(fileReferenceGDS) + gdsRefAnnot <- openfn.gds(fileAnnotGDS) - gdsReference <- snpgdsOpen(fileReferenceGDS) - gdsRefAnnot <- openfn.gds(fileAnnotGDS) - - RAIDS:::runProfileAncestry(gdsReference=gdsReference, + RAIDS:::runProfileAncestry(gdsReference=gdsReference, gdsRefAnnot=gdsRefAnnot, studyDF=studyDF, currentProfile=ped[1,"Name.ID"], pathProfileGDS=pathProfileGDS, @@ -212,12 +206,13 @@ profileFile <- file.path(pathProfileGDS, "ex1.gds") listProfileRef=listProfileRef, studyType="DNA") - closefn.gds(gdsReference) - closefn.gds(gdsRefAnnot) + closefn.gds(gdsReference) + closefn.gds(gdsRefAnnot) - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + } } } diff --git a/man/runWrapperAncestry.Rd b/man/runWrapperAncestry.Rd index 463465372..f2b49db29 100644 --- a/man/runWrapperAncestry.Rd +++ b/man/runWrapperAncestry.Rd @@ -178,22 +178,17 @@ gds1KG <- snpgdsOpen(fileReferenceGDS) dataRef <- select1KGPop(gds1KG, nbProfiles=2L) closefn.gds(gds1KG) -## Chromosome length information for hg38 -## chr23 is chrX, chr24 is chrY and chrM is 25 -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) - -## A formal way to get the chromosome length information for hg38 -## library(GenomeInfoDb) -## library(BSgenome.Hsapiens.UCSC.hg38) -## chrInfo <- GenomeInfoDb::seqlengths(Hsapiens)[1:25] - -\dontrun{ - - RAIDS:::runWrapperAncestry(pedStudy=ped, studyDF=studyDF, +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + \dontrun{ + + RAIDS:::runWrapperAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, @@ -204,9 +199,10 @@ chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, studyType="DNA", genoSource="snp-pileup") - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + } } } From 6e4467e4afa44102b261eb6f1df80ca43684a1c0 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 1 Sep 2023 02:03:39 -0400 Subject: [PATCH 201/385] Change hard-coded chrInfo to use GenomeInfoDb::seqlengths() instead in vignette --- vignettes/RAIDS.Rmd | 198 ++++++++++++++++++++++---------------------- 1 file changed, 100 insertions(+), 98 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index cc2d7b6a0..375a019fd 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -309,44 +309,44 @@ gds1KG <- snpgdsOpen(fileGDS) dataRef <- select1KGPop(gds1KG, nbProfiles=2L) closefn.gds(gds1KG) -## Chromosome length information for hg38 -## chrInfo[23] is chrX, chrInfo[24] is chrY and chrM is chrInfo[25] -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) - -############################################################################# -## The path where the Sample GDS files (one per sample) -## will be created needs to be specified. -############################################################################# -pathProfileGDS <- file.path(tempdir(), "exampleDNA", "out.tmp") - -############################################################################# -## The path where the result files will be created needs to -## be specified -############################################################################# -pathOut <- file.path(tempdir(), "exampleDNA", "res.out") - -## Example can only be run if the current directory is in writing mode -if (!dir.exists(file.path(tempdir(), "exampleDNA"))) { - - dir.create(file.path(tempdir(), "exampleDNA")) - dir.create(pathProfileGDS) - dir.create(pathOut) +## GenomeInfoDb and BSgenome are required libraries to run this example +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + ############################################################################# + ## The path where the Sample GDS files (one per sample) + ## will be created needs to be specified. + ############################################################################# + pathProfileGDS <- file.path(tempdir(), "exampleDNA", "out.tmp") + + ############################################################################# + ## The path where the result files will be created needs to + ## be specified + ############################################################################# + pathOut <- file.path(tempdir(), "exampleDNA", "res.out") + + ## Example can only be run if the current directory is in writing mode + if (!dir.exists(file.path(tempdir(), "exampleDNA"))) { + + dir.create(file.path(tempdir(), "exampleDNA")) + dir.create(pathProfileGDS) + dir.create(pathOut) - ######################################################################### - ## The wrapper function generates the synthetic dataset and uses it - ## to selected the optimal parameters before calling the genetic - ## ancestry on the current profiles. - ## All important information, for each step, are saved in - ## multiple output files. - ## The 'genoSource' parameter has 2 options depending on how the - ## SNP pileup files have been generated: - ## "snp-pileup" (snp-pileup software) or "generic" (other software) - ######################################################################### - runExomeAncestry(pedStudy=ped, studyDF=studyDF, + ######################################################################### + ## The wrapper function generates the synthetic dataset and uses it + ## to selected the optimal parameters before calling the genetic + ## ancestry on the current profiles. + ## All important information, for each step, are saved in + ## multiple output files. + ## The 'genoSource' parameter has 2 options depending on how the + ## SNP pileup files have been generated: + ## "snp-pileup" (snp-pileup software) or "generic" (other software) + ######################################################################### + runExomeAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, @@ -355,22 +355,23 @@ if (!dir.exists(file.path(tempdir(), "exampleDNA"))) { chrInfo=chrInfo, syntheticRefDF=dataRef, genoSource="snp-pileup") - list.files(pathOut) - list.files(file.path(pathOut, ped$Name.ID[1])) - - ######################################################################### - ## The file containing the ancestry inference (SuperPop column) and - ## optimal number of PCA component (D column) - ## optimal number of neighbours (K column) - ######################################################################### - resAncestry <- read.csv(file.path(pathOut, + list.files(pathOut) + list.files(file.path(pathOut, ped$Name.ID[1])) + + ######################################################################### + ## The file containing the ancestry inference (SuperPop column) and + ## optimal number of PCA component (D column) + ## optimal number of neighbours (K column) + ######################################################################### + resAncestry <- read.csv(file.path(pathOut, paste0(ped$Name.ID[1], ".Ancestry.csv"))) - print(resAncestry) + print(resAncestry) - ## Remove temporary files created for this demo - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) - unlink(file.path(tempdir(), "exampleDNA"), recursive=TRUE, force=TRUE) + ## Remove temporary files created for this demo + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + unlink(file.path(tempdir(), "exampleDNA"), recursive=TRUE, force=TRUE) + } } @@ -527,44 +528,44 @@ gds1KG <- snpgdsOpen(fileGDS) dataRef <- select1KGPop(gds1KG, nbProfiles=2L) closefn.gds(gds1KG) -## Chromosome length information for hg38 -## chrInfo[23] is chrX, chrInfo[24] is chrY and chrM is chrInfo[25] -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) +## GenomeInfoDb and BSgenome are required libraries to run this example +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { -############################################################################# -## The path where the Sample GDS files (one per sample) -## will be created needs to be specified. -############################################################################# -pathProfileGDS <- file.path(tempdir(), "exampleRNA", "outRNA.tmp") + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] -############################################################################# -## The path where the result files will be created needs to -## be specified -############################################################################# -pathOut <- file.path(tempdir(), "exampleRNA", "resRNA.out") + ############################################################################# + ## The path where the Sample GDS files (one per sample) + ## will be created needs to be specified. + ############################################################################# + pathProfileGDS <- file.path(tempdir(), "exampleRNA", "outRNA.tmp") + + ############################################################################# + ## The path where the result files will be created needs to + ## be specified + ############################################################################# + pathOut <- file.path(tempdir(), "exampleRNA", "resRNA.out") -## Example can only be run if the current directory is in writing mode -if (!dir.exists(file.path(tempdir(), "exampleRNA"))) { + ## Example can only be run if the current directory is in writing mode + if (!dir.exists(file.path(tempdir(), "exampleRNA"))) { - dir.create(file.path(tempdir(), "exampleRNA")) - dir.create(pathProfileGDS) - dir.create(pathOut) + dir.create(file.path(tempdir(), "exampleRNA")) + dir.create(pathProfileGDS) + dir.create(pathOut) - ######################################################################### - ## The wrapper function generates the synthetic dataset and uses it - ## to selected the optimal parameters before calling the genetic - ## ancestry on the current profiles. - ## All important information, for each step, are saved in - ## multiple output files. - ## The 'genoSource' parameter has 2 options depending on how the - ## SNP pileup files have been generated: - ## "snp-pileup" (snp-pileup software) or "generic" (other software) - ######################################################################### - runRNAAncestry(pedStudy=ped, studyDF=studyDF, + ######################################################################### + ## The wrapper function generates the synthetic dataset and uses it + ## to selected the optimal parameters before calling the genetic + ## ancestry on the current profiles. + ## All important information, for each step, are saved in + ## multiple output files. + ## The 'genoSource' parameter has 2 options depending on how the + ## SNP pileup files have been generated: + ## "snp-pileup" (snp-pileup software) or "generic" (other software) + ######################################################################### + runRNAAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, @@ -575,22 +576,23 @@ if (!dir.exists(file.path(tempdir(), "exampleRNA"))) { blockTypeID="GeneS.Ensembl.Hsapiens.v86", genoSource="snp-pileup") - list.files(pathOut) - list.files(file.path(pathOut, ped$Name.ID[1])) - - ######################################################################### - ## The file containing the ancestry inference (SuperPop column) and - ## optimal number of PCA component (D column) - ## optimal number of neighbours (K column) - ######################################################################### - resAncestry <- read.csv(file.path(pathOut, + list.files(pathOut) + list.files(file.path(pathOut, ped$Name.ID[1])) + + ######################################################################### + ## The file containing the ancestry inference (SuperPop column) and + ## optimal number of PCA component (D column) + ## optimal number of neighbours (K column) + ######################################################################### + resAncestry <- read.csv(file.path(pathOut, paste0(ped$Name.ID[1], ".Ancestry.csv"))) - print(resAncestry) + print(resAncestry) - ## Remove temporary files created for this demo - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) - unlink(file.path(tempdir(), "example"), recursive=TRUE, force=TRUE) + ## Remove temporary files created for this demo + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + unlink(file.path(tempdir(), "example"), recursive=TRUE, force=TRUE) + } } ``` From 227eaaf76eb8a363572822632c7851ef1b04a742 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 1 Sep 2023 11:13:18 -0400 Subject: [PATCH 202/385] Change the chromosome info object in some unit tests --- tests/testthat/test-processStudy.R | 12 ++++++------ tests/testthat/test-processStudy_internal.R | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/testthat/test-processStudy.R b/tests/testthat/test-processStudy.R index b8774e080..31805e529 100644 --- a/tests/testthat/test-processStudy.R +++ b/tests/testthat/test-processStudy.R @@ -1923,7 +1923,7 @@ test_that("runExomeAncestry() must return error when pathOut is numeric", { fileGDS <- file.path(pathOut, "ex1_good_small_1KG_GDS.gds") gdsFileAnnot <- file.path(pathOut, "ex1_good_small_1KG_Annot_GDS.gds") - chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L) + chromosome <- c(956422L, 193529L, 295559L, 214555L) studyDF <- data.frame(study.id="MYDATA", study.desc="Description", study.platform="PLATFORM", stringsAsFactors=FALSE) @@ -1945,7 +1945,7 @@ test_that("runExomeAncestry() must return error when pathOut is numeric", { expect_error(runExomeAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathOut, pathGeno=pathOut, pathOut=33, fileReferenceGDS=fileGDS, - fileReferenceAnnotGDS=gdsFileAnnot, chrInfo=chrInfo, + fileReferenceAnnotGDS=gdsFileAnnot, chrInfo=chromosome, syntheticRefDF=syntheticRefDF, genoSource="snp-pileup"), error_message) }) @@ -1957,7 +1957,7 @@ test_that("runExomeAncestry() must return error when fileReferenceGDS is numeric fileGDS <- file.path(pathOut, "ex1_good_small_1KG_GDS.gds") gdsFileAnnot <- file.path(pathOut, "ex1_good_small_1KG_Annot_GDS.gds") - chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L) + chromosome <- c(956422L, 193529L, 295559L, 214555L) studyDF <- data.frame(study.id="MYDATA", study.desc="Description", study.platform="PLATFORM", stringsAsFactors=FALSE) @@ -1979,7 +1979,7 @@ test_that("runExomeAncestry() must return error when fileReferenceGDS is numeric expect_error(runExomeAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathOut, pathGeno=pathOut, pathOut=pathOut, fileReferenceGDS=33, fileReferenceAnnotGDS=gdsFileAnnot, - chrInfo=chrInfo, syntheticRefDF, + chrInfo=chromosome, syntheticRefDF, genoSource="snp-pileup"), error_message) }) @@ -1990,7 +1990,7 @@ test_that("runExomeAncestry() must return error when fileReferenceAnnotGDS is nu fileGDS <- file.path(pathOut, "ex1_good_small_1KG_GDS.gds") gdsFileAnnot <- file.path(pathOut, "ex1_good_small_1KG_Annot_GDS.gds") - chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L) + chromosome <- c(956422L, 193529L, 295559L, 214555L) studyDF <- data.frame(study.id="MYDATA", study.desc="Description", study.platform="PLATFORM", stringsAsFactors=FALSE) @@ -2013,7 +2013,7 @@ test_that("runExomeAncestry() must return error when fileReferenceAnnotGDS is nu expect_error(runExomeAncestry(pedStudy=ped, studyDF=studyDF, pathProfileGDS=pathOut, pathGeno=pathOut, pathOut=pathOut, fileReferenceGDS=fileGDS, fileReferenceAnnotGDS=32, - chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, + chrInfo=chromosome, syntheticRefDF=syntheticRefDF, genoSource="snp-pileup"), error_message) }) diff --git a/tests/testthat/test-processStudy_internal.R b/tests/testthat/test-processStudy_internal.R index 9c3615666..1c24553db 100644 --- a/tests/testthat/test-processStudy_internal.R +++ b/tests/testthat/test-processStudy_internal.R @@ -209,13 +209,13 @@ test_that("validateRunExomeOrRNAAncestry() must return expected results when all "FIN", "FIN"), superPop=c("EUR", "EUR", "EUR", "EUR"), stringsAsFactors=FALSE) - chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L) + chromosome <- c(956422L, 193529L, 295559L, 214555L) result <- RAIDS:::validateRunExomeOrRNAAncestry(pedStudy=ped, studyDF=studyInfo, pathProfileGDS=dataDir, pathGeno=dataDir, pathOut=dataDir, fileReferenceGDS=gdsRefFile, fileReferenceAnnotGDS=gdsRefAnnotFile, - chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, + chrInfo=chromosome, syntheticRefDF=syntheticRefDF, genoSource="snp-pileup", verbose=TRUE) expect_identical(result, 0L) @@ -304,11 +304,11 @@ test_that("validateEstimateAllelicFraction() must return expected results when a gdsSample <- openfn.gds(fileProfileGDS) withr::defer((gdsfmt::closefn.gds(gdsSample)), envir = parent.frame()) - chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L) + chromosome <- c(956422L, 193529L, 295559L, 214555L) result <- RAIDS:::validateEstimateAllelicFraction(gdsReference=gdsRef, gdsProfile=gdsSample, currentProfile="ex1", studyID="MYDATA", - chrInfo=chrInfo, studyType="DNA", minCov=10L, minProb=0.999, + chrInfo=chromosome, studyType="DNA", minCov=10L, minProb=0.999, eProb=0.001, cutOffLOH=-5, cutOffHomoScore=-3, wAR=9, cutOffAR=3, gdsRefAnnot=NULL, blockID=NULL, verbose=FALSE) From 0a252e36f07c7194945c1c9cdd966d037059dcb5 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 1 Sep 2023 15:08:51 -0400 Subject: [PATCH 203/385] Change the chromosome info object in some unit tests --- tests/testthat/test-allelicFraction.R | 8 ++------ tests/testthat/test-allelicFraction_internal.R | 4 ++-- tests/testthat/test-processStudy.R | 7 ------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/tests/testthat/test-allelicFraction.R b/tests/testthat/test-allelicFraction.R index e10de5250..6679efc6a 100644 --- a/tests/testthat/test-allelicFraction.R +++ b/tests/testthat/test-allelicFraction.R @@ -494,15 +494,11 @@ test_that("estimateAllelicFraction() must return valid results", { readonly=FALSE) withr::defer((gdsfmt::closefn.gds(gdsProfile)), envir=parent.frame()) - chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, - 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, - 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, - 156040895L, 57227415L, 16569L) + chromosome <- c(95642L, 93529L, 95559L) result <- estimateAllelicFraction(gdsReference=gds1KG, gdsProfile=gdsProfile, currentProfile="ex1", studyID="MYDATA", - chrInfo=chrInfo, studyType="DNA", minCov=10L, minProb=0.999, + chrInfo=chromosome, studyType="DNA", minCov=10L, minProb=0.999, eProb=0.001, cutOffLOH=-5, cutOffHomoScore=-3, wAR=9, cutOffAR=3, gdsRefAnnot=NULL, blockID=NULL, verbose=FALSE) diff --git a/tests/testthat/test-allelicFraction_internal.R b/tests/testthat/test-allelicFraction_internal.R index 1442c6511..9ef01fb68 100644 --- a/tests/testthat/test-allelicFraction_internal.R +++ b/tests/testthat/test-allelicFraction_internal.R @@ -50,7 +50,7 @@ test_that("computeLOHBlocksDNAChr() must return expected results", { gds1KG <- snpgdsOpen(fileGDS) withr::defer((gdsfmt::closefn.gds(gds1KG)), envir = parent.frame()) - chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, + chromosome <- c(248956422L, 242193529L, 198295559L, 190214555L, 181538259L, 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, 90338345L, 83257441L, 80373285L, 58617616L, 64444167L, 46709983L, 50818468L, @@ -73,7 +73,7 @@ test_that("computeLOHBlocksDNAChr() must return expected results", { stringAsFactor=FALSE) result <- RAIDS:::computeLOHBlocksDNAChr(gdsReference=gds1KG, - chrInfo=chrInfo, snpPos=snpInfo, chr=1L, genoN=0.0001) + chrInfo=chromosome, snpPos=snpInfo, chr=1L, genoN=0.0001) expected <- data.frame(chr=rep(1, 12), start=c(1, snpInfo$snp.pos[seq_len(8)]+1, 6313146, diff --git a/tests/testthat/test-processStudy.R b/tests/testthat/test-processStudy.R index 31805e529..9c186b6fd 100644 --- a/tests/testthat/test-processStudy.R +++ b/tests/testthat/test-processStudy.R @@ -4,13 +4,6 @@ library(RAIDS) library(withr) library(gdsfmt) -chrInfo <- c(248956422L, 242193529L, 198295559L, 190214555L, 181538259L, - 170805979L, 159345973L, 145138636L, 138394717L, 133797422L, - 135086622L, 133275309L, 114364328L, 107043718L, 101991189L, - 90338345L, 83257441L, 80373285L, 58617616L, 64444167L, - 46709983L, 50818468L, 156040895L, 57227415L, 16569L) - - ############################################################################# From 7df6cef246b6eeb0a802830a67e9a5af4bd0e07a Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 1 Sep 2023 15:46:30 -0400 Subject: [PATCH 204/385] Update vignette about Reference GDS --- vignettes/Create_Reference_GDS_File.Rmd | 31 +++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index a1410a7d6..fcf47d2d2 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -100,12 +100,12 @@ size, compressed or not + compression ratio. The mandatory fields are: * **sample.id**: a *character* string (saved in *Str8* format) used as unique identifier for each sample -* **snp.id**: a a *character* string (saved in *Str8* format) used as unique identifier for each SNV * **sample.annot**: a *data.frame* where each row correspond to a sample and containing those columns: * **sex**: a *character* string (saved in *Str8* format) used as identifier of the sex of the sample * **pop.Group**: a *character* string (saved in *Str8* format) representing the sub-population ancestry of the sample (ex:GBR, etc) * **superPop**: a *character* string (saved in *Str8* format) representing the super-population ancestry of the sample (ex:EUR, AFR, EAS, SAS, AMR) * **batch**: an *integer* (saved in *Float64* format) representing the batch of provenance of the sample +* **snp.id**: a a *character* string (saved in *Str8* format) used as unique identifier for each SNV * **snp.chromosome**: an *integer* or *character* (saved in *UInt16 * format) mapping for each chromosome. Integer: numeric values 1-26, mapped in order from 1-22, 23=X, 24=XY (the pseudoautosomal region), 25=Y, 26=M (the mitochondrial probes), and 0 for probes with unknown positions; it does not allow NA. Character: “X”, “XY”, “Y” and “M” can be used here, and a blank string indicating unknown position * **snp.position**: an *integer* (saved in *Int32* format) representing the base position of each SNV on the chromosome, and 0 for unknown position; it does not allow NA. * **snp.allele**: a *character* string (saved as *Str8* format) representing the reference allele and alternative allele for each of the SNVs present in the *snp.id* field @@ -142,10 +142,37 @@ sample.id <- c("HG00243", "HG00150", "HG00149", "HG00246", "HG00138", add.gdsn(node=gdsRefNew, name="sample.id", val=sample.id, storage="string", check=TRUE) -## TODO +## A data frame containing the information about the 10 samples +## (in the same order than in the 'sample.id') is created and added to +## the 'sample.annot' entry +## The data frame must contain those columns: +## 'sex': '1'=male, '2'=female +## 'pop.group': acronym for the population (ex: GBR, CDX, MSL, ASW, etc..) +## 'superPop': acronym for the super-population (ex: AFR, EUR, etc...) +## 'batch': number identifying the batch of provenance +sampleInformation <- data.frame(sex=c("1", "2", "1", "1", "1", + "1", "2", "2", "1", "2"), pop.group=c(rep("GBR", 6), rep("FIN", 4)), + superPop=c(rep("EUR", 10)), batch=rep(0, 10), stringsAsFactors=FALSE) +add.gdsn(node=gdsRefNew, name="sample.annot", val=sampleInformation, + check=TRUE) + +## The identifier of each SNV is added in the 'snp.id' entry +snvID <- c("s29603", "s29605", "s29633", "s29634", "s29635", "s29637", + "s29638", "s29663", "s29664", "s29666", "s29667", "s29686", + "s29687", "s29711", "s29741", "s29742", "s29746", "s29750", + "s29751", "s29753") +add.gdsn(node=gdsRefNew, name="snp.id", val=snvID, + check=TRUE) + +## The chromosome of each SNV is added to the 'snp.chromosome' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvChrom <- c(rep(1, 20)) +add.gdsn(node=gdsRefNew, name="snp.chromosome", val=snvChrom, storage="uint16", + check=TRUE) ## The entry 'sample.ref' is filled with 1 indicating that all 10 ## samples are retained to be used as reference +## The order of the samples is the same than in the 'sample.id' entry add.gdsn(node=gdsRefNew, name="sample.ref", val=rep(1L, 10), storage="bit1", check=TRUE) From 4204bf95d9fb7f28a61e3d7e083a9906fae74974 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 6 Sep 2023 15:33:27 -0400 Subject: [PATCH 205/385] Update GDS Reference vignette --- vignettes/Create_Reference_GDS_File.Rmd | 83 ++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index fcf47d2d2..ef08bd92c 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -95,7 +95,7 @@ closefn.gds(gdsRef) This output lists all variables stored in the *Population Reference GDS file*. At the first level, it stores variables *sample.id*, *snp.id*, etc. The additional information displayed in the braces indicate the data type, -size, compressed or not + compression ratio. +size, compressed or not with compression ratio. The mandatory fields are: @@ -120,7 +120,11 @@ The mandatory fields are:
-This following example shows how to create a *Population GDS Reference file*. +This following example shows how to create a *Population GDS Reference file*. +This example is for demonstration purpose only. A working +*Population GDS Reference file* would have to contain multiple samples from +each continental population and would also have to contain the SNVs from the +entire genome. ```{r createRefGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# @@ -170,13 +174,86 @@ snvChrom <- c(rep(1, 20)) add.gdsn(node=gdsRefNew, name="snp.chromosome", val=snvChrom, storage="uint16", check=TRUE) +## The position on the chromosome of each SNV is added to +## the 'snp.position' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvPos <- c(3467333, 3467428, 3469375, 3469387, 3469502, 3469527, + 3469737, 3471497, 3471565, 3471618) +add.gdsn(node=gdsRefNew, name="snp.position", val=snvPos, storage="int32", + check=TRUE) + +## The allele information of each SNV is added to the 'snp.allele' entry +## The order of the SNVs is the same than in the 'snp.allele' entry +snvAllele <- c("A/G", "C/G", "C/T", "C/T", "T/G", "C/T", + "G/A", "A/G", "G/A", "G/A") +add.gdsn(node=gdsRefNew, name="snp.allele", val=snvAllele, storage="string", + check=TRUE) + +## The allele frequency in the general population (between 0 and 1) of each +## SNV is added to the 'snp.AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.86, 0.01, 0.00, 0.00, 0.01, 0.00, 0.00, 0.00, 0.00, 0.01) +add.gdsn(node=gdsRefNew, name="snp.AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The allele frequency in the East Asian population (between 0 and 1) of each +## SNV is added to the 'snp.EAS_AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.80, 0.00, 0.00, 0.01, 0.00, 0.00, 0.01, 0.00, 0.02, 0.00) +add.gdsn(node=gdsRefNew, name="snp.EAS_AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The allele frequency in the European population (between 0 and 1) of each +## SNV is added to the 'snp.EUR_AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.91, 0.00, 0.01, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03) +add.gdsn(node=gdsRefNew, name="snp.EUR_AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The allele frequency in the African population (between 0 and 1) of each +## SNV is added to the 'snp.AFR_AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.85, 0.04, 0.00, 0.00, 0.00, 0.01, 0.00, 0.00, 0.00, 0.00) +add.gdsn(node=gdsRefNew, name="snp.AFR_AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The allele frequency in the American population (between 0 and 1) of each +## SNV is added to the 'snp.AMR_AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.83, 0.01, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.02) +add.gdsn(node=gdsRefNew, name="snp.AMR_AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The allele frequency in the South Asian population (between 0 and 1) of each +## SNV is added to the 'snp.SAS_AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.89, 0.00, 0.00, 0.00, 0.05, 0.00, 0.00, 0.01, 0.00, 0.00) +add.gdsn(node=gdsRefNew, name="snp.SAS_AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The genotype of each SNV for each sample is added to the 'genotype' entry +## The genotype correspond to the number of A alleles +## The rows represent the SNVs is the same order than in 'snp.id' entry +## The columns represent the samples is the same order than in 'sample.id' entry +genotypeInfo <- matrix(data=c(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 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, + 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, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), byrow=TRUE) +add.gdsn(node=gdsRefNew, name="genotype", val=genotypeInfo, + storage="sbit2", check=TRUE) + ## The entry 'sample.ref' is filled with 1 indicating that all 10 ## samples are retained to be used as reference ## The order of the samples is the same than in the 'sample.id' entry add.gdsn(node=gdsRefNew, name="sample.ref", val=rep(1L, 10), storage="bit1", check=TRUE) - ## Show the file format print(gdsRefNew) From 19f88a8cb568d187002a5ebfee91cda7eb75de88 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 6 Sep 2023 17:09:32 -0400 Subject: [PATCH 206/385] update GDS reference vignette --- vignettes/Create_Reference_GDS_File.Rmd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index ef08bd92c..88de63da4 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -244,9 +244,10 @@ genotypeInfo <- matrix(data=c(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 0, 0, 0, 0), byrow=TRUE) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), nrow=10, + byrow=TRUE) add.gdsn(node=gdsRefNew, name="genotype", val=genotypeInfo, - storage="sbit2", check=TRUE) + storage="bit2", check=TRUE) ## The entry 'sample.ref' is filled with 1 indicating that all 10 ## samples are retained to be used as reference From 224bf58e8fcc29f73221aae226b58b3c23acb8f8 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 6 Sep 2023 17:12:59 -0400 Subject: [PATCH 207/385] update GDS reference vignette --- vignettes/Create_Reference_GDS_File.Rmd | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 88de63da4..c84853fa4 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -236,16 +236,15 @@ add.gdsn(node=gdsRefNew, name="snp.SAS_AF", val=snvAF, storage="packedreal24", ## The rows represent the SNVs is the same order than in 'snp.id' entry ## The columns represent the samples is the same order than in 'sample.id' entry genotypeInfo <- matrix(data=c(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 0, 0, 0, 0, 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, - 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, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), nrow=10, - byrow=TRUE) + 0, 0, 0, 0, 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, + 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, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), nrow=10, byrow=TRUE) add.gdsn(node=gdsRefNew, name="genotype", val=genotypeInfo, storage="bit2", check=TRUE) From cfe619e190a3064775641a354e9914c21693c70c Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 6 Sep 2023 17:44:40 -0400 Subject: [PATCH 208/385] Remove one GDS file from extdata and adapt examples to use updated 1KG_demo.gds file instead --- R/process1KG.R | 2 +- inst/extdata/1KG_Demo.gds | Bin 3148 -> 3379 bytes inst/extdata/1KG_Demo_with_sampleREF.gds | Bin 3379 -> 0 bytes man/getRef1KGPop.Rd | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 inst/extdata/1KG_Demo_with_sampleREF.gds diff --git a/R/process1KG.R b/R/process1KG.R index 8a9d6b65e..7fed4feb1 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -717,7 +717,7 @@ addRef2GDS1KG <- function(fileNameGDS, filePart) { #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## Open existing demo 1K GDS file with "sample.ref" node -#' nameFileGDS <- file.path(dataDir, "1KG_Demo_with_sampleREF.gds") +#' nameFileGDS <- file.path(dataDir, "1KG_Demo.gds") #' fileGDS <- snpgdsOpen(nameFileGDS) #' #' ## Extract super population information for the 1KG profiles diff --git a/inst/extdata/1KG_Demo.gds b/inst/extdata/1KG_Demo.gds index 5338fcaee199eeeb92dac45aadf561b17a501d37..dbb7375e7fc49ce333c0958d1e6d70c508052b4a 100644 GIT binary patch delta 396 zcmX>ju~}+@l42JV0}wz+76y)E&ZU0e82NxgjK`fz#h=zXZgl?0$~1##vl*KNlfEWM zF#|ILC(~C3Wgv^wrNmGOBqZu`EJ1*)I5D>%CsnT~HI0M)bM4&8n`=4z8F>vEA<&2s z2q)jSG5oxdB8lFmM5}2AIX{8XCkL>=?}K z3c^6PqZ%jPL{p(jV+09OCK8gl42qg0}wz+76y)E&ZU0e77%Q6n^&F@lVqG*A%%E;wZEW2ArU(An3t!1c}Ch=;t_61p$UsL=ImFLi4y1OvD0Z?D%`lG-}vUZ+EdciN36{ zw_RKBUYTC^wA|coMk-Y5@^uz4-Oq>o-ZY zs>#*MP=!lf;9efOiv>2R?r~G83+&^eHWt|LW-4>nS>OPROX$m*oyM~}mtXrVvi{z! z=<_L;V>eA3WPIPNgUR7P5Jlqad*#>Ykni{W=B1DBY)va$plTapX#3jkxX7)F~Kx2bK`t($kIz@(TEgsj|#MnV>?OUz$9?p5~r8TmD(c;6dB4**=3bY=6g&5 zA^EsLJpe7|tCdp4s+0^>IkJlz+zqf$!o! z3kILvMbl8%JoYbGSe|s%Sh4+Z1*8pB;ARIDQs6{78jVGxvW>}hT((DKJ0aUi*-pv! zsBDkP_K6L_>Qr!dXC-(nxL2ZC#+vHZB6!?xZC1?4g=%HhRQCi|yqhU#t(rzPQ!yWg zKDl+czuhqZ3wmuiFT)ZSg(rBs{$uju2vRHuZ#J@A)GezgoYQN1WTmQ?jKdgcpdvyp zz|F<;V$I*UNB*WU&_KnJ&qb~*{Zv*4G zLSyIEAhXLgi!&CV%c`@HFYMVY+|?(dwqZl@^gxvH)6$B0t#Pk)#A{7>tx2yn<+YBA z{cVVGk*@&f?Qs3Z@uvnVJJ;bxA^L@F9Q=~#ldp)r<8t#Gq7T0%`jm@00~>75&`v*| z<`UNuT++>w;QndVWZeC>$r}N>bC{kSp{0G)dw{+_L%}SmP+Z(Llm-4S_0eyL1vy8B z!X<3zJ9}t!o_>nZ2UChNL8vOz19<2n9rOO|HG*H1blWrv1zuCch)*aIPLcFe*lT_My>z= diff --git a/man/getRef1KGPop.Rd b/man/getRef1KGPop.Rd index 544c37fc2..19871ae85 100644 --- a/man/getRef1KGPop.Rd +++ b/man/getRef1KGPop.Rd @@ -39,7 +39,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## Open existing demo 1K GDS file with "sample.ref" node -nameFileGDS <- file.path(dataDir, "1KG_Demo_with_sampleREF.gds") +nameFileGDS <- file.path(dataDir, "1KG_Demo.gds") fileGDS <- snpgdsOpen(nameFileGDS) ## Extract super population information for the 1KG profiles From 0b451751e0a835c06c9ab5e1680068b8317abc00 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 6 Sep 2023 21:20:05 -0400 Subject: [PATCH 209/385] Remove one GDS file from extdata and adapt examples to use updated 1KG_demo.gds file instead --- R/processStudy_internal.R | 12 ++++++------ R/synthetic.R | 4 ++-- R/synthetic_internal.R | 2 +- R/tools_internal.R | 2 +- inst/extdata/gds1KG.gds | Bin 3238 -> 0 bytes man/select1KGPop.Rd | 4 ++-- man/validateAdd1KG2SampleGDS.Rd | 2 +- man/validateComputeAncestryFromSyntheticFile.Rd | 2 +- man/validateCreateStudy2GDS1KG.Rd | 2 +- man/validateEstimateAllelicFraction.Rd | 2 +- man/validateGDSClass.Rd | 2 +- man/validatePruningSample.Rd | 2 +- man/validateRunExomeOrRNAAncestry.Rd | 2 +- man/validateSyntheticGeno.Rd | 2 +- 14 files changed, 20 insertions(+), 20 deletions(-) delete mode 100644 inst/extdata/gds1KG.gds diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index c9e90394b..2ee7c4c79 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -75,7 +75,7 @@ #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG GDS file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) #' #' ## The validation should be successful #' RAIDS:::validatePruningSample(gdsReference=gds1KG, method="corr", @@ -377,7 +377,7 @@ validateComputePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG Population Reference GDS Demo file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) #' #' ## The GDS Sample (opened) #' gdsSample <- openfn.gds(file.path(dataDir, @@ -515,7 +515,7 @@ validateEstimateAllelicFraction <- function(gdsReference, gdsProfile, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## Demo 1KG Population Reference GDS file -#' gds1KG <- file.path(dataDir, "gds1KG.gds") +#' gds1KG <- file.path(dataDir, "1KG_Demo.gds") #' #' ## The data.frame containing the information about the study #' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" @@ -675,7 +675,7 @@ validateCreateStudy2GDS1KG <- function(pathGeno, pedStudy, fileNameGDS, batch, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG Population Reference GDS demo file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) #' #' ## The Profile GDS (opened) #' gdsSample <- openfn.gds(file.path(dataDir, @@ -890,7 +890,7 @@ validateComputePCARefSample <- function(gdsProfile, currentProfile, studyIDRef, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG Population Reference GDS demo file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) #' #' ## The validatiion should be successful #' RAIDS:::validateAdd1KG2SampleGDS(gdsReference=gds1KG, @@ -1003,7 +1003,7 @@ validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, currentProfil #' stringsAsFactors = FALSE) #' #' ## Population Reference GDS demo file -#' gds1KG <- file.path(dataDir, "gds1KG.gds") +#' gds1KG <- file.path(dataDir, "1KG_Demo.gds") #' #' gdsAnnot1KG <- file.path(dataDir, "gdsAnnot1KG.gds") #' diff --git a/R/synthetic.R b/R/synthetic.R index 1a2ae1d7b..d80a4e1ee 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -38,8 +38,8 @@ #' ## Open 1KG GDS Demo file #' ## This file only one superpopulation (for demonstration purpose) #' dataDir <- system.file("extdata", package="RAIDS") -#' fileGDS <- file.path(dataDir, "gds1KG.gds") -#' gdsFileOpen <- openfn.gds(fileGDS) +#' fileGDS <- file.path(dataDir, "1KG_Demo.gds") +#' gdsFileOpen <- openfn.gds(fileGDS, readonly=TRUE) #' #' ## Extract a selected number of random samples #' ## for each subcontinental population diff --git a/R/synthetic_internal.R b/R/synthetic_internal.R index 46eeb526b..92b0f77a8 100644 --- a/R/synthetic_internal.R +++ b/R/synthetic_internal.R @@ -42,7 +42,7 @@ #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG GDS file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) #' #' ## The 1KG GDS Annotation file (opened) #' gds1KGAnnot <- openfn.gds(file.path(dataDir, "gdsAnnot1KG.gds"), diff --git a/R/tools_internal.R b/R/tools_internal.R index c8885197c..aca2a2895 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -20,7 +20,7 @@ #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG GDS file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) #' #' ## The validation should be successful #' RAIDS:::validateGDSClass(gds=gds1KG, name="gds") diff --git a/inst/extdata/gds1KG.gds b/inst/extdata/gds1KG.gds deleted file mode 100644 index 338fb0240c597fc7804fac4912d18d3fd6bd2bf4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3238 zcmbVOU1%It6h1Sv$?m3U8cma^F+Unhf5dgRrfKsMT(_G@wQ1OHAVrEDvy*OQe}

*ac5LrI{iYVbbfY+`ka{s|#5x$2ymaxEZjC#M`0e%gHrKi5vH!RO zeYT`u(D7uJ9sP zj#Yn#_i^_SbWdW2o!cLrpWalOy1Ji{Qdsf^_VG{)6Wks4RAto!7K+D-}lBqZsboKBk}aT{;NJ1`=fMY6VbwmO+EbdH*5%+(Xx!iwzRRLN zIXKi2H@I8;_rNzqpMOjA6Su416Mgyv(HGpVb5pMn4Re#N!QonKg(qjZWwb1}*`Q@v zFNiVsotFadjU4 z4JqLnbLYYae91gGw64wjyJ&2VuBYgeNt&M_>uuV44Lq!}7ug0!&$YR*1K}|bl|0FbNyD^ZD4IuTB$_udPIR#sVAm{rduD&%Sx~JatC1y=ytgIDg$9 z;qDRWo{VuecNC3xQ*J$0#g|3`2^xHDJj#kxcE@4tKoDUFcOp@tpB$A6YEGHotsKKY z4g?Y4VsSj_6OM!~fPm~VhD&6q>%J!pxwpbl0Uu1k<7E*g)xX4-RPtyejohUEqnFS0 zCT*i)mCe*j@o{0H2^@z(0tZh5*X`kqYPHtbBSA62u**)nYO%j3BoOZNFsKKhrBc0C zsoAxPDU;*E4uiV^wrciDW2IKzFZsoV9ENrQYLv@n*_5N~zY8d$%*@E%u$)c2BS2hEO@Nu1C=mBbGvM(k5Cy9V@T7=wFAs8k6rl{#Cmty*%($-8g~d(|@Q z^EC_E?GxgYHSDhAC8M!a@}k8dP!hM-f6kp7MSbGyET38`8@AokRWuq#YPoJy%zpuc CvNL7? diff --git a/man/select1KGPop.Rd b/man/select1KGPop.Rd index 7369badd6..fc4db1e17 100644 --- a/man/select1KGPop.Rd +++ b/man/select1KGPop.Rd @@ -48,8 +48,8 @@ nbProfiles <- 5L ## Open 1KG GDS Demo file ## This file only one superpopulation (for demonstration purpose) dataDir <- system.file("extdata", package="RAIDS") -fileGDS <- file.path(dataDir, "gds1KG.gds") -gdsFileOpen <- openfn.gds(fileGDS) +fileGDS <- file.path(dataDir, "1KG_Demo.gds") +gdsFileOpen <- openfn.gds(fileGDS, readonly=TRUE) ## Extract a selected number of random samples ## for each subcontinental population diff --git a/man/validateAdd1KG2SampleGDS.Rd b/man/validateAdd1KG2SampleGDS.Rd index 5ee82b863..922bf8885 100644 --- a/man/validateAdd1KG2SampleGDS.Rd +++ b/man/validateAdd1KG2SampleGDS.Rd @@ -37,7 +37,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The 1KG Population Reference GDS demo file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) ## The validatiion should be successful RAIDS:::validateAdd1KG2SampleGDS(gdsReference=gds1KG, diff --git a/man/validateComputeAncestryFromSyntheticFile.Rd b/man/validateComputeAncestryFromSyntheticFile.Rd index 4b6ae5294..50c488ad2 100644 --- a/man/validateComputeAncestryFromSyntheticFile.Rd +++ b/man/validateComputeAncestryFromSyntheticFile.Rd @@ -101,7 +101,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The 1KG Population Reference GDS demo file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) ## The Profile GDS (opened) gdsSample <- openfn.gds(file.path(dataDir, diff --git a/man/validateCreateStudy2GDS1KG.Rd b/man/validateCreateStudy2GDS1KG.Rd index e40050792..bc2f3eeaf 100644 --- a/man/validateCreateStudy2GDS1KG.Rd +++ b/man/validateCreateStudy2GDS1KG.Rd @@ -68,7 +68,7 @@ This function validates the input parameters for the dataDir <- system.file("extdata", package="RAIDS") ## Demo 1KG Population Reference GDS file -gds1KG <- file.path(dataDir, "gds1KG.gds") +gds1KG <- file.path(dataDir, "1KG_Demo.gds") ## The data.frame containing the information about the study ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" diff --git a/man/validateEstimateAllelicFraction.Rd b/man/validateEstimateAllelicFraction.Rd index 0764eb59e..5f82f5793 100644 --- a/man/validateEstimateAllelicFraction.Rd +++ b/man/validateEstimateAllelicFraction.Rd @@ -93,7 +93,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The 1KG Population Reference GDS Demo file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) ## The GDS Sample (opened) gdsSample <- openfn.gds(file.path(dataDir, diff --git a/man/validateGDSClass.Rd b/man/validateGDSClass.Rd index efbc4173d..5f609e2e5 100644 --- a/man/validateGDSClass.Rd +++ b/man/validateGDSClass.Rd @@ -27,7 +27,7 @@ the \link[gdsfmt]{gds.class} class. dataDir <- system.file("extdata", package="RAIDS") ## The 1KG GDS file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) ## The validation should be successful RAIDS:::validateGDSClass(gds=gds1KG, name="gds") diff --git a/man/validatePruningSample.Rd b/man/validatePruningSample.Rd index b0aef51df..8f3863f41 100644 --- a/man/validatePruningSample.Rd +++ b/man/validatePruningSample.Rd @@ -102,7 +102,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The 1KG GDS file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) ## The validation should be successful RAIDS:::validatePruningSample(gdsReference=gds1KG, method="corr", diff --git a/man/validateRunExomeOrRNAAncestry.Rd b/man/validateRunExomeOrRNAAncestry.Rd index e7a492207..ae439a75d 100644 --- a/man/validateRunExomeOrRNAAncestry.Rd +++ b/man/validateRunExomeOrRNAAncestry.Rd @@ -92,7 +92,7 @@ study <- data.frame(study.id = "MYDATA", stringsAsFactors = FALSE) ## Population Reference GDS demo file -gds1KG <- file.path(dataDir, "gds1KG.gds") +gds1KG <- file.path(dataDir, "1KG_Demo.gds") gdsAnnot1KG <- file.path(dataDir, "gdsAnnot1KG.gds") diff --git a/man/validateSyntheticGeno.Rd b/man/validateSyntheticGeno.Rd index 6d7aba4b9..1a18251cd 100644 --- a/man/validateSyntheticGeno.Rd +++ b/man/validateSyntheticGeno.Rd @@ -63,7 +63,7 @@ This function validates the input parameters for the dataDir <- system.file("extdata", package="RAIDS") ## The 1KG GDS file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "gds1KG.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) ## The 1KG GDS Annotation file (opened) gds1KGAnnot <- openfn.gds(file.path(dataDir, "gdsAnnot1KG.gds"), From 13817551b68cace9d9cb761092e6afa5f1580426 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 7 Sep 2023 13:07:52 -0400 Subject: [PATCH 210/385] Remove one GDS file from extdata and adapt unit tests to use updated 1KG_Test.gds file in fixtures instead --- inst/extdata/tests/1KG_Test.gds | Bin 3148 -> 0 bytes tests/testthat/fixtures/1KG_Test.gds | Bin 3148 -> 3299 bytes tests/testthat/test-processStudy.R | 18 +++++----- tests/testthat/test-synthetic.R | 52 +++++++++++++-------------- 4 files changed, 33 insertions(+), 37 deletions(-) delete mode 100644 inst/extdata/tests/1KG_Test.gds diff --git a/inst/extdata/tests/1KG_Test.gds b/inst/extdata/tests/1KG_Test.gds deleted file mode 100644 index 5338fcaee199eeeb92dac45aadf561b17a501d37..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3148 zcmbVOO>7%Q6nZ z{_BAF5JZ3r4k;syjBXq_^HDfm|*e$FeTb!f@>6}H+b3b?KYlHU@awl z+qLn<<*C(BOXv15QlV0>hbQ=WN5Ki=G4<+9Z}PHX)DE6bVl5?%ifz1e=h(;hNwuoU z)yGi9D)oXpd20(7Y*Ia;Q>hp1=dCs_IG{6CdD*z&AWu(WEhPs{XnS#S`Mc!mmk&~J z<+Z?Wnl{Av{tt$7BYz`{MC*V5_tbFYuf_FCUq9NIQe2>F8)j(x+II1&PP9GQk+!Eg z)V8}LZBKWo?U|0WjdZAOv?Fa}ZDVqRPfmN}2(= zhZi#D_T!)rL4?1NMntm%1JMt6Mk0e|Gz?=35ZN;0W|ZQfk=W@z+;<%h~E~#Ibq{I-X!^`5qdf>e!=EvchR+F zc%k5h;tyAT&RrZu@)C9DOJzIn)GAiJH!(LedscjNoX3_A0d5XJF^j!6ol2!sDLJO) zn33ZlIgZP5LXMMiJS@i}a(sDBur>t3y>SzKEa*20d-k##)*^ZIuy!3cd77s4E7kL&7be1-(4d9tM@ zveplv`1C-Q@u#JiHoT1C9WuOe!<#U?Ny9rV{OgN-QLg}JcWA#1{_-J$S{DT6Z*1ex zZK7{}Ao_{>{kue8{YdmJcl87u9GnQBd}*4y8P0N_ZuTs%PpT&4-5;2|7NbW8>6KAB zwVV3((Y@0YFOUkwi#vewgxjTl`UANj&!|v@L;(GK2aV0pFG;#ONwax!KcThvG**}! zK(B2hwt-pQVN4k9PifE*70Q&13v9h&(f4OG=vWiVOn=VfLi?Y?h0axIxkUc~_C6y+ diff --git a/tests/testthat/fixtures/1KG_Test.gds b/tests/testthat/fixtures/1KG_Test.gds index 5338fcaee199eeeb92dac45aadf561b17a501d37..21c188e30dd9620c299b4399800af4731aaea128 100644 GIT binary patch delta 204 zcmX>j@mO+#l42JV0}wz+76y)E&ZU0e82NxgjK`fz#h=zXZgl?0%CwGWvl*KNlfEWM zF#|ILC(~C3Wgv^wrNmGOBqZu`EJ1*)I5D>%CsnT~HI0M)bM4&8n`=4FGxK_Z6f}Sc z1_tGc7e#zi5@*RVvmbe!BG1Ucbl5qOg$pRddE{^nj|z|h(OL^qEde4LKm-E=NDAy$ QhX2f_U=av0IfO$K0QDUzt^fc4 delta 68 zcmaDXc}8M_l42qg0}wz+76y)E&ZU0e7 Date: Thu, 7 Sep 2023 13:31:30 -0400 Subject: [PATCH 211/385] Remove unused Sample_Info_Test.RDS in inst directory --- inst/extdata/tests/Sample_Info_Test.RDS | Bin 189 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 inst/extdata/tests/Sample_Info_Test.RDS diff --git a/inst/extdata/tests/Sample_Info_Test.RDS b/inst/extdata/tests/Sample_Info_Test.RDS deleted file mode 100644 index 7ba00d9ded2d4ef6bf78b3f1d67db45c4ec463e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 189 zcmV;u07CyCiwFP!0000028-ZgU|?WoU||B1tUx9MYiNj@t_6@M4B`N>01z`WurP1} zX^!B;+=84`14A@%u7Jdn%+$P+cnlflaMxfoA(j9aM`v_{{fp8Q^YSxO7{E?}i?ik> z=B5@y6|+JG+5LcmdY&#Yu5)5B5|fvwr%PsHdR~5UW-(NNEjYilC^;3~ rvgDk^;$n2Kr6iUl>ZKI{twdAKS(IO{hwMIVq4W;`>AN?BVF3UDJHk-Q From af1292fcaab82f4c10d3c780069db29c923ee5bd Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 7 Sep 2023 17:25:06 -0400 Subject: [PATCH 212/385] Remove 1KG_Demo.gds and add PopulationReferenceDemo.gds --- R/gdsWrapper.R | 4 +- R/process1KG.R | 6 +- R/process1KG_internal.R | 4 +- R/processStudy_internal.R | 18 ++- R/synthetic.R | 2 +- R/synthetic_internal.R | 5 +- R/tools.R | 3 +- R/tools_internal.R | 3 +- ...G_Demo.gds => PopulationReferenceDemo.gds} | Bin .../create_PopulationReferenceDemoGDS.R | 125 ++++++++++++++++++ man/appendGDSgenotype.Rd | 2 +- man/generateGDSgenotype.Rd | 2 +- man/generatePhase1KG2GDS.Rd | 2 +- man/getRef1KGPop.Rd | 2 +- man/identifyRelative.Rd | 2 +- man/prepPedSynthetic1KG.Rd | 2 +- man/pruning1KGbyChr.Rd | 2 +- man/select1KGPop.Rd | 2 +- man/snvListVCF.Rd | 3 +- man/validateAdd1KG2SampleGDS.Rd | 3 +- man/validateAddStudy1Kg.Rd | 2 +- ...alidateComputeAncestryFromSyntheticFile.Rd | 3 +- man/validateCreateStudy2GDS1KG.Rd | 2 +- man/validateEstimateAllelicFraction.Rd | 3 +- man/validateGDSClass.Rd | 3 +- man/validateGenerateGDS1KG.Rd | 2 +- man/validatePruningSample.Rd | 3 +- man/validateRunExomeOrRNAAncestry.Rd | 2 +- man/validateSyntheticGeno.Rd | 3 +- vignettes/Create_Reference_GDS_File.Rmd | 4 +- vignettes/RAIDS.Rmd | 110 ++++++++------- 31 files changed, 241 insertions(+), 88 deletions(-) rename inst/extdata/{1KG_Demo.gds => PopulationReferenceDemo.gds} (100%) create mode 100644 inst/extdata/create_PopulationReferenceDemoGDS.R diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 56ac637c4..6e936e774 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -126,7 +126,7 @@ generateGDSSNPinfo <- function(gdsReference, fileFreq, verbose) { #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The RDS file containing the pedigree information -#' pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +#' pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") #' #' ## The RDS file containing the indexes of the retained SNPs #' snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") @@ -250,7 +250,7 @@ generateGDSgenotype <- function(gds, pathGeno, fileSNPsRDS, listSamples, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The RDS file containing the pedigree information -#' pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +#' pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") #' #' ## The RDS file containing the indexes of the retained SNPs #' snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") diff --git a/R/process1KG.R b/R/process1KG.R index 7fed4feb1..f8a6da09c 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -374,7 +374,7 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The RDS file containing the pedigree information -#' pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +#' pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") #' #' ## The RDS file containing the indexes of the retained SNPs #' snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") @@ -504,7 +504,7 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## Open existing demo Reference GDS file -#' fileGDS <- file.path(dataDir, "1KG_Demo.gds") +#' fileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") #' tmpGDS <- snpgdsOpen(fileGDS) #' #' ## Temporary output files @@ -717,7 +717,7 @@ addRef2GDS1KG <- function(fileNameGDS, filePart) { #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## Open existing demo 1K GDS file with "sample.ref" node -#' nameFileGDS <- file.path(dataDir, "1KG_Demo.gds") +#' nameFileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") #' fileGDS <- snpgdsOpen(nameFileGDS) #' #' ## Extract super population information for the 1KG profiles diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index 235f918be..178deb04b 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -63,7 +63,7 @@ #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG Population Reference GDS demo file (opened) -#' gds1KG <- snpgdsOpen(file.path(dataDir, "1KG_Demo.gds")) +#' gds1KG <- snpgdsOpen(file.path(dataDir, "PopulationReferenceDemo.gds")) #' #' ## The prefix of the RDS file to be created and containing the pruned SNVs #' outPrefix <- file.path(tempdir(), "Pruned_Demo_Reference") @@ -554,7 +554,7 @@ validatePrepPed1KG <- function(filePed, pathGeno, batch) { #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The RDS file containing the pedigree information -#' pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +#' pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") #' #' ## The RDS file containing the indexes of the retained SNPs #' snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 2ee7c4c79..7d7f51df3 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -75,7 +75,8 @@ #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG GDS file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, +#' "PopulationReferenceDemo.gds"), readonly=TRUE) #' #' ## The validation should be successful #' RAIDS:::validatePruningSample(gdsReference=gds1KG, method="corr", @@ -377,7 +378,8 @@ validateComputePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG Population Reference GDS Demo file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, +#' "PopulationReferenceDemo.gds"), readonly=TRUE) #' #' ## The GDS Sample (opened) #' gdsSample <- openfn.gds(file.path(dataDir, @@ -515,7 +517,7 @@ validateEstimateAllelicFraction <- function(gdsReference, gdsProfile, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## Demo 1KG Population Reference GDS file -#' gds1KG <- file.path(dataDir, "1KG_Demo.gds") +#' gds1KG <- file.path(dataDir, "PopulationReferenceDemo.gds") #' #' ## The data.frame containing the information about the study #' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" @@ -675,7 +677,8 @@ validateCreateStudy2GDS1KG <- function(pathGeno, pedStudy, fileNameGDS, batch, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG Population Reference GDS demo file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, +#' "PopulationReferenceDemo.gds"), readonly=TRUE) #' #' ## The Profile GDS (opened) #' gdsSample <- openfn.gds(file.path(dataDir, @@ -890,7 +893,8 @@ validateComputePCARefSample <- function(gdsProfile, currentProfile, studyIDRef, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG Population Reference GDS demo file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, +#' "PopulationReferenceDemo.gds"), readonly=TRUE) #' #' ## The validatiion should be successful #' RAIDS:::validateAdd1KG2SampleGDS(gdsReference=gds1KG, @@ -1003,7 +1007,7 @@ validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, currentProfil #' stringsAsFactors = FALSE) #' #' ## Population Reference GDS demo file -#' gds1KG <- file.path(dataDir, "1KG_Demo.gds") +#' gds1KG <- file.path(dataDir, "PopulationReferenceDemo.gds") #' #' gdsAnnot1KG <- file.path(dataDir, "gdsAnnot1KG.gds") #' @@ -1245,7 +1249,7 @@ validateStudyDataFrameParameter <- function(studyDF) { #' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") -#' fileReferenceGDS <- file.path(dataDir, "1KG_Demo.gds") +#' fileReferenceGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") #' gds1KG <- snpgdsOpen(fileReferenceGDS) #' #' ## Path to demo Profile GDS file diff --git a/R/synthetic.R b/R/synthetic.R index d80a4e1ee..86e9c69bb 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -38,7 +38,7 @@ #' ## Open 1KG GDS Demo file #' ## This file only one superpopulation (for demonstration purpose) #' dataDir <- system.file("extdata", package="RAIDS") -#' fileGDS <- file.path(dataDir, "1KG_Demo.gds") +#' fileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") #' gdsFileOpen <- openfn.gds(fileGDS, readonly=TRUE) #' #' ## Extract a selected number of random samples diff --git a/R/synthetic_internal.R b/R/synthetic_internal.R index 92b0f77a8..70a331e4f 100644 --- a/R/synthetic_internal.R +++ b/R/synthetic_internal.R @@ -42,7 +42,8 @@ #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG GDS file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, +#' "PopulationReferenceDemo.gds"), readonly=TRUE) #' #' ## The 1KG GDS Annotation file (opened) #' gds1KGAnnot <- openfn.gds(file.path(dataDir, "gdsAnnot1KG.gds"), @@ -393,7 +394,7 @@ validateComputeSyntheticRoc <- function(matKNN, matKNNAncestryColumn, pedCall, #' #' ## The open 1KG GDS file is required (this is a demo file) #' dataDir <- system.file("extdata", package="RAIDS") -#' gds_1KG_file <- file.path(dataDir, "1KG_Demo.gds") +#' gds_1KG_file <- file.path(dataDir, "PopulationReferenceDemo.gds") #' gds1KG <- openfn.gds(gds_1KG_file) #' #' fileSampleGDS <- file.path(dataDir, "GDS_Sample_with_study_demo.gds") diff --git a/R/tools.R b/R/tools.R index 859ef319e..90f546264 100644 --- a/R/tools.R +++ b/R/tools.R @@ -31,7 +31,8 @@ #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## Demo 1KG Reference GDS file -#' fileGDS <- openfn.gds(file.path(dataDir, "1KG_Demo.gds")) +#' fileGDS <- openfn.gds(file.path(dataDir, +#' "PopulationReferenceDemo.gds")) #' #' ## Output VCF file that will be created (temporary) #' vcfFile <- file.path(tempdir(), "Demo_TMP_01.vcf") diff --git a/R/tools_internal.R b/R/tools_internal.R index aca2a2895..be13e4be6 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -20,7 +20,8 @@ #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG GDS file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +#' gds1KG <- openfn.gds(file.path(dataDir, +#' "PopulationReferenceDemo.gds"), readonly=TRUE) #' #' ## The validation should be successful #' RAIDS:::validateGDSClass(gds=gds1KG, name="gds") diff --git a/inst/extdata/1KG_Demo.gds b/inst/extdata/PopulationReferenceDemo.gds similarity index 100% rename from inst/extdata/1KG_Demo.gds rename to inst/extdata/PopulationReferenceDemo.gds diff --git a/inst/extdata/create_PopulationReferenceDemoGDS.R b/inst/extdata/create_PopulationReferenceDemoGDS.R new file mode 100644 index 000000000..3c1c64677 --- /dev/null +++ b/inst/extdata/create_PopulationReferenceDemoGDS.R @@ -0,0 +1,125 @@ + +############################################################ +## How to create the PopulationReferenceDemo.gds file +## This file is a small population reference GDS file +## with limited number of samples and SNVs +############################################################ + +## Required librairies +library(SNPRelate) +library(gdsfmt) + +## Create a GDS file +gdsRefNew <- createfn.gds("PopulationReferenceDemo.gds") + +## The entry 'sample.id' contain the unique identifiers of 10 samples +## that constitute the reference dataset +sample.id <- c("HG00100", "HG00101", "HG00102", "HG00103", "HG00104", + "HG00105", "HG00106", "HG00107", "HG00108", "HG00109") +add.gdsn(node=gdsRefNew, name="sample.id", val=sample.id, + storage="string", check=TRUE) + +## A data frame containing the information about the 10 samples +## (in the same order than in the 'sample.id') is created and added to +## the 'sample.annot' entry +## The data frame must contain those columns: +## 'sex': '1'=male, '2'=female +## 'pop.group': acronym for the population (ex: GBR, CDX, MSL, ASW, etc..) +## 'superPop': acronym for the super-population (ex: AFR, EUR, etc...) +## 'batch': number identifying the batch of provenance +sampleInformation <- data.frame(sex=c("1", "1", "1", "1", "1", + "2", "2", "2", "2", "2"), + pop.group=c("GBR", "GIH", "CDX", "GBR", "LWK", + "LWK", "LWK", "GBR", "GIH", "PEL"), + superPop=c("EUR", "SAS", "EAS", "EUR", "AFR", "AFR", "AFR", + "EUR", "SAS", "AMR"), batch=rep(0, 10), stringsAsFactors=FALSE) +add.gdsn(node=gdsRefNew, name="sample.annot", val=sampleInformation, + check=TRUE) + +## The identifier of each SNV is added in the 'snp.id' entry +snvID <- c("s1", "s2", "s3", "s4", "s5", "s6", "s7") +add.gdsn(node=gdsRefNew, name="snp.id", val=snvID, + check=TRUE) + +## The chromosome of each SNV is added to the 'snp.chromosome' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvChrom <- c(rep(1, 7)) +add.gdsn(node=gdsRefNew, name="snp.chromosome", val=snvChrom, storage="uint16", + check=TRUE) + +## The position on the chromosome of each SNV is added to +## the 'snp.position' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvPos <- c(16102, 51478, 51897, 51927, 54489, 54707, 54715) +add.gdsn(node=gdsRefNew, name="snp.position", val=snvPos, storage="int32", + check=TRUE) + +## The allele information of each SNV is added to the 'snp.allele' entry +## The order of the SNVs is the same than in the 'snp.allele' entry +snvAllele <- c("T/G", "T/A", "C/A", "G/A", "G/A", "G/C", "C/T") +add.gdsn(node=gdsRefNew, name="snp.allele", val=snvAllele, storage="string", + check=TRUE) + +## The allele frequency in the general population (between 0 and 1) of each +## SNV is added to the 'snp.AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.02, 0.11, 0.08, 0.07, 0.10, 0.23, 0.21) +add.gdsn(node=gdsRefNew, name="snp.AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The allele frequency in the East Asian population (between 0 and 1) of each +## SNV is added to the 'snp.EAS_AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.00, 0.00, 0.05, 0.01, 0.00, 0.08, 0.07) +add.gdsn(node=gdsRefNew, name="snp.EAS_AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The allele frequency in the European population (between 0 and 1) of each +## SNV is added to the 'snp.EUR_AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.04, 0.20, 0.12, 0.14, 0.18, 0.38, 0.34) +add.gdsn(node=gdsRefNew, name="snp.EUR_AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The allele frequency in the African population (between 0 and 1) of each +## SNV is added to the 'snp.AFR_AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.03, 0.02, 0.05, 0.06, 0.02, 0.18, 0.16) +add.gdsn(node=gdsRefNew, name="snp.AFR_AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The allele frequency in the American population (between 0 and 1) of each +## SNV is added to the 'snp.AMR_AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.03, 0.12, 0.06, 0.07, 0.10, 0.25, 0.24) +add.gdsn(node=gdsRefNew, name="snp.AMR_AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The allele frequency in the South Asian population (between 0 and 1) of each +## SNV is added to the 'snp.SAS_AF' entry +## The order of the SNVs is the same than in the 'snp.id' entry +snvAF <- c(0.02, 0.22, 0.10, 0.09, 0.21, 0.28, 0.27) +add.gdsn(node=gdsRefNew, name="snp.SAS_AF", val=snvAF, storage="packedreal24", + check=TRUE) + +## The genotype of each SNV for each sample is added to the 'genotype' entry +## The genotype correspond to the number of A alleles +## The rows represent the SNVs is the same order than in 'snp.id' entry +## The columns represent the samples is the same order than in 'sample.id' entry +genotypeInfo <- matrix(data=c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 2, 0, 0, 0, 1, 1, 0, 0, + 1, 1, 2, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 2, 0, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 0, 1, 1, 1, 1, 0, 0), ncol=10, byrow=TRUE) +add.gdsn(node=gdsRefNew, name="genotype", val=genotypeInfo, + storage="bit2", check=TRUE) + +## The entry 'sample.ref' is filled with 0 or 1 indicating that 8 samples out +## of 10 samples are retained to be used as reference +## The order of the samples is the same than in the 'sample.id' entry +add.gdsn(node=gdsRefNew, name="sample.ref", val=c(rep(1L, 7), 0, 0, 1), + storage="bit1", check=TRUE) + +closefn.gds(gdsRefNew) diff --git a/man/appendGDSgenotype.Rd b/man/appendGDSgenotype.Rd index 6a6f1d22b..4e7274f9e 100644 --- a/man/appendGDSgenotype.Rd +++ b/man/appendGDSgenotype.Rd @@ -46,7 +46,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The RDS file containing the pedigree information -pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") ## The RDS file containing the indexes of the retained SNPs snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") diff --git a/man/generateGDSgenotype.Rd b/man/generateGDSgenotype.Rd index 4999dce2a..2ad46abd0 100644 --- a/man/generateGDSgenotype.Rd +++ b/man/generateGDSgenotype.Rd @@ -46,7 +46,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The RDS file containing the pedigree information -pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") ## The RDS file containing the indexes of the retained SNPs snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") diff --git a/man/generatePhase1KG2GDS.Rd b/man/generatePhase1KG2GDS.Rd index 863f687d4..a6153342e 100644 --- a/man/generatePhase1KG2GDS.Rd +++ b/man/generatePhase1KG2GDS.Rd @@ -51,7 +51,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The RDS file containing the pedigree information -pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") ## The RDS file containing the indexes of the retained SNPs snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") diff --git a/man/getRef1KGPop.Rd b/man/getRef1KGPop.Rd index 19871ae85..f6e226a3e 100644 --- a/man/getRef1KGPop.Rd +++ b/man/getRef1KGPop.Rd @@ -39,7 +39,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## Open existing demo 1K GDS file with "sample.ref" node -nameFileGDS <- file.path(dataDir, "1KG_Demo.gds") +nameFileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") fileGDS <- snpgdsOpen(nameFileGDS) ## Extract super population information for the 1KG profiles diff --git a/man/identifyRelative.Rd b/man/identifyRelative.Rd index 9c80a293c..29aad31d6 100644 --- a/man/identifyRelative.Rd +++ b/man/identifyRelative.Rd @@ -50,7 +50,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## Open existing demo Reference GDS file -fileGDS <- file.path(dataDir, "1KG_Demo.gds") +fileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") tmpGDS <- snpgdsOpen(fileGDS) ## Temporary output files diff --git a/man/prepPedSynthetic1KG.Rd b/man/prepPedSynthetic1KG.Rd index 6fb8ed77c..193d7f528 100644 --- a/man/prepPedSynthetic1KG.Rd +++ b/man/prepPedSynthetic1KG.Rd @@ -58,7 +58,7 @@ library(gdsfmt) ## The open 1KG GDS file is required (this is a demo file) dataDir <- system.file("extdata", package="RAIDS") -gds_1KG_file <- file.path(dataDir, "1KG_Demo.gds") +gds_1KG_file <- file.path(dataDir, "PopulationReferenceDemo.gds") gds1KG <- openfn.gds(gds_1KG_file) fileSampleGDS <- file.path(dataDir, "GDS_Sample_with_study_demo.gds") diff --git a/man/pruning1KGbyChr.Rd b/man/pruning1KGbyChr.Rd index 7b2a78c50..c12df35e8 100644 --- a/man/pruning1KGbyChr.Rd +++ b/man/pruning1KGbyChr.Rd @@ -85,7 +85,7 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The 1KG Population Reference GDS demo file (opened) -gds1KG <- snpgdsOpen(file.path(dataDir, "1KG_Demo.gds")) +gds1KG <- snpgdsOpen(file.path(dataDir, "PopulationReferenceDemo.gds")) ## The prefix of the RDS file to be created and containing the pruned SNVs outPrefix <- file.path(tempdir(), "Pruned_Demo_Reference") diff --git a/man/select1KGPop.Rd b/man/select1KGPop.Rd index fc4db1e17..4bbedab8b 100644 --- a/man/select1KGPop.Rd +++ b/man/select1KGPop.Rd @@ -48,7 +48,7 @@ nbProfiles <- 5L ## Open 1KG GDS Demo file ## This file only one superpopulation (for demonstration purpose) dataDir <- system.file("extdata", package="RAIDS") -fileGDS <- file.path(dataDir, "1KG_Demo.gds") +fileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") gdsFileOpen <- openfn.gds(fileGDS, readonly=TRUE) ## Extract a selected number of random samples diff --git a/man/snvListVCF.Rd b/man/snvListVCF.Rd index 2b43a6d39..13e69e1da 100644 --- a/man/snvListVCF.Rd +++ b/man/snvListVCF.Rd @@ -41,7 +41,8 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## Demo 1KG Reference GDS file -fileGDS <- openfn.gds(file.path(dataDir, "1KG_Demo.gds")) +fileGDS <- openfn.gds(file.path(dataDir, + "PopulationReferenceDemo.gds")) ## Output VCF file that will be created (temporary) vcfFile <- file.path(tempdir(), "Demo_TMP_01.vcf") diff --git a/man/validateAdd1KG2SampleGDS.Rd b/man/validateAdd1KG2SampleGDS.Rd index 922bf8885..175abaaaa 100644 --- a/man/validateAdd1KG2SampleGDS.Rd +++ b/man/validateAdd1KG2SampleGDS.Rd @@ -37,7 +37,8 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The 1KG Population Reference GDS demo file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, + "PopulationReferenceDemo.gds"), readonly=TRUE) ## The validatiion should be successful RAIDS:::validateAdd1KG2SampleGDS(gdsReference=gds1KG, diff --git a/man/validateAddStudy1Kg.Rd b/man/validateAddStudy1Kg.Rd index 7c1bf04df..c9056751f 100644 --- a/man/validateAddStudy1Kg.Rd +++ b/man/validateAddStudy1Kg.Rd @@ -30,7 +30,7 @@ expected, an error message is generated. ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata", package="RAIDS") -fileReferenceGDS <- file.path(dataDir, "1KG_Demo.gds") +fileReferenceGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") gds1KG <- snpgdsOpen(fileReferenceGDS) ## Path to demo Profile GDS file diff --git a/man/validateComputeAncestryFromSyntheticFile.Rd b/man/validateComputeAncestryFromSyntheticFile.Rd index 50c488ad2..7082429e1 100644 --- a/man/validateComputeAncestryFromSyntheticFile.Rd +++ b/man/validateComputeAncestryFromSyntheticFile.Rd @@ -101,7 +101,8 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The 1KG Population Reference GDS demo file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, + "PopulationReferenceDemo.gds"), readonly=TRUE) ## The Profile GDS (opened) gdsSample <- openfn.gds(file.path(dataDir, diff --git a/man/validateCreateStudy2GDS1KG.Rd b/man/validateCreateStudy2GDS1KG.Rd index bc2f3eeaf..cd4caa18b 100644 --- a/man/validateCreateStudy2GDS1KG.Rd +++ b/man/validateCreateStudy2GDS1KG.Rd @@ -68,7 +68,7 @@ This function validates the input parameters for the dataDir <- system.file("extdata", package="RAIDS") ## Demo 1KG Population Reference GDS file -gds1KG <- file.path(dataDir, "1KG_Demo.gds") +gds1KG <- file.path(dataDir, "PopulationReferenceDemo.gds") ## The data.frame containing the information about the study ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" diff --git a/man/validateEstimateAllelicFraction.Rd b/man/validateEstimateAllelicFraction.Rd index 5f82f5793..3c5eb7a51 100644 --- a/man/validateEstimateAllelicFraction.Rd +++ b/man/validateEstimateAllelicFraction.Rd @@ -93,7 +93,8 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The 1KG Population Reference GDS Demo file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, + "PopulationReferenceDemo.gds"), readonly=TRUE) ## The GDS Sample (opened) gdsSample <- openfn.gds(file.path(dataDir, diff --git a/man/validateGDSClass.Rd b/man/validateGDSClass.Rd index 5f609e2e5..9dfb95cf6 100644 --- a/man/validateGDSClass.Rd +++ b/man/validateGDSClass.Rd @@ -27,7 +27,8 @@ the \link[gdsfmt]{gds.class} class. dataDir <- system.file("extdata", package="RAIDS") ## The 1KG GDS file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, + "PopulationReferenceDemo.gds"), readonly=TRUE) ## The validation should be successful RAIDS:::validateGDSClass(gds=gds1KG, name="gds") diff --git a/man/validateGenerateGDS1KG.Rd b/man/validateGenerateGDS1KG.Rd index c0c25e29f..8311ed760 100644 --- a/man/validateGenerateGDS1KG.Rd +++ b/man/validateGenerateGDS1KG.Rd @@ -59,7 +59,7 @@ This function validates the input parameters for the dataDir <- system.file("extdata", package="RAIDS") ## The RDS file containing the pedigree information -pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") ## The RDS file containing the indexes of the retained SNPs snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") diff --git a/man/validatePruningSample.Rd b/man/validatePruningSample.Rd index 8f3863f41..2aee1b394 100644 --- a/man/validatePruningSample.Rd +++ b/man/validatePruningSample.Rd @@ -102,7 +102,8 @@ library(gdsfmt) dataDir <- system.file("extdata", package="RAIDS") ## The 1KG GDS file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, + "PopulationReferenceDemo.gds"), readonly=TRUE) ## The validation should be successful RAIDS:::validatePruningSample(gdsReference=gds1KG, method="corr", diff --git a/man/validateRunExomeOrRNAAncestry.Rd b/man/validateRunExomeOrRNAAncestry.Rd index ae439a75d..a1270bddf 100644 --- a/man/validateRunExomeOrRNAAncestry.Rd +++ b/man/validateRunExomeOrRNAAncestry.Rd @@ -92,7 +92,7 @@ study <- data.frame(study.id = "MYDATA", stringsAsFactors = FALSE) ## Population Reference GDS demo file -gds1KG <- file.path(dataDir, "1KG_Demo.gds") +gds1KG <- file.path(dataDir, "PopulationReferenceDemo.gds") gdsAnnot1KG <- file.path(dataDir, "gdsAnnot1KG.gds") diff --git a/man/validateSyntheticGeno.Rd b/man/validateSyntheticGeno.Rd index 1a18251cd..c8404281b 100644 --- a/man/validateSyntheticGeno.Rd +++ b/man/validateSyntheticGeno.Rd @@ -63,7 +63,8 @@ This function validates the input parameters for the dataDir <- system.file("extdata", package="RAIDS") ## The 1KG GDS file (opened) -gds1KG <- openfn.gds(file.path(dataDir, "1KG_Demo.gds"), readonly=TRUE) +gds1KG <- openfn.gds(file.path(dataDir, + "PopulationReferenceDemo.gds"), readonly=TRUE) ## The 1KG GDS Annotation file (opened) gds1KGAnnot <- openfn.gds(file.path(dataDir, "gdsAnnot1KG.gds"), diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index c84853fa4..08c2af6f8 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -78,9 +78,9 @@ Beware that only unrelated samples should be present in the GDS files. library(RAIDS) library(SNPRelate) -pathReference <- system.file("extdata/example/", package="RAIDS") +pathRef <- system.file("extdata/", package="RAIDS") -fileReferenceGDS <- file.path(pathReference, "gdsRef", "ex1kg.gds") +fileReferenceGDS <- file.path(pathRef, "PopulationReferenceDemo.gds") gdsRef <- snpgdsOpen(fileReferenceGDS) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 375a019fd..5fe733f43 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -110,7 +110,7 @@ devtools::install_github('KrasnitzLab/RAIDS') This is an overview of genetic ancestry inference from cancer-derived molecular data: -```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference process.", out.width='120%', results='asis', warning=FALSE, message=FALSE} +```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference process.", out.width='130%', results='asis', warning=FALSE, message=FALSE} knitr::include_graphics("MainSteps_v04.png") ``` @@ -128,48 +128,8 @@ run together using one wrapper function.

-## Step 1 - Format population reference dataset (optional) - -```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from the population reference dataset (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step1_v04.png") -``` - - -****** - -At this step three important reference files are created: - -- The population reference GDS File -- The population reference SNV Annotation GDS file -- The population reference SNV Retained VCF file - - -The format of those files are described the [Population reference dataset GDS files](Create_Reference_GDS_File.html) -vignette. - -The reference files associated to -the Cancer Research associated paper are available. Note that these -pre-processed files are for 1000 Genomes (1KG), in hg38. The files are -available here: - - -[https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper](https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper) - - -The size of the 1KG GDS file -is 15GB. - -The 1KG GDS file is mapped on -hg38 [@Lowy-Gallego2019a]. - -This section can be skipped if -you choose to use the pre-processed files. - -
-
- -## Step 2 - Ancestry Inference +## Main Step - Ancestry Inference A wrapper function encapsulates multiple steps of the workflow. @@ -195,17 +155,28 @@ The wrapper function, called _runExomeAncestry()_, requires 4 files as input: - The **Profile SNP pileup file** (one per sample present in the study) - The **Profile PED RDS file** (one file with information for all profiles in the study) -A *data.frame* containing the general information about the study is -also required. The *data.frame* must contain those 3 columns: +In addtions, a *data.frame* containing the general information about the +study is also required. The *data.frame* must contain those 3 columns: - _study.id_: The study identifier (example: TCGA-BRCA). - _study.desc_: The description of the study. - _study.platform_: The type of sequencing (example: RNA-seq). +#### Population reference files + +For demonstration purpose, a small +**population reference GDS file** (called _ex1kg.gds_) and a small +**population reference SNV Annotation GDS file** (called _exAnnot1kg.gds_) are +included in this package. Beware that those two files should not be used to +run a real ancestry inference.The results obtained with those files won't be +reliable. + The required **population reference GDS file** and **population reference SNV Annotation GDS file** should be stored in the same directory. In the example below, this directory is referred to -as **pathReference**. +as **pathReference**. + +#### Population SNP pileup file The generic **Profile SNP pileup file** format is coma separated and the mandatory columns are: @@ -227,6 +198,8 @@ correspond to the profile identifier (Name.ID) in the following analysis. For example, a SNP pileup file called "Sample.01.txt.gz" would be associated to the "Sample.01" profile. +#### Profile PED RDS file + The **Profile PED RDS file** must contain a *data.frame* describing all the profiles to be analyzed. These 5 mandatory columns: @@ -245,6 +218,14 @@ Alternatively, the PED information can be saved in another type of file (CVS, etc..) as long as the *data.frame* information can be regenerated in R (with _read.csv()_ or else). + +#### Example + +This example run an ancestry inference on an exome sample. Both population +reference files are demonstration files and should not be +used for a real ancestry inference. Beware that an ancestry inference done +on real data will take longer to run. + ```{r runExomeAncestry, echo=TRUE, eval=TRUE, collapse=FALSE, warning=FALSE, message=FALSE} ############################################################################# ## Load required packages @@ -622,13 +603,46 @@ file (**".Ancestry.csv"** file) which also contains those columns:

-# Pre-processed reference files are available for 1000 Genomes (1KG) in hg38 -Pre-processed files, such as the 1KG GDS file, are available at this address: +## Format population reference dataset (optional) + + +```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from the population reference dataset (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_Step1_v04.png") +``` + + +A population reference dataset with known ancestry is required to infer +ancestry. The population must be large enough to ensure ??? + +Three important reference files, containing formatted information about +the reference dataset, are required: + +- The population reference GDS File +- The population reference SNV Annotation GDS file +- The population reference SNV Retained VCF file + +The format of those files are described the [Population reference dataset GDS files](Create_Reference_GDS_File.html) +vignette. + +The reference files associated to +the Cancer Research associated paper are available. Note that these +pre-processed files are for 1000 Genomes (1KG), in hg38. The files are +available here: + + [https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper](https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper) + -Beware that some of these files are large. +The size of the 1KG GDS file +is 15GB. + +The 1KG GDS file is mapped on +hg38 [@Lowy-Gallego2019a]. + +This section can be skipped if +you choose to use the pre-processed files.

From 9528285c9959c7824c8b3665a409df7716ac942e Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 7 Sep 2023 17:30:13 -0400 Subject: [PATCH 213/385] Add missing Pedigree gds file --- inst/extdata/PedigreeReferenceDemo.rds | Bin 0 -> 271 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 inst/extdata/PedigreeReferenceDemo.rds diff --git a/inst/extdata/PedigreeReferenceDemo.rds b/inst/extdata/PedigreeReferenceDemo.rds new file mode 100644 index 0000000000000000000000000000000000000000..4a760f5b9762541c19d0b96b99ce75deaa509067 GIT binary patch literal 271 zcmV+q0r37GiwFP!0000028-ZgU|?WoU}0opU}gm}8Q7cy42?{UfP%sx9uNxvF&6_1 z11FGX_i#5bFf=egGy#rz*jPV``+ z+v*lX4<;h4hy*Oi@xYpwn44M*bvheVkh3^3w;(4~FEa%e&wfBvdY&#Ydy7*mU`h+} z3-r>9@=FV#0vyGq1*t^=`7l0fQesJR2AZv$Mfv4=$Tkn!bd4HV$vKI|Fek$Vxl$5K V67|xGfW85xJpfp5Ktg8(003fSZTkQK literal 0 HcmV?d00001 From b5ee28fe8479204e8552b722e0dc933a23a629e9 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 7 Sep 2023 21:50:59 -0400 Subject: [PATCH 214/385] Update main vignette --- inst/extdata/PedigreeDemo.rds | Bin 271 -> 0 bytes vignettes/RAIDS.Rmd | 47 +++++++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 6 deletions(-) delete mode 100644 inst/extdata/PedigreeDemo.rds diff --git a/inst/extdata/PedigreeDemo.rds b/inst/extdata/PedigreeDemo.rds deleted file mode 100644 index 4a760f5b9762541c19d0b96b99ce75deaa509067..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 271 zcmV+q0r37GiwFP!0000028-ZgU|?WoU}0opU}gm}8Q7cy42?{UfP%sx9uNxvF&6_1 z11FGX_i#5bFf=egGy#rz*jPV``+ z+v*lX4<;h4hy*Oi@xYpwn44M*bvheVkh3^3w;(4~FEa%e&wfBvdY&#Ydy7*mU`h+} z3-r>9@=FV#0vyGq1*t^=`7l0fQesJR2AZv$Mfv4=$Tkn!bd4HV$vKI|Fek$Vxl$5K V67|xGfW85xJpfp5Ktg8(003fSZTkQK diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 5fe733f43..479b3da73 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -155,14 +155,16 @@ The wrapper function, called _runExomeAncestry()_, requires 4 files as input: - The **Profile SNP pileup file** (one per sample present in the study) - The **Profile PED RDS file** (one file with information for all profiles in the study) -In addtions, a *data.frame* containing the general information about the +In addition, a *data.frame* containing the general information about the study is also required. The *data.frame* must contain those 3 columns: - _study.id_: The study identifier (example: TCGA-BRCA). - _study.desc_: The description of the study. - _study.platform_: The type of sequencing (example: RNA-seq). -#### Population reference files +
+ +#### **Population reference files** For demonstration purpose, a small **population reference GDS file** (called _ex1kg.gds_) and a small @@ -176,7 +178,9 @@ The required **population reference GDS file** and directory. In the example below, this directory is referred to as **pathReference**. -#### Population SNP pileup file +
+ +#### **Population SNP pileup file** The generic **Profile SNP pileup file** format is coma separated and the mandatory columns are: @@ -198,7 +202,9 @@ correspond to the profile identifier (Name.ID) in the following analysis. For example, a SNP pileup file called "Sample.01.txt.gz" would be associated to the "Sample.01" profile. -#### Profile PED RDS file +
+ +#### **Profile PED RDS file** The **Profile PED RDS file** must contain a *data.frame* describing all the profiles to be analyzed. These 5 mandatory columns: @@ -218,12 +224,13 @@ Alternatively, the PED information can be saved in another type of file (CVS, etc..) as long as the *data.frame* information can be regenerated in R (with _read.csv()_ or else). +
-#### Example +#### **Example** This example run an ancestry inference on an exome sample. Both population reference files are demonstration files and should not be -used for a real ancestry inference. Beware that an ancestry inference done +used for a real ancestry inference. Beware that running an ancestry inference on real data will take longer to run. ```{r runExomeAncestry, echo=TRUE, eval=TRUE, collapse=FALSE, warning=FALSE, message=FALSE} @@ -402,11 +409,26 @@ also required. The *data.frame* must contain those 3 columns: - _study.desc_: The description of the study. - _study.platform_: The type of sequencing (example: RNA-seq). +
+ +#### **Population reference files** + +For demonstration purpose, a small +**population reference GDS file** (called _ex1kg.gds_) and a small +**population reference SNV Annotation GDS file** (called _exAnnot1kg.gds_) are +included in this package. Beware that those two files should not be used to +run a real ancestry inference.The results obtained with those files won't be +reliable. + The required **population reference GDS file** and **population reference SNV Annotation GDS file** should be stored in the same directory. In the example below, this directory is referred to as **pathReference**. +
+ +#### **Profile SNP pileup file** + The generic **Profile SNP pileup file** format is coma separated and the mandatory columns are: @@ -427,6 +449,10 @@ correspond to the profile identifier (Name.ID) in the following analysis. For example, a SNP pileup file called "Sample.01.txt.gz" would be associated to the "Sample.01" profile. +
+ +#### **Profile PED RDS file** + The **Profile PED RDS file** must contain a *data.frame* describing all the profiles to be analyzed. These 5 mandatory columns: @@ -445,6 +471,15 @@ Alternatively, the PED information can be saved in another type of file (CVS, etc..) as long as the *data.frame* information can be regenerated in R (with _read.csv()_ or else). +
+ +#### **Example** + +This example run an ancestry inference on an RNA sample. Both population +reference files are demonstration files and should not be +used for a real ancestry inference. Beware that running an ancestry inference +on real data will take longer to run. + ```{r runRNAAncestry, echo=TRUE, eval=TRUE, collapse=FALSE, warning=FALSE, message=FALSE} ############################################################################# ## Load required packages From c579cccecc277d9ac88d7be3e5d528e1e8f881b5 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 7 Sep 2023 22:53:58 -0400 Subject: [PATCH 215/385] Update example to use new Pedigree rds file --- R/process1KG.R | 2 +- man/generateGDS1KG.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index f8a6da09c..a7a522d7f 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -275,7 +275,7 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The RDS file containing the pedigree information -#' pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +#' pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") #' #' ## The RDS file containing the indexes of the retained SNPs #' snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") diff --git a/man/generateGDS1KG.Rd b/man/generateGDS1KG.Rd index bae30bc35..26c9e3597 100644 --- a/man/generateGDS1KG.Rd +++ b/man/generateGDS1KG.Rd @@ -68,7 +68,7 @@ https://bioconductor.org/packages/gdsfmt/ dataDir <- system.file("extdata", package="RAIDS") ## The RDS file containing the pedigree information -pedigreeFile <- file.path(dataDir, "PedigreeDemo.rds") +pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") ## The RDS file containing the indexes of the retained SNPs snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") From c432007ef4c97da44008cea5b46df514aec45751 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 8 Sep 2023 10:37:20 -0400 Subject: [PATCH 216/385] New script to generate the PedigreeReferenceDemo RDS file --- inst/extdata/create_PedigreeReferenceDemoRDS.R | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 inst/extdata/create_PedigreeReferenceDemoRDS.R diff --git a/inst/extdata/create_PedigreeReferenceDemoRDS.R b/inst/extdata/create_PedigreeReferenceDemoRDS.R new file mode 100644 index 000000000..141e11629 --- /dev/null +++ b/inst/extdata/create_PedigreeReferenceDemoRDS.R @@ -0,0 +1,17 @@ + +############################################################ +## How to create the PedigreeReferenceDemo.rds file +## This file contains a small pedigree reference data.frame +############################################################ + +pedigree <- data.frame(sample.id=c("HG00100", "HG00101", "HG00102", + "HG00103", "HG00104", "HG00105", "HG00106", "HG00107", + "HG00108", "HG00109"), + Name.ID=c("HG00100", "HG00101", "HG00102", "HG00103", + "HG00104", "HG00105", "HG00106", "HG00107", + "HG00108", "HG00109"), + sex=c("1", "2", "2", "1", "2", "1", "2", "1", "2", "2"), + pop.group=rep("ABC", 10), superPop=rep("AFR", 10), + batch=rep(0, 10), stringsAsFactors=FALSE) + +saveRDS(pedigree, file="PedigreeReferenceDemo.rds") From b2538903482f68570076868151ded066977b1a55 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 8 Sep 2023 11:37:09 -0400 Subject: [PATCH 217/385] Remove unused 1KG_Test_02.gds file --- inst/extdata/tests/1KG_Test_02.gds | Bin 3238 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 inst/extdata/tests/1KG_Test_02.gds diff --git a/inst/extdata/tests/1KG_Test_02.gds b/inst/extdata/tests/1KG_Test_02.gds deleted file mode 100644 index 338fb0240c597fc7804fac4912d18d3fd6bd2bf4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3238 zcmbVOU1%It6h1Sv$?m3U8cma^F+Unhf5dgRrfKsMT(_G@wQ1OHAVrEDvy*OQe}
*ac5LrI{iYVbbfY+`ka{s|#5x$2ymaxEZjC#M`0e%gHrKi5vH!RO zeYT`u(D7uJ9sP zj#Yn#_i^_SbWdW2o!cLrpWalOy1Ji{Qdsf^_VG{)6Wks4RAto!7K+D-}lBqZsboKBk}aT{;NJ1`=fMY6VbwmO+EbdH*5%+(Xx!iwzRRLN zIXKi2H@I8;_rNzqpMOjA6Su416Mgyv(HGpVb5pMn4Re#N!QonKg(qjZWwb1}*`Q@v zFNiVsotFadjU4 z4JqLnbLYYae91gGw64wjyJ&2VuBYgeNt&M_>uuV44Lq!}7ug0!&$YR*1K}|bl|0FbNyD^ZD4IuTB$_udPIR#sVAm{rduD&%Sx~JatC1y=ytgIDg$9 z;qDRWo{VuecNC3xQ*J$0#g|3`2^xHDJj#kxcE@4tKoDUFcOp@tpB$A6YEGHotsKKY z4g?Y4VsSj_6OM!~fPm~VhD&6q>%J!pxwpbl0Uu1k<7E*g)xX4-RPtyejohUEqnFS0 zCT*i)mCe*j@o{0H2^@z(0tZh5*X`kqYPHtbBSA62u**)nYO%j3BoOZNFsKKhrBc0C zsoAxPDU;*E4uiV^wrciDW2IKzFZsoV9ENrQYLv@n*_5N~zY8d$%*@E%u$)c2BS2hEO@Nu1C=mBbGvM(k5Cy9V@T7=wFAs8k6rl{#Cmty*%($-8g~d(|@Q z^EC_E?GxgYHSDhAC8M!a@}k8dP!hM-f6kp7MSbGyET38`8@AokRWuq#YPoJy%zpuc CvNL7? From bfcfb1a366ff8bcd1235bafd814ddd135e2d5e37 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 8 Sep 2023 15:35:13 -0400 Subject: [PATCH 218/385] Add script to create PedigreeDemoPED file --- inst/extdata/create_PedigreeDemoPED.R | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 inst/extdata/create_PedigreeDemoPED.R diff --git a/inst/extdata/create_PedigreeDemoPED.R b/inst/extdata/create_PedigreeDemoPED.R new file mode 100644 index 000000000..048574bdf --- /dev/null +++ b/inst/extdata/create_PedigreeDemoPED.R @@ -0,0 +1,29 @@ + +############################################################ +## How to create the PedigreeDemo.ped file +## This file contains a small pedigree reference data.frame +############################################################ + +pedigreeDemo <- data.frame(Family.ID=c("BB01", "BB01", "BB01", "BB02", "BB02", + "BB02", "BB03", "BB03", "BB03", "BB04"), + Individual.ID=c("HG00100", "HG00101", "HG00102", "HG00103", + "HG00104", "HG00105", "HG00106", "HG00107", "HG00108", + "HG00109"), + Paternal.ID=c("0", "0", "HG00100", "0", "0", "HG00103", + "HG00107", "0", "0", "0"), + Maternal.ID=c("0", "0", "HG00101", "0", "0", "HG00104", + "HG00108", "0", "0", "0"), + Gender=c(1, 2, 2, 1, 2, 1, 2, 1, 2, 2), + Phenotype=rep(0, 10), + Population=rep("ACB", 10), + Relationship=c("father", "mother", "child", "father", + "mother", "child", "child", "father", "mother", + "mother"), + Siblings=rep(0, 10), + Second.Order=rep(0, 10), + Third.Order=rep(0, 10), + Other.Comments=rep(0, 10), + stringsAsFactors=FALSE) + +write.table(pedigreeDemo, file="PedigreeDemo.ped", quote=FALSE, + row.names=FALSE, col.names=TRUE, sep="\t") From f0d513b4b5e853342284ee75a7f8d5d407600ef9 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 12 Sep 2023 15:41:35 -0400 Subject: [PATCH 219/385] Change gdsAnnot1KG to PopulationReferenceSNVAnnotationDemo --- R/process1KG_internal.R | 2 +- R/processStudy_internal.R | 6 +++--- R/synthetic_internal.R | 12 ++++++------ ...gds => PopulationReferenceSNVAnnotationDemo.gds} | Bin man/generateGeneBlock.Rd | 2 +- man/validateRunExomeOrRNAAncestry.Rd | 6 +++--- man/validateSyntheticGeno.Rd | 12 ++++++------ 7 files changed, 20 insertions(+), 20 deletions(-) rename inst/extdata/{gdsAnnot1KG.gds => PopulationReferenceSNVAnnotationDemo.gds} (100%) diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index 178deb04b..56c70ab3f 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -191,7 +191,7 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, #' #' path1KG <- file.path(dataDir, "example", "gdsRef") #' -#' ## Temporary Profile GDS file for one profile +#' ## Reference GDS file #' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") #' #' ## Open the reference GDS file (demo version) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 7d7f51df3..d288f3cf6 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -1007,9 +1007,9 @@ validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, currentProfil #' stringsAsFactors = FALSE) #' #' ## Population Reference GDS demo file -#' gds1KG <- file.path(dataDir, "PopulationReferenceDemo.gds") +#' gdsRef <- file.path(dataDir, "PopulationReferenceDemo.gds") #' -#' gdsAnnot1KG <- file.path(dataDir, "gdsAnnot1KG.gds") +#' gdsAnnotRef <- file.path(dataDir, "PopulationReferenceSNVAnnotationDemo.gds") #' #' ## Pedigree Study data frame #' ped <- data.frame(Name.ID=c("Sample_01", "Sample_02"), @@ -1033,7 +1033,7 @@ validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, currentProfil #' ## Returns OL when all parameters are valid #' RAIDS:::validateRunExomeOrRNAAncestry(pedStudy=ped, studyDF=study, #' pathProfileGDS=dataDir, pathGeno=dataDir, pathOut=pathOut, -#' fileReferenceGDS=gds1KG, fileReferenceAnnotGDS=gdsAnnot1KG, +#' fileReferenceGDS=gdsRef, fileReferenceAnnotGDS=gdsAnnotRef, #' chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, #' genoSource="snp-pileup", verbose=FALSE) #' diff --git a/R/synthetic_internal.R b/R/synthetic_internal.R index 70a331e4f..d33c09b8e 100644 --- a/R/synthetic_internal.R +++ b/R/synthetic_internal.R @@ -42,25 +42,25 @@ #' dataDir <- system.file("extdata", package="RAIDS") #' #' ## The 1KG GDS file (opened) -#' gds1KG <- openfn.gds(file.path(dataDir, +#' gdsRef <- openfn.gds(file.path(dataDir, #' "PopulationReferenceDemo.gds"), readonly=TRUE) #' #' ## The 1KG GDS Annotation file (opened) -#' gds1KGAnnot <- openfn.gds(file.path(dataDir, "gdsAnnot1KG.gds"), -#' readonly=TRUE) +#' gdsRefAnnot <- openfn.gds(file.path(dataDir, +#' "PopulationReferenceSNVAnnotationDemo.gds"), readonly=TRUE) #' #' ## The GDS Sample file #' gdsSample <- file.path(dataDir, "GDS_Sample_with_study_demo.gds") #' #' ## The validation should be successful -#' RAIDS:::validateSyntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gds1KGAnnot, +#' RAIDS:::validateSyntheticGeno(gdsReference=gdsRef, gdsRefAnnot=gdsRefAnnot, #' fileProfileGDS=gdsSample, profileID="A101TCGA", #' listSampleRef="A101TCGA", nbSim=1L, prefix="TCGA", pRecomb=0.02, #' minProb=0.999, seqError=0.002) #' #' ## All GDS file must be closed -#' closefn.gds(gdsfile=gds1KG) -#' closefn.gds(gdsfile=gds1KGAnnot) +#' closefn.gds(gdsfile=gdsRef) +#' closefn.gds(gdsfile=gdsRefAnnot) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom S4Vectors isSingleNumber diff --git a/inst/extdata/gdsAnnot1KG.gds b/inst/extdata/PopulationReferenceSNVAnnotationDemo.gds similarity index 100% rename from inst/extdata/gdsAnnot1KG.gds rename to inst/extdata/PopulationReferenceSNVAnnotationDemo.gds diff --git a/man/generateGeneBlock.Rd b/man/generateGeneBlock.Rd index e9c1e5342..ab261891e 100644 --- a/man/generateGeneBlock.Rd +++ b/man/generateGeneBlock.Rd @@ -67,7 +67,7 @@ if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { path1KG <- file.path(dataDir, "example", "gdsRef") - ## Temporary Profile GDS file for one profile + ## Reference GDS file fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") ## Open the reference GDS file (demo version) diff --git a/man/validateRunExomeOrRNAAncestry.Rd b/man/validateRunExomeOrRNAAncestry.Rd index a1270bddf..8b13619a4 100644 --- a/man/validateRunExomeOrRNAAncestry.Rd +++ b/man/validateRunExomeOrRNAAncestry.Rd @@ -92,9 +92,9 @@ study <- data.frame(study.id = "MYDATA", stringsAsFactors = FALSE) ## Population Reference GDS demo file -gds1KG <- file.path(dataDir, "PopulationReferenceDemo.gds") +gdsRef <- file.path(dataDir, "PopulationReferenceDemo.gds") -gdsAnnot1KG <- file.path(dataDir, "gdsAnnot1KG.gds") +gdsAnnotRef <- file.path(dataDir, "PopulationReferenceSNVAnnotationDemo.gds") ## Pedigree Study data frame ped <- data.frame(Name.ID=c("Sample_01", "Sample_02"), @@ -118,7 +118,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && ## Returns OL when all parameters are valid RAIDS:::validateRunExomeOrRNAAncestry(pedStudy=ped, studyDF=study, pathProfileGDS=dataDir, pathGeno=dataDir, pathOut=pathOut, - fileReferenceGDS=gds1KG, fileReferenceAnnotGDS=gdsAnnot1KG, + fileReferenceGDS=gdsRef, fileReferenceAnnotGDS=gdsAnnotRef, chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, genoSource="snp-pileup", verbose=FALSE) diff --git a/man/validateSyntheticGeno.Rd b/man/validateSyntheticGeno.Rd index c8404281b..f59009200 100644 --- a/man/validateSyntheticGeno.Rd +++ b/man/validateSyntheticGeno.Rd @@ -63,25 +63,25 @@ This function validates the input parameters for the dataDir <- system.file("extdata", package="RAIDS") ## The 1KG GDS file (opened) -gds1KG <- openfn.gds(file.path(dataDir, +gdsRef <- openfn.gds(file.path(dataDir, "PopulationReferenceDemo.gds"), readonly=TRUE) ## The 1KG GDS Annotation file (opened) -gds1KGAnnot <- openfn.gds(file.path(dataDir, "gdsAnnot1KG.gds"), - readonly=TRUE) +gdsRefAnnot <- openfn.gds(file.path(dataDir, + "PopulationReferenceSNVAnnotationDemo.gds"), readonly=TRUE) ## The GDS Sample file gdsSample <- file.path(dataDir, "GDS_Sample_with_study_demo.gds") ## The validation should be successful -RAIDS:::validateSyntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gds1KGAnnot, +RAIDS:::validateSyntheticGeno(gdsReference=gdsRef, gdsRefAnnot=gdsRefAnnot, fileProfileGDS=gdsSample, profileID="A101TCGA", listSampleRef="A101TCGA", nbSim=1L, prefix="TCGA", pRecomb=0.02, minProb=0.999, seqError=0.002) ## All GDS file must be closed -closefn.gds(gdsfile=gds1KG) -closefn.gds(gdsfile=gds1KGAnnot) +closefn.gds(gdsfile=gdsRef) +closefn.gds(gdsfile=gdsRefAnnot) } \author{ From bcfdfb45a1fc17d25dce32d2e71965574bc5705c Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 12 Sep 2023 16:24:24 -0400 Subject: [PATCH 220/385] Update Reference GDS vignette --- vignettes/Create_Reference_GDS_File.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 08c2af6f8..2ca1b51a4 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -302,7 +302,7 @@ size, compressed or not + compression ratio. The mandatory fields are: -* **phase**: a *integer* (saved in *Bit2* format) representing the phase of the SNVs in the *Population Annotation GDS file*; 0 means the first allele is a reference; 1 means the first allele is the alternative and 3 means unknown. The first allele combine with the genotype of the variant determine the phase for a biallelic variant. The SNVs in phase are in the same order as in the *Population Annotation GDS file*. +* **phase**: a *integer* (saved in *Bit2* format) representing the phase of the SNVs in the *Population Annotation GDS file*; 0 means the first allele is a reference; 1 means the first allele is the alternative and 3 means unknown. The first allele combine with the genotype of the variant determine the phase for a biallelic variant. The SNVs (rows) and samples (columns) in phase are in the same order as in the *Population Annotation GDS file*. * **block.annot**: a *data.frame* containing those columns: * **block.id**: a *character* string (saved in *Str8* format) representing an identifier of block group. A block can be linkage disequilibrium block relative to a population or a gene. * **block.desc**: a *character* string (saved in *Str8* format) describing the block group. From 9e9cec190ea628db0c4fb16d880c2719184007b0 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 12 Sep 2023 17:16:35 -0400 Subject: [PATCH 221/385] Update demo files and associated creation R script --- inst/extdata/PopulationReferenceDemo.gds | Bin 3379 -> 3280 bytes .../PopulationReferenceSNVAnnotationDemo.gds | Bin 1447 -> 1358 bytes .../create_PopulationReferenceDemoGDS.R | 13 ++-- ..._PopulationReferenceSNVAnnotationDemoGDS.R | 64 ++++++++++++++++++ 4 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 inst/extdata/create_PopulationReferenceSNVAnnotationDemoGDS.R diff --git a/inst/extdata/PopulationReferenceDemo.gds b/inst/extdata/PopulationReferenceDemo.gds index dbb7375e7fc49ce333c0958d1e6d70c508052b4a..737eb19d1a4410a39bd8c8d2d2ff1b6ca8aaa741 100644 GIT binary patch delta 183 zcmdlibwP51gt#jk0}wC*aT*hd1tFOy>ZddQ-#DF{k=F+#+5jRL7`P`#@)&Hs$9RsJ z!w?7oz~9^2CcGtSO1J^QoXsB;|`-> x8i?5dA{ZEWfH+`sA(z_Z1}Zdb4-Z-6`k=Gj}+5jRL7`P`-WKx@~%f`9+ zKI1uN4lj^cgB;uBt*lOyC-7)U2!I5TfIryC89bYP+1!~n&*ZqnC};#>QW73K0O4wIFvga(u46>sl!<0~X?P%gjl2 z%P-1JEaBq}_6vx23<`3LOasX^fE6&P0I2{76HI=vhj56aSr`~T*aO`t#`M7+0Ir`j AZ~y=R diff --git a/inst/extdata/PopulationReferenceSNVAnnotationDemo.gds b/inst/extdata/PopulationReferenceSNVAnnotationDemo.gds index 920a27d19652ea867d7aceadc51896f4157acc5c..159d01b8030d03ce41429b9d39682ef48de6364b 100644 GIT binary patch delta 398 zcmZ3^eU58_1k-B9iBdYoehfg+03sL|n1I*<%z}_C3=E8{DT%Z6nAwj!PLXF~U^?ua z$iX%7wIWk0(_}uz1M2=D)eT@R44gp963m2N$U!XY1FCYw4hfVGeP!fhg>R@U>G{|hQ8Szj9LGA@%kV23oOfj-$FvCDJ M2;g%dNFN9T03}_KIRF3v delta 488 zcmX@dwVZo`1XDlLL@AwmF9slJ*aadPn1Hwh%z}^{3=E8{DT%Z6m_?7cwE0i-9$QGiMCKO>MQ01*R|U_uQ@ zvYrAOSm3Bw!pOvW8pym5As6bz!hYm&iaZko(_!aC4%Ug4icC_>6XzVL_XcTea0WS* zffI;JK@2DfaxdGHC9~}&Gh%n}39w=Yh6FGTaj*y2!CXL*bg(F@gMA=kU=l<~fe7pl zp4`m1dGcyTzRkr=z+l1<4+>}I00tTU1q_^E9Uxsm JH=h7W005opV5I;6 diff --git a/inst/extdata/create_PopulationReferenceDemoGDS.R b/inst/extdata/create_PopulationReferenceDemoGDS.R index 3c1c64677..b79d250d8 100644 --- a/inst/extdata/create_PopulationReferenceDemoGDS.R +++ b/inst/extdata/create_PopulationReferenceDemoGDS.R @@ -107,12 +107,13 @@ add.gdsn(node=gdsRefNew, name="snp.SAS_AF", val=snvAF, storage="packedreal24", ## The rows represent the SNVs is the same order than in 'snp.id' entry ## The columns represent the samples is the same order than in 'sample.id' entry genotypeInfo <- matrix(data=c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, - 1, 1, 2, 0, 0, 0, 1, 1, 0, 0, - 1, 1, 2, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, - 1, 1, 2, 0, 1, 1, 1, 1, 0, 0, - 1, 1, 1, 0, 1, 1, 1, 1, 0, 0), ncol=10, byrow=TRUE) + 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 2, 0, 0, 0, 1, 1, 0, 0, + 1, 1, 2, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 2, 0, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 0, 1, 1, 1, 1, 0, 0), ncol=10, + byrow=TRUE) add.gdsn(node=gdsRefNew, name="genotype", val=genotypeInfo, storage="bit2", check=TRUE) diff --git a/inst/extdata/create_PopulationReferenceSNVAnnotationDemoGDS.R b/inst/extdata/create_PopulationReferenceSNVAnnotationDemoGDS.R new file mode 100644 index 000000000..0e7712a4c --- /dev/null +++ b/inst/extdata/create_PopulationReferenceSNVAnnotationDemoGDS.R @@ -0,0 +1,64 @@ + +###################################################################### +## How to create the PopulationReferenceSNVAnnotationDemo.gds file +## This file is a small population reference SNV Annotation GDS file +## with limited number of samples and SNVs +###################################################################### + +## Required librairies +library(SNPRelate) +library(gdsfmt) + +## Create a GDS file +gdsRefNew <- createfn.gds("PopulationReferenceSNVAnnotationDemo.gds") + +## The entry 'phase' contain the phase of the SNVs in the +## Population Annotation GDS file +## 0 means the first allele is a reference; 1 means the first allele is +## the alternative and 3 means unknown +## The SNVs (rows) and samples (columns) in phase are in the same order as +## in the Population Annotation GDS file. +phase <- matrix(data=c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, + 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, + 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 0, 1, 1, 1, 1), ncol=10, byrow=TRUE) +add.gdsn(node=gdsRefNew, name="phase", val=phase, storage="bit2", check=TRUE) + +## The entry 'blockAnnot' contain the information for each group of blocks +## that are present in the 'block' entry. +blockAnnot <- data.frame(block.id=c("EAS.0.05.500k", "EUR.0.05.500k", + "AFR.0.05.500k", "AMR.0.05.500k", "SAS.0.05.500k"), + block.desc=c( + "EAS populationblock base on SNP 0.05 and windows 500k", + "EUR populationblock base on SNP 0.05 and windows 500k", + "AFR populationblock base on SNP 0.05 and windows 500k", + "AMR populationblock base on SNP 0.05 and windows 500k", + "SAS populationblock base on SNP 0.05 and windows 500k"), + stringsAsFactors=FALSE) +add.gdsn(node=gdsRefNew, name="block.annot", val=blockAnnot, check=TRUE) + +## The entry 'block' contain the block information for the SNVs in the +## Population Annotation GDS file. +## The SNVs (rows) are in the same order as in +## the Population Annotation GDS file. +## The block groups (columns) are in the same order as in +## the 'block.annot' entry. +block <- matrix(data=c(-1, -1, -1, -1, -1, + -2, -2, 1, -2, -2, + -2, 1, 1, 1, -2, + -2, 1, 1, 1, -2, + -2, -3, -2, -3, -2, + 1, 2, 2, 2, 1, + 1, 2, 2, 2, 1, + -3, -4, -3, -4, -3, + 2, -4, 3, -4, -3, + 2, -4, 3, -4, -3), ncol=5, byrow=TRUE) +add.gdsn(node=gdsRefNew, name="block", val=block, storage="int32", check=TRUE) + +closefn.gds(gdsRefNew) From ef61ddc5a913973ab260ce3a38e0162689b2e5f0 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 12 Sep 2023 19:00:03 -0400 Subject: [PATCH 222/385] Update mapSNVSelected_Demo file and add associated R script --- inst/extdata/create_mapSNVSelected_DemoRDS.R | 20 +++++++++++++++++++ inst/extdata/mapSNVSelected_Demo.rds | Bin 345 -> 388 bytes 2 files changed, 20 insertions(+) create mode 100644 inst/extdata/create_mapSNVSelected_DemoRDS.R diff --git a/inst/extdata/create_mapSNVSelected_DemoRDS.R b/inst/extdata/create_mapSNVSelected_DemoRDS.R new file mode 100644 index 000000000..dc6e5e896 --- /dev/null +++ b/inst/extdata/create_mapSNVSelected_DemoRDS.R @@ -0,0 +1,20 @@ + +############################################################ +## How to create the mapSNVSelected_Demo.rds file +## This file contains a data.frame with the SNV allelic +## frequency in the continental populations +############################################################ + +selectedSNVs <- data.frame(CHROM=rep("chr1", 7), + POS=c(16102, 51478, 51897, 51927, 54489, 54707, 54715), + REF=c("T", "T", "C", "G", "G", "G", "C"), + ALT=c("G", "A", "A", "A", "A", "C", "T"), + AF=c(0.02, 0.11, 0.08, 0.07, 0.1, 0.23, 0.21), + EAS_AF=c(0.0, 0.0, 0.05, 0.01, 0.0, 0.08, 0.07), + EUR_AF=c(0.04, 0.2, 0.12, 0.14, 0.18, 0.38, 0.34), + AFR_AF=c(0.03, 0.02, 0.05, 0.06, 0.02, 0.18, 0.16), + AMR_AF=c(0.03, 0.12, 0.06, 0.07, 0.1, 0.25, 0.24), + SAS_AF=c(0.02, 0.22, 0.1, 0.09, 0.21, 0.28, 0.27), + stringsAsFactors=FALSE) + +saveRDS(selectedSNVs, file="mapSNVSelected_Demo.rds") diff --git a/inst/extdata/mapSNVSelected_Demo.rds b/inst/extdata/mapSNVSelected_Demo.rds index 243c71b63708ab9b95efab36e7b1c02bcd48fc35..6a5c3b538b231b22dbb77ff35fecab56a5946982 100644 GIT binary patch literal 388 zcmV-~0ek)*iwFP!0000028-ZgU|?WoU||B1tUx9MYiNj@t_6@M4CH_$1%Q~HfrWt+ zNV6no6d6*D&A`A1GTY&NG00*DhnGqRAau9_gpPUureDp5@Lz39fY95)G@9EOLogW5 zForvBhBLY`a2ZD;7|sYgp}w)7QuWY%ok+F)9*wVu`eQWhw?O$DU$@Hb2z+C|b0!GP zvOim}_&S$uq5Ub4bk#$ceg-sPzY?mx1!4|d9L-#~{Y#+YC!zZG?Fa;^us;a3|2UT| z$Y%Q+VBsM9t3X$3d_4@;KM$%N<`0(Inu<{W{$3spbNUYI^~|6hRm;~YdDBmB-l z!w;r@JJddCc-dcsns*V*^? zFs7pqEcq}w!UWk|9fRYMc%eZ^JV!Sao-Z;l7@`l&X~{W>#W1JA1i4ZYOA__cih!<0 iQ_fkGU#zwYh80{{R>#Ia2P literal 345 zcmV-f0jB;RiwFP!000002CbCMO2a@9$EQhJZ9otNA0uQpY1NCcEUg|aEs26R303jn z2c&`z=1F`4JuBi1_!#1B&APM6Mm%^J@|)S&|IAJ{ISv89hoIwu-$jI;oH0J&7~DWl zt*)c3KmdJw2J?%O{TlB;Q0aV4dCS+;PoEuu~xrx*Z`?vuN`Dv=4VCx z0i>x}n?@YP+%RJ#zD;BK!6tLtIQ_=q+e{;o}Xwe(s>P0Dju+eD6Yr$oGCy)DC}YmUPXJatp5SogZPI$Kor zLLHR**>s|d%%-`R(RqoQ=zV?xv$7k>S_A+9F@B|y From 3923fe0dbc86c5ac45900baf7d3716fb6efdbcb2 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 13 Sep 2023 11:53:26 -0400 Subject: [PATCH 223/385] Update version to 0.99.11 --- DESCRIPTION | 2 +- inst/NEWS.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index ab7129050..78258c84d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.10 +Version: 0.99.11 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index 2e3395876..c2b18249d 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,10 @@ +CHANGES IN VERSION 0.99.11 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o Update main vignette. + CHANGES IN VERSION 0.99.10 ------------------------ From e401059a3011ddbf4e84068a7b3ca6999b5cfddd Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 13 Sep 2023 14:18:17 -0400 Subject: [PATCH 224/385] Update Reference GDS vignette --- vignettes/Create_Reference_GDS_File.Rmd | 82 +++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 2ca1b51a4..0d764246c 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -311,6 +311,88 @@ The mandatory fields are:

+This following example shows how to create a +*Population Reference Annotation GDS file*. +This example is for demonstration purpose only. A working +*Population Reference Annotation GDS file* would have to contain multiple +samples from each continental population and would also have to contain +the SNVs from the entire genome. + +```{r createRefAnnotGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +############################################################################# +## Load required packages +############################################################################# +library(RAIDS) +library(gdsfmt) + +## Create a temporary GDS Reference file in the temporary directory +fileNewReferenceAnnotGDS <- + file.path(tempdir(), "reference_SNV_Annotation_DEMO.gds") + +gdsRefAnnotNew <- createfn.gds(fileNewReferenceAnnotGDS) + +## The entry 'phase' contain the phase of the SNVs in the +## Population Annotation GDS file +## 0 means the first allele is a reference; 1 means the first allele is +## the alternative and 3 means unknown +## The SNVs (rows) and samples (columns) in phase are in the same order as +## in the Population Annotation GDS file. +phase <- matrix(data=c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, + 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, + 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 0, 1, 1, 1, 1), ncol=10, byrow=TRUE) +add.gdsn(node=gdsRefAnnotNew, name="phase", val=phase, storage="bit2", + check=TRUE) + +## The entry 'blockAnnot' contain the information for each group of blocks +## that are present in the 'block' entry. +blockAnnot <- data.frame(block.id=c("EAS.0.05.500k", "EUR.0.05.500k", + "AFR.0.05.500k", "AMR.0.05.500k", "SAS.0.05.500k"), + block.desc=c( + "EAS populationblock base on SNP 0.05 and windows 500k", + "EUR populationblock base on SNP 0.05 and windows 500k", + "AFR populationblock base on SNP 0.05 and windows 500k", + "AMR populationblock base on SNP 0.05 and windows 500k", + "SAS populationblock base on SNP 0.05 and windows 500k"), + stringsAsFactors=FALSE) +add.gdsn(node=gdsRefAnnotNew, name="block.annot", val=blockAnnot, check=TRUE) + +## The entry 'block' contain the block information for the SNVs in the +## Population Annotation GDS file. +## The SNVs (rows) are in the same order as in +## the Population Annotation GDS file. +## The block groups (columns) are in the same order as in +## the 'block.annot' entry. +block <- matrix(data=c(-1, -1, -1, -1, -1, + -2, -2, 1, -2, -2, + -2, 1, 1, 1, -2, + -2, 1, 1, 1, -2, + -2, -3, -2, -3, -2, + 1, 2, 2, 2, 1, + 1, 2, 2, 2, 1, + -3, -4, -3, -4, -3, + 2, -4, 3, -4, -3, + 2, -4, 3, -4, -3), ncol=5, byrow=TRUE) +add.gdsn(node=gdsRefAnnotNew, name="block", val=block, storage="int32", + check=TRUE) + +## Show the file format +print(gdsRefAnnotNew) + +closefn.gds(gdsRefAnnotNew) + +unlink(fileNewReferenceAnnotGDS, force=TRUE) + +``` + +
+
# Pre-processed files, from 1000 Genomes in hg38, are available From 29c3df4492a18c171acf23c9df9cd4273d7d2065 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 13 Sep 2023 16:10:40 -0400 Subject: [PATCH 225/385] Add R script to create the demo unrelatedPatients RDS file --- .../create_unrelatedPatientsInfo_DemoRDS.R | 13 +++++++++++++ inst/extdata/unrelatedPatientsInfo_Demo.rds | Bin 107 -> 108 bytes 2 files changed, 13 insertions(+) create mode 100644 inst/extdata/create_unrelatedPatientsInfo_DemoRDS.R diff --git a/inst/extdata/create_unrelatedPatientsInfo_DemoRDS.R b/inst/extdata/create_unrelatedPatientsInfo_DemoRDS.R new file mode 100644 index 000000000..189defb7c --- /dev/null +++ b/inst/extdata/create_unrelatedPatientsInfo_DemoRDS.R @@ -0,0 +1,13 @@ + +############################################################ +## How to create the unrelatedPatientsInfo_Demo.rds file +## This file contains a list with the unrelated/related +## status for Reference samples +############################################################ + +unrelatedPatients <- list() +unrelatedPatients$rels <- c("HG00109", NA) + +unrelatedPatients$unrels <- rep(NA, 9) + +saveRDS(unrelatedPatients, file="unrelatedPatientsInfo_Demo.rds") diff --git a/inst/extdata/unrelatedPatientsInfo_Demo.rds b/inst/extdata/unrelatedPatientsInfo_Demo.rds index be2027454008f97e14712a0c9a1bf895a1a2f503..75014a6da7896cd682e054d2648497087057065f 100644 GIT binary patch literal 108 zcmb2|=3oE=w(bW>2?+^l35iUT);Op!XJ>TGUdPJJJlS9Zvq-7{!(|D<4sXkjKws_|GpeeJ0c~Un|eb!jX!}FhE LpOTW*QlKRO7|$r> literal 107 zcmb2|=3oE=w(bW>2?+^l35h9532CfGk~iis^Yr@kN=VFTX|z#O5M#Kk!!yTW*4@K* z4;;8~K Date: Fri, 15 Sep 2023 11:56:59 -0400 Subject: [PATCH 226/385] Add script to create the listSNPIndexes_Demo RDS file --- inst/extdata/create_listSNPIndexes_DemoRDS.R | 10 ++++++++++ inst/extdata/listSNPIndexes_Demo.rds | Bin 65 -> 67 bytes 2 files changed, 10 insertions(+) create mode 100644 inst/extdata/create_listSNPIndexes_DemoRDS.R diff --git a/inst/extdata/create_listSNPIndexes_DemoRDS.R b/inst/extdata/create_listSNPIndexes_DemoRDS.R new file mode 100644 index 000000000..d1885fe30 --- /dev/null +++ b/inst/extdata/create_listSNPIndexes_DemoRDS.R @@ -0,0 +1,10 @@ + +############################################################ +## How to create the listSNPIndexes_Demo.rds file +## This file contains a vector containing indexes +## of the retained SNVs +############################################################ + +retainedSNVs <- c(1, 2, 3, 4, 6, 8, 9) + +saveRDS(retainedSNVs, file="listSNPIndexes_Demo.rds") diff --git a/inst/extdata/listSNPIndexes_Demo.rds b/inst/extdata/listSNPIndexes_Demo.rds index 4cf5165ae677bd452242ba35eaec82aea6279908..67cdf670011dbb297112ab65b7f2a2c204289f71 100644 GIT binary patch literal 67 zcmb2|=3oE=w(bW>2?+^l35iUT);Op!XJ>TGUdKA&Ap4Ow-{d6@9B5?pDt5?Z)X-&I TD!O2cPzxJF|3n+#aG+iQ*K-xU literal 65 zcmb2|=3oE=w(bW>2?+^l35h9532CfGk~iis^Yr@kHt57Dq_HQtDWoy21}b1&$&kdS P@Qj7QD&?!Z4NxZlR7(;# From bbdc04d6e0498b8a221f0aec602166e4b5f847bc Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 15 Sep 2023 17:33:45 -0400 Subject: [PATCH 227/385] Add script to generate demoSnpPos RDS file --- .../demoAllelicFraction/create_demSnpPosRDS.R | 350 ++++++++++++++++++ .../extdata/demoAllelicFraction/demSnpPos.rds | Bin 3008 -> 2509 bytes 2 files changed, 350 insertions(+) create mode 100644 inst/extdata/demoAllelicFraction/create_demSnpPosRDS.R diff --git a/inst/extdata/demoAllelicFraction/create_demSnpPosRDS.R b/inst/extdata/demoAllelicFraction/create_demSnpPosRDS.R new file mode 100644 index 000000000..8aa891783 --- /dev/null +++ b/inst/extdata/demoAllelicFraction/create_demSnpPosRDS.R @@ -0,0 +1,350 @@ + +############################################################## +## How to create the demSnpPos.rds file +## This file contains a data.frame with the SNVs information +############################################################## + +snpInfo <- data.frame(cnt.tot=c(15, 545, 17, 24, 24, 61, 39, 31, 59, 57, 56, + 78, 76, 45, 39, 51, 43, 46, 47, 47, 39, 48, + 44, 45, 44, 56, 53, 59, 36, 42, 45, 51, 11, + 11, 10, 11, 29, 29, 12, 10, 11, 10, 11, 18, + 11, 16, 20, 21, 16, 23, 44, 52, 62, 104, 182, + 12, 12, 17, 12, 13, 13, 14, 11, 96, 121, 107, + 84, 91, 107, 159, 183, 10, 21, 14, 119, 148, + 199, 147, 172, 125, 167, 234, 240, 238, 169, + 153, 164, 185, 159, 132, 102, 137, 138, 153, + 22, 25, 26, 25, 21, 12, 11, 34, 28, 32, 35, + 18, 20, 38, 34, 46, 40, 28, 31, 21, 24, 31, + 22, 19, 60, 61, 31, 31, 27, 52, 57, 55, 43, + 13, 11, 12, 14, 10, 15, 11, 10, 10, 10, 14, + 12, 10, 14, 13, 15, 35, 29, 25, 14, 29, 26, + 17, 21, 17, 23, 39, 33, 65, 14, 10, 65, 66, + 10, 10, 10, 13, 10, 12, 14, 10, 11, 14, 18, + 15, 12, 17, 11, 11, 13, 14, 12, 13, 13, 10, + 12, 21, 59, 54, 40, 160, 118, 107, 119, 48, + 66, 36, 12, 26, 36, 41, 46, 41), + cnt.ref=c(3, 544, 17, 14, 14, 61, 39, 31, 59, 57, 56, 78, + 76, 45, 39, 51, 43, 46, 31, 31, 28, 47, 17, + 44, 44, 56, 53, 59, 36, 42, 45, 51, 11, 11, + 10, 11, 29, 29, 12, 10, 11, 10, 11, 18, 11, + 16, 20, 0, 0, 23, 44, 1, 62, 104, 182, 0, + 12, 17, 0, 0, 13, 14, 0, 96, 121, 107, 84, + 91, 107, 159, 183, 10, 21, 14, 119, 148, + 199, 145, 172, 125, 167, 234, 240, 238, + 168, 153, 164, 185, 159, 132, 1, 137, 138, + 153, 22, 25, 26, 25, 0, 0, 11, 34, 27, 32, + 35, 18, 20, 38, 34, 46, 40, 28, 31, 21, 24, + 31, 22, 19, 60, 61, 31, 31, 27, 52, 57, 55, + 43, 13, 11, 12, 14, 10, 15, 11, 10, 10, 10, + 14, 12, 10, 14, 13, 15, 35, 29, 25, 14, 29, + 26, 17, 21, 17, 23, 25, 33, 65, 12, 10, 65, + 66, 10, 4, 10, 13, 10, 12, 14, 10, 11, 14, + 18, 15, 12, 12, 11, 11, 13, 14, 12, 13, 13, + 5, 12, 21, 59, 54, 17, 70, 118, 106, 119, + 48, 65, 36, 12, 26, 36, 41, 46, 41), + cnt.alt=c(11, 1, 0, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 16, 16, 11, 0, 27, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 21, 16, 0, 0, 51, 0, 0, 0, + 12, 0, 0, 12, 13, 0, 0, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, + 0, 0, 0, 21, 12, 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, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 14, 0, 0, 2, 0, 0, 0, 0, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, + 0, 0, 0, 5, 0, 0, 0, 0, 23, 90, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0), + snp.pos=c(31810, 633962, 944237, 944295, 944306, 944530, + 945085, 945102, 945561, 945563, 945572, + 946221, 946246, 946537, 948168, 948537, + 952061, 952090, 952420, 953258, 953278, + 953835, 953857, 953874, 954022, 954045, + 954069, 955978, 957170, 957188, 957212, + 957267, 957334, 957343, 957346, 999354, + 999420, 999556, 999639, 999656, 999665, + 999883, 1014041, 1014057, 1014130, + 1014198, 1014216, 1014227, 1014273, + 1014450, 1020182, 1020216, 1020238, + 1022259, 1035306, 1038915, 1038929, + 1038972, 1038974, 1038975, 1039010, + 1039088, 1039113, 1040731, 1041173, + 1041182, 1041244, 1041248, 1041582, + 1041647, 1041975, 1042440, 1042539, + 1042665, 1043247, 1043287, 1043353, + 1043381, 1043593, 1043838, 1044133, + 1044175, 1044339, 1044367, 1045392, + 1045443, 1045750, 1045842, 1045964, + 1046477, 1046550, 1046561, 1046844, + 1046853, 1046999, 1047022, 1047038, + 1047044, 1047063, 1047081, 36569, 38937, + 39339, 39355, 39554, 39605, 39618, 39775, + 39789, 39979, 40079, 40285, 40291, 40423, + 40468, 40511, 40568, 40572, 40634, 40752, + 41053, 41151, 41186, 41365, 41392, 41403, + 41508, 42056, 42108, 42109, 42251, 42480, + 43091, 43209, 43324, 43360, 43361, 43772, + 43921, 43952, 44612, 44765, 44967, 45494, + 45520, 45610, 45788, 45932, 46144, 46340, + 46494, 46506, 218197, 218385, 218475, + 218991, 224918, 230657, 231066, 234230, + 239963, 239968, 240341, 240566, 240629, + 240695, 240823, 241691, 241718, 242799, + 242823, 242859, 243364, 243503, 245612, + 245660, 247302, 247318, 247465, 257431, + 257433, 260676, 262118, 264947, 264984, + 272050, 272202, 277002, 277249, 277313, + 277325, 277730, 277994, 278147, 279899, + 669277, 669565, 677294, 677341, 677360), + snp.chr=c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2), + normal.geno=c(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3), + pruned=c(TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, + TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, + FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, + TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, + TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, + FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, + FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, + TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, + TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, + FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, + FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, + TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, + FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, + FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, + TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, + FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, + FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, + FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, + TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, + FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, + TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, + TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, + TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, + FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, + TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE), + snp.index=c(157, 161, 1718, 1719, 1720, 1721, 1725, + 1726, 1730, 1731, 1732, 1739, 1740, 1742, + 1760, 1763, 1809, 1810, 1816, 1826, 1827, + 1833, 1834, 1835, 1837, 1838, 1839, 1863, + 1878, 1879, 1880, 1881, 1882, 1883, 1884, + 2408, 2409, 2410, 2411, 2412, 2413, 2415, + 2593, 2594, 2595, 2596, 2597, 2598, 2599, + 2600, 2658, 2659, 2660, 2687, 2813, 2858, + 2859, 2860, 2861, 2862, 2863, 2864, 2865, + 2886, 2891, 2892, 2893, 2894, 2897, 2898, + 2903, 2906, 2907, 2908, 2915, 2916, 2917, + 2918, 2921, 2922, 2924, 2925, 2929, 2930, + 2949, 2950, 2955, 2956, 2957, 2960, 2961, + 2962, 2964, 2965, 2966, 2967, 2968, 2969, + 2970, 2971, 1909263, 1909292, 1909293, + 1909294, 1909295, 1909296, 1909297, + 1909298, 1909299, 1909300, 1909301, + 1909302, 1909303, 1909304, 1909305, + 1909306, 1909307, 1909308, 1909309, + 1909310, 1909311, 1909312, 1909313, + 1909314, 1909315, 1909316, 1909317, + 1909321, 1909322, 1909323, 1909325, + 1909326, 1909330, 1909331, 1909332, + 1909333, 1909334, 1909335, 1909336, + 1909337, 1909341, 1909342, 1909343, + 1909345, 1909346, 1909347, 1909348, + 1909349, 1909350, 1909351, 1909352, + 1909353, 1911106, 1911107, 1911108, + 1911109, 1911156, 1911202, 1911205, + 1911224, 1911253, 1911254, 1911259, + 1911260, 1911261, 1911262, 1911264, + 1911272, 1911273, 1911290, 1911291, + 1911292, 1911294, 1911295, 1911309, + 1911310, 1911321, 1911322, 1911323, + 1911383, 1911384, 1911408, 1911413, + 1911438, 1911439, 1911490, 1911491, + 1911518, 1911520, 1911521, 1911522, + 1911523, 1911524, 1911525, 1911534, + 1915635, 1915636, 1915706, 1915707, + 1915708), + keep=rep(TRUE, 200), + hetero=c(TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, + TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, + FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, + TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE), + homo=c(FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, + FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, + TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, + FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE), + block.id=c(3833, 3834, 2693, 2693, 2693, 2693, 2750, + 2750, 2750, 2750, 2750, 2750, 2750, 2750, + 2750, 2750, 2750, 2750, 2750, 2750, 2750, + 2750, 2750, 2750, 2750, 2750, 2750, 2750, + 2750, 2750, 2750, 2750, 2750, 2750, 2750, + 2714, 2714, 2714, 2714, 2714, 2714, 2714, + 2689, 2689, 2689, 2689, 2689, 2689, 2689, + 2689, 2711, 2711, 2711, 2711, 2711, 2711, + 2711, 2711, 2711, 2711, 2711, 2711, 2711, + 2711, 2711, 2711, 2711, 2711, 2711, 2711, + 2711, 2711, 2711, 2711, 2711, 2711, 2711, + 2711, 2711, 2711, 2711, 2711, 2711, 2711, + 2711, 2711, 2711, 2711, 2711, 2711, 2711, + 2711, 2711, 2711, 2711, 2711, 2711, 2711, + 2711, 2711, -10818, 7085, 7085, 7085, + 7085, 7085, 7085, 7085, 7085, 7085, 7085, + 7085, 7085, 7085, 7085, 7085, 7085, 7085, + 7085, 7085, 7085, 7085, 7085, 7085, 7085, + 7085, 7085, 7085, 7085, 7085, 7085, 7085, + 7085, 7085, 7085, 7085, 7085, 7085, 7085, + 7085, 7085, 7085, 7085, 7085, 7085, 7085, + 7085, 7085, 7085, 7085, 7085, 7085, 5275, + 5275, 5275, 5275, 5275, 5275, 5275, 5275, + 5275, 5275, 5275, 5275, 5275, 5275, 5275, + 5275, 5275, 5275, 5275, 5275, 5275, 5275, + 5275, 5275, 5275, 5275, 5275, 5275, 5275, + 5275, 5275, 5276, 5276, 6252, 6252, 6252, + 6252, 6252, 6252, 6252, 6252, 6252, 7164, + 6440, 6440, 6441, 6441, 6441), + phase=rep(3, 200), + lap=c(0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.338983050847458, 0.338983050847458, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 0.429990069513406, 0.429990069513406, 0.5, + 0.5, 0.5), + LOH=rep(0, 200), + imbAR=rep(-1, 200), + freq=c(0.01, 0.04, 0, 0.88, 0.92, 0.01, 0, 0, 0, 0, 0, 0, + 0.44, 0.03, 0, 0, 0, 0.01, 0.92, 0.92, 0.92, 0, + 0.06, 0, 0.01, 0, 0, 0, 0.01, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0.06, 0, 0.01, 0, 0, 0, 0, 0.34, 0.83, + 0.02, 0.01, 0.28, 0.01, 0.03, 0, 0.89, 0.02, 0.01, + 0.89, 0.89, 0.01, 0.01, 0.89, 0.01, 0.03, 0.01, 0, + 0.04, 0.01, 0, 0, 0, 0, 0.03, 0, 0, 0, 0, 0.01, 0, + 0.01, 0, 0, 0.02, 0.01, 0.03, 0.04, 0, 0, 0, 0.8, + 0.01, 0, 0, 0, 0.01, 0.01, 0, 0.82, 0.98, 0, 0.13, + 0.22, 0.07, 0.03, 0, 0, 0, 0.01, 0.09, 0.01, 0, 0, + 0, 0, 0, 0.24, 0, 0, 0, 0.05, 0, 0.01, 0.03, 0, + 0.19, 0.01, 0.01, 0, 0, 0, 0, 0.15, 0.08, 0, 0, + 0.08, 0, 0, 0, 0.02, 0.01, 0, 0, 0, 0.01, 0, 0, + 0, 0, 0, 0.09, 0.01, 0.27, 0.02, 0, 0.25, 0.01, + 0, 0, 0, 0.29, 0.02, 0.01, 0.32, 0, 0, 0.01, 0.01, + 0.33, 0, 0, 0, 0.32, 0, 0, 0.01, 0, 0, 0.01, 0, + 0.31, 0.1, 0, 0.01, 0.02, 0.24, 0.26, 0, 0.02, + 0.01, 0, 0.25, 0, 0, 0.01, 0, 0.12, 0, 0), + stringsAsFactors=FALSE) +saveRDS(snpInfo, file="demSnpPos.rds") diff --git a/inst/extdata/demoAllelicFraction/demSnpPos.rds b/inst/extdata/demoAllelicFraction/demSnpPos.rds index 25b35631376fd509552b5100724d843b24d63661..23485a9cf2014965522cccb3054b85d7f106dae0 100644 GIT binary patch literal 2509 zcmV;;2{QH{iwFP!000002JPGrOqAyx2k;lg4N>si-1^Ts=7q5`XyP9vBa zYh-ut@B6!P5BG9+XsFufNnStq{NCq%{=LupJ_p(sMk>xtb}I=Q!UVUf-!go}U|jPnh6hlmGE>e6e%z@gxX&t@)WE#CaVU zgzKgW%+DvkPkA2rJ<0X+ymLGoS1&kR`-u2l@bkv|3iofm;6t{Lh)LW>jMtIZ*hjqA3F~w~y}~;6#)o|$i6KMY zN01M4AMwuH5cd%=4cJHcJ#FGR`Xl!d-+G37AK~l8eMIb!);^*W%H8jMMEqV7>OL|- zIIp#j@VqQR+`Er(zLE6qBPQ}*_YsVTpFd9GIvK9yec!TEg!6b##Qr{PN&I!e|M>mtiAMbshUa?kzFOc6 zs{DO;E@>b6P^UJS_3gsbs`{35WH7TQ|a;WLq*!gE?gTO1PE0bc($8DtW`9 zIyLGx8J$Avn#sqO!I#LV&XN;HK6J8jWNsc zlWKU2q+k5GJqTOiCGw}QkvEcIKBV>yJvR6%r1lNHG#Ha33T@7iT z5?hnu56FL`{d4H&2f6Td@2kqtvJm<8?PLYwFQfb~5#Nvan~1-S zc$1U-8}k2BAmXj4zl-7>W2l~v$EbYAL^|J*jCdN#p}!sUMbgyqbHr9gAaADUBFYM#xNZ~5y+Q3o)zkYWY7g}z>TnEs6z4xHChw^8kQJSj1gW0rRC<4o zvo%0^AC5ak^^EJI^1APyAoWzAu9nK_cEyn&!R~PK6PDhyx*nP@-KR7@-R-few@$W~ZQmIrb4MBJE{DZD$_YsDC znDYM=*6$EwV$zC*37-SCBOdZH2&suG3&81d*!Hm=2XMbh2 zV*c)5pwGdq3x8wMs$;NnT74aC44#9&ZfT?;$~Ps6hi z^Hg^ZULfn|K#Z$?KE(LybKxSG2N%P?z;|IYyi4x6O}duB0*GmbCuyN*E2zYG0#q2I25z!MPj>B4-vFpnM90b*V5HNYg83{xQe-ZU$7@;Io6Q=tJS!X!8iCd2741*XC@I0L4` znQ#`&fU{vHd>R^|31-1La4yV-^WZZu7cPX)!aSG{m%?RmIV^zRgN1MfTm@IdHP8%8 zU@5dfD=dR+VL4n!#$%lE7-u}j8IN(sSHn8E2R6Vn@GNYD=ivwN0&IsL!7K1K{0!cK zcVQoy5Cx;*6Yxp+6vTWcU_KM<@CEn_SOc5jaftpVpuY(h;U#z(cEC>fUvgFt>?Jd> z9y72WGw?5}e7AUE%-xC?Ym%bpT4ABwy zs6qMw+4$FQQU2Hg>4WH@9bZs)`r2T-KOVb79*q->_p2iR-d!q{N~QOp!v7Aqoiagt z=B>_8^X;vVyrIsER4SD|Dz43b^XUkwc=3Mqw${s>i;c`cR+jMdTCa(`C8-FtpE6QH5m_S z+$W8=_x!ft+6#GJg!wd{bpN^WVh*?GE!PrU{l-%o&*5o}af{E@nMs}r|E6aB0qO}9 zH@?@Z4%m29<9>6$v0jWVv|hdCH0}e>Pr&xy(OQR||HHfzri3e_-Hxg>S6DZ=Kj;+C z|74zmUoNezHdI$t_s=@4W&N{eoA>O7O1r^cwV{8uwA_L0n93?gh1q6UYptw8=u39T z3zb$2a-%)v*Hv1qFCq}W-fFdT(Q<3G)xj5rmseHr=ZF$pRq1-eI<97vz1+OPip)rx znQIui=(!v&vaX^eE1&Bsb6B4j=c3eR-oSIg!AOg_+H5FuxTi@dKH5?BBLh#L=f9;G X;dKAe*VmWs=I;Lh2Ac9l&tCul2u3=V literal 3008 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 Date: Tue, 26 Sep 2023 15:20:48 -0400 Subject: [PATCH 228/385] Update doc for computeSyntheticROC() function --- R/synthetic.R | 1 + man/computeSyntheticROC.Rd | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/R/synthetic.R b/R/synthetic.R index 86e9c69bb..9765425d6 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -714,6 +714,7 @@ syntheticGeno <- function(gdsReference, gdsRefAnnot, fileProfileGDS, profileID, #' the super-population information from the 1KG GDS file #' for profiles used to generate the synthetic profiles. The \code{data.frame} #' must contained a column named as the \code{pedCallAncestryColumn} argument. +#' The row names must correspond to the sample identifiers (mandatory). #' #' @param pedCallAncestryColumn a \code{character} string representing the #' name of the column that contains the known ancestry for the reference diff --git a/man/computeSyntheticROC.Rd b/man/computeSyntheticROC.Rd index c9c3366ed..f23aef2cf 100644 --- a/man/computeSyntheticROC.Rd +++ b/man/computeSyntheticROC.Rd @@ -30,7 +30,8 @@ argument.} \item{pedCall}{a \code{data.frame} containing the information about the super-population information from the 1KG GDS file for profiles used to generate the synthetic profiles. The \code{data.frame} -must contained a column named as the \code{pedCallAncestryColumn} argument.} +must contained a column named as the \code{pedCallAncestryColumn} argument. +The row names must correspond to the sample identifiers (mandatory).} \item{pedCallAncestryColumn}{a \code{character} string representing the name of the column that contains the known ancestry for the reference From 6b86aa1360840645b7245f9b9e04fca3576876d4 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 26 Sep 2023 17:20:26 -0400 Subject: [PATCH 229/385] Add script to create deom pedSyn.RDS file --- .../demoAncestryCall/create_pedSynRDS.R | 47 ++++++++++++++++++ inst/extdata/demoAncestryCall/pedSyn.RDS | Bin 714 -> 715 bytes 2 files changed, 47 insertions(+) create mode 100644 inst/extdata/demoAncestryCall/create_pedSynRDS.R diff --git a/inst/extdata/demoAncestryCall/create_pedSynRDS.R b/inst/extdata/demoAncestryCall/create_pedSynRDS.R new file mode 100644 index 000000000..85131504a --- /dev/null +++ b/inst/extdata/demoAncestryCall/create_pedSynRDS.R @@ -0,0 +1,47 @@ + +############################################################ +## How to create the pedSyn.RDS file +## This file contains a small synthetic pedigree data.frame +############################################################ + +synthetic <- data.frame(data.id=c('1.ex1.HG00246.1', '1.ex1.HG00138.1', + '1.ex1.HG00325.1', '1.ex1.HG00330.1', '1.ex1.HG00611.1', + '1.ex1.HG00406.1', '1.ex1.HG01173.1', '1.ex1.HG01403.1', + '1.ex1.HG02165.1', '1.ex1.HG02390.1', '1.ex1.HG01112.1', + '1.ex1.HG01142.1', '1.ex1.HG01615.1', '1.ex1.HG01606.1', + '1.ex1.HG01968.1', '1.ex1.HG02299.1', '1.ex1.HG02658.1', + '1.ex1.HG03238.1', '1.ex1.HG01850.1', '1.ex1.HG02016.1', + '1.ex1.HG02013.1', '1.ex1.HG02339.1', '1.ex1.HG02465.1', + '1.ex1.HG02884.1', '1.ex1.HG02974.1', '1.ex1.HG03300.1', + '1.ex1.HG03814.1', '1.ex1.HG04153.1', '1.ex1.HG03445.1', + '1.ex1.HG03557.1', '1.ex1.HG03689.1', '1.ex1.HG03848.1', + '1.ex1.HG03789.1', '1.ex1.HG04239.1', '1.ex1.NA12751.1', + '1.ex1.NA12717.1', '1.ex1.NA19107.1', '1.ex1.NA19143.1', + '1.ex1.NA18548.1', '1.ex1.NA18616.1', '1.ex1.NA19075.1', + '1.ex1.NA19010.1', '1.ex1.NA19475.1', '1.ex1.NA19466.1', + '1.ex1.NA19712.1', '1.ex1.NA20126.1', '1.ex1.NA19731.1', + '1.ex1.NA19794.1', '1.ex1.NA20528.1', '1.ex1.NA20757.1', + '1.ex1.NA20908.1', '1.ex1.NA20847.1'), + case.id=c('HG00246', 'HG00138', 'HG00325', 'HG00330', 'HG00611', 'HG00406', + 'HG01173', 'HG01403', 'HG02165', 'HG02390', 'HG01112', 'HG01142', + 'HG01615', 'HG01606', 'HG01968', 'HG02299', 'HG02658', 'HG03238', + 'HG01850', 'HG02016', 'HG02013', 'HG02339', 'HG02465', 'HG02884', + 'HG02974', 'HG03300', 'HG03814', 'HG04153', 'HG03445', 'HG03557', + 'HG03689', 'HG03848', 'HG03789', 'HG04239', 'NA12751', 'NA12717', + 'NA19107', 'NA19143', 'NA18548', 'NA18616', 'NA19075', 'NA19010', + 'NA19475', 'NA19466', 'NA19712', 'NA20126', 'NA19731', 'NA19794', + 'NA20528', 'NA20757', 'NA20908', 'NA20847'), + sample.type=rep('Synthetic', 52), + diagnosis=rep('Cancer', 52), + source=rep('Synthetic', 52), + study.id=rep('MYDATA.Synthetic', 52), + superPop=c('EUR', 'EUR', 'EUR', 'EUR', 'EAS', 'EAS', 'AMR', 'AMR', 'EAS', + 'EAS', 'AMR', 'AMR', 'EUR', 'EUR', 'AMR', 'AMR', 'SAS', 'SAS', 'EAS', + 'EAS', 'AFR', 'AFR', 'AFR', 'AFR', 'AFR', 'AFR', 'SAS', 'SAS', 'AFR', + 'AFR', 'SAS', 'SAS', 'SAS', 'SAS', 'EUR', 'EUR', 'AFR', 'AFR', 'EAS', + 'EAS', 'EAS', 'EAS', 'AFR', 'AFR', 'AFR', 'AFR', 'AMR', 'AMR', 'EUR', + 'EUR', 'SAS', 'SAS'), stringsAsFactors=FALSE) + +rownames(synthetic) <- synthetic$data.id + +saveRDS(synthetic, file="pedSyn.RDS") diff --git a/inst/extdata/demoAncestryCall/pedSyn.RDS b/inst/extdata/demoAncestryCall/pedSyn.RDS index b264779208053dcb798db0336beda57ab6f7333e..fae2f436556c307a216eb9b340491b993da3f3ac 100644 GIT binary patch literal 715 zcmV;+0yO;}iwFP!000002JM;OZ__Xk$1~cl>v&)ie+N;{cH-o*0tPReP`gR+7_|W^ zZEe-Gg8lOomnv1y^%seX9|Gius{Vd_vG2~g%Y)yaM^V&?x}B4#)8k>(yS=%5ku!VF zqR+nz{+Xy74fy{V#no4e-@Zu_WwMxjOgcwcs}y3LAe<2)Y!b93k<|#B1Yt!P@6Hofr+)y+9*FK*F#b^_1@SmCeIVb1tl08FG|LF>O0ur z%sQO$OJtel=VV`R!5ITBDp4w(yR)StL~;O2yHDRH>v$pmlB< zYqw|h+ioQ#cPS~kJ2_G(QgSzvlDm+QP4|(KyN-}ew~>;&jPoohM;b?RH*uu9FLw{Q zGItFrxmyU?bP4$^cL!0(Pkwy#IRG*aDK38qEIg%17jXTR#C8gb;ep^M(tR_bm zMjCUqNNH0mC0B=(Tong3F&ID0*PpBPY!W~K0sLOz*52vMaz3e6K?U`nsPJtGAb`K& z+j4RB;nnbF7#}_mc;JBt{_k?P&vjnkj(&VN9E0KTY6ONy*}~nh?RdY~7;YhVyBz)G z5bt)3?RWge5yN$HY`-AlBhKO=im3a9hbJxS&CC0$ZeOf^3;WY@UBn&< x&$rHeT(O@A=7ZJZODz2l7c>VrT+nzpT+jdVR!%l literal 714 zcmV;*0yX^~iwFP!000002JKnFZqq;zHMD7(a-b65f#umK@N#-L1enp#9>IVwlz1~%5hXrug|+?1qj>b>3iXTL{>?gnX9WK?d{ME_6y@7m(1n6|w3iWVOqES>+P4x&>@iEoWKH60(XVWc4~r z8K*$&%(g1s!A_kHBr9O6Mh6-#V5>d}vwg2RwKd|NKB zKfW$+%lPntzz06?f&X`T*XK^&+zo$ySdPH3ydHw#QL%7096Q=CHiBEo-L8heImEji z6Z?~Vam8?5T-zV0_=vMOsA7A|5k2Xs-mH44o9@NxcVvH3t*UrB*}-wu)O+}>sU8;h zb-dav>fNV!GOa$(=FPO}h_hzCUXFLu=gn$8+3Z(1Z`O-?`F_4QNM^8{e~o2A;l|~F w4mU0y9d29z9d2BF`tfgETxT8MSIy4IcI3s@SwAh=;~0Ja0c!S9*?1lR0E2j4ng9R* From 6156e735fc9986ebd71a3b2d08b9639d904eed04 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 26 Sep 2023 22:37:01 -0400 Subject: [PATCH 230/385] Create pedSynthetic dataset with documentation --- R/RAIDS.R | 102 ++++++++++++++++++ R/processStudy_internal.R | 11 +- R/synthetic.R | 11 +- R/synthetic_internal.R | 24 +++-- data/pedSynthetic.RData | Bin 0 -> 672 bytes .../demoAncestryCall/create_pedSynRDS.R | 47 -------- inst/extdata/demoAncestryCall/pedSyn.RDS | Bin 715 -> 0 bytes man/computeSyntheticConfMat.Rd | 13 +-- man/computeSyntheticROC.Rd | 11 +- man/pedSynthetic.Rd | 99 +++++++++++++++++ man/selParaPCAUpQuartile.Rd | 11 +- man/validateComputeSyntheticRoc.Rd | 11 +- 12 files changed, 251 insertions(+), 89 deletions(-) create mode 100644 data/pedSynthetic.RData delete mode 100644 inst/extdata/demoAncestryCall/create_pedSynRDS.R delete mode 100644 inst/extdata/demoAncestryCall/pedSyn.RDS create mode 100644 man/pedSynthetic.Rd diff --git a/R/RAIDS.R b/R/RAIDS.R index 8a83324e0..6a5878e47 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -60,3 +60,105 @@ #' @encoding UTF-8 #' @keywords package NULL + + +#' A small \code{data.frame} containing the information related to +#' synthetic profiles. The ancestry of the profiles used to generate the +#' synthetic profiles must be present. +#' +#' The object is a \code{data.frame} with 7 columns. The row names of +#' the \code{data.frame} must be the profile unique identifiers. +#' +#' This dataset can be +#' used to test the \code{\link{computeSyntheticROC}} function. +#' +#' @name pedSynthetic +#' +#' @docType data +#' +#' @aliases pedSynthetic +#' +#' @format The \code{data.frame} containing the information about the +#' synthetic profiles. The row names of +#' the \code{data.frame} correspond to the profile unique identifiers. +#' The \code{data.frame} contains 7 columns: +#' \itemize{ +#' \item \code{data.id} {a \code{character} string representing the unique +#' synthetic profile identifier.} +#' \item \code{case.id} {a \code{character} string representing the unique +#' profile identifier that was used to generate the synthetic profile.} +#' \item \code{sample.type} {a \code{character} string representing the type +#' of profile. } +#' \item \code{diagnosis} {a \code{character} string representing the +#' diagnosis of profile that was used to generate the synthetic profile. } +#' \item \code{source} {a \code{character} string representing the +#' source of the synthetic profile. } +#' \item \code{study.id} {a \code{character} string representing the +#' name of the study to which the synthetic profile is associated. } +#' \item \code{superPop} {a \code{character} string representing the +#' super population of the profile that was used to generate the synthetic +#' profile. } +#' } +#' +#' @return The \code{data.frame} containing the information about the +#' synthetic profiles. The row names of +#' the \code{data.frame} correspond to the profile unique identifiers. +#' The \code{data.frame} contains 7 columns: +#' \itemize{ +#' \item \code{data.id} {a \code{character} string representing the unique +#' synthetic profile identifier.} +#' \item \code{case.id} {a \code{character} string representing the unique +#' profile identifier that was used to generate the synthetic profile.} +#' \item \code{sample.type} {a \code{character} string representing the type +#' of profile. } +#' \item \code{diagnosis} {a \code{character} string representing the +#' diagnosis of profile that was used to generate the synthetic profile. } +#' \item \code{source} {a \code{character} string representing the +#' source of the synthetic profile. } +#' \item \code{study.id} {a \code{character} string representing the +#' name of the study to which the synthetic profile is associated. } +#' \item \code{superPop} {a \code{character} string representing the +#' super population of the profile that was used to generate the synthetic +#' profile. } +#' } +#' +#' @seealso +#' \itemize{ +#' \item \code{\link{computeSyntheticROC}} {for calculating the AUROC of +#' the inferences for specific values of D and K using the inferred +#' ancestry results from the synthetic profiles} +#' } +#' +#' @usage data(pedSynthetic) +#' +#' @keywords datasets +#' +#' @examples +#' +#' ## Loading demo dataset containing pedigree information for synthetic +#' ## profiles +#' data(pedSynthetic) +#' +#' dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") +#' +#' ## The inferred ancestry results for the synthetic data using +#' ## values of D=5 and K=5 +#' matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) +#' matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] +#' +#' ## Compile statistics from the +#' ## synthetic profiles for fixed values of D and K +#' results <- RAIDS:::computeSyntheticROC(matKNN=matKNN, +#' matKNNAncestryColumn="SuperPop", +#' pedCall=pedSynthetic, pedCallAncestryColumn="superPop", +#' listCall=c("EAS", "EUR", "AFR", "AMR", "SAS")) +#' +#' results$matAUROC.All +#' results$matAUROC.Call +#' results$listROC.Call +#' +#' +NULL + + + diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index d288f3cf6..06d6dbcb1 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -1839,21 +1839,22 @@ computePCARefRMMulti <- function(gdsProfile, refProfileIDs, listRM, np=1L, #' #' @examples #' +#' ## Loading demo dataset containing pedigree information for synthetic +#' ## profiles and known ancestry of the profiles used to generate the +#' ## synthetic profiles +#' data(pedSynthetic) +#' #' dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") #' #' ## The inferred ancestry results for the synthetic data using different #' ## values of D and K #' matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) #' -#' ## The known ancestry from the reference profiles used to generate the -#' ## synthetic profiles -#' syntheticInfo <- readRDS(file.path(dataDirRes, "pedSyn.RDS")) -#' #' ## Compile all the results for ancestry inference done on the #' ## synthetic profiles for different D and K values #' ## Select the optimal D and K values #' results <- RAIDS:::selParaPCAUpQuartile(matKNN=matKNN, -#' pedCall=syntheticInfo, refCall="superPop", predCall="SuperPop", +#' pedCall=pedSynthetic, refCall="superPop", predCall="SuperPop", #' listCall=c("EAS", "EUR", "AFR", "AMR", "SAS"), kList=seq(3,15,1), #' pcaList=seq(2,15,1)) #' results$D diff --git a/R/synthetic.R b/R/synthetic.R index 9765425d6..f55ae41b5 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -737,6 +737,11 @@ syntheticGeno <- function(gdsReference, gdsRefAnnot, fileProfileGDS, profileID, #' #' @examples #' +#' ## Loading demo dataset containing pedigree information for synthetic +#' ## profiles and known ancestry of the profiles used to generate the +#' ## synthetic profiles +#' data(pedSynthetic) +#' #' dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") #' #' ## The inferred ancestry results for the synthetic data using @@ -744,15 +749,11 @@ syntheticGeno <- function(gdsReference, gdsRefAnnot, fileProfileGDS, profileID, #' matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) #' matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] #' -#' ## The known ancestry from the reference profiles used to generate the -#' ## synthetic profiles -#' syntheticInfo <- readRDS(file.path(dataDirRes, "pedSyn.RDS")) -#' #' ## Compile statistics from the #' ## synthetic profiles for fixed values of D and K #' results <- RAIDS:::computeSyntheticROC(matKNN=matKNN, #' matKNNAncestryColumn="SuperPop", -#' pedCall=syntheticInfo, pedCallAncestryColumn="superPop", +#' pedCall=pedSynthetic, pedCallAncestryColumn="superPop", #' listCall=c("EAS", "EUR", "AFR", "AMR", "SAS")) #' #' results$matAUROC.All diff --git a/R/synthetic_internal.R b/R/synthetic_internal.R index d33c09b8e..7f473ad6f 100644 --- a/R/synthetic_internal.R +++ b/R/synthetic_internal.R @@ -266,6 +266,11 @@ validatePepSynthetic <- function(fileProfileGDS, #' #' @examples #' +#' ## Loading demo dataset containing pedigree information for synthetic +#' ## profiles and known ancestry of the profiles used to generate the +#' ## synthetic profiles +#' data(pedSynthetic) +#' #' ## Directory where demo GDS files are located #' dataDir <- system.file("extdata/demoAncestryCall", package="RAIDS") #' @@ -274,14 +279,10 @@ validatePepSynthetic <- function(fileProfileGDS, #' matKNN <- readRDS(file.path(dataDir, "matKNN.RDS")) #' matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] #' -#' ## The known ancestry from the reference profiles used to generate the -#' ## synthetic profiles -#' syntheticData <- readRDS(file.path(dataDir, "pedSyn.RDS")) -#' #' ## The validation should be successful #' RAIDS:::validateComputeSyntheticRoc(matKNN=matKNN, #' matKNNAncestryColumn="SuperPop", -#' pedCall=syntheticData, pedCallAncestryColumn="superPop", +#' pedCall=pedSynthetic, pedCallAncestryColumn="superPop", #' listCall=c("EAS", "EUR", "AFR", "AMR", "SAS")) #' #' @@ -483,22 +484,23 @@ prepPedSynthetic1KG <- function(gdsReference, gdsSample, studyID, popName) { #' #' @examples #' +#' ## Loading demo dataset containing pedigree information for synthetic +#' ## profiles and known ancestry of the profiles used to generate the +#' ## synthetic profiles +#' data(pedSynthetic) +#' #' dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") #' #' ## The inferred ancestry results for the synthetic data using #' ## values of D=6 and K=5 #' matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) -#' matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] -#' -#' ## The known ancestry from the reference profiles used to generate the -#' ## synthetic profiles -#' syntheticInfo <- readRDS(file.path(dataDirRes, "pedSyn.RDS")) +#' matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ]) #' #' ## Compile the confusion matrix using the #' ## synthetic profiles for fixed values of D and K values #' results <- RAIDS:::computeSyntheticConfMat(matKNN=matKNN, #' matKNNAncestryColumn="SuperPop", -#' pedCall=syntheticInfo, pedCallAncestryColumn="superPop", +#' pedCall=pedSynthetic, pedCallAncestryColumn="superPop", #' listCall=c("EAS", "EUR", "AFR", "AMR", "SAS")) #' #' results$confMat diff --git a/data/pedSynthetic.RData b/data/pedSynthetic.RData new file mode 100644 index 0000000000000000000000000000000000000000..e9ef8066ebfcbfb8bd1cf972e57235a8c3ee1bb3 GIT binary patch literal 672 zcmV;R0$=_8H+ooF0004LBHlIv03iV!0000G&sfah9-IPXT>vQ&2UKVgRpfklJ zX=^v9WE6OKWtF?;!#~}43m-yaauGr z4Q8NNur`DZ8JG`&S`E`Z(KytN(ZN{tV3EhI)LAS`2-G%VOs8h1@{jsWcgXFQKNjg# ziZ#tqbAJya-z`8)ko`t_(8z-;`6SH5DGAQlbHQGsm%+Omn`J|?qhg#c!oijArJxO^ z-4`}71mH5C)j342J`)B={~xn*Q+OX8*zCEr6M|5TDp5`O z6U;6_2aVHiWNl^Cah;14Ero5ySpa0$wb`|hr3$!+oQk6#?nfM(Tjt~gnpAp_+z&pG z`i2p41f*Q=;D(1k%w;Wn<+fSao=MjTb+>F4aaUs=lS5*?U?!q9(4@Z03(Z{dukbcH zh?=0hNEPFx4yDFFKA_$zlj}{UE0dJMxnCJqP}919n5dj0v&)ie+N;{cH-o*0tPReP`gR+7_|W^ zZEe-Gg8lOomnv1y^%seX9|Gius{Vd_vG2~g%Y)yaM^V&?x}B4#)8k>(yS=%5ku!VF zqR+nz{+Xy74fy{V#no4e-@Zu_WwMxjOgcwcs}y3LAe<2)Y!b93k<|#B1Yt!P@6Hofr+)y+9*FK*F#b^_1@SmCeIVb1tl08FG|LF>O0ur z%sQO$OJtel=VV`R!5ITBDp4w(yR)StL~;O2yHDRH>v$pmlB< zYqw|h+ioQ#cPS~kJ2_G(QgSzvlDm+QP4|(KyN-}ew~>;&jPoohM;b?RH*uu9FLw{Q zGItFrxmyU?bP4$^cL!0(Pkwy#IRG*aDK38qEIg%17jXTR#C8gb;ep^M(tR_bm zMjCUqNNH0mC0B=(Tong3F&ID0*PpBPY!W~K0sLOz*52vMaz3e6K?U`nsPJtGAb`K& z+j4RB;nnbF7#}_mc;JBt{_k?P&vjnkj(&VN9E0KTY6ONy*}~nh?RdY~7;YhVyBz)G z5bt)3?RWge5yN$HY`-AlBhKO=im3a9hbJxS&CC0$ZeOf^3;WY@UBn&< x&$rHeT(O@A=7ZJZODz2l7c>VrT+nzpT+jdVR!%l diff --git a/man/computeSyntheticConfMat.Rd b/man/computeSyntheticConfMat.Rd index ca849346e..5d08c9b13 100644 --- a/man/computeSyntheticConfMat.Rd +++ b/man/computeSyntheticConfMat.Rd @@ -54,22 +54,23 @@ on the synthetic profiles. } \examples{ +## Loading demo dataset containing pedigree information for synthetic +## profiles and known ancestry of the profiles used to generate the +## synthetic profiles +data(pedSynthetic) + dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") ## The inferred ancestry results for the synthetic data using ## values of D=6 and K=5 matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) -matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] - -## The known ancestry from the reference profiles used to generate the -## synthetic profiles -syntheticInfo <- readRDS(file.path(dataDirRes, "pedSyn.RDS")) +matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ]) ## Compile the confusion matrix using the ## synthetic profiles for fixed values of D and K values results <- RAIDS:::computeSyntheticConfMat(matKNN=matKNN, matKNNAncestryColumn="SuperPop", - pedCall=syntheticInfo, pedCallAncestryColumn="superPop", + pedCall=pedSynthetic, pedCallAncestryColumn="superPop", listCall=c("EAS", "EUR", "AFR", "AMR", "SAS")) results$confMat diff --git a/man/computeSyntheticROC.Rd b/man/computeSyntheticROC.Rd index f23aef2cf..c79c7d4ae 100644 --- a/man/computeSyntheticROC.Rd +++ b/man/computeSyntheticROC.Rd @@ -61,6 +61,11 @@ well as on all the results together. } \examples{ +## Loading demo dataset containing pedigree information for synthetic +## profiles and known ancestry of the profiles used to generate the +## synthetic profiles +data(pedSynthetic) + dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") ## The inferred ancestry results for the synthetic data using @@ -68,15 +73,11 @@ dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] -## The known ancestry from the reference profiles used to generate the -## synthetic profiles -syntheticInfo <- readRDS(file.path(dataDirRes, "pedSyn.RDS")) - ## Compile statistics from the ## synthetic profiles for fixed values of D and K results <- RAIDS:::computeSyntheticROC(matKNN=matKNN, matKNNAncestryColumn="SuperPop", - pedCall=syntheticInfo, pedCallAncestryColumn="superPop", + pedCall=pedSynthetic, pedCallAncestryColumn="superPop", listCall=c("EAS", "EUR", "AFR", "AMR", "SAS")) results$matAUROC.All diff --git a/man/pedSynthetic.Rd b/man/pedSynthetic.Rd new file mode 100644 index 000000000..39e8501a1 --- /dev/null +++ b/man/pedSynthetic.Rd @@ -0,0 +1,99 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RAIDS.R +\docType{data} +\name{pedSynthetic} +\alias{pedSynthetic} +\title{A small \code{data.frame} containing the information related to +synthetic profiles. The ancestry of the profiles used to generate the +synthetic profiles must be present.} +\format{ +The \code{data.frame} containing the information about the +synthetic profiles. The row names of +the \code{data.frame} correspond to the profile unique identifiers. +The \code{data.frame} contains 7 columns: +\itemize{ +\item \code{data.id} {a \code{character} string representing the unique +synthetic profile identifier.} +\item \code{case.id} {a \code{character} string representing the unique +profile identifier that was used to generate the synthetic profile.} +\item \code{sample.type} {a \code{character} string representing the type +of profile. } +\item \code{diagnosis} {a \code{character} string representing the +diagnosis of profile that was used to generate the synthetic profile. } +\item \code{source} {a \code{character} string representing the +source of the synthetic profile. } +\item \code{study.id} {a \code{character} string representing the +name of the study to which the synthetic profile is associated. } +\item \code{superPop} {a \code{character} string representing the +super population of the profile that was used to generate the synthetic +profile. } +} +} +\usage{ +data(pedSynthetic) +} +\value{ +The \code{data.frame} containing the information about the +synthetic profiles. The row names of +the \code{data.frame} correspond to the profile unique identifiers. +The \code{data.frame} contains 7 columns: +\itemize{ +\item \code{data.id} {a \code{character} string representing the unique +synthetic profile identifier.} +\item \code{case.id} {a \code{character} string representing the unique +profile identifier that was used to generate the synthetic profile.} +\item \code{sample.type} {a \code{character} string representing the type +of profile. } +\item \code{diagnosis} {a \code{character} string representing the +diagnosis of profile that was used to generate the synthetic profile. } +\item \code{source} {a \code{character} string representing the +source of the synthetic profile. } +\item \code{study.id} {a \code{character} string representing the +name of the study to which the synthetic profile is associated. } +\item \code{superPop} {a \code{character} string representing the +super population of the profile that was used to generate the synthetic +profile. } +} +} +\description{ +The object is a \code{data.frame} with 7 columns. The row names of +the \code{data.frame} must be the profile unique identifiers. +} +\details{ +This dataset can be +used to test the \code{\link{computeSyntheticROC}} function. +} +\examples{ + +## Loading demo dataset containing pedigree information for synthetic +## profiles +data(pedSynthetic) + +dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") + +## The inferred ancestry results for the synthetic data using +## values of D=5 and K=5 +matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) +matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] + +## Compile statistics from the +## synthetic profiles for fixed values of D and K +results <- RAIDS:::computeSyntheticROC(matKNN=matKNN, + matKNNAncestryColumn="SuperPop", + pedCall=pedSynthetic, pedCallAncestryColumn="superPop", + listCall=c("EAS", "EUR", "AFR", "AMR", "SAS")) + +results$matAUROC.All +results$matAUROC.Call +results$listROC.Call + + +} +\seealso{ +\itemize{ +\item \code{\link{computeSyntheticROC}} {for calculating the AUROC of +the inferences for specific values of D and K using the inferred +ancestry results from the synthetic profiles} +} +} +\keyword{datasets} diff --git a/man/selParaPCAUpQuartile.Rd b/man/selParaPCAUpQuartile.Rd index a669fbd38..81a0e5797 100644 --- a/man/selParaPCAUpQuartile.Rd +++ b/man/selParaPCAUpQuartile.Rd @@ -111,21 +111,22 @@ accuracy. } \examples{ +## Loading demo dataset containing pedigree information for synthetic +## profiles and known ancestry of the profiles used to generate the +## synthetic profiles +data(pedSynthetic) + dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") ## The inferred ancestry results for the synthetic data using different ## values of D and K matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) -## The known ancestry from the reference profiles used to generate the -## synthetic profiles -syntheticInfo <- readRDS(file.path(dataDirRes, "pedSyn.RDS")) - ## Compile all the results for ancestry inference done on the ## synthetic profiles for different D and K values ## Select the optimal D and K values results <- RAIDS:::selParaPCAUpQuartile(matKNN=matKNN, - pedCall=syntheticInfo, refCall="superPop", predCall="SuperPop", + pedCall=pedSynthetic, refCall="superPop", predCall="SuperPop", listCall=c("EAS", "EUR", "AFR", "AMR", "SAS"), kList=seq(3,15,1), pcaList=seq(2,15,1)) results$D diff --git a/man/validateComputeSyntheticRoc.Rd b/man/validateComputeSyntheticRoc.Rd index 6e13bcd97..83ca2e132 100644 --- a/man/validateComputeSyntheticRoc.Rd +++ b/man/validateComputeSyntheticRoc.Rd @@ -47,6 +47,11 @@ This function validates the input parameters for the } \examples{ +## Loading demo dataset containing pedigree information for synthetic +## profiles and known ancestry of the profiles used to generate the +## synthetic profiles +data(pedSynthetic) + ## Directory where demo GDS files are located dataDir <- system.file("extdata/demoAncestryCall", package="RAIDS") @@ -55,14 +60,10 @@ dataDir <- system.file("extdata/demoAncestryCall", package="RAIDS") matKNN <- readRDS(file.path(dataDir, "matKNN.RDS")) matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] -## The known ancestry from the reference profiles used to generate the -## synthetic profiles -syntheticData <- readRDS(file.path(dataDir, "pedSyn.RDS")) - ## The validation should be successful RAIDS:::validateComputeSyntheticRoc(matKNN=matKNN, matKNNAncestryColumn="SuperPop", - pedCall=syntheticData, pedCallAncestryColumn="superPop", + pedCall=pedSynthetic, pedCallAncestryColumn="superPop", listCall=c("EAS", "EUR", "AFR", "AMR", "SAS")) From 0fc229f3ec8a06d8f28dfd0d80e6e6786b2d291f Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 26 Sep 2023 23:37:48 -0400 Subject: [PATCH 231/385] Create matKNNSynthetic dataset with documentation --- R/RAIDS.R | 87 +++++++++++++++++++++-- R/processStudy_internal.R | 10 ++- R/synthetic.R | 7 +- R/synthetic_internal.R | 15 ++-- data/matKNNSynthetic.RData | Bin 0 -> 3088 bytes inst/extdata/demoAncestryCall/matKNN.RDS | Bin 5293 -> 0 bytes man/computeSyntheticConfMat.Rd | 7 +- man/computeSyntheticROC.Rd | 7 +- man/matKNNSynthetic.Rd | 79 ++++++++++++++++++++ man/pedSynthetic.Rd | 10 +-- man/selParaPCAUpQuartile.Rd | 10 ++- man/validateComputeSyntheticRoc.Rd | 8 +-- 12 files changed, 198 insertions(+), 42 deletions(-) create mode 100644 data/matKNNSynthetic.RData delete mode 100644 inst/extdata/demoAncestryCall/matKNN.RDS create mode 100644 man/matKNNSynthetic.Rd diff --git a/R/RAIDS.R b/R/RAIDS.R index 6a5878e47..ed7d2da1d 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -139,12 +139,12 @@ NULL #' ## profiles #' data(pedSynthetic) #' -#' dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") +#' ## Loading demo dataset containing the inferred ancestry results +#' ## for the synthetic data +#' data(matKNNSynthetic) #' -#' ## The inferred ancestry results for the synthetic data using -#' ## values of D=5 and K=5 -#' matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) -#' matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] +#' ## Retain one K and one D value +#' matKNN <- matKNNSynthetic[matKNNSynthetic$D == 5 & matKNNSynthetic$K == 4, ] #' #' ## Compile statistics from the #' ## synthetic profiles for fixed values of D and K @@ -161,4 +161,81 @@ NULL NULL +#' A small \code{data.frame} containing the +#' inferred ancestry on the synthetic profiles. +#' +#' The object is a \code{data.frame} with 4 columns. +#' +#' This dataset can be +#' used to test the \code{\link{computeSyntheticROC}} function. +#' +#' @name matKNNSynthetic +#' +#' @docType data +#' +#' @aliases matKNNSynthetic +#' +#' @format The \code{data.frame} containing the information about the +#' synthetic profiles. The \code{data.frame} contains 4 columns: +#' \itemize{ +#' \item \code{sample.id} {a \code{character} string representing the unique +#' synthetic profile identifier.} +#' \item \code{D} {a \code{numeric} representing the number of dimensions used +#' to infer the ancestry of the synthetic profile.} +#' \item \code{K} {a \code{numeric} representing the number of neighbors used +#' to infer the ancestry of the synthetic profile.} +#' \item \code{SuperPop} {a \code{character} string representing the +#' inferred ancestry of the synthetic profile for the specific D and K values.} +#' } +#' +#' @return The \code{data.frame} containing the information about the +#' synthetic profiles. The \code{data.frame} contains 4 columns: +#' \itemize{ +#' \item \code{sample.id} {a \code{character} string representing the unique +#' synthetic profile identifier.} +#' \item \code{D} {a \code{numeric} representing the number of dimensions used +#' to infer the ancestry of the synthetic profile.} +#' \item \code{K} {a \code{numeric} representing the number of neighbors used +#' to infer the ancestry of the synthetic profile.} +#' \item \code{SuperPop} {a \code{character} string representing the +#' inferred ancestry of the synthetic profile for the specific D and K values.} +#' } +#' +#' @seealso +#' \itemize{ +#' \item \code{\link{computeSyntheticROC}} {for calculating the AUROC of +#' the inferences for specific values of D and K using the inferred +#' ancestry results from the synthetic profiles} +#' } +#' +#' @usage data(matKNNSynthetic) +#' +#' @keywords datasets +#' +#' @examples +#' +#' ## Loading demo dataset containing pedigree information for synthetic +#' ## profiles +#' data(pedSynthetic) +#' +#' ## Loading demo dataset containing the inferred ancestry results +#' ## for the synthetic data +#' data(matKNNSynthetic) +#' +#' ## Retain one K and one D value +#' matKNN <- matKNNSynthetic[matKNNSynthetic$D == 5 & matKNNSynthetic$K == 4, ] +#' +#' ## Compile statistics from the +#' ## synthetic profiles for fixed values of D and K +#' results <- RAIDS:::computeSyntheticROC(matKNN=matKNN, +#' matKNNAncestryColumn="SuperPop", +#' pedCall=pedSynthetic, pedCallAncestryColumn="superPop", +#' listCall=c("EAS", "EUR", "AFR", "AMR", "SAS")) +#' +#' results$matAUROC.All +#' results$matAUROC.Call +#' results$listROC.Call +#' +#' +NULL diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 06d6dbcb1..a031ba896 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -1844,16 +1844,14 @@ computePCARefRMMulti <- function(gdsProfile, refProfileIDs, listRM, np=1L, #' ## synthetic profiles #' data(pedSynthetic) #' -#' dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") -#' -#' ## The inferred ancestry results for the synthetic data using different -#' ## values of D and K -#' matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) +#' ## Loading demo dataset containing the inferred ancestry results +#' ## for the synthetic data +#' data(matKNNSynthetic) #' #' ## Compile all the results for ancestry inference done on the #' ## synthetic profiles for different D and K values #' ## Select the optimal D and K values -#' results <- RAIDS:::selParaPCAUpQuartile(matKNN=matKNN, +#' results <- RAIDS:::selParaPCAUpQuartile(matKNN=matKNNSynthetic, #' pedCall=pedSynthetic, refCall="superPop", predCall="SuperPop", #' listCall=c("EAS", "EUR", "AFR", "AMR", "SAS"), kList=seq(3,15,1), #' pcaList=seq(2,15,1)) diff --git a/R/synthetic.R b/R/synthetic.R index f55ae41b5..5828118b2 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -742,12 +742,13 @@ syntheticGeno <- function(gdsReference, gdsRefAnnot, fileProfileGDS, profileID, #' ## synthetic profiles #' data(pedSynthetic) #' -#' dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") +#' ## Loading demo dataset containing the inferred ancestry results +#' ## for the synthetic data +#' data(matKNNSynthetic) #' #' ## The inferred ancestry results for the synthetic data using #' ## values of D=6 and K=5 -#' matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) -#' matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] +#' matKNN <- matKNNSynthetic[matKNNSynthetic$K == 6 & matKNNSynthetic$D == 5, ] #' #' ## Compile statistics from the #' ## synthetic profiles for fixed values of D and K diff --git a/R/synthetic_internal.R b/R/synthetic_internal.R index 7f473ad6f..56e7e2aa9 100644 --- a/R/synthetic_internal.R +++ b/R/synthetic_internal.R @@ -271,13 +271,13 @@ validatePepSynthetic <- function(fileProfileGDS, #' ## synthetic profiles #' data(pedSynthetic) #' -#' ## Directory where demo GDS files are located -#' dataDir <- system.file("extdata/demoAncestryCall", package="RAIDS") +#' ## Loading demo dataset containing the inferred ancestry results +#' ## for the synthetic data +#' data(matKNNSynthetic) #' #' ## The inferred ancestry results for the synthetic data using #' ## values of D=6 and K=5 -#' matKNN <- readRDS(file.path(dataDir, "matKNN.RDS")) -#' matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] +#' matKNN <- matKNNSynthetic[matKNNSynthetic$K == 6 & matKNNSynthetic$D == 5, ] #' #' ## The validation should be successful #' RAIDS:::validateComputeSyntheticRoc(matKNN=matKNN, @@ -489,12 +489,13 @@ prepPedSynthetic1KG <- function(gdsReference, gdsSample, studyID, popName) { #' ## synthetic profiles #' data(pedSynthetic) #' -#' dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") +#' ## Loading demo dataset containing the inferred ancestry results +#' ## for the synthetic data +#' data(matKNNSynthetic) #' #' ## The inferred ancestry results for the synthetic data using #' ## values of D=6 and K=5 -#' matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) -#' matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ]) +#' matKNN <- matKNNSynthetic[matKNNSynthetic$K == 6 & matKNNSynthetic$D == 5, ] #' #' ## Compile the confusion matrix using the #' ## synthetic profiles for fixed values of D and K values diff --git a/data/matKNNSynthetic.RData b/data/matKNNSynthetic.RData new file mode 100644 index 0000000000000000000000000000000000000000..b4b7771a77a41106414bbe56916bbdeacd2fc93d GIT binary patch literal 3088 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 literal 0 HcmV?d00001 diff --git a/inst/extdata/demoAncestryCall/matKNN.RDS b/inst/extdata/demoAncestryCall/matKNN.RDS deleted file mode 100644 index 83e79b3f65208a8775c04a87556216f23a3d5f21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5293 zcmeHIX;{)}yPxVksZ(m^n;VsLveJA-%G6X0dUHlgOC2?LMW+x=1+x@)ozb*%Yo>&9 zBimfiOi*!!)HIXa1w;|I(A`uN0Y&7D( zfK2($4+hd&PnSHtJ2HGHj`zM~8Rr*KxH0IXtIy;7Xl)%J5ed+ZV`y|QZcHMP6L6N3 z9TK@*=onkFP`NDO#tA~sEJbR^N5JBvBr6olru9XM5-36VU`reoy*2e++sVCu9n^22 zEH|0|wpHtOVOWyCM(SUO)RNZL{a^nvX*=1Z2s!-9jvC}Aqc!=DIJ1LU-y%8Y6Mp>* zNP1CS9a{r_1LX^Aku?KMwk^>P|L1vs4fbwrLE01!_1ktN_(rA0HcN%|<(d844PmUq z+nlUe<-mi?6=glh|FsgevP~&-b(=zyf|yBdGI*rsB-9#&8JCg<JqP>-wiF{sIlX(*t*ujW{4npZ24JbLX$`$c`+yWBf^$Wv8Pim(zTB-mq%Mdmnz)d}3-Dlri`?`$ z)>(ZB&S$2)dQ{PDT8%Iyg>9Z5{+ifv_q*~e*Dh_-HxofbE>oWIsQ?Hln(I2PpJ#ty z*F)Wo2c_dvEU9{U$`YMP=+^Q$9Gd;w#75(zUQU<54jXR!f>-r0cOhV7i82xu=f9t2w05Xg%AIqaqZ{9lD=a zA&0683~CDiGwQ%mt$&ES3%xtztNkk!M`H`iGtuGdEw@a07qLKa=gbRULPUdgLqEAYl7)<6ULMLRn#kTpGG*!V^nm|6ok&c*nX#2vc z)J4fN>m(^03Ey}cmBO3+fiRgG)hh0bwjsU$g-dcL7y8w=^8onf4(&6GC)2T4zp(GZ z=8zGsHzU@3QF^DBSI_)t6VJ72Q`ZXFva0FL&2R>oyPLO0*?cVvTh25PEa%BN6-w=; zSN6+k+^s1;zPMPzf%Y*8DWL}&cHXSu6zhDjxsnGtf3xT55JGqfm+6spQks*Tu44Dp z!W^4NefF>Q&_nVM){OW7kv~_bLSaQQRMXQ?JM6f(!fa1P#>w5vTOA5SmuA>$0_#H^ z5zf)pD1z&J@ff_udL566z4Nw^fh86Bx7B`G@dzO$MQ8S*OR66#=7qfuXOR@$U~(HL%rgS}I5*uv#yU+fZmg**W75Z73 z*J)nCt^(@K81%DFEC*MYJ{;|Ncd_K9jvx0|XVadjT@&&m4;z;l|509|9kBL5M|ks1)Bc_6zFak-#j z;3A2HXN<7Yp=YN1@DW3P#Y;jA3~yeu6|!LuK2Nm(W#%fS=Il-_NG|4J7dQlgR(Mjs zZF4hlb}c6cLFBPUL}p!SgYJqp=rsmCrn(5y?{2x%-aru*WcAVMLCukBOI2pH>Gx(> z<7xxJ^L;VFPaqA~=Y~2@MFlbkel7qrG~c<+p8E2MTqUhC{oW_ubFLj%4Q(EsH9H0I z+6<;SxI^-Wc=dT_jmM2t)I=YnuL0)W($hgLRx78EQkwr=8g~nBLXJUDj(C}#x4F`b z(5VhdLHL&q=IR*FvbuO5*z(<)Md*}odXK2aN3+YikL2b0AE*vVW zzIlyI{~;d#4aUwDwq7-ybgUx43n9ai#LrK4vN*^uhZBJ`Mx zg{OuH!0YcE5juIEu66{>&o|bnu|_BkVN#2yfK1|DM3;xNFeh-Xk7Ebx;AX@t&-UFj=AnCmuEE3H7jkAkv@Um4>DW z4&cm^E60yfv9_6g2Z3M_!7@w}Em_K_RB4D|O+O_%t6Kj+r33^5$|$C-=-7cdV|Qk_ z&bq)3P>Csi0q;Ut-aV1?{$Cia1mIPNrQpY3TZ1AUBjbtAU&rOBQDngL z^?EAK;4HU3ejHe&sAKH3agCZP5_3!pshQO3MNB`To#WRn9gw>UOf1|~v-%Fk*WQ5Y z<@`C#3k~sCpS2*rH0k&3Bpvx$7gXw&LZ_;naG`ul)Sil3!P_PX+vDhh}V9$x<~HS`JqbTwfTuhg5Dr5#fetYYUHR=HkCUeejjeAOV?$iJmd3fEUG^y2svhn4z9F^&0`MEolHlqi*Tk=XAdx zbH?^Y%_>pKmM(X8_h2GSjV2qf@J(egO-V`RcK8|D?9bE%bdhvlD(VMd5Osk5mGBu-vf^h#8~Pk$~dxRd6F zt-5p{?lr_SuGJ$8I3ChzbCK8wNpDWC8!$vq8HSFN+#yirK&J|S|JTJS-B8dR9dFW~ zOw^0i+=itaLt6>#S$HjaRiOxv5_VVvDVS49_+|lqq?7{-&i%L$OQiAMCHv9>5z9xCD?s~@ z?$oshK#`DVI2V^y)?i|_>xDglPaK8>GoS6&5a$1+DSRF<>r4zjYu2z?G~Dfp5tYx@ zH=n$gQeYQt&8Y)DFiSTQyeTF7m2o0m@h0KJJeGYW?ZWk#SdTVcm&$Q_Zx`bamNbBe z0p1~=0jj4bUZ{iz)-zQcDXhD3jEh@yH6!9i4{8~ro}+u41KiV0cE`hY9AFY~n8HCU310Dxo1j;sq?~4O+Yr z$_1hBt;F-7xI}(CWoza$8nV&`O886xu@h!sEQw$dEszM-7?g2J@TN8;W{cxBOn+a diff --git a/man/computeSyntheticConfMat.Rd b/man/computeSyntheticConfMat.Rd index 5d08c9b13..8709504b4 100644 --- a/man/computeSyntheticConfMat.Rd +++ b/man/computeSyntheticConfMat.Rd @@ -59,12 +59,13 @@ on the synthetic profiles. ## synthetic profiles data(pedSynthetic) -dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") +## Loading demo dataset containing the inferred ancestry results +## for the synthetic data +data(matKNNSynthetic) ## The inferred ancestry results for the synthetic data using ## values of D=6 and K=5 -matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) -matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ]) +matKNN <- matKNNSynthetic[matKNNSynthetic$K == 6 & matKNNSynthetic$D == 5, ] ## Compile the confusion matrix using the ## synthetic profiles for fixed values of D and K values diff --git a/man/computeSyntheticROC.Rd b/man/computeSyntheticROC.Rd index c79c7d4ae..c4e8e4f7a 100644 --- a/man/computeSyntheticROC.Rd +++ b/man/computeSyntheticROC.Rd @@ -66,12 +66,13 @@ well as on all the results together. ## synthetic profiles data(pedSynthetic) -dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") +## Loading demo dataset containing the inferred ancestry results +## for the synthetic data +data(matKNNSynthetic) ## The inferred ancestry results for the synthetic data using ## values of D=6 and K=5 -matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) -matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] +matKNN <- matKNNSynthetic[matKNNSynthetic$K == 6 & matKNNSynthetic$D == 5, ] ## Compile statistics from the ## synthetic profiles for fixed values of D and K diff --git a/man/matKNNSynthetic.Rd b/man/matKNNSynthetic.Rd new file mode 100644 index 000000000..d58692803 --- /dev/null +++ b/man/matKNNSynthetic.Rd @@ -0,0 +1,79 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RAIDS.R +\docType{data} +\name{matKNNSynthetic} +\alias{matKNNSynthetic} +\title{A small \code{data.frame} containing the +inferred ancestry on the synthetic profiles.} +\format{ +The \code{data.frame} containing the information about the +synthetic profiles. The \code{data.frame} contains 4 columns: +\itemize{ +\item \code{sample.id} {a \code{character} string representing the unique +synthetic profile identifier.} +\item \code{D} {a \code{numeric} representing the number of dimensions used +to infer the ancestry of the synthetic profile.} +\item \code{K} {a \code{numeric} representing the number of neighbors used +to infer the ancestry of the synthetic profile.} +\item \code{SuperPop} {a \code{character} string representing the +inferred ancestry of the synthetic profile for the specific D and K values.} +} +} +\usage{ +data(matKNNSynthetic) +} +\value{ +The \code{data.frame} containing the information about the +synthetic profiles. The \code{data.frame} contains 4 columns: +\itemize{ +\item \code{sample.id} {a \code{character} string representing the unique +synthetic profile identifier.} +\item \code{D} {a \code{numeric} representing the number of dimensions used +to infer the ancestry of the synthetic profile.} +\item \code{K} {a \code{numeric} representing the number of neighbors used +to infer the ancestry of the synthetic profile.} +\item \code{SuperPop} {a \code{character} string representing the +inferred ancestry of the synthetic profile for the specific D and K values.} +} +} +\description{ +The object is a \code{data.frame} with 4 columns. +} +\details{ +This dataset can be +used to test the \code{\link{computeSyntheticROC}} function. +} +\examples{ + +## Loading demo dataset containing pedigree information for synthetic +## profiles +data(pedSynthetic) + +## Loading demo dataset containing the inferred ancestry results +## for the synthetic data +data(matKNNSynthetic) + +## Retain one K and one D value +matKNN <- matKNNSynthetic[matKNNSynthetic$D == 5 & matKNNSynthetic$K == 4, ] + +## Compile statistics from the +## synthetic profiles for fixed values of D and K +results <- RAIDS:::computeSyntheticROC(matKNN=matKNN, + matKNNAncestryColumn="SuperPop", + pedCall=pedSynthetic, pedCallAncestryColumn="superPop", + listCall=c("EAS", "EUR", "AFR", "AMR", "SAS")) + +results$matAUROC.All +results$matAUROC.Call +results$listROC.Call + + +} +\seealso{ +\itemize{ +\item \code{\link{computeSyntheticROC}} {for calculating the AUROC of +the inferences for specific values of D and K using the inferred +ancestry results from the synthetic profiles} +} +} +\keyword{datasets} diff --git a/man/pedSynthetic.Rd b/man/pedSynthetic.Rd index 39e8501a1..6139c30c2 100644 --- a/man/pedSynthetic.Rd +++ b/man/pedSynthetic.Rd @@ -69,12 +69,12 @@ used to test the \code{\link{computeSyntheticROC}} function. ## profiles data(pedSynthetic) -dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") +## Loading demo dataset containing the inferred ancestry results +## for the synthetic data +data(matKNNSynthetic) -## The inferred ancestry results for the synthetic data using -## values of D=5 and K=5 -matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) -matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] +## Retain one K and one D value +matKNN <- matKNNSynthetic[matKNNSynthetic$D == 5 & matKNNSynthetic$K == 4, ] ## Compile statistics from the ## synthetic profiles for fixed values of D and K diff --git a/man/selParaPCAUpQuartile.Rd b/man/selParaPCAUpQuartile.Rd index 81a0e5797..25b94167c 100644 --- a/man/selParaPCAUpQuartile.Rd +++ b/man/selParaPCAUpQuartile.Rd @@ -116,16 +116,14 @@ accuracy. ## synthetic profiles data(pedSynthetic) -dataDirRes <- system.file("extdata/demoAncestryCall", package="RAIDS") - -## The inferred ancestry results for the synthetic data using different -## values of D and K -matKNN <- readRDS(file.path(dataDirRes, "matKNN.RDS")) +## Loading demo dataset containing the inferred ancestry results +## for the synthetic data +data(matKNNSynthetic) ## Compile all the results for ancestry inference done on the ## synthetic profiles for different D and K values ## Select the optimal D and K values -results <- RAIDS:::selParaPCAUpQuartile(matKNN=matKNN, +results <- RAIDS:::selParaPCAUpQuartile(matKNN=matKNNSynthetic, pedCall=pedSynthetic, refCall="superPop", predCall="SuperPop", listCall=c("EAS", "EUR", "AFR", "AMR", "SAS"), kList=seq(3,15,1), pcaList=seq(2,15,1)) diff --git a/man/validateComputeSyntheticRoc.Rd b/man/validateComputeSyntheticRoc.Rd index 83ca2e132..a997cb7db 100644 --- a/man/validateComputeSyntheticRoc.Rd +++ b/man/validateComputeSyntheticRoc.Rd @@ -52,13 +52,13 @@ This function validates the input parameters for the ## synthetic profiles data(pedSynthetic) -## Directory where demo GDS files are located -dataDir <- system.file("extdata/demoAncestryCall", package="RAIDS") +## Loading demo dataset containing the inferred ancestry results +## for the synthetic data +data(matKNNSynthetic) ## The inferred ancestry results for the synthetic data using ## values of D=6 and K=5 -matKNN <- readRDS(file.path(dataDir, "matKNN.RDS")) -matKNN <- matKNN[matKNN$K == 6 & matKNN$D == 5, ] +matKNN <- matKNNSynthetic[matKNNSynthetic$K == 6 & matKNNSynthetic$D == 5, ] ## The validation should be successful RAIDS:::validateComputeSyntheticRoc(matKNN=matKNN, From 95c390cf2b988062d98ec8a95c1f13324afae3f4 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 27 Sep 2023 11:26:33 -0400 Subject: [PATCH 232/385] Remove unused listPCASample.RDS file --- inst/extdata/demoAncestryCall/listPCASample.RDS | Bin 38458 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 inst/extdata/demoAncestryCall/listPCASample.RDS diff --git a/inst/extdata/demoAncestryCall/listPCASample.RDS b/inst/extdata/demoAncestryCall/listPCASample.RDS deleted file mode 100644 index 34f2fa9c41ab1c749c68a9a2d87036fce767583a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38458 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
IpEQ-BP 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 From 6edd94829ee1d3bc5c7ac7599357bcb0e1d152bf Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 27 Sep 2023 12:40:58 -0400 Subject: [PATCH 233/385] Replace RDS demSnpPos for a RData object --- R/RAIDS.R | 108 ++++++ R/allelicFraction_internal.R | 23 +- data/snpPositionDemo.RData | Bin 0 -> 1988 bytes .../demoAllelicFraction/create_demSnpPosRDS.R | 350 ------------------ .../extdata/demoAllelicFraction/demSnpPos.rds | Bin 2509 -> 0 bytes man/calcAFMLRNA.Rd | 12 +- man/computeAllelicFractionDNA.Rd | 2 +- man/snpPositionDemo.Rd | 109 ++++++ man/tableBlockAF.Rd | 9 +- 9 files changed, 245 insertions(+), 368 deletions(-) create mode 100644 data/snpPositionDemo.RData delete mode 100644 inst/extdata/demoAllelicFraction/create_demSnpPosRDS.R delete mode 100644 inst/extdata/demoAllelicFraction/demSnpPos.rds create mode 100644 man/snpPositionDemo.Rd diff --git a/R/RAIDS.R b/R/RAIDS.R index ed7d2da1d..6bed43af7 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -239,3 +239,111 @@ NULL #' NULL + +#' A small \code{data.frame} containing the +#' SNV information. +#' +#' The object is a \code{data.frame} with 17 columns. +#' +#' This dataset can be +#' used to test the \code{\link{calcAFMLRNA}} and \code{\link{tableBlockAF}} +#' internal functions. +#' +#' @name snpPositionDemo +#' +#' @docType data +#' +#' @aliases snpPositionDemo +#' +#' @format The \code{data.frame} containing the information about the +#' synthetic profiles. The \code{data.frame} contains 4 columns: +#' \itemize{ +#' \item \code{cnt.tot} {a \code{integer} representing the number of reads at +#' the SNV position.} +#' \item \code{cnt.ref} {a \code{integer} representing the number of reads +#' corresponding to the reference at the SNV position.} +#' \item \code{cnt.alt} {a \code{integer} representing the number of reads +#' different than the reference at the SNV position.} +#' \item \code{snp.pos} {a \code{integer} representing the position of the +#' SNV on the chromosome.} +#' \item \code{snp.chr} {a \code{integer} representing the chromosome on which +#' the SNV is located.} +#' \item \code{normal.geno} {a \code{integer} representing the genotype +#' (0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown).} +#' \item \code{pruned} {a \code{logical} indicated if the SNV is pruned.} +#' \item \code{snp.index} {a \code{integer} representing the index of the +#' SNV in the reference SNV GDS file.} +#' \item \code{keep} {a \code{logical} indicated if the genotype +#' exists for the SNV.} +#' \item \code{hetero} {a \code{logical} indicated if the SNV is heterozygote.} +#' \item \code{homo} {a \code{logical} indicated if the SNV is homozygote.} +#' \item \code{block.id} {a \code{integer} representing the block identifier +#' associated to the current SNV.} +#' \item \code{phase} {a \code{integer} representing the block identifier +#' associated to the current SNV.} +#' \item \code{lap} {a \code{numeric} representing the lower allelic fraction.} +#' \item \code{LOH} {a \code{integer} indicating if the SNV is in an LOH region +#' (0=not LOH, 1=in LOH).} +#' \item \code{imbAR} {a \code{integer} indicating if the SNV is in an +#' imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; +#' 1=tested positive for imbalance in at least 1 window).} +#' \item \code{freq} {a \code{numeric} representing the frequency of the +#' variant in the the reference.} +#' } +#' +#' @return The \code{data.frame} containing the information about the +#' synthetic profiles. The \code{data.frame} contains 4 columns: +#' \itemize{ +#' \item \code{cnt.tot} {a \code{integer} representing the number of reads at +#' the SNV position.} +#' \item \code{cnt.ref} {a \code{integer} representing the number of reads +#' corresponding to the reference at the SNV position.} +#' \item \code{cnt.alt} {a \code{integer} representing the number of reads +#' different than the reference at the SNV position.} +#' \item \code{snp.pos} {a \code{integer} representing the position of the +#' SNV on the chromosome.} +#' \item \code{snp.chr} {a \code{integer} representing the chromosome on which +#' the SNV is located.} +#' \item \code{normal.geno} {a \code{integer} representing the genotype +#' (0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown).} +#' \item \code{pruned} {a \code{logical} indicated if the SNV is pruned.} +#' \item \code{snp.index} {a \code{integer} representing the index of the +#' SNV in the reference SNV GDS file.} +#' \item \code{keep} {a \code{logical} indicated if the genotype +#' exists for the SNV.} +#' \item \code{hetero} {a \code{logical} indicated if the SNV is heterozygote.} +#' \item \code{homo} {a \code{logical} indicated if the SNV is homozygote.} +#' \item \code{block.id} {a \code{integer} representing the block identifier +#' associated to the current SNV.} +#' \item \code{phase} {a \code{integer} representing the block identifier +#' associated to the current SNV.} +#' \item \code{lap} {a \code{numeric} representing the lower allelic fraction.} +#' \item \code{LOH} {a \code{integer} indicating if the SNV is in an LOH region +#' (0=not LOH, 1=in LOH).} +#' \item \code{imbAR} {a \code{integer} indicating if the SNV is in an +#' imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; +#' 1=tested positive for imbalance in at least 1 window).} +#' \item \code{freq} {a \code{numeric} representing the frequency of the +#' variant in the the reference.} +#' } +#' +#' @usage data(snpPositionDemo) +#' +#' @keywords datasets +#' +#' @examples +#' +#' ## Loading demo dataset containing SNV information +#' data(snpPositionDemo) +#' +#' ## Only use a subset of heterozygote SNVs related to one block +#' subset <- snpPositionDemo[which(snpPositionDemo$block.id == 2750 & +#' snpPositionDemo$hetero), c("cnt.ref", "cnt.alt", "phase")] +#' +#' ## Compute the log likelihood ratio based on the coverage of +#' ## each allele in a specific block +#' result <- RAIDS:::calcAFMLRNA(subset) +#' head(result) +#' +#' +NULL diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 0ca3a01aa..e3f73cc98 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -691,7 +691,7 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { #' \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} #' \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} #' \item{homo} {a \code{logical} indicating if the SNV is homozygote} -#' \item{lap} {a \code{numeric} indicating lower allelic fraction} +#' \item{lap} {a \code{numeric} representing the lower allelic fraction} #' \item{LOH} {a \code{integer} indicating if the SNV is in an LOH region #' (0=not LOH, 1=in LOH)} #' \item{imbAR} {a \code{integer} indicating if the SNV is in an imbalanced @@ -1402,13 +1402,15 @@ testEmptyBox <- function(matCov, pCutOff=-3) { #' #' @examples #' -#' dataDir <- system.file("extdata", package="RAIDS") +#' ## Loading demo dataset containing SNV information +#' data(snpPositionDemo) +#' +#' ## Only use a subset of heterozygote SNVs related to one block +#' subset <- snpPositionDemo[which(snpPositionDemo$block.id == 2750 & +#' snpPositionDemo$hetero), c("cnt.ref", "cnt.alt", "phase")] #' -#' snpPos <- readRDS(file.path(dataDir, "demoAllelicFraction", "demSnpPos.rds")) +#' result <- RAIDS:::calcAFMLRNA(subset) #' -#' result <- RAIDS:::calcAFMLRNA(snpPos[which(snpPos$block.id == 2750 & -#' snpPos$hetero), -#' c("cnt.ref", "cnt.alt", "phase")]) #' head(result) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz @@ -1513,11 +1515,14 @@ calcAFMLRNA <- function(snpPosHetero) { #' #' @examples #' -#' dataDir <- system.file("extdata", package="RAIDS") +#' ## Loading demo dataset containing SNV information +#' data(snpPositionDemo) #' -#' snpPos <- readRDS(file.path(dataDir, "demoAllelicFraction", "demSnpPos.rds")) +#' ## Retain SNVs on chromosome 1 +#' subset <- snpPositionDemo[which(snpPositionDemo$snp.chr == 1),] #' -#' result <- RAIDS:::tableBlockAF(snpPos[which(snpPos$snp.chr == 1),]) +#' ##Compile the information about the SNVs for each block +#' result <- RAIDS:::tableBlockAF(subset) #' head(result) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz diff --git a/data/snpPositionDemo.RData b/data/snpPositionDemo.RData new file mode 100644 index 0000000000000000000000000000000000000000..76a7e092b1f5f330b9bcec090b9b61b31aaff866 GIT binary patch literal 1988 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 X;dKAe*VmWs=I;Lh2Ac9l&tCul2u3=V diff --git a/man/calcAFMLRNA.Rd b/man/calcAFMLRNA.Rd index 4260beb80..baf49ca7f 100644 --- a/man/calcAFMLRNA.Rd +++ b/man/calcAFMLRNA.Rd @@ -46,13 +46,15 @@ haplotype are grouped together. } \examples{ -dataDir <- system.file("extdata", package="RAIDS") +## Loading demo dataset containing SNV information +data(snpPositionDemo) -snpPos <- readRDS(file.path(dataDir, "demoAllelicFraction", "demSnpPos.rds")) +## Only use a subset of heterozygote SNVs related to one block +subset <- snpPositionDemo[which(snpPositionDemo$block.id == 2750 & + snpPositionDemo$hetero), c("cnt.ref", "cnt.alt", "phase")] + +result <- RAIDS:::calcAFMLRNA(subset) -result <- RAIDS:::calcAFMLRNA(snpPos[which(snpPos$block.id == 2750 & - snpPos$hetero), - c("cnt.ref", "cnt.alt", "phase")]) head(result) } diff --git a/man/computeAllelicFractionDNA.Rd b/man/computeAllelicFractionDNA.Rd index a1ece9cab..252d3a3e2 100644 --- a/man/computeAllelicFractionDNA.Rd +++ b/man/computeAllelicFractionDNA.Rd @@ -81,7 +81,7 @@ SNV in the Reference GDS file that contains all SNVs} \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} \item{homo} {a \code{logical} indicating if the SNV is homozygote} -\item{lap} {a \code{numeric} indicating lower allelic fraction} +\item{lap} {a \code{numeric} representing the lower allelic fraction} \item{LOH} {a \code{integer} indicating if the SNV is in an LOH region (0=not LOH, 1=in LOH)} \item{imbAR} {a \code{integer} indicating if the SNV is in an imbalanced diff --git a/man/snpPositionDemo.Rd b/man/snpPositionDemo.Rd new file mode 100644 index 000000000..e0c857c04 --- /dev/null +++ b/man/snpPositionDemo.Rd @@ -0,0 +1,109 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RAIDS.R +\docType{data} +\name{snpPositionDemo} +\alias{snpPositionDemo} +\title{A small \code{data.frame} containing the +SNV information.} +\format{ +The \code{data.frame} containing the information about the +synthetic profiles. The \code{data.frame} contains 4 columns: +\itemize{ +\item \code{cnt.tot} {a \code{integer} representing the number of reads at +the SNV position.} +\item \code{cnt.ref} {a \code{integer} representing the number of reads +corresponding to the reference at the SNV position.} +\item \code{cnt.alt} {a \code{integer} representing the number of reads +different than the reference at the SNV position.} +\item \code{snp.pos} {a \code{integer} representing the position of the +SNV on the chromosome.} +\item \code{snp.chr} {a \code{integer} representing the chromosome on which +the SNV is located.} +\item \code{normal.geno} {a \code{integer} representing the genotype +(0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown).} +\item \code{pruned} {a \code{logical} indicated if the SNV is pruned.} +\item \code{snp.index} {a \code{integer} representing the index of the +SNV in the reference SNV GDS file.} +\item \code{keep} {a \code{logical} indicated if the genotype +exists for the SNV.} +\item \code{hetero} {a \code{logical} indicated if the SNV is heterozygote.} +\item \code{homo} {a \code{logical} indicated if the SNV is homozygote.} +\item \code{block.id} {a \code{integer} representing the block identifier +associated to the current SNV.} +\item \code{phase} {a \code{integer} representing the block identifier +associated to the current SNV.} +\item \code{lap} {a \code{numeric} representing the lower allelic fraction.} +\item \code{LOH} {a \code{integer} indicating if the SNV is in an LOH region +(0=not LOH, 1=in LOH).} +\item \code{imbAR} {a \code{integer} indicating if the SNV is in an +imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; +1=tested positive for imbalance in at least 1 window).} +\item \code{freq} {a \code{numeric} representing the frequency of the +variant in the the reference.} +} +} +\usage{ +data(snpPositionDemo) +} +\value{ +The \code{data.frame} containing the information about the +synthetic profiles. The \code{data.frame} contains 4 columns: +\itemize{ +\item \code{cnt.tot} {a \code{integer} representing the number of reads at +the SNV position.} +\item \code{cnt.ref} {a \code{integer} representing the number of reads +corresponding to the reference at the SNV position.} +\item \code{cnt.alt} {a \code{integer} representing the number of reads +different than the reference at the SNV position.} +\item \code{snp.pos} {a \code{integer} representing the position of the +SNV on the chromosome.} +\item \code{snp.chr} {a \code{integer} representing the chromosome on which +the SNV is located.} +\item \code{normal.geno} {a \code{integer} representing the genotype +(0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown).} +\item \code{pruned} {a \code{logical} indicated if the SNV is pruned.} +\item \code{snp.index} {a \code{integer} representing the index of the +SNV in the reference SNV GDS file.} +\item \code{keep} {a \code{logical} indicated if the genotype +exists for the SNV.} +\item \code{hetero} {a \code{logical} indicated if the SNV is heterozygote.} +\item \code{homo} {a \code{logical} indicated if the SNV is homozygote.} +\item \code{block.id} {a \code{integer} representing the block identifier +associated to the current SNV.} +\item \code{phase} {a \code{integer} representing the block identifier +associated to the current SNV.} +\item \code{lap} {a \code{numeric} representing the lower allelic fraction.} +\item \code{LOH} {a \code{integer} indicating if the SNV is in an LOH region +(0=not LOH, 1=in LOH).} +\item \code{imbAR} {a \code{integer} indicating if the SNV is in an +imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; +1=tested positive for imbalance in at least 1 window).} +\item \code{freq} {a \code{numeric} representing the frequency of the +variant in the the reference.} +} +} +\description{ +The object is a \code{data.frame} with 17 columns. +} +\details{ +This dataset can be +used to test the \code{\link{calcAFMLRNA}} and \code{\link{tableBlockAF}} +internal functions. +} +\examples{ + +## Loading demo dataset containing SNV information +data(snpPositionDemo) + +## Only use a subset of heterozygote SNVs related to one block +subset <- snpPositionDemo[which(snpPositionDemo$block.id == 2750 & + snpPositionDemo$hetero), c("cnt.ref", "cnt.alt", "phase")] + +## Compute the log likelihood ratio based on the coverage of +## each allele in a specific block +result <- RAIDS:::calcAFMLRNA(subset) +head(result) + + +} +\keyword{datasets} diff --git a/man/tableBlockAF.Rd b/man/tableBlockAF.Rd index ea3f5cbc8..232ecf86c 100644 --- a/man/tableBlockAF.Rd +++ b/man/tableBlockAF.Rd @@ -54,11 +54,14 @@ In the case of RNA-seq, the blocks are genes. } \examples{ -dataDir <- system.file("extdata", package="RAIDS") +## Loading demo dataset containing SNV information +data(snpPositionDemo) -snpPos <- readRDS(file.path(dataDir, "demoAllelicFraction", "demSnpPos.rds")) +## Retain SNVs on chromosome 1 +subset <- snpPositionDemo[which(snpPositionDemo$snp.chr == 1),] -result <- RAIDS:::tableBlockAF(snpPos[which(snpPos$snp.chr == 1),]) +##Compile the information about the SNVs for each block +result <- RAIDS:::tableBlockAF(subset) head(result) } From 3da2ad2559cd8bee2c6bc931873258036f0b4477 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 27 Sep 2023 13:26:39 -0400 Subject: [PATCH 234/385] Change pca1KG RDS file into a RData object --- R/RAIDS.R | 81 +++++++++++++++++++++++ R/processStudy.R | 9 +-- R/processStudy_internal.R | 7 +- data/demoPCA1KG.RData | Bin 0 -> 15604 bytes inst/extdata/demoKNNSynthetic/pca1KG.RDS | Bin 16190 -> 0 bytes man/computePCAMultiSynthetic.Rd | 9 +-- man/demoPCA1KG.Rd | 79 ++++++++++++++++++++++ man/validateComputePCAMultiSynthetic.Rd | 7 +- 8 files changed, 178 insertions(+), 14 deletions(-) create mode 100644 data/demoPCA1KG.RData delete mode 100644 inst/extdata/demoKNNSynthetic/pca1KG.RDS create mode 100644 man/demoPCA1KG.Rd diff --git a/R/RAIDS.R b/R/RAIDS.R index 6bed43af7..667519495 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -347,3 +347,84 @@ NULL #' #' NULL + + + + +#' The PCA results of the demo 1KG reference dataset for demonstration purpose. +#' Beware that the PCA has been run on a very small subset of the +#' 1KG reference dataset +#' and should not be used to call ancestry inference on a real profile. +#' +#' The object is a \code{list}. +#' +#' This object can be +#' used to test the \code{\link{computePCAMultiSynthetic}} function. +#' +#' @name demoPCA1KG +#' +#' @docType data +#' +#' @aliases demoPCA1KG +#' +#' @format The \code{list} containing the PCA results for a small subset of +#' the reference 1KG dataset. The \code{list} contains 2 entries: +#' \itemize{ +#' \item{pruned}{ a \code{vector} of SNV identifiers specifying selected SNVs +#' for the PCA analysis.} +#' \item{pca.unrel}{ a \code{snpgdsPCAClass} object containing the eigenvalues +#' as generated by \link[SNPRelate]{snpgdsPCA} function.} +#' } +#' +#' @return The \code{list} containing the PCA results for a small subset of +#' the reference 1KG dataset. The \code{list} contains 2 entries: +#' \itemize{ +#' \item{pruned}{ a \code{vector} of SNV identifiers specifying selected SNVs +#' for the PCA analysis.} +#' \item{pca.unrel}{ a \code{snpgdsPCAClass} object containing the eigenvalues +#' as generated by \link[SNPRelate]{snpgdsPCA} function.} +#' } +#' +#' @usage data(demoPCA1KG) +#' +#' @keywords datasets +#' +#' @examples +#' +#' +#' ## Required library +#' library(gdsfmt) +#' +#' ## Loading demo PCA on subset of 1KG reference dataset +#' data(demoPCA1KG) +#' +#' ## Path to the demo Profile GDS file is located in this package +#' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") +#' +#' # The name of the synthetic study +#' studyID <- "MYDATA.Synthetic" +#' +#' samplesRM <- c("HG00246", "HG00325", "HG00611", "HG01173", "HG02165", +#' "HG01112", "HG01615", "HG01968", "HG02658", "HG01850", "HG02013", +#' "HG02465", "HG02974", "HG03814", "HG03445", "HG03689", "HG03789", +#' "NA12751", "NA19107", "NA18548", "NA19075", "NA19475", "NA19712", +#' "NA19731", "NA20528", "NA20908") +#' names(samplesRM) <- c("GBR", "FIN", "CHS","PUR", "CDX", "CLM", "IBS", +#' "PEL", "PJL", "KHV", "ACB", "GWD", "ESN", "BEB", "MSL", "STU", "ITU", +#' "CEU", "YRI", "CHB", "JPT", "LWK", "ASW", "MXL", "TSI", "GIH") +#' +#' ## Open the Profile GDS file +#' gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) +#' +#' ## Projects synthetic profiles on demo 1KG PCA +#' results <- computePCAMultiSynthetic(gdsProfile=gdsProfile, +#' listPCA=demoPCA1KG, sampleRef=samplesRM, studyIDSyn=studyID, +#' verbose=FALSE) +#' +#' ## The eigenvectors for the synthetic profiles +#' head(results$eigenvector) +#' +#' ## Close Profile GDS file (important) +#' closefn.gds(gdsProfile) +#' +NULL diff --git a/R/processStudy.R b/R/processStudy.R index bedaead18..a53544de4 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -777,6 +777,9 @@ addStudy1Kg <- function(gdsReference, fileProfileGDS, verbose=FALSE) { #' ## Required library #' library(gdsfmt) #' +#' ## Loading demo PCA on subset of 1KG reference dataset +#' data(demoPCA1KG) +#' #' ## Path to the demo Profile GDS file is located in this package #' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' @@ -792,14 +795,12 @@ addStudy1Kg <- function(gdsReference, fileProfileGDS, verbose=FALSE) { #' "PEL", "PJL", "KHV", "ACB", "GWD", "ESN", "BEB", "MSL", "STU", "ITU", #' "CEU", "YRI", "CHB", "JPT", "LWK", "ASW", "MXL", "TSI", "GIH") #' -#' ## The PCA on the 1KG reference profiles -#' pca <- readRDS(file.path(dataDir, "pca1KG.RDS")) -#' #' ## Open the Profile GDS file #' gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) #' #' ## Projects synthetic profiles on 1KG PCA -#' results <- computePCAMultiSynthetic(gdsProfile=gdsProfile, listPCA=pca, +#' results <- computePCAMultiSynthetic(gdsProfile=gdsProfile, +#' listPCA=demoPCA1KG, #' sampleRef=samplesRM, studyIDSyn=studyID, verbose=FALSE) #' #' ## The eigenvectors for the synthetic profiles diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index a031ba896..a7b382aa6 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -1354,6 +1354,9 @@ validateProfileGDSExist <- function(pathProfile, profile) { #' #' @examples #' +#' ## Loading demo PCA on subset of 1KG reference dataset +#' data(demoPCA1KG) +#' #' ## Path to the demo GDS file is located in this package #' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' fileProfileGDS <- file.path(dataDir, "ex1.gds") @@ -1361,11 +1364,9 @@ validateProfileGDSExist <- function(pathProfile, profile) { #' ## Open GDS files #' gdsProfile <- openfn.gds(fileProfileGDS) #' -#' pca <- readRDS(file.path(dataDir, "pca1KG.RDS")) -#' #' ## The function returns 0L when all parameters are valid #' RAIDS:::validateComputePCAMultiSynthetic(gdsProfile=gdsProfile, -#' listPCA=pca, sampleRef=c("HG00246", "HG00325"), +#' listPCA=demoPCA1KG, sampleRef=c("HG00246", "HG00325"), #' studyIDSyn="MyStudy", verbose=FALSE) #' #' ## Close GDS file (it is important to always close the GDS files) diff --git a/data/demoPCA1KG.RData b/data/demoPCA1KG.RData new file mode 100644 index 0000000000000000000000000000000000000000..e5c37ba3a62e33bde1b6a389ec9968aa9f8295a3 GIT binary patch literal 15604 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

_O<2#b> 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 OFb#_W000000a;qj@J~Mg literal 0 HcmV?d00001 diff --git a/inst/extdata/demoKNNSynthetic/pca1KG.RDS b/inst/extdata/demoKNNSynthetic/pca1KG.RDS deleted file mode 100644 index f19a17d9bc62cc4319c1f8557b344bb539570bc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16190 zcmV-EKf%BsiwFP!000002JO6gIMrPnKZ+uRD3qy5MJm~BV{$8!6r~I$4agWWMCJ?` zGSBlo&$gKix2X&XMM$MVhSH=^A)WockN0`(_nbe^b$;iM*L7`QpL^ZY`rK>XYwbUL z&ofd{QLUj`OGExmOa7CJR#QXifD{!K%_cG+OQ~4NpTksZsTjylI$JSOX(EvVN&bU~ zl42r%Bciw%LG*7VAtEU$@edLuh>5KrdRtKu2?;T2(Z4Z~Kp;p-iu{emB_+h9B#Emr zkti*(3QLNJOAuCJDN&+`_-ZUBCi>5~q`0KCl%(`3EG0pZ7Nfw#RryFth>A!{|6?yr zkP?*?mH00#xe7~*NfQ2p8Egq6lA=U05h)6RxR|*3KLRlca!#VFG>8)7Vni|V)dC4g zQK|o%Kw`B(QdC5eKp~J6`Fmbu0htJKsnuc0LB$9Xg#Q*uPzcDSTjfJiM3h`BNeTg( zY|(!NWb&m5t7j`EO0JHS*lK~qzc{88NQz4TBajx6BobF^kOkrd5%JXmDT0^?fl?qL zEwV}=O%M^2_$Loh5%R(j5g}3v#6(0^3#3Fu#aC$%#3V(g|ilc2B_6QdXvm!^pO510RjU4uYBdz4 zsDhX%MUBXNhr+Xj1VvHEJ&qDma3w{tkjM>_q6*|0uZH48ikzjSD5ftaCQUIx$^WvY z7?qNuSPYU9t6hnSi~W}}MUv7KamD^=S^tLrw8g(5fdYz2NK%Yaup#!(nX>{{dnOVn z%1tDQi&H|1tcVoEl212^K;#pTQkkOqA{69^Nf9Zsl9Hl~OF4Z>iW-r3DdVp0+mNlO3Ipwy0tNJ#&E9+4rrPyVwd$&euRPh%u2lP@HM)yn@|2mS@6 z39FUKEA*cV{tHTr{nzMfTQWD&6r-Y2tDyuzf?`yfKrt#t3IAyn|Bfq7;YwP9A};0h z$)l^&kQO0`tcFC22}%b)Z$f{a;XAj3P<$J%a*DQY0xUF1Z>?6DX9Wh!mqz zlA;vKA`+CNUsUs#t6LE(ukdS|O3S-$B|{_a>P z`6h6{URDaiXjy)|j@|`%C8pG))?pAO+nw|$jTchXSv0r32#(S(1kLI0NN^9<2vYd|&am=WqLhqVN}u=FX6rzYM#(%KZ|xqNUC_xXxK;AYqsw8(S{VS%HrdenSaL* zkF}dUKdBF~28}VK+?_yDs;|^sE=61Yiz?=Q(vW)Rso?kR+>lv!VB&exR!q{FH)Z@y z2gPRWz*>44Qd;MC3HTKQ>G*+#ohNi5Mt6Qt^VJ?G^L!>-yx9QTxCaX|MV=v!d>&XP z*kJY7bJ2r+2QW&Co=<>A314sQ{l>>Zi-}qES7;wT#9|jQ_smPPcyD}{>H7Qnn06-F zQuh}RWO1mBrKW^q5huF@oht`6iF0x=mhHo=87!xz*@**mBQDGVvsipgc>~W`28i&@ z<5)J*g`1lT%ME4s0*R$?NXOMc3W|thX}%L|J^FF_|$c`e3!8$_J{iNUW>bjtq%gI8Rd~=?Bo~Tf(Lr ziM&{TAVGZ1pcxiEKg_(>;SaXve|nOVa|zO4Dv)RzFJt6+YMFsRcDxrJc-6)(c!fuH z%qwDlJ+tl`R_Sv}nKC;{D1>UKKs8XvG)lFL=FL%Qk$FT`0 zY#r-Kq!vX3iP^xeSSfJM;*5#nlg5yoE7YkevT%9-rYqm37ogl&C+U2699(U^@#Le` zCvdzS@jduvB-ni)GdcKE2Tl!@u!}2tf!(5EeiUr=g+En=TX{8#?!S(pMS*n} z-&h~$CusA3=o18^5m%Mo1`*J_Te0p}yC+tp&MlwGC_(FG)kfpj9uUQ%6eh&F2sh?B zHx>*kpvSE11xIC;6@Qj1_Tq46?wof_!ez9Ne7f#C!4~yjcIr+kPJ`R2*lYE!mS`jz z8mmE6Lr0Z7N6zY#XifOmUeP>{p$#FOb)nRlZ;EB_G##5*W`Zf&-~0u4Gl-H41>_ZqF+`=aj)s;+no(!CalOIgOj;E}J8}dv}JP%%D;`?>FR`x<*Rg`jX*VcOQ*FrP}14v8|D-yLeM*4zvvw}_uTUauie;>D@yS5lzQUX~^Bss|H2uH5Na z%7;qY!gWE;7w~Qi-$ld2H1Hvyla#7{1fqmk^#8cmfp=VhWsi#p_V)pmAIF#vI0}MWjPQw*=Nh1Bvfh93*II~Q zXyaA>3m*;{*^za zex@3M?RRs3lBFG-e_K9OzeEjG@e8S z$D2#{V%y;4&E=u89vVamiEQ>n6}_QtwkiHrF86H!XwELg|&p*j$CZJZ03 zeciD#WulYCAp=in#k3ox>0_wsV=j+7<4}BD_My&eniU@Fpy24Z!RKTSNT9d(QaryC z&kxHsiyWxOn=)?{9*Ii*hc9Ry+8nV%@ioTgm3(zCX$H%oYZ{YEH_`8#_XggB<>27_ z;N4TkY&=`AJ4QS~8Li(5oQq+3j-Kymh5UMi(b|O9sVXWI9q8sybv!iyi`nr|+ib-6 zR{5-UPDM=kDMHw~?kYx{sfb(}JcThkC0kkM9Kk(b@PzNFk0^6!{`wG46Xx~5eB53X z0MXyAtKYqK!pzN5oK%_Bm~Z)ZQ_zl3h|#xx$~w~nkw#qOI|ZKsi8kHQZ1Yv{$<+Vy z;nq5^|NOD7VnZkdu>aWpc!Mv#QSqOA;<^!Y2%U!xD79j!sEfhXHG|+9Yx~4so_EFH z#})ha5cFfskOI$9FnlZit2>4slLT$3+fNju$Ih|aIqFhSR;1Nbzu_muKHj{0zM}=x zVj@QdC+Xmh!l4{C_d#q?9c|vhl8dg-S=W_sjm7d?UTQRM6&Nnfe}Oy62ugf6+#b3) z1aVE@6xe1zqaEpELjDK(mH5n%@FxFZ<=i{C*%DB1&t`5G>Kze8I8{gTf8p^zC}-J)-MA1Xf_-?CpJ7rkG7W}x=n z1*9+Y(VF`{K|Q;k)~gp+FyesI(Z{tPu#iKb&x@NE(s%!)AHHITRW)(;L%g}{7k8ND#E z`}NfWJ%1ov_}&L|nqbJ%z9nmyDu-%(wvtLZsSsEeF{Buw0_ksR7F23<(dJ+{hkWOi zzw3unoWnk0KhUM@OVhgdIgr^eb3l~)Da5*N3;*$C0=)g7>bsuX4uwssidRE7U{r3| zHgl-J_MTwI?OR81oW>&(-zN;6^Iytn77p!3u+}vJj zuA#oYUFiJmuHxCvx?uO{lv36A0St{OZcA`(hDdg{6NkO!(32)4ruJewc~I zPA!Rm_Vwo%EyLX5*4TAz#);7t9?5;>^_LN@;XHIm8(;}3OMqMxIrlftPqFfoO`bT< z?Z5fTZvMpUCSiz`F;)iJa`Bkn(!1CFFozXoHN8<&-J%KqE(Qa+gT1FwKPiX{so=!ak0WE#RDjb*Sz=4=z@hF_tY zl4?TtE7I&+N&@ljJ(t*y-xHX2?PT!>8DS{m__Q}*sRuI8rdYiQD@J{jOlrL9w-Ub{ zbBNEqLLb{gs6n*4mJJU&{(dFSe|rKWL$xP;I4qIG6ZByC7$anj@z>8B8o(rp$n--? ztx(bWvL}{b6ufMIKYq!Y3OSIcyJpVFU4YGSU zob03-A#MM6KJSVIh!8VWd}6&G)7{2n2HJHYWApC2T-S>5I+fe6?-|{gp`29r>23&Q z&(1ASo7{qm8v^PUcn9EZa{QBX{`*}Q1!E2J;IJ0zN%iHUqaK6{x7LSct$`qus1AiYHMYs)7Qh>O@0 znH2dNN`HP#2szawg@KwY^l#7jg7~^Nielw>lZ?hLt4{Va(6*Y??uk_i49uMM} zy4Z=Y{_|iFwu@_Vt`@V47+)IBbVJ5h(yl35M)bR}ZiLJ24TNT1)Ux2(4$;>;$D{p^ zuJHH@Qx0<{6UQz>!cM*IvKRM3jD=_9x88J&33lhT;@+^r7Zapxzrf0(rBq})9XD!5x9O{)^32O;)jZx`CkAvsx5r$bu}qUe(M*nPNsah2ikT-xU&rp{^jp;=88QF9+8gKDA;@$Ys|jTiFQti<1n8A89yC7SXvd~o}? zq^dvWM2*yTb&8PBsYe~!4(l+D+V0jVB~Of<`((BwgpF&x*@gy`!nBk74*WJ7FsS(Fm*ocN8Z7Ftk1tM ze|Sj&)3lOyF$CIRs4kp6CbDUzez|a;Rlr^1=uf<3w6W!#p&9zWyd`oX$p&M`5}161 zw*#rvJL>m+4G80Wm8#X3jH!0EwZgasOZ$VXxw6Z#lGaiA7lRPAx>^h_J-m*Ydk>%T z>vcnqgnJ8fp|JGZ^>OI$>hxiAoF(_m-HSb66tOF}s5&~T2m*go6+gA^fqNge zpZ;q88=~q@GklBv2rj>QoK6B5D;(`$uL@hIobV+c6 z!{~sv*NJ-YFXYbrvfmuM3l3F}W=UZP&qV@N=qOfgeic1>asb_%hSm*JPodZD;N2|^ zVNkWLL5!hR7D_Ez9@Hq2FiPB)lhs-SaswI_`>@~`l<6>?A9IK{u`6Qu6veK%!ng=zd6r6)1o)jHuxQoDqeZhhf_Zee_^04zA`@(fEUIoGg*C2b*1x&vYcUr}>0c#&P`o`>u#?lurKA&Efi{&52<-C75gSmKt z{)nGE)^qYTi*Rc}^P}-x7yrYUL31_el%X=*ubnD9K}f|6Ni+Y*A0Ke=I+~u@PX~sj z9J6lQ@}Y7*-y)&xE#ySgk6rA!4Q)gj)A&+7ux3ao#96dlB{PPG3dp2kWa?**N?P#EZZyN&V62P8$#>n;2gz|=@{N9A;V zDBH1Jz*Ch{1Ib1jev8gO)RD5zVii4r=)V8&d zrAn7#WcLb-_oaQwW{ZdNPj=}th8`Gw#Be8V&_;;mG2AKCy%Q>jy&$i~Vak^5V9&qr06mySK&*tX7{el)U%`Qz8tgJ8W2ybbVsG zqT*>xyvv>CPIAY)UtHWbZVAFHYK_Js&JS39f+pyfM>baV>S{{uU&a#e7(!ggX>795 zyeQ>lgt>J^q&QPn*xfeld<&?+>XZD3*Xr9btNLYaFx6A2_-GL7UQ>-_(%L~X;WXrP zI*X=w_&L}ypm)yLcsR@;yx+gEsWhoe=;vI=6H&zpF57%?>Wes-EPC{_+OGuTe>VWw3`ZZTC&rvsf^Fd^pa@ zIT|yPo4Af0m_g620=?AnHkfF;<>cW^Uhv%1Q)9AmKgON)*|W5N6iE>Z2lrnpB(Gb! z+i$)3FgRxDmYuE=#2*+M8l!W9t8xY&1&eKHs+iU=)Y}MV>kTyJ`PebPdYS)1gcmj~ z)N*}2uL$>NS-#g(%|gi8(j{BvE1>>>$?I)hGB#1!h)kX6Sn((Jmp#u~Os<}AO;4*L*gJPT#IJb5scm7lY32tmwvs9+{6ei-4I$dwgdTMX*TAy=!pa zGTtvBwjbR!4B;Z>oR@_&u!c!i!8m~x&W4lpjumwPsbBBB+}GDwd?CSK`}IML*j=S! zozK4#-wZN8(|e`2sY2wKWa1^$^;pPyOTJSs8SW)04$$cRfH(y`HvT0$jCFdTkv=tq zPMc0Wa%^3TIWGJGpH8fUoKq7<(wki|Vqfx12VWONZ@=SD@0Eq=q2EKPJyx+SlbC4NE9jM>S4%L}wZKA(d;^5|vC7T#?tQe0eFT5874Ssq)hdDmOgY{2- z@4EjKV@_rX9#lJtVcUxQ-#)B@M}u=-W+OW2s!dmVf8ZCCo0b^-`gs#Oz0~Rxf)t@n z+)hVA*byGz%Sz3?#EE643Dz;l)dHAF<5DdSpwvH{?wZ?5}+| z0}1OGN1lc}gp8ve#tg>iAZLruri00W(4<$LT?oujbtj#-2cN)-+L#XilripNxnPv zFz+2TtNPV+Y`iX~L>sP)jk{$e&Tiwv#^<^vT|XGm=1h6Ze*avopmt|XvCv2Ki7wcw z+=Q{`f^1p2c_4q=hmLu^+t8WH!OmwMe(+8vLW=ekMtn`URRYB9%Y*=zvowYN97PcB0ISzj6chd~&6ccb|?;~Y$LM*kk+Ckt5z4RRGh(SmyEqfyC-P>h~)Kx)m3=UM5_?$QF;^Z_P&`)^FgG&0HC@ zaDP2t(X%XtAD@qvJB1tIlGqm0F)oSrjWjGJH&H^)z5G01+U4z5?S}{;F0;oIWK=Zrr%Tj zbgk793%w<0R z`zgETPROg+=2tbifGGoNA>V8T;imWaRcYNP8282gKrB}%7CP<9qa8hle#}O<=F>Lg z9S&NW;R;90QyXXaYM+Gn*0*dr8Rx#@PiMvcI95)yUSM3?2GKYB@4pEZfw0bmvqe<7 z5R-Su)7iRh=c>h3&aGRR6 z!8K^9f5y9ulmNNanOpf8b|SXk)FkTo z^<&aci}u?!J=m%p^gix^07Oozhc-_JBJL7D$0%unO*!ocf~BmmiSt9vPwQ!{Xkt&O z*6zd5S^d(ZCv>6XbznhV?#;i@; zauphUP}_Ie^Ok2EHcGopGfi*7XhQE9CMI8~JJD;iB&UX%thZ2W{}E{WwBBRwmB!AnG0!8@=E zbJxEg@nQak6|Qwfv)Ni;bn?7cuDjMs{TQGsF>d`n>nW86 zXz|Ra^V5tX@5=|ZkM(uHC*34y+3p+0@3LEem&zTZ93C2swZ{f5d0ye zsRAD?54`a&c1KzMCZk7rsaX7L^YfD-3s|XAtgL7Va;!eB z!UIg}i&?Ar#uYN0f)=jKJ%!fi4Z&E&xWd;sRKI!!mOo=5{@yw!Pp9MHua#aK-uQuh zUfR{yePxGy$GxKT92yX>w#~?%cnoiR`9s4jGYeI|I|DymnTDLTGaI?4nxSav+p;0i z9%_X6Ldz;eA@#|RY>jIc;PSMGP3SxogmQ}b7|jkt&i>TSC@*^m?l}1MOx-pR_X_s&9mQ1If38BYxO5?Z~9ks7_2xE|Ns3dQhH)unGj{79Nt zV`g%Cg2c;IIblzR(enYdYjTS_7HbGQaOcf4CasW?N9_A_15PBpFTkcJB zX6kYoL%|y;OR7>;NgjZr+>V(*^0`=7pFKV5H32F2O9R6wbB%U? zG&ZvhxL;npgf8NXmE!a4c!pg?CO|p#ulSuccxUujNy&>~xb6S^jpvpVkSn+OaEI0d z4F1{{ahoRr{5}uqN|i5zlx~$}exN+~kG{B4+3A6?Dv89$aWt6a)J+p4LBg!M^#KYU z){vqn`p5GCHx`M+X`aq%g7mc551h$$&?4YV-ObI8IWpPmdm8vLbNX`Vi23HaF;`MwXnk+{Y_}p9PGUB$cpucX5TdzlIu9D8&#gD4qejrJ^YJ#*v!Rd zFm+BHGHx;t(gj}x5}UWj+hs$DJ89%eY*M)jVbx#-g!r9S?8mb_lZzh610jET2nssm)aFjeQc@a?!@ zta%W{Dxlc9Qa@RIBIEevC--~se;^lpaxMT<>W;JwMyrDZ!@D;Eici6Lt5m_dEc9H zsK!d>K-=0uT?~(j%3{_`1Q(8*FKWgQKxofqzU(PyFkpEoumj~G)c=#1-lJM9-ZG?y zMep(6{2gDl$+r+6qHaRqz60sTMw4|>F6c6?VC7dv51Bf|7w`CmAp2KMB!i3A^Do_FilA|n0#j`{=_Mb zk(peU9Wfg)b|HdM;rV5_R(fzt$9@aQ;bLsb{&|?(*Cni8xXoa^>eP%*FE!*odNB5S zPcXzx@3?f@>J$=&2;E06T*f<*+~qPM(-`M=#wu~C12XSi=cf1BjiDb0GmjW!o~M$;2Q#7 zzj^=J);ddk^2K=i;vpF{UH_qeLq;iPJp7&LR&p6*550C8Nq7UH>yIsd)I0)Z`fE;{ zqi@IP?tXm@f8~|<65#$;;hS65H*~)}^P-SA4N=xYwei~gSa$kqXaz?Q5cH3lIas+s zyzY;lo}aXMr;_Qn_aGhI_sM+nl6MR$ObVQK&gApe@LS-7kP9?*Cmp@6 z-T}ojk6$Tqgy6m1-cwpeDPZ>Am5%SI6(kS5T66Y{F%*q?eJ+cUhX|#89ZXhE7}KBL ztS4%QnMxmhZgh~~_Ctq;Yy2{h6&n2JTNe)&>P1<8uWtkEXPbkM(#m7DYSU1#`CdpM zI6G{LrN>kk{#oCR2GH1fqM&x11_G;o?A7C=gG^(Og&&=jkn#QGwzK6DSmb%5za(G* z6V@1(NRYn|hu;0@v-Ii&9FiuCpJI=|EM<-e{@NdC*s^W98+d5H_v5;|(1FGs6yv#2_~W z^bgYil$=GCPYOKib8kYi68pv9N@I{d^eXCX>AsT3=4m=<9%)5=~tDwfol@m^0c`OO$9MJDAJ=wkQ-tm zmIs4G{jthl>!#Wvp}%tKg)c-G z4u1pN(X&`Kwjl9Q*bBp!s8yZUCPV5d>qk{~4op`|R)Y655XrYC?Z(vvD4e!6m(nI- zQU#A_rBMgCd+u9i{xO9~x86~)Z4tr%`CR>KPA0swA>Xo_y$O$q_6=Av%3~%7|30r) zfFUXVLql$%=w6$*zNaf5A}?x=rRfP^73nzFe3>XDEC)~Kj z=s7U@=+E;Fi8+|Cp?~@D!P9b( z6a1pLm9Z*=tBvO7FeaaoeHcs#!y0`v(i&MC3}9F*d348fOw<&Px z__1+wFl)VfjsJK$6g2Pcmd`(q{{8ksytzN1iEi@KG5f#Ntxmx`d?dPFx9vh;zuW@15*~ko1?2D#=Q{SmiXSD@Y@4czb7M;jpd-? z6){`;9uGuqV2aHidJT!`i-$CB*TB6stTTZDLl7Qte&^+|Nle-vBS*!V3T4+BcE_-i z@b2vf!*GvWj2J&b+&5`*23+comk`yxZ(R{bGeLZcKA)jx8G+!19bQ7pAYvU~%e2z<1B+~DN}Z2U2|#mK-8?p)pytr}1dz^_y2YO^HU{*{j@rd#x)yWF<=#J>FvBdFt6-rq;14YXtP*u(T-Ec@Ct`VTlbtr(rIso zV!1v{&pbvu8K#ZNKGPmL2d6RnJANkm1JrCe?=*Ql7JH69T4%x1jCnSqAzE1?7!fk- zDzfzl`m?%U;4d{<@n^nbUxq2`(>KFUV_1NsR z{c_^%Nz7~(Sz6cl5za7K!mLD2d!&opk_|@`fGi}lr%Fw-|=D~Wrh^X2g_q_ z8~^S%1TDzh#+krfY?^w!GHWp`5c(XN3ZT*b-rXnN zHROI-_>*;H3-p{{2tl?Zm@dmfub9&ddC{D5J7w9iJbgp6$7^rQ3AGnj(*6jZbH}MN z^5Zc2?vt>L0YOZkNWEI{P9N%2$ShnCK+A>a5hnIc7!h05-fYE+p43sy5@*UV$LXWN zF5N-sxj6sms-Ys@8QQee%Ww}v-#*ZMwN@8H#de=A?7WEy$u~$f?pD}*;&zn4z!8WN zbnokF@4}C{=b&(3yp;U%Oll!6}^c@f3uJJtu zHT=uZ9%nUUTRuI7f>a(NS|(J$lhb>5SVYB{MksYj3zA!$a_$-RY56 zvmI)UU!H6tq_5O39QthDCajaafL{C`6{^p&`U-e8l+_=KEWy?h=E79VF|0cj zU8z^CfvJbCi+s4nh-r*Ik(}NY81YTeDO%vh$*Kd(g5WzCLLDG^XESPUJY- z3Zi#54)M55v?wz56*iYBJCs;17@OTqb>9}|O_gLX;6tfQ9`U)~kSgmTzs`&;mX+wnYHg5^=pw7)8wlrcLr~Ik7 z>-JdaU>U>7c@E0i=!~-OieV*xM%bssXvlcr{QEq0HI{!@-S*-8E+lcJI1ax|0l#fg z@AVG;fe0T1zswvB%n|d;c(C^zX6NiWPaDvWS*~WuGe(mb|IN~cHc%C-g=WUqc@Q!1 z-8I?Vq61hwI;#1qXg@TGPg-nJjt4)zwt%{Lz>i7FVbME+Fl5u_W#RYw&sfc zRg8$3oXA*H0I4+R7+ybigDM)+H0INYdbd6+DY9zHG-~z?)*}|5!keSOugvlamXM# z7dQFnL2(7m?JdL7EAcO*Ut-ql=mKYm>aFkQfByj^gC(7#7Z{-R<}jBj-vs2AargeL z7{zm&q*eL8Hz6r$qxtQuHmth$e&9${HUw~KCVgXyf*gA8lNRr}uxacX)Ak-WOxz*& zSU1)mb+v>V4Ikcw$nl+LRCrHAqz0!}!N(I2^`802Yo;4uoUr}!pyn2QthGgZWKjl+ z?*3*dO^*kuYXj|SUCNmM&i|MGu43>?{=6=JlQPy$k8o|8$bmD*%uelJO9BVh=3^K0 z$@lL(l|yeIlOTCn>Il^zFYNl{Vtr5b3_Ryt^ZC(C7d*<{*g9Hl1G%I#c0yj;;o+71 z?!yNkV${BLyWi`UA&9H@c)70>D$|d2X>8pBIb(-u_naw&9Da|UKca2W&g$dVajkZx ze#h{^tBbdG7fqn$eCXQPd_Sn+Ws_9@a|vSiwFqq+(S`JF2ljR@3}U5RUtss`cTljt zadG(WLntfAws^$Ci+RS@k1xk*VcNtMi@bX#5I1+}Jp=V1R&279A34>AIguNWD{?Ji z+2$5HdBHG9m@_x{!}JRJb`9ATAL+-^quVOq>wLyGU)BhfUvYmooo1PFTX#e&Rh3xRnCL-V7m-KfkSw)WLp}u z!h;pQE?{2U*C+iAzL2rY)7_l&4|=(&Jc{He{rh|7hwkI}U_(TTk7jEqQ9zk(u)={wu#eT>Lfws_b!HByc*7=Sbt zTp`C5i!qDknjky`O}0u5$I%!|hKTQ}O^mQ`&+DVzddpZZFj!u`h7I$G>*h};hOfjA zz)-iHnJpaTb9;w0r^x#wkpE?gO8<8rTIPjo>vE<+MQTx7{j@qH2$dP!?)1m3jj~ct zZ^=XT`un?Y1sOuFiz{QqHAYPF{B@P_w=Gm1cUwc+kPpQ*ft-0=MV+Wj=kN9#WcHr6*NTSvm}|cBKpk`nt7yc=G#W7VhYK~RnXbfgQTeX9lE{QP?n&u^Vcy+jP-T&YbMTu%x5W0R~aHU z8`QHk4rgP;%$B~)iy_!}=j@yP@E+oyNYU*b?!h+d{1?PqBT)5Qg$2n>>>VMsUP|Kv$x6T3le@w}OQXs6 zH;+V4v5YVs2;2RDWqQa3!^URM$twy$+R+0ijrjfW{!&Gf$EP4nd)zP_J9!4$O4*)A zH%USm%d}$g7IMGnI3hiN*d5#r?VV<(snPam*kM5rIUs$a-OMy>0j2lF8s4XQV!kGG zzp2b)@JyVy)3Un=q(eRmoo08?GP%WLrgRsS^>No#3ckRY?o9Qj7s^1oD&*fK;07HF z(d&mZilA&^*O$Y##+XZNy;E0A2W`*AMVN877x&_ z@W_OvY$^0d!;&yZI5v#sF<{yw8z$xRtx)0FxWnoFlNG)qz;)oE>s%8nJ|r=XWHCl! zo=SaX0H-!&=P{Ko(+{GWinYe}2YwL9@AYfXNo6cyd1z{AVuGcci+?QMM<^;=BcYo( zf%!B2R&IJrnCp;sf`9%LLJKs9wy@FD4CCU~Z`#YKifJ3xkkf z;W+Bn7ZT87%S)H%xA=DFMiCm7VP`H^cIXi%gqp zk3-DGRE74vsTh*)`sO{!4ISi*gW857F?^VhdihhxN_-^<6@hDoWADK(W>I+`_Y+8c zbS0*7i4`gYMWgi?CZU1-yX*P{J9PY5a>FwDDi&U4=b)B-0qGI_U(|SRpxC*5#RVJHQv-c5~q z1fNHL6Gri-pB>mBEM3|>br!?himX3c4noc&gKXvnIlOOAH~Yvv2J#M4JKF{%LiQ2w zGfb`WP@$wdG?43nk3!~6!XF-m%$sfpH&07I3PXFnY1VB>V&1cX_o*%96`tp7cE5;j zI{Ur5qp6`(%ei%@(|_t`kI5pTP3J_oFu?C#fczOd4E<59{;QG=lG-}?EdtlWU4rJ$ zD}fG}$$Uos=lM!(em+O@rq&G7-@aUDTiS?0OlwbS1>_-Vd^<}sOB>eu=riS!@5{B$ ze&YGXjF9-fL9O!rIzX*Q+s-6qf~`aB`v=r_;Q8r-&dB-oSW4%=$8T3F)S91>__HAw zOH4nw^p3P*E#ZpfToN_hzHjvA!6!aQKIf_HOG<>45pm{i-#j5gOr|)oR0tYWq7|!WkGP%5~u(?6<)()jqtk%%+5~y^*dP0$S%daq~HNd+!{}WdZ@hyPfuaQ|>l~<3ZV@!{*n%zVk2!Lmlw0A^8MMu-A7?+$$1tipl{5O% z;Og)3`?5|uHrC&8d>>l7!WSFlvdyzTcsY-~XK5aldgj#oc`QrQh5b#q|(YZZNf}HI(8w{2O&`->@JD2GNv?q%QyFXH< z`uF1=_ol+)sDm@M|PmJodyQV;TM#im!amp|!QNuL9q1zb}q7*rk&o4mS=a6lBflCm(ZJ{xzwEzF~zlZA? zp8rp;P55_TpqB3uYM;8w@|OJfzut06y)w4^U+sm~QqRKBmg=w9DAE7@auz)cD|16( z(`$df5y{f(A4G3xYHVm}uV?-r^}n#8!Oj1?oylI$#>(b~)qnIgZ1fBa&ug6j4?e2r zXlQGyXZauRWNQn(oBy4efw`XTe=_@zkcFIx@ip5s3P%)HMpq_8^Jhhq=08rYZ0sxz c|C2I Date: Wed, 27 Sep 2023 15:12:49 -0400 Subject: [PATCH 235/385] Update doc for demoPCA1KG object --- R/RAIDS.R | 87 +++++++++++++++++++++++++++++++++++++++++++++-- man/demoPCA1KG.Rd | 70 +++++++++++++++++++++++++++++++++++++- 2 files changed, 153 insertions(+), 4 deletions(-) diff --git a/R/RAIDS.R b/R/RAIDS.R index 667519495..b1d23dda5 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -349,8 +349,6 @@ NULL NULL - - #' The PCA results of the demo 1KG reference dataset for demonstration purpose. #' Beware that the PCA has been run on a very small subset of the #' 1KG reference dataset @@ -391,7 +389,6 @@ NULL #' #' @examples #' -#' #' ## Required library #' library(gdsfmt) #' @@ -428,3 +425,87 @@ NULL #' closefn.gds(gdsProfile) #' NULL + + +#' The PCA result of one demo synthetic profile projected on the demo subset +#' 1KG reference PCA. +#' +#' The object is a \code{list}. +#' +#' This object can be +#' used to test the \code{\link{computePCAMultiSynthetic}} function. +#' +#' @name demoPCA1KG +#' +#' @docType data +#' +#' @aliases demoPCA1KG +#' +#' @format The \code{list} containing the PCA result of one demo synthetic +#' profile projected on the demo subset 1KG reference PCA. +#' The \code{list} contains 3 entries: +#' \itemize{ +#' \item{sample.id}{ a \code{character} string representing the unique +#' identifier of the synthetic profile.} +#' \item{eigenvector.ref} { a \code{matrix} of \code{numeric} containing +#' the eigenvectors for the reference profiles.} +#' \item{eigenvector}{ a \code{matrix} of \code{numeric} containing the +#' eigenvectors for the current synthetic profile projected on the demo +#' PCA 1KG reference profiles.} +#' } +#' +#' @return The \code{list} containing the PCA result of one demo synthetic +#' profile projected on the demo subset 1KG reference PCA. +#' The \code{list} contains 3 entries: +#' \itemize{ +#' \item{sample.id}{ a \code{character} string representing the unique +#' identifier of the synthetic profile.} +#' \item{eigenvector.ref} { a \code{matrix} of \code{numeric} containing +#' the eigenvectors for the reference profiles.} +#' \item{eigenvector}{ a \code{matrix} of \code{numeric} containing the +#' eigenvectors for the current synthetic profile projected on the demo +#' PCA 1KG reference profiles.} +#' } +#' +#' @usage data(demoPCA1KG) +#' +#' @keywords datasets +#' +#' @examples +#' +#' ## Required library +#' library(gdsfmt) +#' +#' ## Loading demo PCA on subset of 1KG reference dataset +#' data(demoPCA1KG) +#' +#' ## Path to the demo Profile GDS file is located in this package +#' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") +#' +#' # The name of the synthetic study +#' studyID <- "MYDATA.Synthetic" +#' +#' samplesRM <- c("HG00246", "HG00325", "HG00611", "HG01173", "HG02165", +#' "HG01112", "HG01615", "HG01968", "HG02658", "HG01850", "HG02013", +#' "HG02465", "HG02974", "HG03814", "HG03445", "HG03689", "HG03789", +#' "NA12751", "NA19107", "NA18548", "NA19075", "NA19475", "NA19712", +#' "NA19731", "NA20528", "NA20908") +#' names(samplesRM) <- c("GBR", "FIN", "CHS","PUR", "CDX", "CLM", "IBS", +#' "PEL", "PJL", "KHV", "ACB", "GWD", "ESN", "BEB", "MSL", "STU", "ITU", +#' "CEU", "YRI", "CHB", "JPT", "LWK", "ASW", "MXL", "TSI", "GIH") +#' +#' ## Open the Profile GDS file +#' gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) +#' +#' ## Projects synthetic profiles on demo 1KG PCA +#' results <- computePCAMultiSynthetic(gdsProfile=gdsProfile, +#' listPCA=demoPCA1KG, sampleRef=samplesRM, studyIDSyn=studyID, +#' verbose=FALSE) +#' +#' ## The eigenvectors for the synthetic profile +#' head(results$eigenvector) +#' +#' ## Close Profile GDS file (important) +#' closefn.gds(gdsProfile) +#' +NULL diff --git a/man/demoPCA1KG.Rd b/man/demoPCA1KG.Rd index 34affd46b..2f6fe8d88 100644 --- a/man/demoPCA1KG.Rd +++ b/man/demoPCA1KG.Rd @@ -16,8 +16,23 @@ for the PCA analysis.} \item{pca.unrel}{ a \code{snpgdsPCAClass} object containing the eigenvalues as generated by \link[SNPRelate]{snpgdsPCA} function.} } + +The \code{list} containing the PCA result of one demo synthetic +profile projected on the demo subset 1KG reference PCA. +The \code{list} contains 3 entries: +\itemize{ +\item{sample.id}{ a \code{character} string representing the unique +identifier of the synthetic profile.} +\item{eigenvector.ref} { a \code{matrix} of \code{numeric} containing +the eigenvectors for the reference profiles.} +\item{eigenvector}{ a \code{matrix} of \code{numeric} containing the +eigenvectors for the current synthetic profile projected on the demo +PCA 1KG reference profiles.} +} } \usage{ +data(demoPCA1KG) + data(demoPCA1KG) } \value{ @@ -29,17 +44,34 @@ for the PCA analysis.} \item{pca.unrel}{ a \code{snpgdsPCAClass} object containing the eigenvalues as generated by \link[SNPRelate]{snpgdsPCA} function.} } + +The \code{list} containing the PCA result of one demo synthetic +profile projected on the demo subset 1KG reference PCA. +The \code{list} contains 3 entries: +\itemize{ +\item{sample.id}{ a \code{character} string representing the unique +identifier of the synthetic profile.} +\item{eigenvector.ref} { a \code{matrix} of \code{numeric} containing +the eigenvectors for the reference profiles.} +\item{eigenvector}{ a \code{matrix} of \code{numeric} containing the +eigenvectors for the current synthetic profile projected on the demo +PCA 1KG reference profiles.} +} } \description{ +The object is a \code{list}. + The object is a \code{list}. } \details{ +This object can be +used to test the \code{\link{computePCAMultiSynthetic}} function. + This object can be used to test the \code{\link{computePCAMultiSynthetic}} function. } \examples{ - ## Required library library(gdsfmt) @@ -75,5 +107,41 @@ head(results$eigenvector) ## Close Profile GDS file (important) closefn.gds(gdsProfile) + +## Required library +library(gdsfmt) + +## Loading demo PCA on subset of 1KG reference dataset +data(demoPCA1KG) + +## Path to the demo Profile GDS file is located in this package +dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") + +# The name of the synthetic study +studyID <- "MYDATA.Synthetic" + +samplesRM <- c("HG00246", "HG00325", "HG00611", "HG01173", "HG02165", + "HG01112", "HG01615", "HG01968", "HG02658", "HG01850", "HG02013", + "HG02465", "HG02974", "HG03814", "HG03445", "HG03689", "HG03789", + "NA12751", "NA19107", "NA18548", "NA19075", "NA19475", "NA19712", + "NA19731", "NA20528", "NA20908") +names(samplesRM) <- c("GBR", "FIN", "CHS","PUR", "CDX", "CLM", "IBS", + "PEL", "PJL", "KHV", "ACB", "GWD", "ESN", "BEB", "MSL", "STU", "ITU", + "CEU", "YRI", "CHB", "JPT", "LWK", "ASW", "MXL", "TSI", "GIH") + +## Open the Profile GDS file +gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) + +## Projects synthetic profiles on demo 1KG PCA +results <- computePCAMultiSynthetic(gdsProfile=gdsProfile, + listPCA=demoPCA1KG, sampleRef=samplesRM, studyIDSyn=studyID, + verbose=FALSE) + +## The eigenvectors for the synthetic profile +head(results$eigenvector) + +## Close Profile GDS file (important) +closefn.gds(gdsProfile) + } \keyword{datasets} From 8c722889d7d81b4152f66b9889fe08b56e43c671 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 27 Sep 2023 17:25:48 -0400 Subject: [PATCH 236/385] Update README file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 88b658e4a..989f6b01a 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ alterations, such as those caused by cancer. [Pascal Belleau](http://ca.linkedin.com/in/pascalbelleau "Pascal Belleau"), [Astrid Deschênes](https://www.linkedin.com/in/astriddeschenes "Astrid Deschênes"), -David A. Tuveson and +[David A. Tuveson](https://tuvesonlab.labsites.cshl.edu/) and [Alexander Krasnitz](https://www.cshl.edu/research/faculty-staff/alexander-krasnitz/ "Alexander Krasnitz") From 5cecc23ae48fda7fb65ce12e46f650b5d9f13ccc Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 27 Sep 2023 17:27:14 -0400 Subject: [PATCH 237/385] Update README file --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 989f6b01a..f510c33f4 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ # Accurate genetic ancestry inference from cancer-derived molecular data with **RAIDS** # -The Robust Ancestry Inference using Data Synthesis (**_RAIDS_**) package +The Robust Ancestry Inference using Data Synthesis (**RAIDS**) package enables accurate and robust inference of genetic ancestry from various types of molecular data, including whole-genome, whole-exome, targeted gene panels and RNA sequences, as described in our @@ -29,7 +29,7 @@ alterations, such as those caused by cancer. ## Citing ## -If you use the **_RAIDS_** package for a publication, we would ask you to cite +If you use the **RAIDS** package for a publication, we would ask you to cite the following: > Pascal Belleau, Astrid Deschênes, Nyasha Chambwe, David A. Tuveson, Alexander Krasnitz; Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. https://doi.org/10.1158/0008-5472.CAN-22-0682 From 928afc0f7c454475771cde02d54960cadd1dbd32 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 27 Sep 2023 17:32:57 -0400 Subject: [PATCH 238/385] Replace pcaSynthetit.RDS by a RData object --- R/RAIDS.R | 67 +++++++------- R/processStudy.R | 22 +++-- R/processStudy_internal.R | 16 ++-- data/demoPCASyntheticProfiles.RData | Bin 0 -> 18220 bytes .../extdata/demoKNNSynthetic/pcaSynthetic.RDS | Bin 18555 -> 0 bytes man/computeKNNRefSample.Rd | 6 +- man/computeKNNRefSynthetic.Rd | 16 ++-- man/demoPCA1KG.Rd | 69 -------------- man/demoPCASyntheticProfiles.Rd | 87 ++++++++++++++++++ man/validateComputeKNNRefSample.Rd | 9 +- man/validateComputeKNNRefSynthetic.Rd | 7 +- 11 files changed, 170 insertions(+), 129 deletions(-) create mode 100644 data/demoPCASyntheticProfiles.RData delete mode 100644 inst/extdata/demoKNNSynthetic/pcaSynthetic.RDS create mode 100644 man/demoPCASyntheticProfiles.Rd diff --git a/R/RAIDS.R b/R/RAIDS.R index b1d23dda5..f59100f65 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -427,47 +427,53 @@ NULL NULL -#' The PCA result of one demo synthetic profile projected on the demo subset +#' The PCA result of demo synthetic profiles projected on the demo subset #' 1KG reference PCA. #' #' The object is a \code{list}. #' #' This object can be -#' used to test the \code{\link{computePCAMultiSynthetic}} function. +#' used to test the \code{\link{computeKNNRefSynthetic}} function. #' -#' @name demoPCA1KG +#' @name demoPCASyntheticProfiles #' #' @docType data #' -#' @aliases demoPCA1KG +#' @aliases demoPCASyntheticProfiles #' -#' @format The \code{list} containing the PCA result of one demo synthetic -#' profile projected on the demo subset 1KG reference PCA. +#' @format The \code{list} containing the PCA result of demo synthetic +#' profiles projected on the demo subset 1KG reference PCA. #' The \code{list} contains 3 entries: #' \itemize{ #' \item{sample.id}{ a \code{character} string representing the unique -#' identifier of the synthetic profile.} +#' identifier of the synthetic profiles.} #' \item{eigenvector.ref} { a \code{matrix} of \code{numeric} containing #' the eigenvectors for the reference profiles.} #' \item{eigenvector}{ a \code{matrix} of \code{numeric} containing the -#' eigenvectors for the current synthetic profile projected on the demo +#' eigenvectors for the current synthetic profiles projected on the demo #' PCA 1KG reference profiles.} #' } #' -#' @return The \code{list} containing the PCA result of one demo synthetic -#' profile projected on the demo subset 1KG reference PCA. +#' @return The \code{list} containing the PCA result of demo synthetic +#' profiles projected on the demo subset 1KG reference PCA. #' The \code{list} contains 3 entries: #' \itemize{ #' \item{sample.id}{ a \code{character} string representing the unique -#' identifier of the synthetic profile.} +#' identifier of the synthetic profiles.} #' \item{eigenvector.ref} { a \code{matrix} of \code{numeric} containing #' the eigenvectors for the reference profiles.} #' \item{eigenvector}{ a \code{matrix} of \code{numeric} containing the -#' eigenvectors for the current synthetic profile projected on the demo +#' eigenvectors for the current synthetic profiles projected on the demo #' PCA 1KG reference profiles.} #' } #' -#' @usage data(demoPCA1KG) +#' @seealso +#' \itemize{ +#' \item \code{\link{computeKNNRefSynthetic}} {for running a k-nearest +#' neighbors analysis on a subset of the synthetic data set.} +#' } +#' +#' @usage data(demoPCASyntheticProfiles) #' #' @keywords datasets #' @@ -476,34 +482,31 @@ NULL #' ## Required library #' library(gdsfmt) #' -#' ## Loading demo PCA on subset of 1KG reference dataset -#' data(demoPCA1KG) +#' ## Load the demo PCA on the synthetic profiles projected on the +#' ## demo 1KG reference PCA +#' data(demoPCASyntheticProfiles) #' #' ## Path to the demo Profile GDS file is located in this package #' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' -#' # The name of the synthetic study -#' studyID <- "MYDATA.Synthetic" -#' -#' samplesRM <- c("HG00246", "HG00325", "HG00611", "HG01173", "HG02165", -#' "HG01112", "HG01615", "HG01968", "HG02658", "HG01850", "HG02013", -#' "HG02465", "HG02974", "HG03814", "HG03445", "HG03689", "HG03789", -#' "NA12751", "NA19107", "NA18548", "NA19075", "NA19475", "NA19712", -#' "NA19731", "NA20528", "NA20908") -#' names(samplesRM) <- c("GBR", "FIN", "CHS","PUR", "CDX", "CLM", "IBS", -#' "PEL", "PJL", "KHV", "ACB", "GWD", "ESN", "BEB", "MSL", "STU", "ITU", -#' "CEU", "YRI", "CHB", "JPT", "LWK", "ASW", "MXL", "TSI", "GIH") +#' ## The known ancestry for the 1KG reference profiles +#' refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) #' #' ## Open the Profile GDS file #' gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) #' -#' ## Projects synthetic profiles on demo 1KG PCA -#' results <- computePCAMultiSynthetic(gdsProfile=gdsProfile, -#' listPCA=demoPCA1KG, sampleRef=samplesRM, studyIDSyn=studyID, -#' verbose=FALSE) +#' # The name of the synthetic study +#' studyID <- "MYDATA.Synthetic" #' -#' ## The eigenvectors for the synthetic profile -#' head(results$eigenvector) +#' ## Projects synthetic profiles on 1KG PCA +#' results <- computeKNNRefSynthetic(gdsProfile=gdsProfile, +#' listEigenvector=demoPCASyntheticProfiles, +#' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), studyIDSyn=studyID, +#' spRef=refKnownSuperPop) +#' +#' ## The inferred ancestry for the synthetic profiles for differents values +#' ## of D and K +#' head(results$matKNN) #' #' ## Close Profile GDS file (important) #' closefn.gds(gdsProfile) diff --git a/R/processStudy.R b/R/processStudy.R index a53544de4..a0b90fee8 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -1067,23 +1067,25 @@ computePCARefSample <- function(gdsProfile, currentProfile, #' ## Required library #' library(gdsfmt) #' +#' ## Load the demo PCA on the synthetic profiles projected on the +#' ## demo 1KG reference PCA +#' data(demoPCASyntheticProfiles) +#' #' ## Path to the demo Profile GDS file is located in this package #' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' -#' # The name of the synthetic study -#' studyID <- "MYDATA.Synthetic" -#' -#' ## The PCA on the synthetic profiles projected on the 1KG reference PCA -#' pca <- readRDS(file.path(dataDir, "pcaSynthetic.RDS")) -#' #' ## The known ancestry for the 1KG reference profiles #' refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) #' #' ## Open the Profile GDS file #' gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) #' +#' # The name of the synthetic study +#' studyID <- "MYDATA.Synthetic" +#' #' ## Projects synthetic profiles on 1KG PCA -#' results <- computeKNNRefSynthetic(gdsProfile=gdsProfile, listEigenvector=pca, +#' results <- computeKNNRefSynthetic(gdsProfile=gdsProfile, +#' listEigenvector=demoPCASyntheticProfiles, #' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), studyIDSyn=studyID, #' spRef=refKnownSuperPop) #' @@ -1232,12 +1234,16 @@ computeKNNRefSynthetic <- function(gdsProfile, listEigenvector, #' #' @examples #' +#' ## Load the demo PCA on the synthetic profiles projected on the +#' ## demo 1KG reference PCA +#' data(demoPCASyntheticProfiles) +#' #' ## Path to the demo files located in this package #' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' #' ## The PCA with 1 profile projected on the 1KG reference PCA #' ## Only one profile is retained -#' pca <- readRDS(file.path(dataDir, "pcaSynthetic.RDS")) +#' pca <- demoPCASyntheticProfiles #' pca$sample.id <- pca$sample.id[1] #' pca$eigenvector <- pca$eigenvector[1, , drop=FALSE] #' diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index a7b382aa6..16914f241 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -1446,13 +1446,14 @@ validateComputePCAMultiSynthetic <- function(gdsProfile, listPCA, sampleRef, #' #' @examples #' +#' ## Load the demo PCA on the synthetic profiles projected on the +#' ## demo 1KG reference PCA +#' data(demoPCASyntheticProfiles) #' #' ## Path to the demo GDS file is located in this package #' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' fileProfileGDS <- file.path(dataDir, "ex1.gds") #' -#' pcaSynthetic <- readRDS(file.path(dataDir, "pcaSynthetic.RDS")) -#' #' ## The known ancestry for the 1KG reference profiles #' refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) #' @@ -1461,7 +1462,7 @@ validateComputePCAMultiSynthetic <- function(gdsProfile, listPCA, sampleRef, #' #' ## The function returns 0L when all parameters are valid #' RAIDS:::validateComputeKNNRefSynthetic(gdsProfile=gdsProfile, -#' listEigenvector=pcaSynthetic, +#' listEigenvector=demoPCASyntheticProfiles, #' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), #' studyIDSyn="MyStudy", spRef=refKnownSuperPop, #' fieldPopInfAnc="Superpop", kList=c(10, 11, 12), @@ -1558,13 +1559,16 @@ validateComputeKNNRefSynthetic <- function(gdsProfile, listEigenvector, #' #' @examples #' +#' ## Load the demo PCA on the synthetic profiles projected on the +#' ## demo 1KG reference PCA +#' data(demoPCASyntheticProfiles) +#' +#' pcaSynthetic <- demoPCASyntheticProfiles +#' pcaSynthetic$sample.id <- pcaSynthetic$sample.id[1] #' #' ## Path to the demo GDS file is located in this package #' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' -#' pcaSynthetic <- readRDS(file.path(dataDir, "pcaSynthetic.RDS")) -#' pcaSynthetic$sample.id <- pcaSynthetic$sample.id[1] -#' #' ## The known ancestry for the 1KG reference profiles #' refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) #' diff --git a/data/demoPCASyntheticProfiles.RData b/data/demoPCASyntheticProfiles.RData new file mode 100644 index 0000000000000000000000000000000000000000..62846c3cb4b0c82cf53d247618b6883d519258c9 GIT binary patch literal 18220 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 literal 0 HcmV?d00001 diff --git a/inst/extdata/demoKNNSynthetic/pcaSynthetic.RDS b/inst/extdata/demoKNNSynthetic/pcaSynthetic.RDS deleted file mode 100644 index 8ae11a9c79f9c39729fd0b9ec126504b69151d96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18555 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 Date: Wed, 27 Sep 2023 18:30:22 -0400 Subject: [PATCH 239/385] Replace knowSuperPop1KG.RDS with a RData object --- R/RAIDS.R | 78 ++++++++++++++++- R/allelicFraction_internal.R | 79 ++++++++++-------- R/processStudy.R | 38 ++++----- R/processStudy_internal.R | 29 +++---- R/synthetic.R | 3 +- data/demoKnownSuperPop1KG.RData | Bin 0 -> 588 bytes .../demoKNNSynthetic/knownSuperPop1KG.RDS | Bin 600 -> 0 bytes man/computeAllelicImbDNAChr.Rd | 4 +- man/computeAncestryFromSyntheticFile.Rd | 9 +- man/computeKNNRefSample.Rd | 9 +- man/computeKNNRefSynthetic.Rd | 8 +- man/computeLOHBlocksDNAChr.Rd | 10 ++- man/computePCARefRMMulti.Rd | 10 +-- man/computePoolSyntheticAncestryGr.Rd | 12 +-- man/demoKnownSuperPop1KG.Rd | 70 ++++++++++++++++ man/demoPCASyntheticProfiles.Rd | 8 +- man/prepSynthetic.Rd | 3 +- man/validateComputeKNNRefSample.Rd | 11 +-- man/validateComputeKNNRefSynthetic.Rd | 8 +- tests/testthat/test-tools.R | 2 - 20 files changed, 266 insertions(+), 125 deletions(-) create mode 100644 data/demoKnownSuperPop1KG.RData delete mode 100644 inst/extdata/demoKNNSynthetic/knownSuperPop1KG.RDS create mode 100644 man/demoKnownSuperPop1KG.Rd diff --git a/R/RAIDS.R b/R/RAIDS.R index f59100f65..8d2db4cf0 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -486,11 +486,83 @@ NULL #' ## demo 1KG reference PCA #' data(demoPCASyntheticProfiles) #' +#' ## Load the known ancestry for the demo 1KG reference profiles +#' data(demoKnownSuperPop1KG) +#' #' ## Path to the demo Profile GDS file is located in this package #' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' -#' ## The known ancestry for the 1KG reference profiles -#' refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) +#' ## Open the Profile GDS file +#' gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) +#' +#' # The name of the synthetic study +#' studyID <- "MYDATA.Synthetic" +#' +#' ## Projects synthetic profiles on 1KG PCA +#' results <- computeKNNRefSynthetic(gdsProfile=gdsProfile, +#' listEigenvector=demoPCASyntheticProfiles, +#' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), studyIDSyn=studyID, +#' spRef=demoKnownSuperPop1KG) +#' +#' ## The inferred ancestry for the synthetic profiles for differents values +#' ## of D and K +#' head(results$matKNN) +#' +#' ## Close Profile GDS file (important) +#' closefn.gds(gdsProfile) +#' +NULL + + + + +#' The known super population ancestry of the demo 1KG reference profiles. +#' +#' The object is a \code{vector}. +#' +#' This object can be +#' used to test the \code{\link{computeKNNRefSynthetic}} and +#' \code{\link{computePoolSyntheticAncestryGr}} functions. +#' +#' @name demoKnownSuperPop1KG +#' +#' @docType data +#' +#' @aliases demoKnownSuperPop1KG +#' +#' @format The \code{vector} containing the know super population ancestry +#' for the demo 1KG reference profiles. +#' +#' @return The \code{vector} containing the know super population ancestry +#' for the demo 1KG reference profiles. +#' +#' @seealso +#' \itemize{ +#' \item \code{\link{computeKNNRefSynthetic}} {for running a k-nearest +#' neighbors analysis on a subset of the synthetic data set.} +#' \item \code{\link{computePoolSyntheticAncestryGr}} { for running a +#' PCA analysis using 1 synthetic profile from each sub-continental +#' population.} +#' } +#' +#' @usage data(demoKnownSuperPop1KG) +#' +#' @keywords datasets +#' +#' @examples +#' +#' ## Required library +#' library(gdsfmt) +#' +#' ## Load the demo PCA on the synthetic profiles projected on the +#' ## demo 1KG reference PCA +#' data(demoPCASyntheticProfiles) +#' +#' ## Load the known ancestry for the demo 1KG reference profiles +#' data(demoKnownSuperPop1KG) +#' +#' ## Path to the demo Profile GDS file is located in this package +#' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' #' ## Open the Profile GDS file #' gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) @@ -502,7 +574,7 @@ NULL #' results <- computeKNNRefSynthetic(gdsProfile=gdsProfile, #' listEigenvector=demoPCASyntheticProfiles, #' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), studyIDSyn=studyID, -#' spRef=refKnownSuperPop) +#' spRef=demoKnownSuperPop1KG) #' #' ## The inferred ancestry for the synthetic profiles for differents values #' ## of D and K diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index e3f73cc98..cf69a278a 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -319,7 +319,8 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' #' ## Chromosome length information #' ## chr23 is chrX, chr24 is chrY and chrM is 25 -#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' chrInfo <- +#' GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] #' #' ## Data frame with SNV information for the specified chromosome (chr 1) #' snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), @@ -332,12 +333,13 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' TRUE, TRUE, TRUE), #' pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), #' snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), -#' keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), +#' keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, +#' TRUE, rep(FALSE, 2)), #' homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), #' stringAsFactor=FALSE) #' -#' ## The function returns a data frame containing the information about the -#' ## LOH regions in the specified chromosome +#' ## The function returns a data frame containing the information about +#' ## the LOH regions in the specified chromosome #' result <- RAIDS:::computeLOHBlocksDNAChr(gdsReference=gds1KG, #' chrInfo=chrInfo, snpPos=snpInfo, chr=1L, genoN=0.0001) #' head(result) @@ -402,7 +404,8 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, homoBlock$nbSNV[i] <- nrow(blcCur) homoBlock$nbPruned[i] <- length(which(snvH$pruned)) if (length(which(snvH$normal.geno != 3)) > 0) { - listCount <- snvH$cnt.tot[which(snvH$normal.geno == 1)] + listCount <- snvH$cnt.tot[which(snvH$normal.geno + == 1)] homoBlock$nbNorm[i] <- length(listCount) if(homoBlock$nbNorm[i] > 0){ lH1 <-sum(log10(apply(snvH[which(snvH$normal.geno == 1), @@ -413,11 +416,12 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, }))) lM1 <- sum(log10(apply(snvH[which(snvH$normal.geno == 1), - c("cnt.ref", "cnt.tot"), drop=FALSE], - 1, FUN=function(x){ - return(dbinom((x[2] + x[2]%%2)/2, x[2], 0.5)) - #genoN1 *dbinom((x[2] + x[2]%%2)/2, x[2], 0.5) + genoN - }))) + c("cnt.ref", "cnt.tot"), drop=FALSE], + 1, FUN=function(x){ + return(dbinom((x[2] + x[2]%%2)/2, + x[2], 0.5)) + ## genoN1 *dbinom((x[2] + x[2]%%2)/2, x[2], 0.5) + genoN + }))) logLHR <- -100 } @@ -428,7 +432,8 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, snvR <- snvH$cnt.ref[which(snvH$pruned)] > snvH$cnt.alt[which(snvH$pruned)] - # Check if it is unlikely the genotype are homo by error + ## Check if it is unlikely the genotype are + ## homo by error lH1 <- -100 # Freq of the more likely geno @@ -527,23 +532,23 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { end=seq_len(nrow(snpPos))[which(z[,2] < 0)]) listBlockAR <- lapply(seq_len(nrow(segImb)), - FUN=function(i, segImb, snpPos, w, - cutOff){ - listBlockAR <- list() - j<-1 - listSeg <- (segImb$start[i]):(segImb$end[i]) - # index hetero segment - listHetero <- listSeg[snpPos[listSeg,"hetero"] == TRUE] - # SNP hetero for the segment - snp.hetero <- snpPos[listHetero,] - - if(nrow(snp.hetero) >= 2 * w) { - lapCur <- median(apply(snp.hetero[seq_len(w), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[seq_len(w),c("cnt.ref", "cnt.alt")]))) - - start <- 1 - k <- w + 1 + FUN=function(i, segImb, snpPos, w, cutOff){ + listBlockAR <- list() + j<-1 + listSeg <- (segImb$start[i]):(segImb$end[i]) + # index hetero segment + listHetero <- listSeg[snpPos[listSeg,"hetero"] == TRUE] + # SNP hetero for the segment + snp.hetero <- snpPos[listHetero,] + + if(nrow(snp.hetero) >= 2 * w) { + lapCur <- median(apply(snp.hetero[seq_len(w), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[seq_len(w), + c("cnt.ref", "cnt.alt")]))) + + start <- 1 + k <- w + 1 while(k < nrow(snp.hetero)) { # We have (k+w-1) <= nrow(snp.hetero) # Case 1 true because (nrow(snp.hetero) >= 2 * w @@ -604,20 +609,21 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { } } }# End while - }else { + } else { lapCur <- median(apply(snp.hetero[, c("cnt.ref", "cnt.alt")], 1, min) / (rowSums(snp.hetero[,c("cnt.ref", "cnt.alt")]))) - listBlockAR[[j]] <- c(segImb$start[i], segImb$end[i], lapCur) + listBlockAR[[j]] <- c(segImb$start[i], + segImb$end[i], + lapCur) j <- j + 1 } listBlockAR <- do.call(rbind, listBlockAR) return(listBlockAR) }, - segImb=segImb, snpPos=snpPos, - w=w, cutOff=cutOff) + segImb=segImb, snpPos=snpPos, w=w, cutOff=cutOff) } # note NULL if length(listBlockAR) == 0 @@ -1000,7 +1006,8 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, # for each chromosome # listBlock <- list() - listBlock <- lapply(unique(snpPos$snp.chr), FUN = function(x, snpPos, verbose){ + listBlock <- lapply(unique(snpPos$snp.chr), + FUN=function(x, snpPos, verbose){ if (verbose) { message("chr ", x) message("Step 1 ", Sys.time()) @@ -1009,7 +1016,7 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, blockAF <- tableBlockAF(snpPos=snpPos[listChr,]) blockAF$aRF[blockAF$lRhomo <= cutOffLOH] <- 0 blockAF$aRF[blockAF$lR >= cutOffAR] <- blockAF$aFraction[blockAF$lR - >= cutOffAR] + >= cutOffAR] blockAF$aRF[blockAF$lR < cutOffAR & blockAF$nbHetero > 1] <- 0.5 #listBlock[[x]] <- blockAF @@ -1126,8 +1133,8 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, #' lap=rep(-1, 8), LOH=rep(0, 8), imbAR=rep(-1, 8), #' stringAsFactor=FALSE) #' -#' ## The function returns a data frame containing the information about the -#' ## LOH regions in the specified chromosome +#' ## The function returns a data frame containing the information about +#' ## the LOH regions in the specified chromosome #' result <- RAIDS:::computeAllelicImbDNAChr(snpPos=snpInfo, chr=1, wAR=10, #' cutOffEmptyBox=-3) #' head(result) diff --git a/R/processStudy.R b/R/processStudy.R index a0b90fee8..e96794739 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -1071,12 +1071,12 @@ computePCARefSample <- function(gdsProfile, currentProfile, #' ## demo 1KG reference PCA #' data(demoPCASyntheticProfiles) #' +#' ## Load the known ancestry for the demo 1KG reference profiles +#' data(demoKnownSuperPop1KG) +#' #' ## Path to the demo Profile GDS file is located in this package #' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' -#' ## The known ancestry for the 1KG reference profiles -#' refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) -#' #' ## Open the Profile GDS file #' gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) #' @@ -1087,7 +1087,7 @@ computePCARefSample <- function(gdsProfile, currentProfile, #' results <- computeKNNRefSynthetic(gdsProfile=gdsProfile, #' listEigenvector=demoPCASyntheticProfiles, #' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), studyIDSyn=studyID, -#' spRef=refKnownSuperPop) +#' spRef=demoKnownSuperPop1KG) #' #' ## The inferred ancestry for the synthetic profiles for differents values #' ## of D and K @@ -1238,8 +1238,8 @@ computeKNNRefSynthetic <- function(gdsProfile, listEigenvector, #' ## demo 1KG reference PCA #' data(demoPCASyntheticProfiles) #' -#' ## Path to the demo files located in this package -#' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") +#' ## Load the known ancestry for the demo 1KG reference profiles +#' data(demoKnownSuperPop1KG) #' #' ## The PCA with 1 profile projected on the 1KG reference PCA #' ## Only one profile is retained @@ -1247,13 +1247,10 @@ computeKNNRefSynthetic <- function(gdsProfile, listEigenvector, #' pca$sample.id <- pca$sample.id[1] #' pca$eigenvector <- pca$eigenvector[1, , drop=FALSE] #' -#' ## The known ancestry for the 1KG reference profiles -#' refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) -#' #' ## Projects profile on 1KG PCA #' results <- computeKNNRefSample(listEigenvector=pca, #' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), -#' spRef=refKnownSuperPop, fieldPopInfAnc="SuperPop", +#' spRef=demoKnownSuperPop1KG, fieldPopInfAnc="SuperPop", #' kList=seq(10, 15, 1), pcaList=seq(10, 15, 1)) #' #' ## The assigned ancestry to the profile for different values of K and D @@ -1421,8 +1418,9 @@ computeKNNRefSample <- function(listEigenvector, #' ## Required library #' library(gdsfmt) #' -#' ## Path to the demo Profile GDS file is located in this package -#' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") +#' ## Load the known ancestry for the demo 1KG reference profiles +#' data(demoKnownSuperPop1KG) +#' #' #' # The name of the synthetic study #' studyID <- "MYDATA.Synthetic" @@ -1436,8 +1434,8 @@ computeKNNRefSample <- function(listEigenvector, #' "PEL", "PJL", "KHV", "ACB", "GWD", "ESN", "BEB", "MSL", "STU", "ITU", #' "CEU", "YRI", "CHB", "JPT", "LWK", "ASW", "MXL", "TSI", "GIH") #' -#' ## The known ancestry for the 1KG reference profiles -#' refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) +#' ## Path to the demo Profile GDS file is located in this package +#' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' #' ## Open the Profile GDS file #' gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) @@ -1445,7 +1443,8 @@ computeKNNRefSample <- function(listEigenvector, #' ## Run a PCA analysis and a K-nearest neighbors analysis on a small set #' ## of synthetic data #' results <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, -#' sampleRM=samplesRM, studyIDSyn=studyID, np=1L, spRef=refKnownSuperPop, +#' sampleRM=samplesRM, studyIDSyn=studyID, np=1L, +#' spRef=demoKnownSuperPop1KG, #' kList=seq(10,15,1), pcaList=seq(10,15,1), eigenCount=15L) #' #' ## The ancestry inference for the synthetic data using @@ -1727,6 +1726,9 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, #' ## Required library #' library(gdsfmt) #' +#' ## Load the known ancestry for the demo 1KG reference profiles +#' data(demoKnownSuperPop1KG) +#' #' ## The Reference GDS file #' path1KG <- system.file("extdata/example/gdsRef", package="RAIDS") #' @@ -1742,10 +1744,6 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, #' # The name of the synthetic study #' studyID <- "MYDATA.Synthetic" #' -#' ## The known ancestry for the 1KG reference profiles -#' dataDir1KG <- system.file("extdata/demoKNNSynthetic", package="RAIDS") -#' refKnownSuperPop <- readRDS(file.path(dataDir1KG, "knownSuperPop1KG.RDS")) -#' #' ## Path to the demo Profile GDS file is located in this package #' dataDir <- system.file("extdata/demoAncestryCall", package="RAIDS") #' @@ -1759,7 +1757,7 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, #' gdsProfile=gdsProfile, #' listFiles=listFiles, #' currentProfile=c("ex1"), -#' spRef=refKnownSuperPop, +#' spRef=demoKnownSuperPop1KG, #' studyIDSyn=studyID, np=1L) #' #' ## The ancestry called with the optimal D and K values diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 16914f241..817cbe2ff 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -1450,13 +1450,13 @@ validateComputePCAMultiSynthetic <- function(gdsProfile, listPCA, sampleRef, #' ## demo 1KG reference PCA #' data(demoPCASyntheticProfiles) #' +#' ## Load the known ancestry for the demo 1KG reference profiles +#' data(demoKnownSuperPop1KG) +#' #' ## Path to the demo GDS file is located in this package #' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' fileProfileGDS <- file.path(dataDir, "ex1.gds") #' -#' ## The known ancestry for the 1KG reference profiles -#' refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) -#' #' ## Open GDS files #' gdsProfile <- openfn.gds(fileProfileGDS) #' @@ -1464,7 +1464,7 @@ validateComputePCAMultiSynthetic <- function(gdsProfile, listPCA, sampleRef, #' RAIDS:::validateComputeKNNRefSynthetic(gdsProfile=gdsProfile, #' listEigenvector=demoPCASyntheticProfiles, #' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), -#' studyIDSyn="MyStudy", spRef=refKnownSuperPop, +#' studyIDSyn="MyStudy", spRef=demoKnownSuperPop1KG, #' fieldPopInfAnc="Superpop", kList=c(10, 11, 12), #' pcaList=c(13, 14, 15)) #' @@ -1563,19 +1563,16 @@ validateComputeKNNRefSynthetic <- function(gdsProfile, listEigenvector, #' ## demo 1KG reference PCA #' data(demoPCASyntheticProfiles) #' +#' ## Load the known ancestry for the demo 1KG reference profiles +#' data(demoKnownSuperPop1KG) +#' #' pcaSynthetic <- demoPCASyntheticProfiles #' pcaSynthetic$sample.id <- pcaSynthetic$sample.id[1] #' -#' ## Path to the demo GDS file is located in this package -#' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") -#' -#' ## The known ancestry for the 1KG reference profiles -#' refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) -#' #' ## The function returns 0L when all parameters are valid #' RAIDS:::validateComputeKNNRefSample(listEigenvector=pcaSynthetic, #' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), -#' spRef=refKnownSuperPop, fieldPopInfAnc="Superpop", +#' spRef=demoKnownSuperPop1KG, fieldPopInfAnc="Superpop", #' kList=c(10, 11, 12), pcaList=c(13, 14, 15)) #' #' @@ -1688,8 +1685,8 @@ validateComputeKNNRefSample <- function(listEigenvector, listCatPop, spRef, #' ## Required library #' library(SNPRelate) #' -#' ## Path to the demo Profile GDS file is located in this package -#' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") +#' ## Load the known ancestry for the demo 1KG reference profiles +#' data(demoKnownSuperPop1KG) #' #' # The name of the synthetic study #' studyID <- "MYDATA.Synthetic" @@ -1702,8 +1699,8 @@ validateComputeKNNRefSample <- function(listEigenvector, listCatPop, spRef, #' "NA12751", "NA19107", "NA18548", "NA19075", "NA19475", "NA19712", #' "NA19731", "NA20528", "NA20908") #' -#' ## The known ancestry for the 1KG reference profiles -#' refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) +#' ## Path to the demo Profile GDS file is located in this package +#' dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") #' #' ## Open the Profile GDS file #' gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) @@ -1711,7 +1708,7 @@ validateComputeKNNRefSample <- function(listEigenvector, listCatPop, spRef, #' ## Compute PCA for the 1KG reference profiles excluding #' ## the profiles used to generate the synthetic profiles #' results <- RAIDS:::computePCARefRMMulti(gdsProfile=gdsProfile, -#' refProfileIDs=names(refKnownSuperPop), listRM=samplesRM, np=1L, +#' refProfileIDs=names(demoKnownSuperPop1KG), listRM=samplesRM, np=1L, #' algorithm="exact", eigenCount=32L, missingRate=0.025, verbose=FALSE) #' #' ## The PCA on the pruned SNVs data set for selected profiles diff --git a/R/synthetic.R b/R/synthetic.R index 5828118b2..5ab17de9b 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -181,7 +181,8 @@ splitSelectByPop <- function(dataRef) { #' "Sample.Type" entries are always set to 'Synthetic'. #' #' The synthetic profiles are assigned unique names by combining: -#' \code{prefix}.\code{data.id.profile}.\code{listSampleRef}.\code{simulation number(1 to nbSim)} +#' \code{prefix}.\code{data.id.profile}.\code{listSampleRef}.\code{simulation +#' number(1 to nbSim)} #' #' @param fileProfileGDS a \code{character} string representing the file name #' of the Profile GDS file containing the information about the reference diff --git a/data/demoKnownSuperPop1KG.RData b/data/demoKnownSuperPop1KG.RData new file mode 100644 index 0000000000000000000000000000000000000000..4facb3ee55138c965c73e8b993e16d6ab68f46c9 GIT binary patch literal 588 zcmV-S0<-=7H+ooF0004LBHlIv03iV!0000G&sfah5JUnFT>vQ&2UKVgRpfklJ zX=^v9WE6OKWtF?;T$ z+&WL_ceYPxvmOM}W6p-)8MuXr6_%%ha6@RQDrA%V08(I=VrE9xcB{`W-3eP%q7H(> z#PSh1kF=-aL-S1k-}ZZ_ppIL(HF+ufT~N*ym-HNN%CJxNe{T0001&za4G> a0j31SAOHY5*iL{xFb#_W000000a;qi4i1_C literal 0 HcmV?d00001 diff --git a/inst/extdata/demoKNNSynthetic/knownSuperPop1KG.RDS b/inst/extdata/demoKNNSynthetic/knownSuperPop1KG.RDS deleted file mode 100644 index a58a3563829ffd81c90ae18abf82823e34f856b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 600 zcmV-e0;l~SiwFP!000002HlmtZWTccg_n>BL6sLl8rw7WxV!~{28x78v=o%k@H#vz zViF;(zm#kwqBK`??m7PV%zk;ZZQIN3{A~SRtmAfZ`}yka+_tmJ1%7Sk+v_{QyW8vk ze>~kBJf1#YA3Q#Z91eH#cn&vvLH~Gsgic;vKZE1(PCkVk9$_DjZ}s6m9N)=jvei%E zjXJPV_g}N^#oxa!etiA@?dLjNZue!pH{M8c2GhxYrV7A}bZI6)8(lLvvJuY$W3L4wy)C z3`fqQfE~~&QNrNlFZfHh_tp~(touy8~8mRM1_O;)HNOB6|b_~S^f93v`Bfp~VZ4Yo6stdkw<`1=pUq8-2(5C8zTR3jb$ diff --git a/man/computeAllelicImbDNAChr.Rd b/man/computeAllelicImbDNAChr.Rd index 84f498650..1e327550d 100644 --- a/man/computeAllelicImbDNAChr.Rd +++ b/man/computeAllelicImbDNAChr.Rd @@ -93,8 +93,8 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && lap=rep(-1, 8), LOH=rep(0, 8), imbAR=rep(-1, 8), stringAsFactor=FALSE) - ## The function returns a data frame containing the information about the - ## LOH regions in the specified chromosome + ## The function returns a data frame containing the information about + ## the LOH regions in the specified chromosome result <- RAIDS:::computeAllelicImbDNAChr(snpPos=snpInfo, chr=1, wAR=10, cutOffEmptyBox=-3) head(result) diff --git a/man/computeAncestryFromSyntheticFile.Rd b/man/computeAncestryFromSyntheticFile.Rd index fd68cca55..9c4f6f507 100644 --- a/man/computeAncestryFromSyntheticFile.Rd +++ b/man/computeAncestryFromSyntheticFile.Rd @@ -233,6 +233,9 @@ ancestry is inferred for the specific profile. ## Required library library(gdsfmt) +## Load the known ancestry for the demo 1KG reference profiles +data(demoKnownSuperPop1KG) + ## The Reference GDS file path1KG <- system.file("extdata/example/gdsRef", package="RAIDS") @@ -248,10 +251,6 @@ listFiles <- file.path(file.path(dataDirRes) , listFilesName) # The name of the synthetic study studyID <- "MYDATA.Synthetic" -## The known ancestry for the 1KG reference profiles -dataDir1KG <- system.file("extdata/demoKNNSynthetic", package="RAIDS") -refKnownSuperPop <- readRDS(file.path(dataDir1KG, "knownSuperPop1KG.RDS")) - ## Path to the demo Profile GDS file is located in this package dataDir <- system.file("extdata/demoAncestryCall", package="RAIDS") @@ -265,7 +264,7 @@ resCall <- computeAncestryFromSyntheticFile(gdsReference=gdsRef, gdsProfile=gdsProfile, listFiles=listFiles, currentProfile=c("ex1"), - spRef=refKnownSuperPop, + spRef=demoKnownSuperPop1KG, studyIDSyn=studyID, np=1L) ## The ancestry called with the optimal D and K values diff --git a/man/computeKNNRefSample.Rd b/man/computeKNNRefSample.Rd index 2443289d6..18b6af45c 100644 --- a/man/computeKNNRefSample.Rd +++ b/man/computeKNNRefSample.Rd @@ -78,8 +78,8 @@ one specific profile. The function uses the 'knn' package. ## demo 1KG reference PCA data(demoPCASyntheticProfiles) -## Path to the demo files located in this package -dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") +## Load the known ancestry for the demo 1KG reference profiles +data(demoKnownSuperPop1KG) ## The PCA with 1 profile projected on the 1KG reference PCA ## Only one profile is retained @@ -87,13 +87,10 @@ pca <- demoPCASyntheticProfiles pca$sample.id <- pca$sample.id[1] pca$eigenvector <- pca$eigenvector[1, , drop=FALSE] -## The known ancestry for the 1KG reference profiles -refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) - ## Projects profile on 1KG PCA results <- computeKNNRefSample(listEigenvector=pca, listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), - spRef=refKnownSuperPop, fieldPopInfAnc="SuperPop", + spRef=demoKnownSuperPop1KG, fieldPopInfAnc="SuperPop", kList=seq(10, 15, 1), pcaList=seq(10, 15, 1)) ## The assigned ancestry to the profile for different values of K and D diff --git a/man/computeKNNRefSynthetic.Rd b/man/computeKNNRefSynthetic.Rd index 25fcea91c..5386fbc23 100644 --- a/man/computeKNNRefSynthetic.Rd +++ b/man/computeKNNRefSynthetic.Rd @@ -97,12 +97,12 @@ library(gdsfmt) ## demo 1KG reference PCA data(demoPCASyntheticProfiles) +## Load the known ancestry for the demo 1KG reference profiles +data(demoKnownSuperPop1KG) + ## Path to the demo Profile GDS file is located in this package dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") -## The known ancestry for the 1KG reference profiles -refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) - ## Open the Profile GDS file gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) @@ -113,7 +113,7 @@ studyID <- "MYDATA.Synthetic" results <- computeKNNRefSynthetic(gdsProfile=gdsProfile, listEigenvector=demoPCASyntheticProfiles, listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), studyIDSyn=studyID, - spRef=refKnownSuperPop) + spRef=demoKnownSuperPop1KG) ## The inferred ancestry for the synthetic profiles for differents values ## of D and K diff --git a/man/computeLOHBlocksDNAChr.Rd b/man/computeLOHBlocksDNAChr.Rd index 7ddfddf28..113a64dd5 100644 --- a/man/computeLOHBlocksDNAChr.Rd +++ b/man/computeLOHBlocksDNAChr.Rd @@ -103,7 +103,8 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && ## Chromosome length information ## chr23 is chrX, chr24 is chrY and chrM is 25 - chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + chrInfo <- + GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] ## Data frame with SNV information for the specified chromosome (chr 1) snpInfo <- data.frame(cnt.tot=c(41, 17, 27, 15, 11, 37, 16, 32), @@ -116,12 +117,13 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && TRUE, TRUE, TRUE), pruned=c(TRUE, TRUE, FALSE, TRUE, FALSE, rep(TRUE, 3)), snp.index=c(160, 162, 204, 256, 259, 288, 366, 465), - keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, TRUE, rep(FALSE, 2)), + keep=rep(TRUE, 8), hetero=c(rep(FALSE, 4), TRUE, + TRUE, rep(FALSE, 2)), homo=c(rep(TRUE, 4), FALSE, FALSE, TRUE, TRUE), stringAsFactor=FALSE) - ## The function returns a data frame containing the information about the - ## LOH regions in the specified chromosome + ## The function returns a data frame containing the information about + ## the LOH regions in the specified chromosome result <- RAIDS:::computeLOHBlocksDNAChr(gdsReference=gds1KG, chrInfo=chrInfo, snpPos=snpInfo, chr=1L, genoN=0.0001) head(result) diff --git a/man/computePCARefRMMulti.Rd b/man/computePCARefRMMulti.Rd index 26244faab..8b77f3bc7 100644 --- a/man/computePCARefRMMulti.Rd +++ b/man/computePCARefRMMulti.Rd @@ -70,8 +70,8 @@ for a list of pruned SNVs present in a Profile GDS file. The ## Required library library(SNPRelate) -## Path to the demo Profile GDS file is located in this package -dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") +## Load the known ancestry for the demo 1KG reference profiles +data(demoKnownSuperPop1KG) # The name of the synthetic study studyID <- "MYDATA.Synthetic" @@ -84,8 +84,8 @@ samplesRM <- c("HG00246", "HG00325", "HG00611", "HG01173", "HG02165", "NA12751", "NA19107", "NA18548", "NA19075", "NA19475", "NA19712", "NA19731", "NA20528", "NA20908") -## The known ancestry for the 1KG reference profiles -refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) +## Path to the demo Profile GDS file is located in this package +dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") ## Open the Profile GDS file gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) @@ -93,7 +93,7 @@ gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) ## Compute PCA for the 1KG reference profiles excluding ## the profiles used to generate the synthetic profiles results <- RAIDS:::computePCARefRMMulti(gdsProfile=gdsProfile, - refProfileIDs=names(refKnownSuperPop), listRM=samplesRM, np=1L, + refProfileIDs=names(demoKnownSuperPop1KG), listRM=samplesRM, np=1L, algorithm="exact", eigenCount=32L, missingRate=0.025, verbose=FALSE) ## The PCA on the pruned SNVs data set for selected profiles diff --git a/man/computePoolSyntheticAncestryGr.Rd b/man/computePoolSyntheticAncestryGr.Rd index 7d67dfd2b..117b47a98 100644 --- a/man/computePoolSyntheticAncestryGr.Rd +++ b/man/computePoolSyntheticAncestryGr.Rd @@ -118,8 +118,9 @@ analysis using a range of K and D values is done. ## Required library library(gdsfmt) -## Path to the demo Profile GDS file is located in this package -dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") +## Load the known ancestry for the demo 1KG reference profiles +data(demoKnownSuperPop1KG) + # The name of the synthetic study studyID <- "MYDATA.Synthetic" @@ -133,8 +134,8 @@ names(samplesRM) <- c("GBR", "FIN", "CHS","PUR", "CDX", "CLM", "IBS", "PEL", "PJL", "KHV", "ACB", "GWD", "ESN", "BEB", "MSL", "STU", "ITU", "CEU", "YRI", "CHB", "JPT", "LWK", "ASW", "MXL", "TSI", "GIH") -## The known ancestry for the 1KG reference profiles -refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) +## Path to the demo Profile GDS file is located in this package +dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") ## Open the Profile GDS file gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) @@ -142,7 +143,8 @@ gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) ## Run a PCA analysis and a K-nearest neighbors analysis on a small set ## of synthetic data results <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, - sampleRM=samplesRM, studyIDSyn=studyID, np=1L, spRef=refKnownSuperPop, + sampleRM=samplesRM, studyIDSyn=studyID, np=1L, + spRef=demoKnownSuperPop1KG, kList=seq(10,15,1), pcaList=seq(10,15,1), eigenCount=15L) ## The ancestry inference for the synthetic data using diff --git a/man/demoKnownSuperPop1KG.Rd b/man/demoKnownSuperPop1KG.Rd new file mode 100644 index 000000000..0c74347ef --- /dev/null +++ b/man/demoKnownSuperPop1KG.Rd @@ -0,0 +1,70 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RAIDS.R +\docType{data} +\name{demoKnownSuperPop1KG} +\alias{demoKnownSuperPop1KG} +\title{The known super population ancestry of the demo 1KG reference profiles.} +\format{ +The \code{vector} containing the know super population ancestry +for the demo 1KG reference profiles. +} +\usage{ +data(demoKnownSuperPop1KG) +} +\value{ +The \code{vector} containing the know super population ancestry +for the demo 1KG reference profiles. +} +\description{ +The object is a \code{vector}. +} +\details{ +This object can be +used to test the \code{\link{computeKNNRefSynthetic}} and +\code{\link{computePoolSyntheticAncestryGr}} functions. +} +\examples{ + +## Required library +library(gdsfmt) + +## Load the demo PCA on the synthetic profiles projected on the +## demo 1KG reference PCA +data(demoPCASyntheticProfiles) + +## Load the known ancestry for the demo 1KG reference profiles +data(demoKnownSuperPop1KG) + +## Path to the demo Profile GDS file is located in this package +dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") + +## Open the Profile GDS file +gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) + +# The name of the synthetic study +studyID <- "MYDATA.Synthetic" + +## Projects synthetic profiles on 1KG PCA +results <- computeKNNRefSynthetic(gdsProfile=gdsProfile, + listEigenvector=demoPCASyntheticProfiles, + listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), studyIDSyn=studyID, + spRef=demoKnownSuperPop1KG) + +## The inferred ancestry for the synthetic profiles for differents values +## of D and K +head(results$matKNN) + +## Close Profile GDS file (important) +closefn.gds(gdsProfile) + +} +\seealso{ +\itemize{ +\item \code{\link{computeKNNRefSynthetic}} {for running a k-nearest +neighbors analysis on a subset of the synthetic data set.} +\item \code{\link{computePoolSyntheticAncestryGr}} { for running a +PCA analysis using 1 synthetic profile from each sub-continental +population.} +} +} +\keyword{datasets} diff --git a/man/demoPCASyntheticProfiles.Rd b/man/demoPCASyntheticProfiles.Rd index bfa9ba105..e6c11633c 100644 --- a/man/demoPCASyntheticProfiles.Rd +++ b/man/demoPCASyntheticProfiles.Rd @@ -52,12 +52,12 @@ library(gdsfmt) ## demo 1KG reference PCA data(demoPCASyntheticProfiles) +## Load the known ancestry for the demo 1KG reference profiles +data(demoKnownSuperPop1KG) + ## Path to the demo Profile GDS file is located in this package dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") -## The known ancestry for the 1KG reference profiles -refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) - ## Open the Profile GDS file gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) @@ -68,7 +68,7 @@ studyID <- "MYDATA.Synthetic" results <- computeKNNRefSynthetic(gdsProfile=gdsProfile, listEigenvector=demoPCASyntheticProfiles, listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), studyIDSyn=studyID, - spRef=refKnownSuperPop) + spRef=demoKnownSuperPop1KG) ## The inferred ancestry for the synthetic profiles for differents values ## of D and K diff --git a/man/prepSynthetic.Rd b/man/prepSynthetic.Rd index 6a78b519e..6d2df3d98 100644 --- a/man/prepSynthetic.Rd +++ b/man/prepSynthetic.Rd @@ -63,7 +63,8 @@ the Profile GDS file "study.annot" node. Both the "Source" and the "Sample.Type" entries are always set to 'Synthetic'. The synthetic profiles are assigned unique names by combining: -\code{prefix}.\code{data.id.profile}.\code{listSampleRef}.\code{simulation number(1 to nbSim)} +\code{prefix}.\code{data.id.profile}.\code{listSampleRef}.\code{simulation +number(1 to nbSim)} } \examples{ diff --git a/man/validateComputeKNNRefSample.Rd b/man/validateComputeKNNRefSample.Rd index d4c916b18..a710e9aa4 100644 --- a/man/validateComputeKNNRefSample.Rd +++ b/man/validateComputeKNNRefSample.Rd @@ -55,19 +55,16 @@ When a parameter is not as expected, an error message is generated. ## demo 1KG reference PCA data(demoPCASyntheticProfiles) +## Load the known ancestry for the demo 1KG reference profiles +data(demoKnownSuperPop1KG) + pcaSynthetic <- demoPCASyntheticProfiles pcaSynthetic$sample.id <- pcaSynthetic$sample.id[1] -## Path to the demo GDS file is located in this package -dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") - -## The known ancestry for the 1KG reference profiles -refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) - ## The function returns 0L when all parameters are valid RAIDS:::validateComputeKNNRefSample(listEigenvector=pcaSynthetic, listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), - spRef=refKnownSuperPop, fieldPopInfAnc="Superpop", + spRef=demoKnownSuperPop1KG, fieldPopInfAnc="Superpop", kList=c(10, 11, 12), pcaList=c(13, 14, 15)) diff --git a/man/validateComputeKNNRefSynthetic.Rd b/man/validateComputeKNNRefSynthetic.Rd index d836369d6..958db651f 100644 --- a/man/validateComputeKNNRefSynthetic.Rd +++ b/man/validateComputeKNNRefSynthetic.Rd @@ -64,13 +64,13 @@ When a parameter is not as expected, an error message is generated. ## demo 1KG reference PCA data(demoPCASyntheticProfiles) +## Load the known ancestry for the demo 1KG reference profiles +data(demoKnownSuperPop1KG) + ## Path to the demo GDS file is located in this package dataDir <- system.file("extdata/demoKNNSynthetic", package="RAIDS") fileProfileGDS <- file.path(dataDir, "ex1.gds") -## The known ancestry for the 1KG reference profiles -refKnownSuperPop <- readRDS(file.path(dataDir, "knownSuperPop1KG.RDS")) - ## Open GDS files gdsProfile <- openfn.gds(fileProfileGDS) @@ -78,7 +78,7 @@ gdsProfile <- openfn.gds(fileProfileGDS) RAIDS:::validateComputeKNNRefSynthetic(gdsProfile=gdsProfile, listEigenvector=demoPCASyntheticProfiles, listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), - studyIDSyn="MyStudy", spRef=refKnownSuperPop, + studyIDSyn="MyStudy", spRef=demoKnownSuperPop1KG, fieldPopInfAnc="Superpop", kList=c(10, 11, 12), pcaList=c(13, 14, 15)) diff --git a/tests/testthat/test-tools.R b/tests/testthat/test-tools.R index 353275d9c..9745a652a 100644 --- a/tests/testthat/test-tools.R +++ b/tests/testthat/test-tools.R @@ -4,8 +4,6 @@ library(RAIDS) library(withr) library(testthat) - - ############################################################################# ### Tests snvListVCF() results ############################################################################# From 6fc47f6346a81827c6555e4163b9c5a7997e8d3b Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 27 Sep 2023 18:45:14 -0400 Subject: [PATCH 240/385] Correct indents --- R/gdsWrapper_internal.R | 4 ++-- R/processStudy.R | 6 +++--- R/processStudy_internal.R | 15 +++++++-------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index f7c8932af..02bd8231e 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -1179,11 +1179,11 @@ getBlockIDs <- function(gdsRefAnnot, snpIndex, blockTypeID) { if(length(pos) != 1) { stop("The following block type is not found in the ", - "GDS Annotation file: \'", blockTypeID, "\'") + "GDS Annotation file: \'", blockTypeID, "\'") } b <- read.gdsn(index.gdsn(gdsRefAnnot, "block"), start=c(1, pos), - count = c(-1, 1))[snpIndex] + count = c(-1, 1))[snpIndex] return(b) } diff --git a/R/processStudy.R b/R/processStudy.R index e96794739..f58080ee4 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -559,12 +559,12 @@ add1KG2SampleGDS <- function(gdsReference, fileProfileGDS, currentProfile, i <- x[2] j <- x[1] - g <- read.gdsn(index.gdsn(gdsReference, "genotype"), start=c(1,i), - count = c(-1,1))[listSNP] + g <- read.gdsn(index.gdsn(gdsReference, "genotype"), + start=c(1,i), count = c(-1,1))[listSNP] if(! ("genotype" %in% ls.gdsn(gdsSample))){ var.geno <- add.gdsn(gdsSample, "genotype", - valdim=c(length(listSNP), 1), g, storage="bit2") + valdim=c(length(listSNP), 1), g, storage="bit2") }else { if(is.null(var.geno)) { diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 817cbe2ff..722124cd6 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2146,7 +2146,7 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS, np=np) fileGDSProfile <- file.path(pathProfileGDS, - paste0(currentProfile, ".gds")) + paste0(currentProfile, ".gds")) add1KG2SampleGDS(gdsReference=gdsReference, fileProfileGDS=fileGDSProfile, currentProfile=currentProfile, studyID=studyDF$study.id) @@ -2190,15 +2190,14 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, gdsProfile, studyDFSyn, spRef, pathOutProfile, currentProfile) { synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, - sampleRM=sampleRM[x,], - studyIDSyn=studyDFSyn$study.id, - np=np, spRef=spRef, - eigenCount=15L, - verbose=verbose) + sampleRM=sampleRM[x,], + studyIDSyn=studyDFSyn$study.id, + np=np, spRef=spRef, eigenCount=15L, + verbose=verbose) ## Results are saved saveRDS(synthKNN$matKNN, file.path(pathOutProfile, - paste0("KNN.synt.", currentProfile, ".", x, ".rds"))) + paste0("KNN.synt.", currentProfile, ".", x, ".rds"))) return(NULL) }, sampleRM=sampleRM, gdsProfile=gdsProfile, studyDFSyn=studyDFSyn, spRef=spRef, pathOutProfile=pathOutProfile, @@ -2217,7 +2216,7 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, studyIDSyn=studyDFSyn$study.id, np=np) saveRDS(resCall, file.path(pathOut, - paste0(currentProfile, ".infoCall", ".rds"))) + paste0(currentProfile, ".infoCall", ".rds"))) write.csv(x=resCall$Ancestry, file=file.path(pathOut, paste0(currentProfile, ".Ancestry",".csv")), quote=FALSE, From 877bd57b66abab7df43476f968604d608fb95ecc Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 27 Sep 2023 18:55:20 -0400 Subject: [PATCH 241/385] Correct indents in processStudy_internal.R file --- R/processStudy_internal.R | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 722124cd6..599bf6860 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2449,16 +2449,14 @@ runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, study.desc=paste0(studyDF$study.id, " synthetic data"), study.platform=studyDF$study.platform, stringsAsFactors=FALSE) - apply(pedStudy[,"Name.ID", drop=FALSE],1,FUN=function(x,gdsReference, gdsRefAnnot, studyDF,pathProfileGDS, pathOut, chrInfo, syntheticRefDF, studyDFSyn, listProfileRef, studyType, verbose) { runProfileAncestry(gdsReference, gdsRefAnnot, studyDF, - currentProfile=x, pathProfileGDS, pathOut, chrInfo, - syntheticRefDF, studyDFSyn, listProfileRef, - studyType, np=np, blockTypeID=blockTypeID, - verbose) + currentProfile=x, pathProfileGDS, pathOut, chrInfo, + syntheticRefDF, studyDFSyn, listProfileRef, + studyType, np=np, blockTypeID=blockTypeID, verbose=verbose) return(NULL) }, gdsReference=gdsReference, gdsRefAnnot=gdsRefAnnot, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathOut=pathOut, From 9e3fa5dc34439a169e2718535b593238da54a959 Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 27 Sep 2023 19:22:53 -0400 Subject: [PATCH 242/385] Add function readSNVVCF --- DESCRIPTION | 4 +- NAMESPACE | 6 ++ R/allelicFraction_internal.R | 2 +- R/tools_internal.R | 115 ++++++++++++++++++++++ inst/extdata/example/snpPileup/ex1.vcf.gz | Bin 0 -> 104850 bytes man/readSNVVCF.Rd | 58 +++++++++++ 6 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 inst/extdata/example/snpPileup/ex1.vcf.gz create mode 100644 man/readSNVVCF.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 78258c84d..281c6e859 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -36,7 +36,9 @@ Imports: S4Vectors, pROC, IRanges, AnnotationFilter, - rlang + rlang, + VariantAnnotation, + MatrixGenerics, Suggests: testthat, knitr, rmarkdown, diff --git a/NAMESPACE b/NAMESPACE index 2acbf2897..9f4e6315c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -34,7 +34,11 @@ importFrom(BSgenome,strand) importFrom(GENESIS,pcairPartition) importFrom(GenomicRanges,GRanges) importFrom(GenomicRanges,reduce) +importFrom(GenomicRanges,seqnames) +importFrom(GenomicRanges,start) +importFrom(GenomicRanges,width) importFrom(IRanges,IRanges) +importFrom(MatrixGenerics,rowRanges) importFrom(S4Vectors,Rle) importFrom(S4Vectors,aggregate) importFrom(S4Vectors,isSingleNumber) @@ -45,6 +49,8 @@ importFrom(SNPRelate,snpgdsOpen) importFrom(SNPRelate,snpgdsPCA) importFrom(SNPRelate,snpgdsPCASNPLoading) importFrom(SNPRelate,snpgdsPCASampLoading) +importFrom(VariantAnnotation,geno) +importFrom(VariantAnnotation,readVcf) importFrom(class,knn) importFrom(ensembldb,exonsBy) importFrom(ensembldb,genes) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 0ca3a01aa..d607cba8f 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -450,7 +450,7 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, }, homoBlock=homoBlock, blcSNV=blcSNV, listAF=listAF, snpPos=snpPos) - homoBlock = do.call(rbind,homoBlock) + homoBlock <- do.call(rbind,homoBlock) return(homoBlock) } diff --git a/R/tools_internal.R b/R/tools_internal.R index be13e4be6..78bc5d7cd 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -320,3 +320,118 @@ readSNVFileGeneric <- function(fileName, offset = 0L) { return(matSample) } + +#' @title Read a VCF file with the genotypes use for the ancestry call +#' +#' @description The function reads VCF file and +#' returns a data frame +#' containing the information about the read counts for the SNVs present in +#' the file. +#' +#' @param fileName a \code{character} string representing the name, including +#' the path, of a VCF file containing the SNV read counts. +#' The VCF must contain those genotype fields: GT, AD, DP. +#' +#' @param offset a \code{integer} representing the offset to be added to the +#' position of the SNVs. The value of offset +#' is added to the position present in the file. Default: \code{0L}. +#' +#' @return a \code{data.frame} containing at least: +#' \itemize{ +#' \item{Chromosome}{ a \code{numeric} representing the name of +#' the chromosome} +#' \item{Position}{ a \code{numeric} representing the position on the +#' chromosome} +#' \item{Ref}{ a \code{character} string representing the reference nucleotide} +#' \item{Alt}{ a \code{character} string representing the alternative +#' nucleotide} +#' \item{File1R} { a \code{numeric} representing the count for +#' the reference nucleotide} +#' \item{File1A} { a \code{numeric} representing the count for the +#' alternative nucleotide} +#' \item{count} { a \code{numeric} representing the total count} +#' } +#' +#' @examples +#' +#' +#' ## Directory where demo SNP-pileup file +#' dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") +#' +#' ## The SNP-pileup file +#' snpPileupFile <- file.path(dataDir, "ex1.vcf.gz") +#' +#' info <- RAIDS:::readSNVVCF(fileName=snpPileupFile) +#' head(info) +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom VariantAnnotation readVcf geno +#' @importFrom MatrixGenerics rowRanges +#' @importFrom GenomicRanges seqnames start width +#' @encoding UTF-8 +#' @keywords internal +readSNVVCF <- function(fileName, genome = "hg38", + profileName = NULL, offset = 0L) { + + vcf <- readVcf(fileName, genome) + + gtCur <- geno(vcf) + genoPos <- 1 + if(! is.null(profileName)){ + listVcfSample <- colnames(gtCur$GT) + genoPos <- which(listVcfSample == profileName) + } + + colChr <- as.character(seqnames(vcf)) + + infoPos <- rowRanges(vcf) + start <- start(infoPos) + widthRef <- width(infoPos$REF) + refCur <- as.character(infoPos$REF) + listKeep <- seq_len(length(refCur)) + listKeep <- listKeep[which(widthRef == 1)] + + countV <- as.integer(gtCur$DP) + countA <- gtCur$AD + + # Ok + + idVCF <- row.names(gtCur$GT) + tmp <- matrix(unlist(strsplit(idVCF, ":")),nrow=2)[2,] + alleleChar <- matrix(unlist(strsplit(tmp, "_")),nrow=2)[2,] + rm(tmp) + + + + matCur <- lapply(listKeep, FUN=function(x, countA, alleleChar){ + + listAlt <- strsplit(alleleChar[x], "\\/")[[1]] + + keep <- ifelse(listAlt[2] %in% c("A", "C", "G", "T"),TRUE,FALSE) + + res <- data.frame( Alt = as.character(listAlt[2]), + File1R = countA[[x]][1], + File1A = countA[[x]][2], + keep = keep) + + return(res) + }, + countA=countA, + alleleChar=alleleChar) + + matCur <- do.call(rbind, matCur) + listTmp <- which(matCur$keep) + listKeep <- listKeep[listTmp] + matSample <- data.frame(Chromosome = as.integer(gsub("chr", "", + colChr))[listKeep], + Position = start[listKeep] + offset, + Ref = refCur[listKeep], + Alt = matCur$Alt[listTmp], + File1R = matCur$File1R[listTmp], + File1A = matCur$File1A[listTmp], + count = gtCur$DP[,1], + stringsAsFactors = FALSE + ) + + return(matSample) +} diff --git a/inst/extdata/example/snpPileup/ex1.vcf.gz b/inst/extdata/example/snpPileup/ex1.vcf.gz new file mode 100644 index 0000000000000000000000000000000000000000..55101e0916c186b799d67802350dfba1eb61024f GIT binary patch literal 104850 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

S=Di?2WY!mGc)P4c zq39f5Lae(%I+tN98d`^RuD-9rkOn7I-glc9&Npxi8d4j4&M7tsYg()sJ~#5FXjz^o zEdVmeVm-{!Igc0QSUE#A?tv?)xEjB2xVzT_^l;?O6L0N{5Nf*P9`ZxgK|X{bULstZ zC)O)7lTT_#=-<%&nVqv-)9pax&MmjC+SsztnJfP5Z89Zu#ckca^tevvJSNo{BqeiO z|KM}ne=LNneN^uzwayFwP6I32_})HXSMWVqj;(mLm%;kb{ zErVbYZtLD=u;7?02~J+iy5LcAsHPe6R+vkvp&wZH=Q5YadU_Xc_j1E0ftqjozFC&F zwkbTe4eSSBS-42(SJ&e=ox^Sbrtg!s1$bq7+}5j;^-Ak{2~_c>E{lL?JDM{3Wlisy ze1PO*+w)j5gE3^0%fc1(=Nc4=A|3|3xYi)gOV`{%ana+v!ci+vxonaX(N(UYsUZe==o8dtKhb`SV~ROa^9E!dFd9_;CYsF zl(|OOJJ8_a6AK;<6-!uxIYI@}aIOT$%0mRb@6hF=jraWY_y~?%#LM9{InllfYq@z# zdoW=&gY?w0K{{65)}ZoGi+A04&L&%_Q5v7f?R>L1Z~P8L>>;lN#|GvLNWn`Zg>lk%j0HDXa@qnP*eF+A=U;zGe#IEkO{y%@fh7l*fNRn7 zi4i7ODLtG9HXO1qZt&??3k`3LQ7-Tq*tkw*^^GVQiW6&~plMZ51IyTACY**O$dH8P zX~nf#ctV*gvs%Osez2}PfyqJjt(SW$vZ5Y6HkSi*q0 zK5w<(MvUQc#qRA`tscw`P3@dm!RGBs7SF^gh6$D0XThSQ02Q{nP!P<&H8lnn@cuFF zWFFYn?AV-V&@sBg>9^xiaUc#XWIQ@7-zMooU*NPqgdLXnr(lwifmb&g)+A%7i)oe0 z7l!@XELf)558j-)Gq8kp?q?m~xh6}_sGnMva>*4-{Vdy*u?Ec|HLFsv+Ps6ypEM(H zU?D<*u;#m9j5k1Zm^!6u3WAl47l0_5w_ssje*2;?<-`)y=@>Rn6t5F>vjDYw9*a(n zMR#M>VXlg*DO9=X&*iUIM(@BHwlJ{_Ns1BMrW+Pl%x-i{TbHt7-uTNLI1qJBfw2@k z`f(I{aAMfC#`KaYdi35Y*|Y;o1@36ljPi*!to>8^-4Co_1lDkN3x*B3ENfD3S;SRh zm;m12m~CMYc!EVRb9FmVFv8CI+9gW^yP{k-rW9>&4=TC7xk5}< z^DqspHYhSar38(q)#YgoTYtCx+uCIsyH?xvCw;f&Tiezh?f5g@eXwE;Z!NUEvY^>35tJAWKT-_^$n7kvW%xOO+& z#bHxRtvTN00$wzuHUFDjbhua5O*c5~YM@J$!9_^r)2%__QpC$Vb-~xUnm}dO9Vx=` zn#L4h)gT;P{&g13^!bzc{AuCx)?GrW@|s-PE(uX3#NZNm9CQUhvNL=@i&yuJ3n%66 zPwsS6*sMEfA7dUKAk>t_{E9E5~l< z$V2vtmUek@7$(xarg8&ss$10D^1PA>v$gd2Qor#xV3w6>y-3bAIJdOyg~{cNcSfq} z-{7!&hGqX%&!!B>vr}{LdD(Maxdz=3w5*586$krPyUl)b)q~qrkNgZS!A*8r7YyOp zRtu;Y>-sbsq5U$;=YBuk!8sifD@PcQ(W>bOSI4Eef1fR}wZ0o%BZBwTRq@U>kHKX9 z+zdo+57b(oM}F_^sfH3dM-9(SB|CF+wR+GeRNtC#DMT#()a46vZFjkw#&d>iU%8+L zm(c{%^^hQUt>bMMdQ5F_nBQ;YJjxf-ynBg|eZAGMrJbUy7@tw&YQp81QD4&Kb?Axt zm~f(WTbW#T5J|O-ORfRBG8x}!u!Ez)?g$h^ zj!?g9ns@15gFbl6dnR}3$uBH$xw=adOut_G34}`#yYK0VO`RJxmM^Zr8eAP+H{Q;l zkHwY?LD--$)wJXs(#|D#!T4T$`^3v@EZWTI&mS;pdyM>FG zgJV%F84D2v|H)vAPlHLgk!JkQUpr*htJ^QGVcR*wK4LDX2m(%b`~|tSjb4^NOfF-) zI@7$%twI{vA2i*wS_S?qad15SUL1m8w6^< zd=;DU8x~OP*Pp)ZBRIIc)xj7J?#^N2tC72!`Mk(7931w*_a{$_7f;J)p-1vAc+6_l zHEH28&R;ssdy;ui;pS4pexrs+k#OyOyn1q5I}3ed5x-`{0&~m!F_(XR$?nPHC0t9t zwk#(nk(AGYAEkdr!|Stji#y6CQ58LNx@9R`i{NpNr+FWq<8X6qAVQ*C-Je&})g6N^ z%Er&)V=eMe)#U|B!brB^q!TVX%(6Eu1QyM)VqvI_88=pripTCB zmI;-R8ipPW3q4b#?f$M)wTYK%lg~-lIn<~u-^Ye@+~!YreF~TG0^svC-w(?qW|?@H zKhyKVY@GjcW98`FmL+@ISR?|K?s3U}E4+hsHs?X^6}{IPb5|chb7S(0!&}4+8nJKz z*QX(b5LvA)goT=x@njC~-7{Diu}CLKJZN;6M&!-s2wZh~&CuWySeAMYedo5&yTMXt z&Tj>t7KKeXEJ!eDww-I}LOE#C^wgvWhXqHr=h1dAq#i03E+)v)HH2=3%h(X)#L>=` zEw#$BUP9UApdn<~xeOsSiySP{2@e|5hm(8>B40ipFX8gmC|u1rV~*t@o`06}wqI+H zp)tcbR-^$w6l~~;S)Ci6mUpgX;c|lVFC$k7JwgUKDBNa<=$;+sTEkoXEQSHE7FWSD zXOd?rZv_}&_)NJ}L@t$ui(A3EMZTn#Beux1%tLC$qx{rE0m3yxPm5(dbIa(FHOax^ zQh}5%y~Jd274$R9IW39Vn9*(URCli8Eq(`sH-o`jq!k=C7&7RQ!fh>6E%JrAgnEc& zy_8fN-il~&tT5LIiomTLUZQ8w&kCDI70w6kg0RU^MDA3%mL=6RyOk^0+3t95&fW-K zEV%2>^&l;heERiN^h^t(C6BG=EL;^|^4EI>vCbUXcexG1g^UfjEgP%G7|>EzS^y4? z|3ZW5B;bMwxJ97yGRN4eN#VZkQ~nJuV(&@If!L-4VeRE%@R%^SwdAu1)aob`RwEb` zJ?2UQgXtsy@{B!_XT_o=sbQ$DEfPWcYj~*TKL5~Dk_fk5ai<4`JJ()bbUnCO8!SAF zWUfw{2R^^g;u;jLVls}N6eV2S+65Rka+U0umsd?pZgXK8l9c4aof_~;j8jtEu=MVQ zM~$}YVhtK2bJ5dp%%6l1(UW8l#KLV!W=5{Y=eSrbD3<#TWB8_Z9VuX8rDtFx#<^H39bWT28&A#Zr|L?EAzPY$^v2$_aT9E5`-&_a_7y5gK z={=isRsa3Jr{}fxd96RM-CPqNg4cilFMZcxG3Us~TYr9Tw@)A>?U@lpEU?N^## zyybL#@V~!*$ge--uNP1Ln``<@_`&A|l=M}C%hy8q_ltqLxG})rAMESO)y~y#F2vl@ zb3(p%ke9>2R&xIG(g%|n;3Hig7R0E95DgaPW8JE30pU2Ffam8Qr_x(Is z*O~NnCg1B!x0O^J7iK(b(*JY9xtfe~n5!V{bUtafL z?)xv-57%Pxu>YuWX+_-gJ>xnqv5!mqj7xJ-@cRh)V%(4u|Fq7AAa*8*-Nfli`>j0d zoKMQl&+}3;tm}0iq|bwdi3_2?dZE5gQtpc8!!i54Nfrl&0wD)|Yju%J#Ph_3oKQ}X zT&XY*>pJs&o%!!|Cf@si^LJMG%0(wXkk`ujYg{J1BJ1;{KTkf-lk7rxzNf5mNxEE; zGIK*8y^>3!8n?kZOY1sIeVwK6btbv!#Q#=rj{VSVKYXv3;8flE=l7-c`%?eDR3=U? z{V=VUvVLFb-&elBPlZHFU|5Frd7(cqln)nNEYI(Y>-@z&e=$#-qz3bMHb{*NK0M_F zvp$uprNF)=_Ct&@U2<@KPeR`+R|Mq}p*IbS?)|!sI`fMjBjliRQU&%cq5oo16FS24 z{BB))Ti1T(8rp-*xTNYD?00JZQuQ@_y|(LY)@%KGZJ#OE=Y84_gkyJc$^T&gB^56M z@@&;d()E#i%a@pQj_BACc9wDN_YT_iyl&5bJ7~sL0S7y*>ofHA8Pd$5dFa_&#R-)S(X%zK_}Ox%rqt&NFf;x4QTN%=%PoFu}MmewA`z$lcF6+v%fV`Y5!C z%MRojC6~&#et#1nNfsgTU=LFB*PJTd=ku8POJ2oidF~@-9+DJ~{yX(NX+jYvt0OP{wY2{J_{T|o#8TfcKDZ{>S^s?$-fILb@AN5xVJ=ob_F=;BaM6YE8-td_ve+UaQlJ*~>UCYV1) z4i;%OL!5{jml%W8=eWdm-eaHl=qD~?pcwpzE+p z!@4e|)C_(jGw)RuHTr){JjA$GVO&19xaq3UwJZ#3L zuj}Aut~S^YXMLN+Cocuo=Q*ByaRK!^$4RVDc}>`@7l(ewW?XK2&`n%!1;+C%ca1C8 zJWO$-oqwC2{;hJ^JB;_7<#m=6yn}cFVP9X|Wq;1|cb0>yZL2QrueW}Hac$`7H~aSD z3dqm6%E8#>U@RZ5Ndf#Wqn@hA6(|=r3jIDBGX`8#)v{$Eu7LV;u0pVp+{3!u6C|YoQ^Meq-lN6 z)Za5r?^*Ja0Xh5Ya9)=%>)&;3T4EJqVo6wIEO$vRQcT8ec!J zyxbzHI@!f+#9}t`*&!vg2)1rqcUJ5>D^6VW9-nt8qA^Y_`BKo9KS;R2)c`)#DYkTT z4SeF0t=qZieEs^JPc>qg*Vzeh6g{-Fd;-6>gpb7;h# zlAVLAg2AobgnFA$e-D&*rR7r53kf?g7#L=-Rtz_tm%;$cbCVEr>dowK1p`M1JNW{e zZ!N$#5@J9>aXx?n0Z$x*6K!z5pXi-a69Qf}t*?4(5&*&3imQoqtJwMkF$#3n%@-IV zD9e*KaDzP$@*r^HPWS%ncR?5`Zv2J6JG6bGCOc zuq~;ZLrAED#kB+$FC(lJOm0z>XL+n(t+BwXruB)bKQXl#?B#p^Y+DW0W#v)fGmpWC zwg}`yeq(^qWgOMBb#;MWFjGOu)eCIsNbFKu(NbHJlv6MW)OMV5=N%O91SL7MI}{8V zOx<1C@Q~zr0<#O~oKb^g^+%9*CrpP9qPx3WXkH<*Hd3ahq?$JWJTlNrpIjq@AX;fL_>lk|u=ln7RDUD4Xf`T#5LthB0+)W;{y z;}cr$Z~MkxRPcsJ{K{-+(qk)x`qL^kf7lBlz8l5 zbGcv!gBsQ5ssm7VsWP!t*(4#O`h)1HpJLz_s9MM2a-}q#l{tI=992q~C((t2gLC$I z6$~N;d@aVFH}GC^bONMM}Wn8H}SC|N9&B zMgsJC%E7wH0T1WLq~ww$W{qg zFf4Eg?0$n4G#&fI9vXc8jZKYY&>g$A>T#`>C`llFb}Em#!HjwDeLm}x2fM+3fM*6* z2~fHOC}jq#$0*dg$YXzEbQ4&_V+jc(4rj4fJSHl3*@S%E?4rd`T(fAH8Zy5p$Y(9h}?;Cx;nK4wJ8p^fJ(c zYe?w?1+)Ksz3SdkGjQ=@H$LS!i5P0ksw>CeX?8Mo1ummSc{R3lv9_YE^V9nLw9ouh zJ2nC-8A>WuJI8^!KgJ(6u)&U{RIh>};16?P&ix?VoZj3-#D=-=X0YJI=5<1+yTC_Ob*Lxqd z#hN3YWn>JMb{#8)QKi07Et~?{rL0dZ{fT9Mq9wDR-$)rMtu*Ifo?Gak{;9C!m`J2J z=et^(1nujV3FDVyikOHe)}ZCz)C7HgbXYfN=o>WD35<7);FSd`PTxQOJ{Ybi%fMdx{i2k#}pRhbN&*l{ffPh_IK3i^O`yo?r7Fh@)>QG=ska;UzTCFfnK zV;*0HiN#WB4dRlN1h_I{KQIc!Jb?6r>J91c5m-!&BsZ{N`6maqrE>uJs?C*i3kThg z?w6m%W8cc~s?>BSh@J^0kiDvarRbb6U=6HG-zI8zNNXM(dB%V>OS|X%W)-kG;51ag z^s2EX!6XW`0Aec<3UW_JsydkRU3d1XT;Ku|=58rrm2w>=N`Jq7VhtF4CwwM5?ot~@ zv^N>1;mC(F|KF5x60bH$#+2jXpy~iswqp$9T)%vQcRlEvs=N+1=nX;COByJPo4|?7 z9DT-9TGTenF`-Ml3vv_)a&!bZsD?C>0Ac$tQ*qpoEZ#qKGvB!)gUiC0N4_?4&>`q0+oZ z0ZpXiM0c_Hm%USNFr*(u%&q5N?+WzV?rGWMX(T2gZ(z?k|Mk*hRxmC#Yeb0Y0?SV< zW;4<;Mo-CAxsLaKJ<25aXIQ%~dH$I{T9-p_L;2Q%lHhvr(?75JdGY!QtZ8J`Ue%(B zSoISG3W#GZ7Z{df3CtQaFoT;w#Wd^){1EN0Dm5>#qE28$yMh(<9ygD%wFuL}q(UUb zmJ`-mF{5hW5-DQbgp`5{*qMcyj$}u8F_cSGAs840Gr)|XH4tk%s3?kpap^Y2xU>ce zE^@|)vaFqhB}a*N>sKULtIe#Ol3l~J!!FSwkmyj*_e9j}Uob%}>+FeV#wlx}WZjPt z)1bDMYG}c7WGcd7AhyG!c1N*(jc^K(yUPm?e zdCYMJV}RDTyJEX>pfW$e1REJr(fu2X39C;kT3Q=tVBX3cOXW1|#z4r`;4JqIyJJ_m zF=84rgP}pdXXh8@yFWscWSx3~wWW!ZqiDa>&sERwPJHwQE_E)%>9%m41cr}hZ0HMY z;9)Wfvx8`S6Xw2w-7}eE6NJ@nV2loy5^;hrc-LG&w~a9O4V2~7>86xpIQ-=SW~@#p z0^|n92+irKm1Bp-ux^tH0UDTmgavRuk!zr2Oz@xD4&7i$&|ZU)&0rt|*YYx!8?G2V7^ckmAq9)8*sGZ+`7qEo$kH(mzk$o~ z5lYiu4duX~VUE};I1L&Ua zbnqt;IRit$E@9MK)g`{9+X=rt_##n2>~TgxRfP%VFHG3kz?RXXCF($fsXc7DPCl_N z`Q4r9@QdhBumQNw<_zPzSZ@{ys)C{#!;g1w4%2o_0cr5f_kyU`t6q>TEu!lDdCb zryF*KG{FjKLY=`SpTL|RFiMsB5B86>PEoAirl|saU$hcqS4?Eca!(-~}d(k1;m%1!7YYMtvEGJ>RJP zs9;Z0)AXmfA@Cj!4%u7zerEM2cOlx3Xw$pqSc(C3m=%=o?(tD*42KAwHUDx z(msFGk3nZMj&wQr1lcwg z6f9WdRzzzhLV`E!(yhVLtzmwmT0YQhgee2Ozy^WtxZ5t#w#&57RMl1t1Yo{ z>r~Y7QtqJlm;;>(TIBipjZ}!imJU9V3Rl_+SavqE0Q3N-Kv=&|X+L^Z)j|$qxx1AU zZRNxn%u=vNHg_(j;+L>9k*GH?;4K%_JQ^4=a<|cYaVV4d ztX9plB2-n9N7Kz$m4~X8Mk&=~(K0rQ1MA|`G8qg78{W=I z#j90YHUWQ+vM-Z!ZgdHL)8+XB`=}mtLO`9MV8NS6nDSZ$rDE+4wd#|UjCX@j9;Sjt zz=@(vVFfEz3sEs93lvpMVlxstHD9s!3}q%N*zkf0DvV;iXVOpH@9bPCSi8e~WA^U8 zoA90J$lj-fCuf*%R4`+#kSW1YFf7?NDh;GyTh2f-YgOOVd%Pff9T7J0GT2=ESB#(gNERJ=lm`^M;`q6DB8d34Llp+rZq zzHxBql>_aBIA%l`DQ9E4oKm0`xq|5jJv%NiL&$>it<;yR0n>hrJ706|`H8nRcLtW9 zm}Cb2q-5M~P>D;w!Ck&kEMGWP78_Ww(K69y)xheYsE@gf;sUW^fJ)xfU6IPJL$kLI z&3=BO&)7kak~!ATCP6(7mA^M|If}!KYAgQk68H&5GBJJyTf!?o4mTqX&^od`pGbvx z4NQ1KpIHD33bu))tVaXULT13|oSip$uRG$E<-yV)!qtr-xZcv}rS34$*K>*8Vp-|# z_kM97h_z~<;EiF7r=y@XnD}}f>@x7arTdj!y};!X18Q)B%b00qR6tCz_WpQt@R?|s zU|_=j6)adHe&b1%`!5MD`bAcq#OmN0=1op<`Oe9bNt-Gt>`pPho->!=A#h5 zxFk#aN9H}18-bjUt9rP4d2kUA8rD@1-xrGd50@iexn0*yQTwK-apth21IHD?l})V| zt7z&*(d7DV94a?FDi z|6SV40!V*UeS>(1pp0xT;B_{;qg!Fz8mF@O^QYVv*Y!hD@Pf@_46Jii-d^C+xt{!g zqZcktt!+3ra&!$lSC%gNr{rem8p?%Z6l-u88$MPH3~te0CzUWb?6u2q<`d!-+s6xL zE>2AeyqIQ{&$aK&%@oJGdpZ}<^R259 zQo9k-uW!CNtTd{-Dx7LnIFHdu4WdG)Yl;U~BF;XcouhhLc;_RtdzGtrJvF!5bk{?6 z?-)$JxU|@<%x<#41?Ec_t*)Fnj0O#`}JD1Q++I3+c^FEJDc6bp0H=cPp zS%3082KTy9v2!J%`@oIo(!z>cpXv6H`6~X-Rn$sH7ockU>uxM|mnQVSmuEsLA0*nPAy|VzeQ5A_-~4W1 zZ{I~-mg?0oEq14Im`B=@nRvZ6Bl*0#AXs;G3Mmc_FDa!ox{rc|49ByCoy&rE?JyeF z?)+QsVcr}P9>p3yPOqv)3o6TvFYAXh>%%lU>g6xDTW$<2cl(mKlE?AQg$-A&YIY`gIMX9@%958du1UtMu=)ngyGWB;$t1rOnsZP%dOK3#(bC#aCA zZC86Qwl{58I#;lJ4ik+sO7NE+8lE2E~>27LbtPMNv&~>2hJ07Qj@@=_XoUzE2t2m+5xX7}zk7o-8 zhm~2>LKl$$HP+mCir}SIyZ7|#dj^cZ91jTH944zyrH7rX8BY07o~?0s+taJk;|&h;TF1Mv zF3$JTv^S@UJJ%9C)8y}Xhem-R~JV-~z~WvPVRM2HGRh>Tmtg|I`6TZ%++y;##8 z>!sxWO!e7@TjKmf*ja}W;Hiv`$n(`noAb*fgCc2Q~TW(Avc{ zx5PLJ&68D*ps&tYV#Y<7hhy2$&Alx*x;Sx|sZHy=r@lc_oH=YN$XLY6Nxiga~ameiwncfnaAK|22!}ftpf^HRpj0w(^Vy3}X5ZCG}PmBkJ#fBZ(}WD$&~is8Xwyq&54QZ6;HBg?vA zOBVnoPh7^+6ifiN))8o&1u-GOt*0XPdODu{?OejR8C(_dkrw=&a(bvx=L!QlAC}W0fk`u!4oL z)|-0M$WiOsE*Ahj#>Cx>3oxF$czJ+$dGpC(hG|!qH!9EC#4Ts;7`dceT*i|y^qSoY zf`%6nCsHm&INxzRayvMbyG%Spxq@xV_U&4_L6d{3Ssf9PmRz0Onx=L;TAGZ--_$-u z0kB)>0T;TjULYXKxZO>?#E2Jf5dm1;{!5>H#=ua{W8j@h=$p8~QZ2@kHV#{&GX|S- zp<#G{Q25G4k8VEUb}N^b?&RANogQCm(fg7|Gvzo1s+z=#ceU>#)d?ci%`Qa4nxs=N zo{LKkYiKBqtQ_`wJvRHjxwjpZJLf$tbn$?I2v@mesU{`D5ZzYS-2ThszmHs1@~0 z!qdW`)|qC(l`CP%ES}@n7gyePl;~VT%ZQqH zHE2ek!8eA2aW&$-Nasod;~E}&Clvn0;i-2*o+;Oy!!rkGOY`Cc=kJ^c3JL|3pM+jf zE-yFW5+@LiYXQgQTwigL|I%sZV!-WP{?L!zR?xFUF4?KxC_aYO&TF}UqOu3K) zS*{3UZn8`tyblinn`ytYKx6{V`y!9!6aqdNWFH}<89@MgQBiXgUdG;2;Z2Bn^y9Xrd9p|BG8L3!~Pxa&NEc>0HLF zHlyN=8)vQF&R@pcEA|)nT`{#ZS+5t0c^JYARIW4(->zFJ^{teqtyC&%Pa=wD*Of-R zOop+}mCFsiRc7kNB@`7ze&gaWEK20*jmrtVeiU;0Xy*a2@Pe?GjYBJx zu_nFM^>o1utZ^sXiW44myrD~BImz*#v$wam6;&KnsBE}RkE?@x+vmcbh zYB|OVH4dZSl<8xcCcF-3&4YToX4w7NN_wpACIYAC$Y)Bzivf1IUT?YHj|VBf+?P>) zx>THVy~@?Fc1zvJ`&;0DB)*~%yY07ixwZRJNoV)*Ro#KM-2AULy?gC--;>q8J7L&O zl5QppT!y+EqOj1oCJ^-}(py2KhekYc1x%?5#BGoPB&+H3VxAZ~Y zEIL23h6YSQW(SjLzX{x^w>=;~H8AjMZe_dhiqpGY5D-RY{O3}(laXpKZZ)|=hak(Yihn{_?vQ~Y;G?j*<5{k`Wb`#`Q|nmzKZv0;<@fjId~wljTkaBDi<;{=xOK30{t%gv^$| zvI+H1S=VUkYqU&jw3G;Ymk~48k7vnk5`jVEu$qzC^J>F4_rBlQ#bNCdW6efC0?97} zyUN{tOFrUv<%%B$OsLbJ_N&Z4v^20M%C$QO14V5TAJTHe7ZJHrt}geGZ2V(C9Ay9T zkPVGc@#{A?6#8+eua9{~6BK*<&ARnt;rjGIE2co`r#6gE`%M_uk2tLV1Y)mlMHmIz zB+q=fL!8qv#pwA)a*K4 z1;_pvFI%~i&@3dPm)2e=VmFgb&BeHUG|e2|YID5hdvFbE*2?;QrGH&H6e;{b zBie;T;rCTuV;-z+2wpiojZ?7y66S^Qx|Lh1zS_EeT3^(>-XKASJTW1bf+NB({?UB*8$_nDz_Z3;pU;m23J!t5m@E=y#VR$`R~vqjB1!&EjAtTwKJNAZJZ#r8V|@1OdI`zrbm&1&0j1;L9C z+pZL?St;80B^eio9X^-7XICHpn5-{|Nn5*QEnJ@Yrx9BJAxM_)8mRRJI&f8zh@y}_8B^8ZsWALJBHud{2%=v9={b}9NM~Z z+TDTDCCS03Qd=ycsNXsLP{>e>L!8JoF5-+b8ZoC9Bc6{S;(E$e?9;Q!f8=}B###7> zsdU9|w#KU{n1c^$@dyTZNn=;h7{SrqrN8@@|75%Ef@%yWG1WQBErp6qI4P^BaF`8d zM4G1;(PZ*T0pxF8rgI^Jl0aVAiHU_~``kBECd1FW;6R%4UrcrwpZZn5?l z8CR@JHr}~Pcs0dIS!5MqMU}g&#Xq-c9y0Ff6c;;W6QBE*IfGK}oYl+`1+m5MTgLUt zJkQH=FKFMl{~u3oxBdYC001A02m}BC000301^_}s0sw6%rJcKy?zVD;gSY z|8zf{_su0K=ikqo|Kq>^=YPHbh~h(Y@#E*m?~gz9@6V4v|Mj0feEk0F^Vj@CKKyW> z_CFUFB^mci$-#xXaG@Sts27*?9qwE#3m415#d2{i9?$#Z&>8eH_pCw>iSNefxh0hTmzMdE!()B1_2e_{#~R|Q@*;Pd>aPd~hZ zKa(%hKk^yQ7sxIKS-!cgpWONvw~4D6=5)JePwws7>s*rn@3{`J?*r`T?`zE;&-?Xa z4P}>NtM2}u{=U|K{`=>rv+>n&b{Ci2u}6MiTzuFgtqYTQ|K~H#KNMoU|4><9y!00@ z(~GAV%6*`8g&`;L;3Q654gwz>9(HLM+ccC3txfKaZ0nr1KBw)P)0CZL9OH+{alSv& zO<$RHNdx*cuio{6cJ20`PT4%yIUI8~$%}U1170_i`_Y=tb!#^chPth5vh_9D(!`Y% zVJ-W0k=V;0-#ss{EXm)$yRJiB`%u?;sH-%1)%A(3Kd^m0PuG$@@h+eIx|)1nP5x^& zrKZaeo>%?)o_%7gpShBO!|(H-ss4z~!rC1eln0E!57{G;!@XtLFDycU|q9u72&gT%u|XumK3Ut=u9W^12XmUkKSv zT&^I0x4Oo`<&4jJkfY~HcQaQ(roh7Md(uafzh4V4OBR6*64r$m`oar-;<~(_zi%Cv z*x&OK)B3a)LDyi;mn=29F5drmHGj%w7?^kR*%IoUiuNUR2ukZB(<1*;N zVI7yy$0dY|i|)`zrv2d8ee3(a^>T4J`0{@KjLYSI%s!lYf@Qp#f9Qft6wFY@0Ovj6DI=i8P|;z`$md!<|=q4 z;yRwOpZL+w99k{RdTDBUc$8G@^Zc+`{LCdB7h=7%r0Ok7VrD#(Dkkl|ADDfloE#_3 zJP+%BkA1(#JaH}H2}O7WTK1|!-8pKVWv`FCzbB&!wH#tYO`Wg|l*lIr)FMT!ocaQmIq;CqRKTe-M+=$Lg-n#_?TY9fNkjlxTco8m?rpvs7 zD@4})agOJ;KU9H2uNrl(=`tIZ^VfKm^*u{}&k`ptMmR4R{jk+khYRnOXQ0*WL%grE zw91>*5++U+MAV=5>qWU3eSrP9m*2(} z@vrAyx#AD+?qv56^2|6v?=InhS57SvH0<_vh;bS9r?zsfb8Y4%hr9e-Jdge}`5!6i z!KPZ8+UPFV8e$IZaz)w?brkLbuVVP#QWz+=y;}LoK)2B&p zC4f>;*UeTtSlz_Qi1&Rhj=CNq=jIMyT<{eSpR`U^>XVhO$(kOi*P8j9EKGLBS7cQCp1>5&8=s7M7R51$x+Ut=WzHi^B2`> z1R+Z(IpqkKzK<^%7d#k8PeR?HP**O4d$O$DdAQD8u3)SX;Rxl_HbUiy`abhB!r{6P zV;I+!&38_l;&RZD0VQV@y|Ihlc!^$J)e$)Akj!eGV0>_IOdni)AOAc!oCjHzBk9VK z)Qc16z)3{OCFSIOn9aC4jOHH9ru({6`uC+ga|OnQ2=5#mI-!XuiE=R|4{~?!^gg%@=L5Aq zC1!k2Svl#P%v?#Z&Ytzbt^@1gm9Iauf+$hY>Zc|~^$Qd@X?^k37kcs&Ckd@TVgacx z9Z;YW-ok@xc+e1vka97X`$Av@s&d)GdzMw;lrC_J+&GwrXF=R2G?$Pkd8~M;=nUV7 zm5q~x>-ND(I362X@|RtfF7Jc=Pz~Li`!%m={h`zaQM$O`okMRGvEdF5)*rLMjT2B< zsCf-)#o@f}y;TPnK%l^S=!#sixc0Ojf{y|R5M#Lc5PQ___dA16xq$1BkpsqMP^_N3 z)#Zn`6_j+jP5)hPQv0FB9l^M1f^!KqG?F`$Z!bYaxOa>T@WDiKaS0*E0+towRxdif z1>JgSU3jT4yc8#{V)%#%lPDKsgGAJA()GdRfG0e20vd;w6{BexhZ+;3*(nztTGZ?F za(`Z)pV!^avw$W9K(IVE5IBs-=WwK8*l>Mb?a!-m<}k60(ae<#4fYY^X$VnD!>}l| zUPOYs?>{1ZTY|WNmItHp8h3o(oCrmnkjljZMGuVI*-8mAhJ6T2+_(a6bw)voUNvR3 zJcxrdJ|yZf2cmLyq(Qv0#FcAU)WNu`^;q)`!gkHf+II;Yagoi@>ps~CwPjB(|fgG`7gXL|r= zd-OF3h-^kzS1#d^#5li=LuVhim1>T#K8ajX% zb{poUDq>s!p9Et|#?Zo254q2nnN)Jf2;&PzQt<=sSz_t7s`K+9PYRs5Y#$nKplIy9(2-}OO zKUSfh7X6P2`YBf$o_9|skvEg*%HWAP2dp7`%A^{qc%8VO9PrZRVq8L(3nQ+|$o!d2 zDdwD1E@5p5vp%i32j253NbDgElw$#7V)7J?7Yu)ay@Y>GTwojuw=j z^l3>IGkuvLYE;>qmrTZoi5OvGA7?Z)5KV1W9a~o&TbQ`iz#G-pA#Hh_9JfLp`D|tS zp^SBGPj#JrPqsX91ru*%T|+XmQ`^j8q6krNYbzlH&>D zStw3|$9gm(Ze-k{TFqw-bGE4om?1z)sa7IVu>PO1J=7#iC>x&+@ALGYj&D_ZQUdX@ z?;&AaNubs1ik#Wp5ZO1%#ezHj;d#R#pP!c_7$nrVG}mHR z^#9IB+!YNmMdR`jC*4!%@MBWTliAjg4a&@WQmYZ|S|+)`IP5y{WT;gz)RaqwNG-=K zMCBGo46|>QD*>MO%sf=S0hQy=#6I%fg~*j@J=vZ+0?>P|4J?JmVHV0DSS#f zJDqAFs`QZ7{|}i`&a!vj!-{9zRLYeGZd%4P%9dM&;SM4!lYL%t{TVkv_TnNq|DL^% zcl|M2xaxg-r(*dNC_xxK{@{88gO^-%SUbVwd>hxmo6AT@r!BdKGqU5OO4hA?^Ns+sx$TD%+fs=t+X;Jk@$em$C ze~u+NoOj|#%u##>39}r+Jz!-?22cqGajbrr+-t zQ0?tCrvWBvVvP&feT?z`g%exfxeLGL%dRf`avMc2ZCTTK}4a*n7 zipgg$WA9RV|95gb>JMds7htl7a`7&pPlw2g%T^Qrjch@+n_7l?KWe9`cJ8pr4^0&aY%(9t zbmJM7iggfAa_7`SFF~Vd!|(&6W}9Ch7XXt7aQNAAfS8F));k0wIiX!Cw|Fg?&Kf1f z;=qGME%20LhVLuu_m%#AW%|DC6Z9fwPJZ*|HOwOf@^Z-8XCrrUtt`sc7L(YFz%ZqV8Ee&J(cXD{BO1AWNrshSJ&ZUDJ^WLSliq-(L zeynpBnDvZft;i_7n%x0}W2Q*R9`+RzcrFqXcCuv5>>|<%lqxU|KozOo(KSDhXl|ff zUP@F5jkAc(1A45f?`sLefkbC3o%WotImN982$~6b);Zx90&SbjalB@ox8;E|20@@EXbUP6d07*>*EIvj7P_AMP>_dyl zGlFwHFFTjPwei$~Z`6AFiK|N@H9qf99Kz8oJ4{dXxeP@1<%gmqz0LtAu}%(ars3 zBu2SbF`FRk0mzNa1Z=n>ItuEZ%USnxH&s>T%*faNPdXu|&>K3~Hk&o*<#FtjRkHP6f z=JSTsl8Xw?MuAS{B>%Yx*cSz_tSS04*gEjq9CJH$Z8irMFd5wk|1K zoIvj|iO@(8^?-)!N-Qj*j9RUFfI4SZM%OAaJeUF>qPEg%^92l z+nn1DwuDOWR#_fkc2Lr>)d>$!w?YFubnDj}V8zV-ZQ*0afjXFxOC>teV5;^KU-mUiM4LS}S3#&Mt7$L0$HE*U&D_ zql4*vVv>PHKY4MT?Jl`Fz+%OdFw8sOO9!*_Q0PM~UIkZg-L5Oe0GG0HO6(O?ipPy0 zeA)H@>vHSmQ_mH(OZ~hCi&%7Mzt0lxGd0|5geKwCk}G-?Vp{VyNZUcb7ESM*eFF@r z$50Yl!BpV*qGU;_))?V_d~I!+0WR~nb?|pEI)Tc~trx8%*qn24 zU-&lE)4`m}Hw5wlVn*6FrE!3Q(Lw4}y)Oy#C#Y9dP?o+wgjpb7|HYagY90+79d2H! zlM<|B7pg17T2(Oho(6AvD0DFU+eRM;sA~uBUfJHJJixPCCZ7X!f_RN5BgqX+BY4gy&zxY!ZAHzaU0?;_$*l`) zfCb}|TVLb=1x?tkQ*nS56Ye;djsOL7!}}QtJx6Va zbgE>(-h*#%!21G;9=pSYwN}{EoEVL<5ypr#uwgF+YQZKu($U;`or2qcsh!suztap- zbp67fx6;<`9cUP^*hO|an4P@s^x}KGKj(q){9D({vtvWdIpSLZ( zLUJyGcWqmaGQfbH7q^|049scdSkGqWuGQ86Gu~gYO(H+Q96csOY_qcmm_xoVCB}QB zplUT(yFyrt2Ii%dojKI9nVI<;$7r_p=y(?_BYBTHn{T*RI|#XG)IQ4=HUdxMHqw8B z1-_9w4Xuj0fkE_qx-75S94aSFNXNi{v7l`|;{jIh1-l=8$M<~v686O9R)n6P83M1{ zq^be-tmgSX*} zHhw<9vq|wakBl2Y!Gu}DjDKB9$;;hh)XFiiz#Sjkyw(%M+tZkkn}IF%o&Eo)r?g*^ z77CgZOf=rWh830IZygt#SQE(0->P7A8FVVfrD&k{c$eia)ntIFLB292c@->p8{$(3 zu~F`N`^Jj5+HC8GPY?rOl;l;g1&9|j;iv;drwO$NrKvKGVGJV1bAW@&LnzT$btO>FWNAS>y zqk>C!dFmS#6wDx?K(!l|{F?G0+JoI$H7RYD29JHkDZQkXdR~%q9VUzc*i^;E5h^3?y%T4c|1WZUuUW<2YYsiyxhgFTPPjBRO^zS`fRj=)HbkybDcUw6pV6A6Ue(lUyh@c&kE>mzSfHCDqwpzMTml;%T$4i%Rg**0l8e$Wf|v(~@U>Kz zYI0aGLU`p5FoIIc_%si&y=^kq!PY&DZxXf#*uLY3s4hFdcu~J&bm%XIB{s~>k5%$x z(k`_@#n!~f&PG?k>nw`tW-vJf$tPyK5q6uXZlG83wK#H_`SEH2VB#P3syd`S7yqA) z`-U>eZUV(C@felHz`Sg1!iieF>i_6pVnRCx_D;gHXOhrNYOwo`G1Z$eR_rF4lA-k! zC7^>U{21Y-rZHIKRV-Oy&XSNzz?^aFNH9?FEMb<5wgP3_d65O#T2lc87qCb&* zqIEOdZjOghEfQW|$oB<8x+dfLtQLh_9Ff%EsO*Titw=DHz2tZpoT`=-jw-bu)c{M- zAd6A>YjmYx8UwXfqgSmE#p+Wi&s$00B;^#W9+SWhDcCQO2Jv=nYC58C zamkD4Mzwt_UVVVeWn_$ajKN3u9pyd-v)t~IoKk$FHA+Rxo!K2RsBZVRPvZev>OV?3 z4s5Pq5-hcHVvE@Ggfa`&qRk28p^TJ^Sz^N$dDJ&%Dedhwk_Tvs*UKFn%X!LY4 zTBm{u%aAGM!S1|xeIr~4bIm=5!8c{@U~wn`m;yory+Hd~@>NyH!P&utTMX>R_RGjn z2hrQ|=mtK(JcAW4n`WQbmg*8p=2Qs<(|L%joCCy?4Q_W-={ms6d|d+zrcX1O-UiB2 z+|Mllk>##&ZaSpl`AEKMO#!Zwr7Rr<8>ad*MRf``mq7_+;yDMnbmw6~tjlG=rJ$Ed z!l`;#^=S0(m&*JBq9mu(m1boEAjyf$76r#$fN#AmNv#g-22c4&6l`_x>R8XmBa0Dj zE9zA(3l{qxF_Jum)|R*rV_c``9Nv~iZL6eq4wmy%UKs`Ja_u}L9+MSmLw9$|Nur=f zzd2>;C>R4cqq$cts&?Sj^UNYQaETZ)`!N+c3q@ZA#SU=vWqt`-QaCOHw*z zuox(4=};TlioNh!aOTi4utAKH(#exmfPMilG-N-6 zwSaM*SJ3}R)@P;FIX+|!ZyhWiN(dBPIu7I&wX+Ni*vX7Bb}Y}wL70*n*rJQoqwUFT z5NlqD5mjpODCn2&lg#lU&Q-i>kvgyxY*=JUZ4hy~=&(+NG3XR*{yR}O@oRSt%K0EZ zG`#YQ(gVduU!em%rCeE$Ry+mD`l_YBYMEbEBtYS3+2N zT`)y73dRsn)nQBz10%S~SukUBR;G^9z~%Bb$`VwtE^!2E9u-`Qp_r4-u39bVCn59) zyUtKBsh(Nn3TB6`N0|CM1A~C=xxLHy1hI!9Qz~d+^pL#vbkSRXqTHTXP&~F3Y#nSj zP_Uo0U4*{Oha0lo-PrE9m{h^-#mgNm#lxy2$EOJ15?$9dQ2QFF(;84)V5u^rR-M`c z9`8*jtdC|X6zJGz#7^^S?kqR16Q{X>%|lW)=xFZ*VsM+?;#f$Iwx zH-dqJS!YasiGhn6Kn;$8=w)TvK^@?7U@`K_BG_2I{q&6H--( z(7=cbK-O24{;G0&)#XxZN&+aDa5@+T(!h-A1YjkNd@n1S3^%YWT~rC}`T+6j6AC<% zys^zD;hZ@@yjy^ABQz_nT#AJVn?>is@<%`JE@(n4YpIT&AuprJ2A&r-UJHPzJ2UXi zkL7P(AK;nZ^X|}5@C@$1>awPw)a9}yY5`QMk%K2v^VqEQ11tc-Og=!o)sTH+Oc)ZP zzEQz~zB0m0KER5eD{9F#S*|jmzR_|T@n&l3iP#QdhEX{ict<-Y$R;y+Au+ZpkTF@hE339RsmekA2k; zFb2UWy7{b7ed#S%P_+Q8xg^}k9ejIr_W*l?qu1Li>cNUqj&PMLXqR`~UzJIjP%t_V zDjDM{KR~RAAipsefr@c%t;V%iAq!R}pJcHDM4#s{n8>VE1(z$yn0%6E2@^|#AN53Q z0SbK*m|TkktdRan`2o}-b4$y9W&tSZmxLms>f-?MVj`wJrhx(L7%1hz0zwUg`}-vq zosDV6pz!{Q2UwR1rTqd>P!+3XRCiaC9AJ<#`dz%ykQGz`P$A=*@Ub6Y$#?@hH8^To z7wmVj7sv;btBLwjR}@Sx;?2oV=VKf_s;)X_`+FUj$1f#x zn-L~#2UEQ7Y;LrYs~8|6th5ed^Frc?R!~}Va7QV(2Caw?@+b+hXJE_$EK%azi?+#n z!1nDLOeOSUx3{CJU}0`>06o;e*i#|q_&GBj3d-VCW~Rd&gB}|(>`UFn;bKB#+h&p@1Ur z_0QZlTGKix@g-t#2G%s%wqIQlRwY6DSuc44o2ziv*L84eADo(QAo>`oR}~*CW&je( z-T^ke!i?}~4Dh`(q=OiqAWT{XV?Gt3H-W7KTpOrTubR?w#UqiWaDX9WWRsEXc7xqF zY~cZ7_7?{hzc}vpxmX=sZbR57xmh4>EPyu`HX3NfJWKn@2j7&t`=$=Co3s;1tsDhw z11U$XoThfdV(&9jPQjSoyO<8JV4RU?NYTLt)A7`Md34mNGkD%=aV0CR8~N-bm1eMI z=qyH^$kwLDp~A$7jux!|6%HNdU^Ni)TPPi%MZ53%KB|;~*-R&_A8#FZ2DZGEyY3?? z2UyU_Oi8(B*GItuc-U4W?qBX82AZET+(vFgynzi=GEQ_vwS3;UAF!)zgJ4q!q7KNw zB1=b|hbNZxiKSxY5hckD6!gD61)8G;nkOBgSw?K~YdppDEvv0%%K?Nv%0)Ds|m4@?Ge$8z&=9>L}l`nnl? z%$wUB8xZa8su*CxI)%kr@t1W1eNA&{ib%1GpXK&LsJv3=fw$JK{aoigUmdI| zVVIK(?_Dq6Ohm(j8$DJTvUbS@+eSy%_e;a5YU`rU8 z*xjSuL2Dy=f1)60_V14Bo|-1@lSB+bi`OU3NBtFZq+9%i-K*(y=v^2 z;l6QH4sfwjxrtSs2-{+Fhpx49c-uJj0CP&{H>M0R1Bd(fvTk-I7z4}^Z+xaiLe3uJ zIFuf)U_f}3^ z0AY}zffdfP z$6md*lKiZT1-tPIuB+bWA#^Zh^y@C?mp^Vdw1+0KW~;R{>+$MkKG5`+B;yVCjJ6(% zHK&4i-(^)Dptw5Je7?Y|gSlW>l9Fc%O2B$MT!h|g3X_eN3iwtfChMJ`hVU$I?3WrG zRI+}w^pBSLqb<+szGW#P9xQ_vT6k>JI0hKd??d@0P0?EJsG#Pj=Eb!^xf-qgO9AVN zav4XJ%a{mDxs0Q^IhJ0x530(kt4zv@H4qJ8c|E1Mj0@GgFM85AyP4b)E6%)^@k>jo z<2KITK`G6F9N$&f4zN~KnB9X|bwjSYYnGyS0V}Mx#We#=*w|rPTr)t4(5a7dc}4FX zg4j+s+;x9QO^sX?xN^^RwT`i&9WY;uI1SM zERG5!K!79epyHh9Grfa)gP!!b$M@k|O33|@3v86zuCptST`QC1N54zrS1$kS|NP(o zN9hO0m|AG@$6r7G^W$Io^RFNO{_p>y_TxYQ{QCRfzyAK;zyAH-Kf?cnU(|kvU-qvV zm?$XVUqAl2fu$_KQZ8UAPhfxJ-(NskfzpBU0cL6$fNdRW>qBkRP;;STz<)l#v<@}( zp{DW#*6WR5-d#RzjRmn53vcMaCz*er)Gs#e1&(qVU4at&P#?f5xX;(!Dt)ucv{!4&kzlAB=}Y&)oaL`#rNAE8 zd?$|&<;Rz%+~j$v8Mf?S|MQn(!cXqfCB@i;SrTRaKl(S*Hm(u_eg$tt1P>9xVaBG0 z*u0UEdC16IXRO2q%F=aUs}$mEGk=}*xXxVc6Bp-sD=H)4z^=g3f#m^|#5hGe89_sw zS87t2B2g+ik^ap*;d-d(c^Lf@u1}5^b~+uq<8hyl`72tg5AeJ|C&dZ!PZYU({y0dP*J?*O&a{wW^u`_C)+}XrvVp{5{w$gH{^3SGA ztouP_F^!*b7DP#P|79WlGp%oko9T*Uy5fw@0fboFX!<_*7ABxR2G%IAf;#sV%J~7T z8BWtW*x1J!=b>^ccqqd9O8v9(ne$6oF3CAbu)2!e+C^@a8CVm+8g1mw5I1!KMsDd_ zz{C=sLrtsUnY!Vb=m9M4`9_zatiW94xqmjohWnA31d9TNJMi^4*7_ZTB&n`WApd3k zM(N)u^Eb+3JJIHdj1w~Nx)L(z&AkcKy@;g$xtcIB>*^EFHjzGwhU@gvKkE=mA3}Ky zfg=c*jm{e?FF)QGsXb*OuLp+vdExoEl!RM}*P(JBDnEvr2^V%`E&t1RIzOL&$gEoXY3v$USG)X!O(&si(n zzj5-%7DYj~OZ5Q~cjspMMp}(x>P9h@8CWBz1>aC93V-WlD=-Dva+{q~mz|@)3if+m zHCXPGljq5at%8^9lO-f-)q*V9=sx|kVT9%xTZhx|F$p~p8wKiqeJ-WTm`YRvS{Zd6 zZ0##j=b;vJE*>7$F4R+p}V?X+&7I4CR`?qEW=iH|Ysga<_T*sdKY~}U@g1(n^ zH%S1BKy|+#s?0-eT}aQWX_~}!*T;TBhKJ=DKi;AJR82WONd+>xT&j8p?Z5Ax28 zt{6#7>PF!T`XoS%JvTCav`^+(g!Wr@L5xMxbIh$1|KtDo@KI@HpKTIQjO z5WzQk!r)1@SN&Fmq^NI_KqPoV{R+&vE3S`AzN(Qs@E&JiLy_Rys|u`O3h!h|U1Uj7 zsRu@ZPjQt>g5jg*1|U74;V1Dgnnglp5?(Ta4vlBPhCt8h$ofx$xCU)JX&SCHO}?~Z zC4y%1<~%d!k_t}I=2#AAlcoSiW~p^aQ*JUTU+--bR$mKZWD`vv!E~Nyxbzgvyo=Uv zy?4?4rBzY^{oss;8}j5dBK>Gl^-5UyUDFWEi;oq0B8W z8RVTcJPg_yC>SPl38HM)CF%uFlqAOxQJ%Q;c8(M=Oy(kd7_eg0-J?))%mT9J|x&uIjGQp^y9*`*L8rVz8qxITnG8awOWR3Lf}E}KOUUuAUC@EGZ# z&p%_-uU6MS6lwR*nRcL0>H)U5q1h}UFdRsizoI}M0g89gH3jB`o7FYVvbuXavnlp1 z@^H~8&32SNNiY-VlY45nF<7TAE|&rmZpyZvi`F+~o6d#Wm>I%yt^iV&5#*h-$y;?_ zR&{S!40r9M?N_LSXKW=j6?UiLJ`VGFP%MTLUtn9sz$fk4P(#ws_L!tJOrv)(k1RPL zbIlckS0JOPccqIAh_0MZ)`;$U(1SaJ{0=coOO14pDs&3B*+SPR)qpXnb+$^Mt@4YHWro#3OO>CJxvp=l{f%{gW62EaXm62)TQRoze@_!liX;qhZ3BRD2>@oP8M&O> z-FZ6;kKI}8NV|Q)q@J9y0Y_f^rS)7wDJUOZ{z)NbB(ZtiMFUpk+j)Fx1$GDZ^$Ap9 zUFc1ogJk4d*aoi1yjlqo86>jrjX7sDsyqSqT;wMAe1M*?vjG|CM6Q650-HdP++~NT z5ZSNlo9+#jQuu+wDR1JNXaQADvD+({t9zYJIX=nSqSyRNA>1 zw~z4{ZR5IV%Z*XY&hzcwX^S|q0Zz9rTs1?QT@CS$UvUAE?&6^kD3BwpOIp_@^>s<}y2Qxep@JB&fRp8l(y39n zaDf&{LS~~~f%{bTaO6fcN{OjFM2ni27~FADJQP?^WyE!wV;3y(@y6C56y*fwdtpBx z?FpPIkQuVTE*njOIYDmJ71=2{a6x;_3G7_0w_)^_qsVu{kqRvJJE;N%R)zuw*Q^?F z32HlIkxfNzLjvE%&82eZeLknHSy2l3t1j2tfXgxUtY%ZMf-otvVFS>h15l<1wsq3h zN9b-86AjHolWJ;eTsH!Ny%qLx5%%g`^pAb)`OOv_RwPX(mSQ<#1=}WRN+WAZQ`*$9 zNGG68sF+5qnCfH9En;PYM*tfz_j0rk=hfruHsiDdiEnXyE}PJzV_9GG`AxGUWQ>Ng zBx*J>r>|H@nXy#RkZ>?UlU0~;AN@oK+_-%AI(^C@49gkP7j0dp)>o;e2T&l<=ZP~J zH@#F~|9EV|6rxbZ5-W$VXuzA%{53zjYOwK*^BYTP5U2IXLu?vRZLoF5g9GTDo)SjmwO0nC*EuXtx1m z*#K731E#7ckzl~ZBk%;&6v!!}%6G{+;TFL`^8}a`n4)|m5M#i)RQ@@NFbvqx`16GD z>=ct=lxm&T*k?7)vzj9k;62p=2F$3M({9Tp+j42%a#;vw)l+bO0g;aGGX^A=0LGJt z4x>P`KR`S>5~@}KLlJ|&uAQSE=ScqiE;=;mFgB~RB~W5Z-^jFE1q>5p+I>5xBtcFd zSpI#eSqD1tfUR_<1n{eUTTX!qOb8EG^#T_BMn|4ifwB<6J)tuLmI9L8r&tXLEP05z z^;wOgvl=HUR|*A~91o$t17UJ}GN+7O|IAr;9ji*YLA1?hJXE#Q(S~$Ma?7V-s?ZTT zP@t5BGUH$iDzNsl$V1s^-#IzYK(!y?SgmRSqKPb)n!>JPy!q)PieaW3j@#-`AkGP5Kxvq^?C+O0aSn|@@c@8rR6am zh-yX}3J_Yl=qOc1$A`aSz=Gz=PRb>ea>TTTRz2sDA~!)5;L(p1rAH56#w!(A1oflK z>{MVABqn*x&I^bez;hlc)_@YgIn``26}^UE0xL&`BI7hg@uw)Fh`4pbo*o0v(mvL4rCCCl9Tu=pO)LSn9oEnGGE$3BF z1O-~>uIEsF7EiO>E)3NZ+clQ$lDFKLN)=5d4ziR9xI{Kn5R~;x+LBE2a=9o^O|4|L zAbZo3IhvtQDh*qRcuZNfog+58a0yTaCL~aM$lnH(#gcLG5)@c&JO7<2tNJ6hw|V9K zgIf{lLBcm7^b1&MVIm(jV+X2^Sh}_CB5zY6S_j4+37;MI6aUA6mG!_t(~={fy#u-1 zz>kWPb5Ylg6=)ymDX|*ZjM3?%xnjU(+;S+2uIrAieaF@^1M^zcb+F|wpp;gjK;qcS zt^;dCxBb}F^ad6PG9O)`0ZawrHr}CTtVlkd${UCcnvOJ)8z>lJ@*HOc3NmSqp6Lx7 z)jhw<8n2O}0W1Y7SC0JeaPmh+a2A%ske>(F{JP~wE=nl|T?hV-K8gi^^VHjoKt!^zsm zlp>H@p}aYhd4!$R^p~P!f7z7lU)- zgwlxg({Muvwqf%o-sKl>pP4`Jl_b6N_MM>;^_7$((qVl-CiDVa>ZY_*P~9B;jtS%5g}H%C z_TUtv>Of*lb?$c}FFVm9c-YOHH(@Fso*rkw;$ht=N*?d!NmVMgL;_oBL%F2ExuiOM zFXbfI`}6Fvbznu7)+u^;0~-d9PW1i(%!FZkA5bcGe4rfHj<-z=U`@bdDy#QX`dCYwfaPW}_}is*pelT9 z@!$fIN_W&jo8w%s>nUg!%#BjOqBKXC(tvfXZ`_!DcVqCwpMfn`I^;>13|m2`{KS?WZD-g z#HBHr<9e!rO<2KtEV}AIOHP3?w(X8Lq$y8Rlvo;G7~>KT)~FZKQ!ZD}T7O|P70X_F$0sb>Xw)~?bDc^g1~4u4fS&MpvyS)isnd^LDQ;kb z$#F%542UAwlXTF-t1=xVDTR#}6^0uX9@v&4#&NuWvIBV`{dwAy4lFNz=7u6b@s2z{ z-kTaE5onjxxwAT-w2omj;l&@0z8?eIMoYVoOgi1{bOBjHMZP0L{sbSOpin1yuJ6yw=E(Z>dmE9L|pZoB~_hGTq} z!(QkdA|8=rbK3z-0?xSaP>R|N5JYz*{4bzjOEE{n{{q%=Eyb%48CgLp+W1GFTnEOb z>e`d1RbcMr>@Sl=3Y0+5kmP;;!SN)*py}_L`axL8us!w%zGN6#9x_>1md9RtXCPo7T_ zE3lzI?l9^VSQgH4+%XfQF%#pYQ7c8fD%hnM_0ZNOe(N!C)H0Wb5de>VQ(#Zx%(Mm1 zHyUs$UUaw-25fkf__1i?1~%;O;P5{bs4IfTwQp95mWz{I>u4R5!4}&A;}(c%Bkxe- zp9x}nAhVh&OD<-U|NHVD>Ws}uPd@fyyn%S3tb?<80hf!|k1fRpum>@Z?p=$jQs? z-Dk4r1&r8@#$^|A3>m|Kuz5yaHCbLY&A{~=9R!LFgfajZFmhout9QY}J2Do^buR`L zR?lGyCfb9_62bHZ6EE!Ap?KGcbfmDSMY1gIV%Tkj3Js}3@$vC3!lfCOHtaXWyAp9 z*XI7o5gpfwPL8MoOGBERBdun@^%BsvXt4gY#7~m>SD77xR12fi<4Jm6g|iV&Y6Oyb ziPs3Gx~7=pM7Flh2R&l`rrpK`w5UHuT0Jo!1t#oq?DAc*x&2NuZ%yRGkL zHRG%ni*SJL;1Wp+jCi}&vG}wD3*nVs`)ey9n5)2AAsFL2*a~bBLj;a*RIMBGB6c0@ zp$nKGrte8UUqEaO;h}aKP%_qEo%&1OK=fI6DcKAuSpyaZ+iNi%$*h^HNrF-TbbB|7 zt*E4*tjFs~m?!d3mo6Y0_unD_>yzw4(jTwg;R}e@>3KqI24p;Vo`BZ{%y_AoL-MkI zV9#m1l)M)(;?<81L+JuyX_tp7sz46dUC$%y+06Qg;>;0bFiLAcOW8H63giG%$t5F% zn`E$CT_;vz41-1aAyI5DY#%2!&p<*8%fnQ^fHO;Jf8eU_BW1 z!~1ULeYY9dFypu5M+}NankW*A%{N>4mBDAg7V*MSM=(u+B}TB@JojP_Y{L7%-e8x@ zTpdlR2UhS-!JkX(@(gSkHS&;kqb!_|LPL}S2;mtyR8a9nnzZ|KPt zUO<$hVE>y@ovc$!_)9nb~9Mo`v3f4jP|e1-V0 zR%UfpQ}!HWZMgQ80`F@)r?jO*gf|viA~7EOLxEhdONA%)qqbxq?5W|=;TQ02AH^Gp zmwUSo-37#AagUp5z=~-(kAb5=MlQ^;G28&ggs03=w9VE@3g77A;u}z~SG7ydUk#zK z=lJPvy#cIp%I9s5r?i0G>W|kn-oWMNp^cGEb_;}M@SfuHv9K-R&Ay&08w1kP@7EKX zQ((q`m&?FXV6Vo1c|c&c59(})m z^Y7o9yj!t%0rNLBzX6lr1s0ABUc4?(gDbZ@%EW+zU3xu^gaHfQHtU;JyVx8Z3D=fW zV1~5V&MwYi7h7&CB;;W`TIeWH64F&YR*3Y*AnDw z>G32x(FPnskFqu3QgH3s^^_@8=!WRYpc(Lv+I^N|oz>cBwaN@k1l6}56Vn(vwIL(K z(TK(vI=xb5jypTb*bUe(Q=W^vH%@dZWvY@!Q)TmKIfu-#?T7jXa;W)ZV)4SPe^qjOs{z7Zm@f0*_(vH@iVnxV1H0q+ zs`@M@HE;G)_pFB%-v9oO*Yd8xHk8Yk6&>g2SEd}vQf zSV`_lvm3C-Po`EpkPy6M>-~N|T&iw7&TKX+Ao907Csu6_#u&fz8)HJfda5I;HI9NK{*Sm@;;n;NhR-kIX)AZN`i8um~0RCB~!10g}f<+rHR?6k<466YwA zx`5v)t}$RCNT_?dix{wCj|iV6uOlPwWq&hzg)Wp%FSV4De-CeBreLFl;* zBLk-IXarTB5e*|(B-R=*V1&x0vBiP|7#H3_0D=-n1eeALZ5wZr+l6qMC z=894Z$C{y`il;M#0#m=a^6x)eR9L;Cz}j!2d)d2Ff$i>g{kyW*y?hq6;jsIqOI?bZ z#tkTY9`dmP<5HpG(RvE(%InYF?D4TtLTQzW;$UCr;)wO6euCF@gK##Y8Vmp!Qz zkx_3m+rVqoRCgDL>o#D0Pq=@^*$mew^=#W)AH`}d3CW@kYKsEfeN*mBv#XU-pgW+; zpDw{#%fe7Sn#_Pguq_=;4iq>dU~hwU23#bi$Cj~MqX}tPo^>ptgba;y_X_FS_~8L8 zc!$iX39I}dRewSt;Et~5g_9uY+MFb6$F&M6xnrp5!WF@y{i95}aO3vCHy4?9+quZ4xCY}qHj}(?l$R!yo_*G+_xpa+ zD7@nu-V1%KNW5@Ns05AjTJ;@Q z*0kb5hAOUx7Wr*W{=i{_c+a`5)&LvQ;jVF#^ia*4p!^NnR^xTr1_Iwqd=OLXh$ck(lHixAs#z3(RXyh#Oi93$Q1=xkoN6i1Tm zdT^_&cykDg< z-Ui^A-)6l~z@Ay;23e@(YThErEH1mXR>cOjNs#D+2n}10A!ce0E3=Ow?~aQY@AMo{ z#U%#s(xZ^Ax_+V8J2sT!YQwf54u__h>3{pj|i40PaXAxNvFdsp%1vE#-`j6OZZ3juUifb`C}a2SafM z?|I!-&y7qTPq;cbh<_}vMTe#(2?f{BAt)6m4BzK*xD{6d_E++av*6_hyE|kCSK@R2 zQVA%}jx79+TN+3mlZG7^D|EG69Cfk?bh_?_S1(j3kDqPw+?!pIi4C1knfifa$jcqe zFAbN80$Nxe0g&zbv>(qb!?rvHOOX}{jEeij#=CIk zK7W2H)WBf`^LPtZ#|h>>k7c(PPCZSm5A`?{rBX&c=K8)G3FPjvJ>i9GAz%i`5g{@h z7ULW*{p+~id+(o@c1R73^2{~P8ZvfLa2c{S2wpGe(nq@Nc%is&oQbgoiOUhG>KVkR zy!Oqfnxu~Y?E&>eO|1YE?bs{l!sW^sf%Z6rjcIB7e`-0_aT)vF?CgSsc0sEV0}sbi zANj!{gdE;yjto~5usfDa02$6&$V4@grr)2;Kz|NK#Lf{^#Zkz3k<%umNn=InE2wEu zLDTt2N*p*e@g1VWaAo<#bIe3>ED>BSN7B-86?-i?f|`np-Q=Ew#G9nTs69zBm1=i1 zN>f$JpDcqus4W*4IHH9e2bUW9_JWEoyesIOZRKF$iTBZa4jdLI{CG3>z%9MZPaNZc z6AbpOw^gf*wO)c>7sJ&`G0XhD9AqIlde+7I3ch9c7|t3JVgagW<43NT6?5n!>*c(* zZ#XdmJC3sBrcq$MbR5|zYrVhqzdL@Sj5oJRn~7zOwFImTePj7{5JGCsz|S8@18 zipxu{cZctwIN=EE=NqRaZ20PYpCAL@5d`lzWc8e5MAjBQHE8#{I}eQK!K(Y-5>_vq z5VCq)^O+@Kt2EcTtHsI?vvJ8&(KliV1Jcmr9nQXs;$mG&$Ii(f#f?6-Z!XZga5u233k)7wU!&*ovCmcSVHRjHQF&vM5Y8}wgF7fF5 z#;bk0v4b+&L5(98Q*LTO#=hpyI<#2PF4@H#$}{F*xRyb$IbsKF%*>k(bfMN-QM|hF7Da6i64&#ABtJp2Uqa=w!cODJ_K0Iue zM#c75I|fF%i`3?ZwEUrDTn{>Ox5>O0GENU!=g6<$Win^n>c1czf-!gMP=Q26a=8(68e1(!Rz)LRDPj<=*2n zM}sNGBIw>b#5X0iOE8Y+F!Lz2pf}&!+5`RHVb)wpMDWMt$Rqgyx0E z9VN+2%UzGTt+OZ;sqJFeheS;zZ$E}SGRo^qsG`MSXoNzxv< zq;BgHcJ$0=4G}N?Jobm|xP>}$yt3!QnPU0zup&Kffl-zTxp*7nucGl+P1M7DdgO$4 z1A5y<{=%t&gJkE^&E_3fu}J7h0r~$c%)p-j{{R3ViwFb&00000{{{d;LjnNqD4l)H z&Lz2x<@)PqNfbm$l*9yPk+3n|_M+aPH@%*%acz zfBzqq3nwA!|NkFff8RKM;=;efPwqILa2x_ZpI6g@tLehkG~;4^;!0g`rCzvFKe#3_ zT<`g>8yDMxi|xY2_Q44i`OfpC8;ds2T-`u(0U zaFqt@x$Z;l`%uG#lLpV@yzXD_`zX~qdX&!2DKB?pje&-pVPhv&M~bv;$T z(9iH!pv3cke%5(`a{&cc)(tIvL(8+@oNUYwp6Bg^xI z)^%fQ-8{0@{jf9oS~vO*;O5we>0Gnx00|w={_(Y(-vmRqnbfw+UB61>7py zxr=tL6Rr`cint!#*pF`f9Nm;v@qFh!GdB=z-+Stj=sNtff9rd;{+?}mPtIs0>$(p$ z-bSQIQ+hN0`)B3(hc2D->!Yjc`U17TK%HNpG}xH5>Z;UrRr=_vR66UKSzTG#MCojz zd~mh1>uG^^AKV3R{=Q0FpSrlN8(RB@)@ehV@<`Be8|z-sx+iH3jIv9|Kc<$!*s`h)C;VpR?! zEhJ?UT;wNz1S97(l>F}nPwT>^eiBlha2XdauM3y^!sThW!!!c80O(nw4#g{Nkbbv>njpM2JnbKn9RezSk2YnE8& z|IGVYVrF2O9=BF;HI(n*Qn=i=Ns)QnTEkJe6w*hLt?p^+Zb}LhE(fr@w5}6%Ij3n| zazuG`DZr8$Ep}etGxzt*(|amGXiqtCx$ULUAip0uUllHQh08qQQUQjrBh3LxbEzaC zFTAcN_x0pyJu4UVO4fC`pBHAFq^G>_%AB|}Czc6UYkPj5tT^d7nQ)B?Fd!Fms)a9o zGr#9%T?(#CEsbGa^7_2opO>fSwaoauRd3vS@uN4Y1Pn*gSz4a@LZ%FHgD7s~*l>59d7LQUiOD)_qTX-_vK`Tc!-(7uV;-{=CT`HxAdn z&*7SNA5!0klqOu)pY!up{Sv#p#E*Vywd?)qdA|3QOh{ZddLpBq5DUCK<&4(%r2d}t zc~9X|fZ1=(`#87Lc~@KwU+=?-!j-`ux$Li0D&_jVPq=g?bkqqQ(S+m6ZvOfM5z`m! zay{`bsf{b>-E}>0!aA*Im4tl8Lp&8%Fp9J}w=#GF&o)W)5c1O|?Km3^ta5ST-+#{} zP8t&&%AK(xG&UlsK%@o8X7|){QcwLuHd9cy5`>-BLrMKm(gP>pg~U~f$8Ox>ZzZ0n zM)Z0-q*!sefzWymm*Tk5Q;0ldL2)I)q4aozhQo+nTHiDE_e}G9)&>z1kCIbd!%*ZV zCS89dmAf6!gDog7A&biEy4>3Mvo0xCYF~eHleg9_wL;RZ@Sm*B!Y&mT69}3o zsbDx{ZJvF|NxdJC&$vD>_UA?V;6#@ctgu7Q6vvn(_3XRhknMTSgW>SNd)QvisU-+g zd6IKEE6ad=@OYs)x0dmFbz@l6SEfnP=PY5o=jVB=oW(9@F-$mG6q>^eHC%%@rxO=3 zcjSD}j42q8Ayb?J&jvSw!OfiX$UkwOWT)W@oCi;COmU1U3YWYv=PPOXQoks!d#^9! z;)*L7lBAv}g5r7{{_S~CTtfTc(J%U%M4*=($z#PW#Ri_7XfEMS0>6s;XEkF4-`7_8 zY+bI~M?O`}FZqzT(Gxiu0gV%`*6--Eq6D-7pYZ5U-G+cEG}n6Oi08p|j#N5xFZ%fG zyCc>ObYBrWdaiLBV<4V8byS$erK?6g;UBJxSNWGWVH5U_FFJUEl}`b!QOc z?E*(u&rDfRGKMi*NHvfFm`YktOzI~llBv*NWP~W&u|G` zXD6^EeCCVUhdD!pXbF!4f2B?4^?q0{h-Mlaa&zy3XoyiyjYbBPJ}EPWR)*9GZIlox&APNgs8zQwDdWke=#?sb6qEf}DPY;Q zMJ4x-sV9*Wk;GC0GtFftob>;OhtLruR2(hJ$q_a&96<$@YqL{Z+!IgyN^!k{Y7Txo z;z^2=06}_BJkW60;dx2NE*#K5FRpwC*Gdam1>v9_Y{7PLXFYUGajQ}CC_ho}1Om#Q za73xG5CqLV^v`e^t1cW$#c&PW8jtb3a44S}b~27~vQmnwn-@cAQYX4n?0*M8$HV6p z*OuaFN3pBnMm5MQKUHx;5XbZ=4#VXL*31!TH(dRO;wT~&t6gZdX4I`2{kCQ`#3erH zVJC_!4Vxhx3P+DetPoH3lqD$%&rAH;^L?a#D#l+NY(#M_V3yU9NT`(370>!}yg)$T zC@hD59{=$N*rKNtR}+NKJjEu8YlO?`(8GokDCY6##cCb{y8RBZHk<$x@z}#kR*ePv z)S-thRoWtuCeJ>^5HK0+A+L%f27BRgnkpCd-{E-<^`f}A@F0&^b1eeu%u_U?xHfux zK77rQUQwHo7}nFZ58PVpa`sLQvV;QaY{xG~BAArpO0X*H7E0!caOe+pmjCCffM*=F zekHCsFyw`f2lB$z-o!B9DX8X2| zec%ME1y5df#|cJhj^*HnlRyy;@{#9tTukjL*Sw2^v&F%AeqI&KKc0wt#|c(r?V>wr zj_zDITEcb5@L(uXSASwVL_NZe7gjpXF1m-SYXoV++y16>wya<@FtRH!=R} zPwSasJqrb1nou2j(9$ia=RN1WL={hLemqsBcU&rOtNt!r%owfm=-m<%HK;f6?0d1k zgSUBL!=*rk{WYh2V8=0`{W}rT3s-txcDA=Cf@rv0b3+1ks)jTibHc#KvC6mOG6s^4 z1o6TtFTtu*k9;a_L>ph}dBridD0+B7VO5{link&7JOTg!#E@4_WYZ_^?jmm{_ZoB~%DPEXd`f}@UW z0Ru@6Vq&<|6Se*+5Erg21qjDP`@o^R923JGmoPB5ON-E)78$q%iTz^+q2qcwWj+t5 zG)%|!!o>N!yS~q23Scl!Z73brFn8;1t?R8ZA%JwWe{F^~iO#(sd{R^4LwqmGI}x*#14$oo7g!d(K0Rxwpqn zj?Xb-*>MT&m?!Y3IL=t0z1rzA+K8s_%Pp0s-u3XodiCQzpSLUg8jb#G#vxy->%P~% z?{(UDt_?B*FWMio!kcMtzGoM8K{;~do}1v_J0a-Aq(;ibm` zttrMO@#a~V6ca;Y3jB^y=ozfgGfcRgAOPgyA%+{}L$7$2(qsu}S2p{XM?IQ4VU+K` z%es2B+v%z z@n02JGc2nopsTpHbh@1?KL$=9W9;G2RZk`cN?rOxaX6#NlQ>XZdR+@u8pK{PjA$NO)&Go1a0 zmX0}3WM6SH;+&Jy9ETeR25)Cb!gz5}y4Z3eV;)&%%TlOf!LVzmlwU_|0r40TOVMNN zmcx^)mLsU&kql+Ly|m_?Vz0H2@0&HysdnMUy>0MUTniL1B?ty#w5E}@rqP5W^r$_C zvQcDg)jST8=(vJ~%sX6MagyS5A3Ukc3kMqZ*y=EFs3`$=^%9pKu{Xe5E6wk}A3u}{ zT@jDqHBz~Q0jVCLFE_ z1a|C+>^P$GRK&;55W}ef7NC%>{VO)k@`-cFb;+{Ska+Y<;fPGEt$NY%{p zvKtRdMj=0*YAbRN<@iwYQ%hUNl>&y;lOj-D&Di1PTF(*ce>1VD;{;O+F8Qn}7St2# z`P22Z(8_fF>X_+p=%M{{F@67`h!dw>g09Q7#F9LMR|_vA=R7zI&0%Q85mQ%OUSid* z=c(PsqBRdgZRYrZ;5kAo%_ghCf%Ft>7*4QQ(W8hP)rQ4cuJueDAV%sUCM^jTdHB{v zEfnT9T+ho)(6r&hai56(G6d8<#h8CA%EKZuJ&hID#btmM*KmrHhhP{E4XK9+NtJOk z#5;m$eSLVdfFnkA;V?Gt@SK}X(}K{g>)a}C=`M4GU=`PJ-nr}ii3BVL^XMfj9cOS1 zJh5@bEu&0522pXnCHG|{LPB1Lx@_cg6lYmL^dqDSUgPKvAyu3#%EFOgl)#yw#U$=n zjlJdM6<)Zva~};yEMwBchXp$hlTe8jCcAjpiCi7M@0Fb0WjP6P9(hq5>Q5goS0wd598<$qJJ-Jd9`X1`?=GM*B|^D&J&zJzhT>XJCeHYMyTnlU>hp|axOT`xnuP5pgs&$#KcCwiLZygK%lZ2h z*LW#-In9;rIEgqi;vD|ZcHvP1vUR*J?81$Lo_7VUimM3=LL7ND!wJq!*} zT&{Slic8j`Dl2eg91dkx|DY5G8+_IshHKcJ=}5LKE+@RB!BM<+;RJNtuDFu#I~wMH z+Natwha6)@vguI@*<#<%7dYOI(s6k)u4i(jICZ_xL%-LB$~G1IiE|XsWR;#}tgXZN zWV`ARtCk%h>+>h(VfN>u4#m}F@VX;n zX08G!j0k$W6FmmF^c1a07!%Q75tt+4DFvmmK6s zaV+4tSFvly5eYWjI-lLMo|H4DjE^@wUbvyp-pu7U zT+EcP`hOE_8C6~B`R5aT$)t7^z0_Ubb!RG-XB--g{hZAUH$5-)c>-^4v$$}XaL&T6 zJ#8%12dBQ#GH3c6)yQ_K7@6wJxzoL;ik86by&$2QEcbQ^GrK z9bUNNT3e#K=V*xHq%3{&9!0FUW&d33X>)YHPR`}JE=p(?oM#_eOy5%ApVa7^e)|iD z(PY>*Imju9AqN1LGG8kP6!5~;L;gxlc(N2)aL zBmJX&fc9l|Kh=T3OTuY)9xg*F&p(r($2bP~9nxMEU)*lOeV_Kq@xDOeU7upd;d?q1 zPAq9DPTVon0t{7g(r~cEHwHcA*n|RB*Ew933x}gC9TdxO3Cp-0p#mG*yWE@hjYg)N ztlS5ybQ~&IaT0)2dXBn{w!n^c*YgyYzhP=^L9 z#(s0bYR4@j#XK4>s}4fS&TcWE@5!g6D%=Y#?cxs!5f$Ly_<2Qa+d;5(szuk zxNxIi;Xg&!$0(0tqddxlBW$p72|{fZGf*xCpiB*Yc~6ifH+5d#w`vA4-3DwZ~#8&@*h zB@#IM;@s12xR@bYx|#hn1pW8yr+i&GfX<;qb180_3h$v+Ty6Ej@IjJiv%%aS(sC`Pt%mdI2b(fkVs zv-2FYtqj+P$In@Soq@_`pz{2E%MepfT3m5U*4FubnZb~H7^>k45)7A|Sw{~THrIJC z%T+c$y=1p!!MZrIaEcQw`EoRFX10O|G^7qs$Z!qHJsc%_7jC&^&_NIt$0#qJV4mRw z>(3oT$R<|c^E|N_wsgohk`sz6D4(8~5nH$!%XK_*X5r>X_+12v71?W7gk$% z^hAzJlA*2N*ZTLh>H889d|z9i*ZT8Xo^cGf%y_c(Y@=o{c<)GRu(=`-D|F0MGF%Nf z85WzD>gQIA|{rj#iZhHAizC>r}6xs z&xC;Mhp+~7x1qFbXj=@M&p@@s19lMwi?~52wI|zaIP4hqWH}U<7%qu)5leG{;nq*r zdvYM0uI>^94yviX-aC?d9tDZIBP*u3hNDbejqibe z0Tab75ilRFV%FG`QZQV?awrc0&;yCH?L1|LY(vVBIIR27?ppD2Eof`kHK9M-v@x7; zilnRyC4He}S}1*UuSz3pGoA zTQs$c8ma+9D(a%X+;RfV=?cYg>+}16y>!WKbPU!xIV#Q-M>yNTWx-e#0>E0a&fs>#d>_7g6C){He8NyvR#&;gtCmG^Msb|##YeiE|;$9 zBcXtICubv_uYTi{-j-SLTCRjK@r}-z*wY$PEJQ3&-nG=^T3G|SMbYH#2K zQr}0}>$p@v)_1%#&%Ctb7)u_GepJWxKEp7$YX#86kGa< zHp_G`@MDFAAXIg{*KptjXRn<++zY2x3+kDDlE4-D)-hDvaSc<}M_xE^=%KijPFquL zyU^_&IwA?##&7k%?^y2mAuOann$3a3i>!_@%L^yDbfN#yiFJXcFR*+TSYkuR!li;F zg$kr;7t6iJ=>}t>ygqGa0!SBxfietGhb8YISxsPdLVMEI=kT z^VVWe|5}OlPf61c6s>ewn7*J*o`pvKfOvX! zCP50bcu!;v;w6|+=|Kt;IAWTHHbD^@Q4xx5g674!+?BT6wJpRmblKgVV|sh0lqM)6 z|B-cprQWtg4^L=%>SIyg?WfEu-Y-*plw@zTW*BNSlnE-!Jt{kfa#IwV7fmwm^M*|6 z7WEGZEtadQH;7QRs>?X-dD$B!jgzpV)HDgr72xQ|2Jf^HVt}gvM8^SvG=0CG26R-nwk0gKMWN_Y(Lxc)((&aYEYCvZ zpOmHzBnlWU_BrVW#rq}q(6WQ3;^nJG?Bp z=3l_`9B!=Qir}<0N1RDaXDruyo=QABE-#nYoa03o4imgPxgQBvb;jm+{&WzOVy=^H z&H*xI5K7$f{_t~vOk&i7PKO1yYizpz%`w)`pERv_)L+7Mg2P*~F|B!A!28iOjw58a z*R>oSSFyO#5g0LC!+E*83#jN$sZ+E$${AN=!qtE&_1&Pu zI|8XLV`jB(S!E&dJ^66_5LUq)FHGtO!HIAahf`K z;o1^X_MOm12^y;RL-F?gYIXjh22-pYp*^wtgqHgZ&gm+Nm3fSV{OHnCwT|MF6vnIN z+WNtF0Itrs%^hQ=+Q3MT|rBU+s@g){qy;ejBP?n;MR4PAAH%!#~ps=0jBwDpEEqBbL5I1BuF9B=W~U7Aok4#eTpk&!>8f#j@LGvz-VtrV#;t) zufzUl;3-zDmG&;qfhDx78tJKjkOMyZWn+unx558*B`|gO_@iD z$4LtHXQbliI<~Ws(R_HkV>=bMv_0=mdcNK}O$S|(vBG#>&&FIhv?=E#zceK;*bn15 z*R7SMq5n8ew&N0xj`EPiW<`99>$>qJZ>y50SFOtwnk*XD=W_dtI$a5m{n{TaSh^lH>Jtrkg$jvS?)qj&7KL(mC1Isi`sy4gd z#;YX$@kjs7w0pI;UCuGxO%Rzz;~w$+9*r?xzOm9YXcm3!v_Y2wzD-v+jka(q^nfl; z-6)z2~e>cdhP@)P1I=WwL7p@lb8_#-M7SJcvQ5fUtT(NkTTD@Ol0{p%%lT znC`0L28XQ^j&Y)o#}Js$nV}rPQ2}AN&IevUuXY16Ykr3Yw*npkU&&)JELBSwO?T*1 z!{N=h9s{YkHgv@&AmWJRh>f_y3L!^;Lavch&wbeSYjyqI_=Dp(2#3FqZQzy*B|ZC~ zhC2gCKlThl>r*rbKGW41evLjS%`3F4WI;=Dd6C!2IS=)wd2&V3s_ph5?aURU%{RM35K!b02>|`9kid8`lnKxkVt$lN#=Bx}Z z;N5lbk5{kCdN?tpGq_w6W23Q>AgZ9Fy*z+<)JFZTBx>hWOjR z#0|&Po%)IfuoNVbr>^G#tOS0aqb8gzoqDH${-}q;vSD#dfO^wteF0PGeDCj9o|gd= z2k=oHVL1clgjc^ff)f|85NKitsp&wp-i}DF0j1*b^5dM30c?2P#l9!*I% zEC$paf?SEqfT`vRXcc@KL0T;k1a#2?1@^Iczuu}6k$$Pv9DX{@?=xTxqh@bbB_21o zsvTl*0bShJrUor-Ip@fn0+rkq37_6upc=X4mb;_y|EEwO18cz2>B*?s|Y z12W+|R&DSp_%VmSUJePARFz02~sZZ+jm@qY4-g8dTfFcz; zbc?YciI*mjhz@>c8 zXE1Aug2hT6Hle_r@q+u)blw3h6T`#(0XZ<-Z|rjSE+Cdrd4hfhtf)F%nq2gFAYTy~7&5 z-utm)ng?UXo^P~UPjPWv6!HR=ry6h(It5modF-Jc6zu-Ru3TSzBat$CfgFzOi6uy` zpaC4^DHpH`sPnYB!64m}h(l!c9qzx2{)@+3w1{`0Z~D2?Xy{76JGw5c6ySMjqZ!iR zmg%D#sE{f^VBTr7#cAwuiqis+^?852_Pz|532CAe$T%R@V;>Ay0@jc^=!F66q8>c* zXtl14u_K3GQD7#V+2wpyJSNqFu#K`*@;0}2XH z-0-iMZf9XyqB!Q;&Gks<(zgpp0guUPW_<^$1_j{0jqw?lxqz7C@u?*PV!7SvUX=@& z#;DXc7l_=z22E5R@})qDiz~GmmlMatq!{M6l{AW!rmN z(R_TfRoXp|?^1M3Mk&;{v~I}9H7B1cjV53r*@#4Q8Yh}6#50kQV5?FQID~_ zy^MMQOTh7D4nNF*6=&c2>{hO_7z5|4%F^B8G6o9d_x(>DSa4j63)rM!2h^^#Z?v+< z|N8%2jau0N{{R3ViwFb&00000{{{d;LjnNND4m_lt|hx|hR2;}X&i{Uvw;kZW5m-8 z&KqQsamIf5kR{b#s-Nm3*6udifQ_%JmM#?U`k(*(Kk7e-YUdu)k3W9=>&HLj-#>o* z^S}R-LjLiuzkdDWpTGX`U%&qO-#@~?!!HWyXZWT6o&V#1Zk9u+QJ6n}{Po3d&^*Ww z*b3FG;6LQG6D-w$rCwmEE7)4Q-uU&ku^BM73yf_6W1{f<)Jz7yz>|TL1cdLM`S=wOpT2%L-PiPcR4j?O}X-SizR+^`pPO zJw`iPag0`6LGCbGvPcX#mPAYom|E`7(Mt9=rtuq7d4S9p`1y_Yjd{E=KiU;#^6v~z!Ea<7`u3BEMBS)koAp!Euj64G&kDkH}*n#PRAEmpKFl*Ez9p` z?Z4<(?F$$~q33U8`$isbafpTQc1xA6TAEN@y7L2YtCGstKJLN+OIeM`Sq!GyU^G!R32a( z`|Qt`zp+t)iFIvI0b?4A_s`d0&QBqf>^@6lpQUA=)!tHveYP2#JeE>@{ArKTYO!1b zboq9A3eZ3P{l~BLv&n;m3=3H+rHlN0yxl-)Y@oDkpdOeQ){;kpD%kQ9bP2-VDFnxs zC9`F_oa7)Rid{=(tfi7yFcQJ1+M_X#!#MW`C~N1r2-%J*k5T0nOfjFAgxxO!R+tW- zu(l2xcphn}{ z9r`1mV6vhk4bhQS(ZTUL`2KvWLvcz3`*9=6DNJMK0WvIrh)YhCr=P@n2#6|DR#vvw zbJZ0)BW27;;T5dCJVBpgz_nk}ubky~$`M9T`eeYL59%4_$)#rq$RRw(I@`6F$6Cyf-^>J`?mCUQ)0m{UXFRi* zEbvCxp`u`~=M%T%i7Q}=AdJX@G(h?SV-RhGJIEBrX`~<%$P|wS5rh1v4d1|LCD{cK zr`ng7jjC*_s2^CFOGD;TTfiJ62r?scNkwOsmnJH$a~9jWXVHKb8LSUV0d%5de|8$< zmFNLpGqi&C)6@9$^!W5Nh0|xlI8;;x^QFH1^;;RERwez60{+35ALQ%bWy@X<%Hz}j zd^hS*bXJBV(w?pN8VM`d1E_PJy&gjfI(}na!AcEQjz_tQfuo$O zKVCbi6pRU0j&H4U%$=X=itm)*#1({>Z>@4E1pCor?F!g>9-7t5MJ@+nM(x^RdkV;< zwx^tR4Gx7^xjyBpN52p-Q3mnoak(fMr`yl3cJdFgI+B>XZ~~m9UmhY1sT;VPjc&M}_Cai~u&+jW-5I?H9{I?lUe zed?jz;P-jfS?jUqx1oTGOQFFDx;I`%(2r}7QzeNF9OW0@$IbPiTr>KxPj=Vf8meMP z(LcF@6M8z`F0N2dPXUna0?K0nWnQ?9Arsd^P+uhsaJGW@b{)5cs}&94Qz&$BJu)nW zlV)>qO>7OAzth=0II$5y%Q)$77uUJL0etifTpSO-=sGU0`QuhWbKm(sW^_B&hv|De zL&k%8feAetR?4xcxwz0z0sX=CD+v3>K{mMp9=W4)b#g`mopkDpqedMTo<{%(mr+uB z1c0dU1PgX!)Q6u@&bi096rQH|%lT`8z>%A+WX?k}=Z|D&?it)2o(*mfTPP` zaMbX`atMwt!hL!g{5tr>sjB&2b5JgUAdX=(f5bX}%Xh{R!}V8qdiU4uWHtWN-!Jq}lGPJoZ(tAFfkE8`q%`2p1c=*-q|dyWZVqU;8jppKN58y;}tvls#{yh6%#3^G` zZF4}zshMfqk7F)TG&ES_QqxQqcV%K-Omoc@jjOSsCo(d@*eF)?YGnBMVZ z-*LroapQE7*SHSIC>s(4+%Y6IxYXP8fOPG@ z*lvsCqX3*@v4blO6wRZnd2o%u<=`8aPI$2H@p;C_UVDreAETS00 z3?4;AxHj@)Kl|2>OB~~}C@La7F;~u`NQiQ3;m|j;Ckd#XdFj;5iVh=t%9k z|6J>(rqnS)dvY%;r{Orv%S#(Mk&?O?Kfg~jla7jsLw+)eVhgTU&;ApxRB)jlLw18} z4f3x&9tPpKqr#sz5(tOWs`g7 zaQP|6u&zD(R+Nd*zTtV{ND1Sno_#AEN6>pbhKP)2#MA-TxWt&zu=F@0gc~`jYo@$I z&r&Xe2Q1lnPh;LwUpXG3kIz2ZxxllABJ#@hiu=#uSrU#hQ?KmgQc<~7mfx2`0J&7H zT&hDZ)wXgG(cC6h@$*mz76cubYUkcmg{;mWn50qQW!xrIRB*zp*=+{BJU zN2lj}5Dv3?U2>vzo+-BeJi3eHTTlL+V-EZF;xP1R=OK=Hh;`w50l9k&6i|C zMY%RBjo#R|!j+K{{3b0)xzxD6cZ3V4A(7W|Ub)0?D?a_hupom`nEV}at-`T zJ9{k6h-hr<-;aTIJqS0XBT}VY$IP~4YUAWEr>5C~YGa_RE|iPa50$jw6kKVTuZ}%d83eCTn0ynOHk$5J31)Oxnja4 z3g{ql&4U~mpkO!*I~`0)cmSUjlZ!I}m$QPQTtd0zP%thIOHVc_N%P=N>vxU_`dj%a zT>2hY7{+raU+NV6Bx+$1nqKsiOf6B|eP`6~{49jl1D?pPh1a@G-SB8sG7F3;;^zpHav7^39UdCx3fI4#zr8?h zYLfnVYMN({f+nOV2F=f5Au3lgjHhdTiph;tYc35{xT*1f*5}#6P|kR`_o*qC!;)?1 z`%*)V@f^8P&gL>YImT8DXHSH36+KBV0VgJRL&eLZu(6zn7{T@^G|E9LlWRXHhn|76 zWvO)*6fn|Y_mRjYwJg_t#8fb{@7fO>O_H~3TsWDoNsa@bD5QeTLhSG3>wH>&pn#>q z$>tF-L{zxEp9s>LTFkLLhl+%Y-Bf2dCPF!rV&O1>iPET*{`2j)6x;U7p#c-kB=0DKHPjfLT<>66`Zi?0 zbBW*Wk4uI6#`=k&W4WwH;E?=f3>lsZ+%Haj8b4lJLdr4je}~|guN=9(zklEFxR@{{ z&td7w_D>NMb%#sw;_%>hgdUX30YZj5MK<5ArN^H|vy}&x3Loys8Mrv~WqUM!;qEq7 zZ(@PM#bgd1k6;!(jIlMFM=+;mH4Yco3%aCS0-#XDHa4yW)VX1OrX%(ducQ`&18Xx6 z73V<|jslkD`=)HygL0kym;QS9;qrqa80iSMD#yk|b)1-5JWrVX>R1ROm@^~i_|7OA z76#osCZljQ!-lMOJnI++qoqJ~rLI;&%yRbIG``@LDg--h6CW#!OB^~5lQ;|>~??|qH1*^no=q){J& zz7>w3zH$}6)1!&S*a^$@n&sNy+RD`o7Ke`$18(fwFHP*&5pHm?gQ9S3&o;Ompt|PR z4{mZ5Tv^S^&o<;|>kC(~h@)Hi(uX|jap5W^Yc@OYZOnUH=AAogevYKXi^KL99z{<$ zPMDPF(1>G7rpnRdIurHV)Yp4rG$PIjeeNEY@FfPn5o3!vnXVxog-y7cU>-cK)|hio z?~7C}4i!Y#IhIQipA|#c1Ebf^5hy{864Zp9$V>7j!DA;h`y3Wla3MlqE^u4b!RO>rAMh~gSBdZ)kZ%voHE~#e7z47h8)FQOO z@Qr6`m=ob>e~M#JOF7ifTy}Wn%FxfoC9l;y!pMVXT$;M@K!0(B z)Re>GE0^8h%8(PQT-tPL9^ct%;TVfhck-;DJZpUvAHVBcrkshWc|yKXlleg}a1@Ow z$9Vp^>~P`mTsdAja&b&JE-w2)telRaRL^>m&&2Wcy-(YSd}E#Iuw;;*9zBxhIlUGq zZO^~>IR8?liaB#0y-v8hGy9w30pYsw*LmbpN;zW}ABaq?`ynn|V|0W&&ZCrCG3}~0 z#Vymnn-;F3-)6U73al693Klu+`til8-BmvGka};J+T%DMQsRKAQXczATa{yRnaA!I zE@qf_N4FZ~?(_YX|2m146Tack5-#HT=kc?rOg2aMT+B8&Jf|IYoN$ydrNs4}DPnut z-8{@LC0Vvlk2Q2r3##^3UOqra>TfsXHdHKJZjOH6v#(cq{HcottPe7=afjuco6>ZO9^v49T^G26>LE2 zXmh1)e6w+MI@YIhrlYdwJ1Jz-0Qg+Jd)*<3sc9bhqFe_@=We}ZSTC6};ktIsJJpN< zJCDMVwM8zAic zC}$iBj?~2*OT#Wc-^%RCa$KMw_I-dReLfW--w&>2I+c4Cx^Ng__E?%Z+D5+nHhLrX zuC0IiVp?Yn{lka*Rz@2ah`dy!bE0bc(l}fPSrswN6?45Wnh?HAQmSqJjT}MYOu4Ja z#UVBm&HDORAwA(t2WgKhR5*@s8AG-6UdOzDTtCX8q}+vs5`=`5!#)6>P*P5Eu)>M# z(KMCAK4~sVnKUK@@AGj9U6a0b*2(mz^k`y9Z#jhbIZ_71{;hb`kfWbQ%wox#6fcJh zPPmS@zIZG)5$6f7VDY3%=GFpg(k>04wHUwA2SB)lE`HZ|ww5b86nx)lQiNQZN^1oz zS&svwTvt;6c!sTo9Pevl#|9ivhh?c;f&Pt-{&C9PA;eF}a?`G3 z%tK$_*E^<$Ib7K-MN{qVS=Y*8D!rRSOYb|LWO-2S@2{v(jU+m@2~EopN5OF0GV|&LB@zRXE0@-DCQ-GPA{BI1fejmtQxd z{*R#8=1iGiN+Ym(p`z2_y~=E*84vA+`@)$Ewod-Fo9kEs=i~CB$A-~bZw~#xr>P$t zRl)+TjXFqEAEcoW4pggIp6Fgae-6$sZsZoZ8@b;c8jky%fl;0O{5yT@<3Y)m{T?)v z!DT{mb<(&emr?wmiU1~OJCz=`*Wk)X);uKt7vu{^7_8XH7t|URvqSr;g0KnhNhPg&;H;^b@Lr_k|?d;!KRb)M$*v~b+pL3UZc6?Xj9lm zZMGu}rDcWAfI>hn=VnMIL_+LTyU-><$tsA3;Z8wL0kJFv#gPVQq*Z!l2_|nZWl=z5r+#gv(HG9PqjeEsfXg4Ln8OlUGUoz-1UP}Q2Cx-6jFuutQu zCgJ9=n~g^a5snM=lk|wC9*W5w^(}-#rn}6+advSr=9!Y=w&Dhta-`?6;(K4}*mmm_ zP@5b_Sm?WrMYyqICRB%al50BZmft5oFFeI{v)pv>wGUTX!GO#ur*?9UA(hJ17?V0M zlWwee6)Rl{ShCexT^`g4cJ`^5{^s!9_Sh+1%?9Z3?6HeP#~G;yFLGQbmrP`5d#=qT zyPRT*qFxm?=5CngZm0{IaXY(4wdR2Ly|}hX%@JD$ICW=1v&nkiX(+dfLMvLZpp-Uw z9W*m;D6J?5Owrn8gv?Z(g)7~@a^q?KdgbRRsG2+d17bEC^v(vL6(xqAbEmM>pP9(inQ`852=u~mqy4M1tVHKS@NK9Pvau4fAgSrJ%|fa zm)#<#EoXR;x!7svM!o&0R9Dn^#dc@Seb~@Cew83$d%tsw*|}mXV}xhdBxD@KAG=98 z^!>RsIpsh>Y4+g1HOJ4v&%tP%r_2`R^kNLWQR9?RF}QB}Se|n0CYKTv|9gCm%As4^ z^_|p4bDvd$I((_Je21d=(kCih3F91eM=mGVF%!z8i3`UVnf085EH)Yzy`CcS7bkif zV_#l}=Fds1>fxL}gh3`36BMC(PC(@{++5~bFEx#tkac}}##6XjpX1`OOj-MtgZ|@@ z6UsGs-zoexIZEJ?IyF}R;?SM@vc0D~Cx$brgBzU48&teEE{bwH?AO2XLsV&RTDZ_uV_3S{H}bmBSUST(LcPHw9niXS@<~gB<^*)D}n`9x}_HM|G;E8>8nF zx{MdvE$2X#rrc9U1!yzRG$)#tnU)jR^cghaHc~HE@4A|6Ynen4=B^EzmhfA?E_{Zs zr;Y!Fru?Tb4@$o7C^p^lHYelMe(6j7y-=Htw>gaOQ}ydOzEEtlPP=V&ALPr%>X9*5 znC%APak6rKaQ(T+x}D)ZMyRhd%y?(*DJN)fDPwNWsU6+qDqe9z`=p?e6-4VRYlA4P z?2wIKJSQZqXnT7D-{2ZyvHz*Lz~piUJ>31N&Ggq{`>8xWmA^hUM#|x3AJM^SE6S%d z-1&ZPZ+FyN0_VT!;|t0$x1KP(?s8QK+U-5f8$TIMM;X<)peA5I8(#%YX9YD{(1y21 zI-Fk0^?JIKLetswauBgD`$vD$5}1&n+2pBaQMnqqnB)Cy7hGJzcGG9OK)H%`-6=!+ z=CFC7L*E|U$XR*gu+BAwfS!HVcQWS)U6dXEzl+1nV2>OTuHX&dy9f(CBP`0@%`HFj z=WtW-0p`3K+2~Ctba|8WZzgLd>%VvHT7jubNF?1-&np`y(o}K-- z$~8>TJY85fxDp!XrXIXhK8kw8wEdu-Q4B8s(6E*<3R3W3!=dD*y-|%BbLgY zN_B1yyPJVOVcj6Ka;8Z8?2uA!bg_KPX>(n0n0f?duaU5{>r_H9xrogb91-M;!}LDa z{MAIJ%ay~g)5T!Mk|~cu)hmzgf`7eJ7=>f(2J1QKl*2T{eZXRD`gja_OSfn1?}}aS{(PU6(efz6e^Hb(xr$}+8&$OQIRc_5^Hp!8 zwO_pGrd=&^_;A-260_|)I*M={(btVjjP$OqpzfV`tz-?TX)u3rtM#5M_DgWYf`luz zqp#Gnr9>CU>?4m3ul@V*j<}9ngEWkq!)5o0WNM8<*Rt{StEc5b&6C{?skd2gcgG-) zM;XxmY^F1xL-}Bm@5eL8Aq!aVDnnW4kdfETFE4NIxHv5r!?VM&5R}7(?;6h}W;__< zj^I!sF_KWpbvPU@4*P|jZaA3S$ToP)-!9wWPKp$PB5U^k?=Ml9$mGw^P@-8?`Pp8FQmerg!pn^v=Yevj(XGQHt;Ou4By8;}aQ0a# z*XsLN{l&e#fN5~O6iCu@*k;NxrsEj#NWbb&78y`K@=>eA39n!~)ksdxtnHnwm?a6n zt%)h5ssgyC9o{J63MD)!-*yZd52}UUTV2XE?D^`*_Z6-;`p(i9JDQ=FIGog@qhwYu zOlVaUxA|}X9NdMvUWWAJVa2_EuN8%|4U?U{Fc*hjL)Q+{24YYd>BxEzu2k&g z<_H)o$0mX9tms`_hC|ag4>d&0R&tGJ9hH#_cj`|xI8o=Z6Q)Ng=(F|q8go2b9Ln7t zA3w^(*~_flurOZq$+$VJrgw5J*5~^i3719WPe5nJsn3vddN*i<6U;L%!qvC8$4`z4 z`yn0rsthhsfNU(!`b>eiK(xl;brmj}t_F@uXyu~0@*r&FaF~KPtY|U`Zmu+4MH}`r z_UIvrQVZC)+cT=#M-yX;oBWJnzt>n6okG}-9Xj@%VB%LNn49}XnXPa+V%h%b^0djN z+2-ME<#f9|GF4}tS{d!RjZHQBwj+;Z*h3DiIuHs4WF$0y0=$?0+Fv^*FM~9+Vv{e{f zR^xD&3)g%2`%XSv4XE|7 z@9rKOpWErdfvI337gy*jsfS5)V3ip2-?)S_m?{;J)1LhzTuG3!Z_*g9N_pGjNuX@UbMRlZ{7(IvC0zHTMb2H*9`RKLAjzb z?uZ{N*G=w`XMl@3?4LjQJGD&LgU}P>(L(t;MxG<*=pv+C&+n^mi(bHNq@Y8q7cS4L z!H;%zPDT<=13Ax~<|u`@IBf3e2_7qlO*6Y4m%D~$85g~~5=7g%U&7$9y2NJCh<0_g z!6=c$9HTVuQcLp=%%pU*D-*Hh!;- zAw&7@hZj~9dj{?GwF>%L)$V>K$>Z!bQ!dYTCZCS6XRES?BxVWpW<1@)F}NHnG;MaQ z8sQpYwSgmZPmJ`y5xgD_Z;f!;xE^M469%B!0)t^2EgS{>eXbo+V!}H#X>*d$JW42+ z2a2UUo87GKk%zG-_LSH(s-s<&qWnK?eONbb1vU$DR$5U>3z|FboXsw$xy@}>v_Uw)bR7spU$*>>*VrtaSs7A|!Rqn<4}<(M%; z`fNE0SF)+fIqT2DwQ8DqdA4_NY~1%}HLy=g}|mU3gNjI$*qA!O^BgxE4@WI`nnrOvbsxu29ZgXyYhbRc@3>tchd}wO4b! z8yzUCNCF$#q-~7x_)DVbz#tKg2Mz z+22*SDc3N3?vbBS)16RGoWlmf>7~OU&%(wE2=f<)xS%mWA)dpxr(DjMBk2%L${AjUiOwes3%aBJ$oyPN<|Q&EH>gHa~k<-e)ZM8{X+2`!rk;#Gd;z0 zcToqYou0eV;xb$%;oYtti6xwgq&XZPwY3lvIP*OQPiyv4Z%3-;#Z@S$g!fHJpq;1J z_h}_KoB-#5e-r(rV1ph<3bJxFfhM(+$n=!R!s!hsAVJO=v~tCCh+ zg5GqV5)?BzG$Q2+*3dXo!3PH?s-uELxr*cB(4ZUV5RI$L^ZRm$*l00s+weUC+!vR} z@%ARMY;c(9b?#?yaSemL4*4QnGIxf1)^!d;Q+(&*Y~150etXxK;NoVg`$x{(^-{)q zDWCPy^{x(h-#L<_T#sl0dDeArcO%!oO~_97-5R`>XMHlX8?$J0=&tez4*4^6g*T>t z4|>xgEIfw^rd-W<0o+Da?N3!zukwg^&k_i@nPJbGVZU+-O?F4r|GIL-TtXB!J2~8< zF)V0lP#a8}%|&x}(bx7;)K-pdEr8nupa%*o-q+v$x+W!}yXRbKad8;Fj60=BYb8GQ zV;6^EI>+JPDaBUc@OLOv7uVo=1;-)YMU6IV&h?#otvb5FPG%haNK|8w7~nsqn%rQ) zUwAqOF0iomyq(0x1i7Ja`J}jCU`=-y1%KCu0rt|~#w;(e#Xykce-v>S*h@6UODE-F zf_1jH`v}KvJEq0Tn4sx9e>|2ikVC6j2YcK7KPv>K-bnDuqtfpxPM3kwhjlBcFWz@%sDq=j#vs``5q!<-_amf4=_w>+8?| z{`%|RFZUn!<--s6W&ioF|M}nl3;q?oq%65A;Gfse0~pc<46y@4T7boe@;W^+?N3bO ziD`LaZncKj2d|o2^HBjm^<|G&b^EKj@v3eGN^9qDOgk_QU|NCVoa;~g`v6ASfKfUy z${Sc(4DgL9?oS-6n&Jrde!19Y=_^0egOR& zSW|PYKk*wF>b@OyY)3r-n?3Q*e@(#S3U3JAOHE|%a48Z%RcHhW{}meZ^t3z z@dT6xB1e6rxZq$_L)(FE0NWWTp8;bIeO3Q?wyJg@-T51@L@xgDU+xbVLS6r!WKhpb zf?taJFU29eaRnBaJZvl_ywZ~U5Lk*k1G$qeO~v>8jd_=dJR~Bo649jV%XOLe{W+A- zx0LO9{X6Vp$In zSQgf>ZLH7F_g3!T>F0;~)0fs)@3(! zPduE;yaV$%mH7;mbmkOg-_0_1v#h%*Q9!{nyeULACg4+WBzhyzgTk`lMJKu&9>oX|3q{bZMMvdeO^lUhyiPq@`e620rdZ&51ytCk^3#h-uyWRQK;vMmmE zK(iCn(^pE!Z%Qb8myu;&*rKr6q8yuePDpfrslzjmHmljJh7af zC>6f3>;h1R0F*@la!wT`XIBYnsD!krgyMY$UBaooqDB+_lejHT_~GqQtU*z@JeN>=&y2ztY4f?P0qv$8+lOC+0 zxCj<>|Hwlk@(QfkfectwA+L{Y(j1)U>>6L)?T~l-}R>-vpqh6-%Qu4uzhv|&-SEvu*TdhXaLu*7;k$!(X_He|KM z6Hq`2m3=$P*p9MpM^@PZLbI!YI3y=7lB50*l5Zx~q2w}1fyH4QR0T#C!S2O&rz7mABaG7#-lrp#T3Q61gRkmM zOdiqmN?_N|OA{YhgqZOD@?J=%yGPQ?Bfze(Hl&SXK0ar$N4OlUrv&&!{G8h*b zl!q&!GZ8t{_c3i)A${M!m;r+gp%IL5dua1hg{Cp)X} zQPAb2p6F8xNE0tuyGPcpK=GixD1SVAec5zA9c6#jL(#6Ung>l>pU4nX16BwGQB+ug z!GlVmSi34OkDeoSkPV0-M2ayfu%Q!0ok#VlxAPcxMH|O<#I^vF>l$ELRf_m1(0h!3 zGtRIA)t&$;V9sMv-`sx?Up2lwbk4dsW&g%9zOk&p*gca~lQVun(SscDRre?Q@kGBq zG5HFogYv!<7#*h0IAE=Dyy~-nO!3a;p;v!CTO0+}{CXY=Hef@G%=i<<>**-xeWZv_ ziB971+aDzn6zIJ`ELZkbl>wBn0$cF#s^k-!g!AHXBBv53=od1qqokNKCL|e$zohJ@ zDSw~GeR1LtxfoWU?|G{=K+13c_0kK*IpZ!laY#;FBu5>5%<@szssqu??IL%?(Uw(J zZ`-3=Kpo`f6Osptk}0rc2>DU=QHiz`Sk?|)80-?C)L z`*W(K)sZ^==c)2)ErbH6g-N*?us~>nGVKbCj##W+BQ!P901UfE2ty-;MI%UZg4sbz zBS`WMR+UPb6j3%QXCRfUQ=rGdYTHjs8>gi$r$tnBG3v~iz3Nm!qX01Ur79y3kX33` zs|6TPvtPWb-(EG;ItvTlPV`0ELB=u5tHxAp!}^wl!sAWOLsM{ZO}C;b(N>Sr$FEdQ zzm!3tT?H&N1}qKOFoeC!ZyEAiPEQmM@hU1GT0`@gW1^f>0}329PAF2&DT5wj;v5Pr z3F3}SC58cOKuSZ@SQ)T|1X_VQF>171Ia_VY8&cp=-thC;H)cQbp-+{x`fUz<6Ur=9 zi!lI;W`P+^A(cs2V4Z=kXThQ>DJP6FF+m2kCds3xz-V^^HVoY`5o@zw5i6qzo2i~q zIh>kDxqAiLi9GAtw!dl{uiDZItOD$d(K!Zev7Vo}rQp47N3>i}$!YnUmz;e6B|$fr zIA;cw&_H+zzbZN-QQ$hXeSg~6pXOI!OJEb&CrScQVz{aTy^Hm13-fMF@-Qa(+n89% zlVE8nwW=Lh&acWu9Xb%*BgR|pzy?obitMa9%SEtzjEU~`PKn^(m`U%YM?qeXBi2^y z(sBSRL^z!Wl#0#@p@e#Yf=4%ZKcLc6wP`W#Jv|&C(7~9Yo*u5q+zB2M)jt}=#jD|? zRwr3_6_%Azm{qIs! zX1`Ro2o_PPXTVmV(12U59EL$#l?h`B6(~M`^2B0a{TZ;JC1lc*3RL2T5^xOe*=r=rF*~1ZjG-%^{G;w-`_v1^|itv;j+iq$0T;B}zOSKJH`}#K%|ll6TUL9P7t9xk+}I9P(0&y; zQ*)c$V}v~RdPh)J47<}cbs0kij0sR+L5GiGK2fPQl5NWF#T4Vr47^1yZma5lq@ZR` zYN;uynQ}=bJgnz4TKy1YU@4PrWvm#}CV}D$G)plN00SmuP)v#;T8U?XU^sXtQv|b# z;QO>B7t1C|%o9^kK7$=D4Bb!ag9r@U{<{R}X(rqrQ*jwP$tVFx zN`yT`&6$i(Os$E)6Pa>k1~afY+i?|{9e9R3`#bD*ra?FcG4P+&`ui5z`u zaI7dptH2!biH!9!V3D)3;v~n;2PQF?^O&Q!0_kb)RjsuJ3seDQ7MtmaIuiqi1ilt0 za(b!)tSS>)x61jg(Khc2`3T7_0+8KcArFi7J1~Awg{440x-}k_yBe?w21xz>k>1TP z@G9roy1xMHE(G08@o|f&>*JnF=ppqolHpUF5NA?wx zAqKLpPjy@WAmgg#UjB7H&XgaUv-tW!|AJCc7d;$jDq@(6wIRG7ClNYuD#=IPwF+#4 z(E*CIWRUg z7*4>M^?1ft6_^{G4vJcf&t+pBB(P#Cff0b@YOL6K%8+>jHY|l<5~!-hOPKMTN8wom zj@FHb^R*OMy#oPYbdCWlCc>HWf(~p%hty1juTPxgm42Osy5y_YVv;;G zK_b7gM(7J*{70*U7(G~vCTD7S6&S|kjHj}yK#yaX(p6PJvZ{czuBy7an4;yrF%+Eq z#mu|wz&QlzQNmP#G2<{vP#yCd%?(^shXPxHP6Q_HWkA8jVX_YjRP%@>6WrpY8i93O z$*S9BHSM+aL?Ma+1v4y^vQqu;B2-9I>QRBd;o=aEL}k+Sra(R$#>`B8=l{6-?1%)S6jUD}8cct(g2{2V(yK z6YJJ8ur!Dj;=1A(8pfd-7=l$EQp=3>mMoW8L%Y|JC_9SV$b>u#rx zmCarRZ!TPsz)^v{E>6iAgq%B8p_GKQljs&OpkM@bDfO&L4uS0biPOd<|)dmys)ebBe(kEh8 z1`G*OGZeGxK&b2BfMpIxe%Kyvz&sb{Epm*Dq`=}p1Jqpu)S&@tTY;@%yU5kDeh;x< z7PdO)vE-7->kVK#??~RyavoD|^Zg;&rIv^jLI-?b#{`Jf4G4btVei!*>NU{F_f)ha`^ioAg#j*izS zH~&oFu^oIv-2@&(Lik3H2^1VBc&m0g(8w;9vfuIf4$MAAXsEmOStc-}PQJC~0~lRI zhwd&oKY;dHrp5MTK8 z4SYI@bOI|5bLUo7xs``fB`gZ!4sx-%*5@bQ zM)fDK%;I^ze5C_x5}c!aO9MKvg)wD(<$-q*wr?Pk)qH1#gYJEnywN z=(dS@cO-cL(|)7c9V;8a95DmM9psi%fhptc6OU0yZ(4rmvrM4ifT`Q)(*PES4d?#K zFZ13q!Y5#=AUU^jk_jAbiBHM`58#%%y7M3=u;QxT#z_XS7QFuEHu_}1(r3zoLcYuF zA3&TqKtB;%qgkL&U^{L@ItLI9Yq;wE4ZZvKJ;Tj%EJtxk{~@K?0n1tLJp2hP9=ILF zLOMssj%VtdjiG_ryG;*tVAJD?mEw#>Q1U7XhT&dO?TA#nT7vlL{Sgz`0(d^uX{jz% z+>R?FROax_y8dr9O4Zwph}Sc3cmPwzQMHu%RA8OMs`(0z1BjOa-d0q712L+>JyF#l zMyD9{slbYw{x;;(fx(X{*Xy)Ah9oNR=pyCI>Ibl7ERNX@u zj&7x#np$$IK)=Z+nkNn0an<(jt?hj=M74gm_CFMKOBumordV{fb`AvYl2fOy^+ELT z&wt}rmGy^m-Fj{>-rY^==uU56JtkT2QY;#>8)5H2X=xkxK$%hf@~sY)p+^c7 zOb3!c38-$b_;DCJ6wiNG!mPg(@g@aIOEen{jJ>qXL1@md^nx>c*SOJvUgZP*P$o>* zd<@&{P{w~zV8Wsl$~ZN%ql1w>ed4sEPv)a`pmAm(kCf6@m+&)9sK6vJa)i=L*0~dL zbU!2Y9S9|qoUBH*Oi+5qy=u0Ke_$s}=%d-a_t-~smsuV_aULSW6gx3s!0^sp68r#W z9GOQQWCd2pn^5#rfgX#CxMP*S+tc3O!(GMB0mPydD!!+uF<{u7Th${sbaRK;seQWx zP0fKqzRqR)cP{$?R&>&-eQZ8pnJ5(*ZZ@M0)Fb)CnllcRWP#g=Y(`nxqzMdtQ1N#0 z-%auS9EJn9%_^Z@)vE7sfc#zmeg~Gil@?H|Ds|2bxd~!>3}P!V&nv_Dj*kOaao7lB zAH|##jJMy_Burq!Z=?>g0*eFHL4|V^*tVjSJ%ptPIod&v3s9{N4nJi$fON0s^_))j z>3L5Z8wXI`aBOR00=x=58gTgT-EZJlAwWrvwT!=>yTekO^B+C2xrXHdoUAHvyNKvI6ZF{bmGCO6H3oxMk9(e6ONXr#x zUvlSBfr5iUuLAYK0`;ryFlvR1!vs=#R}&Vda<5uPs%{O6QR>k;Tb~Ya7{KPR7W%3o zZeDO7Q)*T`U3$2?9vyPymsHi_0j1QQSnt3mGAOQ8EL5b9i(C|dGua3Qwry}L!?n%5 z$Gg6-ikoJi(+W%pD^jU^gNTLL@AuK|`&c8YJ@Qp$h}@sgXo$K!ZVOo6j@cVPe>A%B^HwJ? z;N_gRU4RD=2W;F{I1XSKV+bEs(^!Y3M@!4Nu)VbshtY1^;lHYJH1|jGr$6WIXA(VQq1@v590LeF zldCges@S4MgwYJxuuq?TRY`Dv0Fx3|U~$;>z?gOgD)~mwlscaw$R;^N4yyyP4ej=p z&jHMJo76#&2?I8~SCkVZDSvNV@klq>V6FBI0m(zfEC=ht3hCK?oZ6?|BlIE^Op(^+++L! z12)VrFdj$;eo|B7T?(V;an&}Ixv{1$jP;SgV>l$=xO4!w>Ut8`1caBVS2Up9T-E&x zV980IUXwe41q~civ24Ko3NvbP6o~huaQj$_;50&xHx|oj!4ruzfdOMf>rYYKQfv4i zD%F7v@(Y}~Q6Nr~Vu4%bIj1j+ZX?PnwH?)sJH7vWx{p?KgG`kH`Zl{|pUhi3fLqBO zLpW2)4t<=fdEG}rQIe4L9eqr8o9Z#Zd;ZckF7$R#&;&M|hj#@`hxK3o2K*&KBhFYx z1s){$x7QxjV->2iS>7=RNj@Cie8(?gz>A7L7!bw#c5=l4mW{c{t~6vQ4M{67;%YHv zTn4Pz@J?|hB@vRb(TS4MYVp9=<2bUgJp_s8JQjB8XNHO6_y6H z2oDajW?Ghf>8J0v=J?uh^hR>L8kVuD=E7m?Iz_8WXxU?d!R2Ki)2_O_VAa2X(BAF! zz!R9T;gM-tF<{1PxG9aIK*5%0ifbDXLqJy*p2MGbS9JOkox{t`xmUH@%`kY#@Eil; z6m;r17quQZ`Q&!g#srQM-y28da1>*art32QyE-EJOBFlIZ`-veu;FEtl=4&H7QG;W z7bg1d=CJ`RTazDCS!2MqO*FYEPo90=>&8}BfHE_^dfpmY1L$dPJ5tE#h)_|eV$~`j zN}K{qq0R33N8N!P7_s`9(zPiH*7H)FqNL<840%oN`l>EUsDA@idA)#mbOGI=U;27G)S#RRsk z;-AUm8W4SQrqNh|#d#n~=IpHy5e1HWWgeCjcHq1){#j;4O4#nUr_`eYYs1B1oNooT8CH8Q z4ijKd0zGWUubWJMajX=G7hrIzqeN+7JE&4SrR?5;e@U4D1*R>x$~dNCgHKR$n6R4I z7%3PecRLog18sI84g+FHpaKOmFjS=5`oIfb@IH`ZF%|zEh#oDK1vDU<01_B# z!BwU9v8I5xgi;Jyff>VZRDi)6qCEIooUGPda1QD1Jr)yKu>~vbGbsI!RJ(U4zI^|w zt50n|6d|gXu4XVKo528YfEUO!`x?AY+jJ~U%@Gua~8-2R5Gt_0QYK!Hpu<1!hr%)HQ}GL2vZ{~hGa8IIn84d%Wu0eJ&%qwH>P zVmyF2nYdmxNL6c)dNVCsREGfthN5*KHZ|PNCZE8Fl?V(A=|E&!%q*r36ui6RN>-y? zi4)5T9J6g67Qck(N}IP$KB~4bpcE{(A-J7g-4nJvHsRhYQ0-SdYdPvz88850Vwjcz zMfZY%ODycFjJy1`aSYPR@WSY_)7x$8sJo ze|l)zDkv|p{t8>Siw7_IxcqG7^6ySA!#1}Sd|eb^#91Qil&J;f`MFfDo=MaHXI%lM z@f(f15U=kQa4Xg$1(aP;$dMs;N=b?eWeqOHFNvog!nVeX>Y!6`4;dY|lMuE)-$Z|2!Rs*Jl!8Rfg6|CGA z$C5KHngJWOH8N2;1B%BgCK?DMNjY7U-H1f4UI;N8(SQ-J#tuY&v;*T z!bdmYHiGne#Nqyp$9xt34yFTGq5PEudWU9}3DX*I(>dI+QtBx1jpRNihnWG2R~fJk z$@%&48&kwoE)z~rpi&M@4N=M}7umu>H&&~jUUlniC|9CXOq5Dp zfkTwmi(DA5(157Dm{dUr&T&MGkH#^&jzwv57gFJ-Sh)2|t!x1G^py-BLL5)njfGys zYy6D#_$6Xv*oL==T&0eW+_7(G?1*SB&%Jo(aD=8#@9Z=9i4B*^TlIdlvEF)UnlE-& zyXwIZzuJ4{npJYa@Ifjdr@(-tj+i+L28`Q$J%$@KiKSr(kVw-TaGPtwWcLi%Fdjqc zVgqK}TN?O5E3yG)Bgag1q)9&R!+SJq*nkP6Tukq42jX-JruC!)GZ-o=1gOA_Q`Rp+ zfO8Vu5&|?JMx7~NMS-Q_RhmTR%Sz_Qbc$c6A?BzfivcgHNP*Eo4d6B5C}+YU);Wi@ zD2xMO>O`L2r8$X1u=W%=R-lv*MzBPeXP?Hy^Ju`jHJ=exOwkozv4?@N9SV%QBX?ou z3YfVL%!GQJW4VI*U}~e)GG=?(MPJ&mwX(JRQ}1p?Cg8m?HJA!ivH)Skt9s(uiV#*{ z#Aq`0L?t&7X9F_j-3CmXgGLz4=%e3Pl@VS8PVV&_SQ7vVcgfl}9hLzznaJps?cuy2 zrY?K{!Ovm_Vi+*t^-sT@81Vl!P$n{c*#H0^iwFb&00000{{{d;LjnLB00RI300000 G0002!%Vp94 literal 0 HcmV?d00001 diff --git a/man/readSNVVCF.Rd b/man/readSNVVCF.Rd new file mode 100644 index 000000000..781bfee4a --- /dev/null +++ b/man/readSNVVCF.Rd @@ -0,0 +1,58 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tools_internal.R +\encoding{UTF-8} +\name{readSNVVCF} +\alias{readSNVVCF} +\title{Read a VCF file with the genotypes use for the ancestry call} +\usage{ +readSNVVCF(fileName, genome = "hg38", profileName = NULL, offset = 0L) +} +\arguments{ +\item{fileName}{a \code{character} string representing the name, including +the path, of a VCF file containing the SNV read counts. +The VCF must contain those genotype fields: GT, AD, DP.} + +\item{offset}{a \code{integer} representing the offset to be added to the +position of the SNVs. The value of offset +is added to the position present in the file. Default: \code{0L}.} +} +\value{ +a \code{data.frame} containing at least: +\itemize{ +\item{Chromosome}{ a \code{numeric} representing the name of +the chromosome} +\item{Position}{ a \code{numeric} representing the position on the +chromosome} +\item{Ref}{ a \code{character} string representing the reference nucleotide} +\item{Alt}{ a \code{character} string representing the alternative +nucleotide} +\item{File1R} { a \code{numeric} representing the count for +the reference nucleotide} +\item{File1A} { a \code{numeric} representing the count for the +alternative nucleotide} +\item{count} { a \code{numeric} representing the total count} +} +} +\description{ +The function reads VCF file and +returns a data frame +containing the information about the read counts for the SNVs present in +the file. +} +\examples{ + + +## Directory where demo SNP-pileup file +dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") + +## The SNP-pileup file +snpPileupFile <- file.path(dataDir, "ex1.vcf.gz") + +info <- RAIDS:::readSNVVCF(fileName=snpPileupFile) +head(info) + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} From 66580bd5c8921243b439ad621e350994f0e5d64b Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 27 Sep 2023 20:14:15 -0400 Subject: [PATCH 243/385] Replace pedEx.rds with a RData object --- R/RAIDS.R | 145 +++++++++++++++++++++++++++++++- R/processStudy.R | 22 ++--- R/processStudy_internal.R | 27 +++--- data/demoPedigreeEx1.RData | Bin 0 -> 252 bytes inst/extdata/example/pedEx.rds | Bin 188 -> 0 bytes man/computeKNNRefSynthetic.Rd | 2 +- man/demoKnownSuperPop1KG.Rd | 2 +- man/demoPCASyntheticProfiles.Rd | 2 +- man/demoPedigreeEx1.Rd | 138 ++++++++++++++++++++++++++++++ man/runExomeAncestry.Rd | 10 +-- man/runProfileAncestry.Rd | 8 +- man/runRNAAncestry.Rd | 10 +-- man/runWrapperAncestry.Rd | 19 ++--- vignettes/RAIDS.Rmd | 20 ++--- 14 files changed, 327 insertions(+), 78 deletions(-) create mode 100644 data/demoPedigreeEx1.RData delete mode 100644 inst/extdata/example/pedEx.rds create mode 100644 man/demoPedigreeEx1.Rd diff --git a/R/RAIDS.R b/R/RAIDS.R index 8d2db4cf0..34529e684 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -504,7 +504,7 @@ NULL #' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), studyIDSyn=studyID, #' spRef=demoKnownSuperPop1KG) #' -#' ## The inferred ancestry for the synthetic profiles for differents values +#' ## The inferred ancestry for the synthetic profiles for different values #' ## of D and K #' head(results$matKNN) #' @@ -514,8 +514,6 @@ NULL NULL - - #' The known super population ancestry of the demo 1KG reference profiles. #' #' The object is a \code{vector}. @@ -576,7 +574,7 @@ NULL #' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), studyIDSyn=studyID, #' spRef=demoKnownSuperPop1KG) #' -#' ## The inferred ancestry for the synthetic profiles for differents values +#' ## The inferred ancestry for the synthetic profiles for different values #' ## of D and K #' head(results$matKNN) #' @@ -584,3 +582,142 @@ NULL #' closefn.gds(gdsProfile) #' NULL + + +#' The pedigree information about a demo profile called 'ex1'. +#' +#' The object is a \code{data.frame}. +#' +#' This object can be +#' used to test the \code{\link{runExomeAncestry}} function. +#' +#' @name demoPedigreeEx1 +#' +#' @docType data +#' +#' @aliases demoPedigreeEx1 +#' +#' @format The \code{data.frame} containing the information about a demo +#' profile called 'ex1'. the \code{data.frame} has 5 columns: +#' \itemize{ +#' \item{Name.ID}{ a \code{character} string representing the unique +#' identifier of the profile.} +#' \item{Case.ID}{ a \code{character} string representing the unique +#' identifier of the case associated to the profile.} +#' \item{Sample.Type}{ a \code{character} string describing the type of +#' profile.} +#' \item{Diagnosis}{ a \code{character} string describing the diagnosis of the +#' profile.} +#' \item{Source}{ a \code{character} string describing the source of the +#' profile.} +#' } +#' +#' +#' @return The \code{data.frame} containing the information about a demo +#' profile called 'ex1'. the \code{data.frame} has 5 columns: +#' \itemize{ +#' \item{Name.ID}{ a \code{character} string representing the unique +#' identifier of the profile.} +#' \item{Case.ID}{ a \code{character} string representing the unique +#' identifier of the case associated to the profile.} +#' \item{Sample.Type}{ a \code{character} string describing the type of +#' profile.} +#' \item{Diagnosis}{ a \code{character} string describing the diagnosis of the +#' profile.} +#' \item{Source}{ a \code{character} string describing the source of the +#' profile.} +#' } +#' +#' @seealso +#' \itemize{ +#' \item \code{\link{runExomeAncestry}} {for running runs most +#' steps leading to the ancestry inference call on a specific exome +#' profile.} +#' } +#' +#' @usage data(demoPedigreeEx1) +#' +#' @keywords datasets +#' +#' @examples +#' +#' +#' ## Required library for GDS +#' library(SNPRelate) +#' +#' ## Path to the demo 1KG GDS file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ################################################################# +#' ## Load the information about the profile +#' ################################################################# +#' data(demoPedigreeEx1) +#' head(demoPedigreeEx1) +#' +#' ################################################################# +#' ## The 1KG GDS file and the 1KG SNV Annotation GDS file +#' ## need to be located in the same directory +#' ## Note that the 1KG GDS file used for this example is a +#' ## simplified version and CANNOT be used for any real analysis +#' ################################################################# +#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' +#' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") +#' fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +#' +#' ################################################################# +#' ## The Sample SNP pileup files (one per sample) need +#' ## to be located in the same directory. +#' ################################################################# +#' pathGeno <- file.path(dataDir, "example", "snpPileup") +#' +#' ################################################################# +#' ## The path where the Profile GDS Files (one per sample) +#' ## will be created need to be specified. +#' ################################################################# +#' pathProfileGDS <- file.path(tempdir(), "out.tmp") +#' +#' pathOut <- file.path(tempdir(), "res.out") +#' +#' ################################################################# +#' ## A data frame containing general information about the study +#' ## is also required. The data frame must have +#' ## those 3 columns: "studyID", "study.desc", "study.platform" +#' ################################################################# +#' studyDF <- data.frame(study.id="MYDATA", +#' study.desc="Description", +#' study.platform="PLATFORM", +#' stringsAsFactors=FALSE) +#' +#' #################################################################### +#' ## Fix seed to ensure reproducible results +#' #################################################################### +#' set.seed(2043) +#' +#' gds1KG <- snpgdsOpen(fileReferenceGDS) +#' dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +#' closefn.gds(gds1KG) +#' +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' \dontrun{ +#' runExomeAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, +#' pathProfileGDS=pathProfileGDS, +#' pathGeno=pathGeno, pathOut=pathOut, +#' fileReferenceGDS=fileReferenceGDS, +#' fileReferenceAnnotGDS=fileAnnotGDS, +#' chrInfo=chrInfo, syntheticRefDF=dataRef, +#' genoSource="snp-pileup") +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' } +#' } +#' +NULL diff --git a/R/processStudy.R b/R/processStudy.R index f58080ee4..6430ea48e 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -1089,7 +1089,7 @@ computePCARefSample <- function(gdsProfile, currentProfile, #' listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), studyIDSyn=studyID, #' spRef=demoKnownSuperPop1KG) #' -#' ## The inferred ancestry for the synthetic profiles for differents values +#' ## The inferred ancestry for the synthetic profiles for different values #' ## of D and K #' head(results$matKNN) #' @@ -1959,12 +1959,10 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ################################################################# -#' ## The path and file name for the PED RDS file -#' ## will the information about the analyzed samples +#' ## Load the information about the profile #' ################################################################# -#' filePED <- file.path(dataDir, "example", "pedEx.rds") -#' ped <- readRDS(filePED) -#' head(ped) +#' data(demoPedigreeEx1) +#' head(demoPedigreeEx1) #' #' ################################################################# #' ## The 1KG GDS file and the 1KG SNV Annotation GDS file @@ -2020,7 +2018,7 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' #' \dontrun{ #' -#' runExomeAncestry(pedStudy=ped, studyDF=studyDF, +#' runExomeAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, #' pathGeno=pathGeno, #' pathOut=pathOut, @@ -2173,12 +2171,10 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ################################################################# -#' ## The path and file name for the PED RDS file -#' ## will the information about the analyzed samples +#' ## Load the information about the profile #' ################################################################# -#' filePED <- file.path(dataDir, "example", "pedEx.rds") -#' ped <- readRDS(filePED) -#' head(ped) +#' data(demoPedigreeEx1) +#' head(demoPedigreeEx1) #' #' ################################################################# #' ## The 1KG GDS file and the 1KG SNV Annotation GDS file @@ -2234,7 +2230,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' #' \dontrun{ #' -#' runRNAAncestry(pedStudy=ped, studyDF=studyDF, +#' runRNAAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, #' pathGeno=pathGeno, #' pathOut=pathOut, diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 599bf6860..1bee32dee 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2034,12 +2034,10 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ################################################################# -#' ## The path and file name for the PED RDS file -#' ## will the information about the analyzed samples +#' ## Load the information about the profile #' ################################################################# -#' filePED <- file.path(dataDir, "example", "pedEx.rds") -#' ped <- readRDS(filePED) -#' head(ped) +#' data(demoPedigreeEx1) +#' head(demoPedigreeEx1) #' #' ################################################################# #' ## The 1KG GDS file and the 1KG SNV Annotation GDS file @@ -2341,12 +2339,10 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' dataDir <- system.file("extdata", package="RAIDS") #' #' ################################################################# -#' ## The path and file name for the PED RDS file -#' ## will the information about the analyzed samples +#' ## Load the information about the profile #' ################################################################# -#' filePED <- file.path(dataDir, "example", "pedEx.rds") -#' ped <- readRDS(filePED) -#' head(ped) +#' data(demoPedigreeEx1) +#' head(demoPedigreeEx1) #' #' ################################################################# #' ## The 1KG GDS file and the 1KG SNV Annotation GDS file @@ -2402,16 +2398,13 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' #' \dontrun{ #' -#' RAIDS:::runWrapperAncestry(pedStudy=ped, studyDF=studyDF, +#' RAIDS:::runWrapperAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, -#' pathGeno=pathGeno, -#' pathOut=pathOut, +#' pathGeno=pathGeno, pathOut=pathOut, #' fileReferenceGDS=fileReferenceGDS, #' fileReferenceAnnotGDS=fileAnnotGDS, -#' chrInfo=chrInfo, -#' syntheticRefDF=dataRef, -#' studyType="DNA", -#' genoSource="snp-pileup") +#' chrInfo=chrInfo, syntheticRefDF=dataRef, +#' studyType="DNA", genoSource="snp-pileup") #' #' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) #' unlink(pathOut, recursive=TRUE, force=TRUE) diff --git a/data/demoPedigreeEx1.RData b/data/demoPedigreeEx1.RData new file mode 100644 index 0000000000000000000000000000000000000000..3aaf3166fa80a899c0c163744d5305863617c7b0 GIT binary patch literal 252 zcmVvQ&2UKVgRpfklJ zX=^v9WE6OKWtF?;bvpQ;a2#Fke`InKS2V!Ym_@_{B|nBNhGw1W*B$QU<>XF&D$agr9OM?_DAMi<9BU4+H;Ra$rjSSx`t@2;_T z?ypqkvNXu6RhSnnOb2b%iY4Fx0000dAOv0j0oDPA0{{TwRVMI0Fb#_W000000a;q$ C&S-}K literal 0 HcmV?d00001 diff --git a/inst/extdata/example/pedEx.rds b/inst/extdata/example/pedEx.rds deleted file mode 100644 index 59be2b5279981fe30f1de46b917f7b31afe5f45e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188 zcmV;t07L&DiwFP!000001B>8dU|?WoU||B1tUx9MYiNj@t_6@M4B`N>01z`WurP3f z6sA@f5*FeOD9X%DEUHupDb39 Date: Wed, 27 Sep 2023 20:22:13 -0400 Subject: [PATCH 244/385] Update vignette --- vignettes/RAIDS.Rmd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 98edf93ee..02f3873f3 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -342,7 +342,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && syntheticRefDF=dataRef, genoSource="snp-pileup") list.files(pathOut) - list.files(file.path(pathOut, ped$Name.ID[1])) + list.files(file.path(pathOut, demoPedigreeEx1$Name.ID[1])) ######################################################################### ## The file containing the ancestry inference (SuperPop column) and @@ -350,7 +350,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && ## optimal number of neighbours (K column) ######################################################################### resAncestry <- read.csv(file.path(pathOut, - paste0(ped$Name.ID[1], ".Ancestry.csv"))) + paste0(demoPedigreeEx1$Name.ID[1], ".Ancestry.csv"))) print(resAncestry) ## Remove temporary files created for this demo @@ -589,7 +589,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && genoSource="snp-pileup") list.files(pathOut) - list.files(file.path(pathOut, ped$Name.ID[1])) + list.files(file.path(pathOut, demoPedigreeEx1$Name.ID[1])) ######################################################################### ## The file containing the ancestry inference (SuperPop column) and @@ -597,7 +597,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && ## optimal number of neighbours (K column) ######################################################################### resAncestry <- read.csv(file.path(pathOut, - paste0(ped$Name.ID[1], ".Ancestry.csv"))) + paste0(demoPedigreeEx1$Name.ID[1], ".Ancestry.csv"))) print(resAncestry) ## Remove temporary files created for this demo From 279ad515e8956ce77f3886a5dd86914f215a1424 Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 27 Sep 2023 20:26:17 -0400 Subject: [PATCH 245/385] Add to generateGDS1KGgenotypeFromSNPPileup the genoSource VCF --- R/gdsWrapper_internal.R | 19 ++++++++++++++++--- man/generateGDS1KGgenotypeFromSNPPileup.Rd | 6 ++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index f7c8932af..cc5533d16 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -293,13 +293,15 @@ appendGDSgenotypeMat <- function(gds, matG) { #' the directory where the GDS Sample files will be created. #' #' @param genoSource a \code{character} string with two possible values: -#' 'snp-pileup' or 'generic'. It specifies if the genotype files +#' 'snp-pileup', 'generic' or "VCF". It specifies if the genotype files #' are generated by snp-pileup (Facets) or are a generic format CSV file #' with at least those columns: #' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. #' The 'Count' is the depth at the specified position; #' 'FileR' is the depth of the reference allele and #' 'File1A' is the depth of the specific alternative allele. +#' Finally the file file can be VCF file with at least those genotype +#' fields: GT, AD, DP. #' #' @param verbose a \code{logical} indicating if the function must print #' messages when running. @@ -369,8 +371,14 @@ generateGDS1KGgenotypeFromSNPPileup <- function(pathGeno, genoSource, verbose) { # File with the description of the SNP keep - listMat <- dir(pathGeno, pattern = ".+.txt.gz") - listSampleFile <- gsub(".txt.gz", "", listMat) + if(genoSource == "VCF"){ + listMat <- dir(pathGeno, pattern = ".+.vcf.gz") + listSampleFile <- gsub(".vcf.gz", "", listMat) + }else{ + listMat <- dir(pathGeno, pattern = ".+.txt.gz") + listSampleFile <- gsub(".txt.gz", "", listMat) + } + g <- as.matrix(rep(-1, nrow(listPos))) @@ -388,6 +396,11 @@ generateGDS1KGgenotypeFromSNPPileup <- function(pathGeno, } else if(genoSource == "generic") { matSample <- readSNVFileGeneric(file.path(pathGeno, listMat[pos]), offset) + } else if(genoSource == "VCF") { + tmpProfile <- gsub(".vcf.gz", "",listMat[pos]) + matSample <- readSNVVCF(file.path(pathGeno, + listMat[pos]), + profileName=tmpProfile, offset) } # matAll <- merge(matSample[,c( "Chromosome", "Position", # "File1R", "File1A", diff --git a/man/generateGDS1KGgenotypeFromSNPPileup.Rd b/man/generateGDS1KGgenotypeFromSNPPileup.Rd index 9053724b8..998d5fbaf 100644 --- a/man/generateGDS1KGgenotypeFromSNPPileup.Rd +++ b/man/generateGDS1KGgenotypeFromSNPPileup.Rd @@ -70,13 +70,15 @@ must be in \code{character} strings.} the directory where the GDS Sample files will be created.} \item{genoSource}{a \code{character} string with two possible values: -'snp-pileup' or 'generic'. It specifies if the genotype files +'snp-pileup', 'generic' or "VCF". It specifies if the genotype files are generated by snp-pileup (Facets) or are a generic format CSV file with at least those columns: 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. The 'Count' is the depth at the specified position; 'FileR' is the depth of the reference allele and -'File1A' is the depth of the specific alternative allele.} +'File1A' is the depth of the specific alternative allele. +Finally the file file can be VCF file with at least those genotype +fields: GT, AD, DP.} \item{verbose}{a \code{logical} indicating if the function must print messages when running.} From 9ed5a91739a495c93b2cd808078680179d782136 Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 27 Sep 2023 20:40:36 -0400 Subject: [PATCH 246/385] Add to createStudy2GDS1KG the genoSource VCF --- R/gdsWrapper_internal.R | 4 ++-- R/processStudy.R | 6 ++++-- man/createStudy2GDS1KG.Rd | 8 +++++--- man/generateGDS1KGgenotypeFromSNPPileup.Rd | 4 ++-- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 8924a2d2b..99eec9113 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -293,14 +293,14 @@ appendGDSgenotypeMat <- function(gds, matG) { #' the directory where the GDS Sample files will be created. #' #' @param genoSource a \code{character} string with two possible values: -#' 'snp-pileup', 'generic' or "VCF". It specifies if the genotype files +#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files #' are generated by snp-pileup (Facets) or are a generic format CSV file #' with at least those columns: #' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. #' The 'Count' is the depth at the specified position; #' 'FileR' is the depth of the reference allele and #' 'File1A' is the depth of the specific alternative allele. -#' Finally the file file can be VCF file with at least those genotype +#' Finally the file can be a VCF file with at least those genotype #' fields: GT, AD, DP. #' #' @param verbose a \code{logical} indicating if the function must print diff --git a/R/processStudy.R b/R/processStudy.R index f58080ee4..1aaf897c3 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -54,13 +54,15 @@ #' Default: \code{NULL}. #' #' @param genoSource a \code{character} string with two possible values: -#' 'snp-pileup' or 'generic'. It specifies if the genotype files +#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files #' are generated by snp-pileup (Facets) or are a generic format CSV file #' with at least those columns: #' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. #' The 'Count' is the depth at the specified position; #' 'FileR' is the depth of the reference allele and #' 'File1A' is the depth of the specific alternative allele. +#' Finally the file can be a VCF file with at least those genotype +#' fields: GT, AD, DP. #' #' @param verbose a \code{logical} indicating if message information should be #' printed. Default: \code{FALSE}. @@ -121,7 +123,7 @@ createStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), filePedRDS=NULL, pedStudy=NULL, fileNameGDS, batch=1, studyDF, listProfiles=NULL, pathProfileGDS=NULL, - genoSource=c("snp-pileup", "generic"), + genoSource=c("snp-pileup", "generic", "VCF"), verbose=FALSE) { ## When filePedRDS is defined and pedStudy is null diff --git a/man/createStudy2GDS1KG.Rd b/man/createStudy2GDS1KG.Rd index 83d9c1f94..1b8647ac7 100644 --- a/man/createStudy2GDS1KG.Rd +++ b/man/createStudy2GDS1KG.Rd @@ -16,7 +16,7 @@ createStudy2GDS1KG( studyDF, listProfiles = NULL, pathProfileGDS = NULL, - genoSource = c("snp-pileup", "generic"), + genoSource = c("snp-pileup", "generic", "VCF"), verbose = FALSE ) } @@ -68,13 +68,15 @@ the directory where the Profile GDS files will be created. Default: \code{NULL}.} \item{genoSource}{a \code{character} string with two possible values: -'snp-pileup' or 'generic'. It specifies if the genotype files +'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files are generated by snp-pileup (Facets) or are a generic format CSV file with at least those columns: 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. The 'Count' is the depth at the specified position; 'FileR' is the depth of the reference allele and -'File1A' is the depth of the specific alternative allele.} +'File1A' is the depth of the specific alternative allele. +Finally the file can be a VCF file with at least those genotype +fields: GT, AD, DP.} \item{verbose}{a \code{logical} indicating if message information should be printed. Default: \code{FALSE}.} diff --git a/man/generateGDS1KGgenotypeFromSNPPileup.Rd b/man/generateGDS1KGgenotypeFromSNPPileup.Rd index 998d5fbaf..b60489397 100644 --- a/man/generateGDS1KGgenotypeFromSNPPileup.Rd +++ b/man/generateGDS1KGgenotypeFromSNPPileup.Rd @@ -70,14 +70,14 @@ must be in \code{character} strings.} the directory where the GDS Sample files will be created.} \item{genoSource}{a \code{character} string with two possible values: -'snp-pileup', 'generic' or "VCF". It specifies if the genotype files +'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files are generated by snp-pileup (Facets) or are a generic format CSV file with at least those columns: 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. The 'Count' is the depth at the specified position; 'FileR' is the depth of the reference allele and 'File1A' is the depth of the specific alternative allele. -Finally the file file can be VCF file with at least those genotype +Finally the file can be a VCF file with at least those genotype fields: GT, AD, DP.} \item{verbose}{a \code{logical} indicating if the function must print From 30d592e325733acce1bb091c3f46c93411a99d9a Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 27 Sep 2023 22:15:45 -0400 Subject: [PATCH 247/385] Add to runWrapperAncestry the genoSource VCF --- R/processStudy_internal.R | 20 +++++++++++--------- man/runWrapperAncestry.Rd | 20 +++++++++++--------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 599bf6860..27de7abd1 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2287,14 +2287,16 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' The possible choices are: "DNA" and "RNA". The type of study affects the #' way the estimation of the allelic fraction is done. Default: \code{"DNA"}. #' -#' @param genoSource a \code{stirng} with two possible values: -#' snp-pileup and generic. It specifies if the genotype files -#' have been generated by snp-pileup (Facets) or are in a generic format csv -#' with at least the columns: -#' Chromosome,Position,Ref,Alt,Count,File1R,File1A -#' where Count is the deep at the position, -#' FileR is the deep of the reference allele, and -#' File1A is the deep of the specific alternative allele +#' @param genoSource a \code{character} string with two possible values: +#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +#' are generated by snp-pileup (Facets) or are a generic format CSV file +#' with at least those columns: +#' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +#' The 'Count' is the depth at the specified position; +#' 'FileR' is the depth of the reference allele and +#' 'File1A' is the depth of the specific alternative allele. +#' Finally the file can be a VCF file with at least those genotype +#' fields: GT, AD, DP. #' #' @param np a single positive \code{integer} specifying the number of #' threads to be used. Default: \code{1L}. @@ -2426,7 +2428,7 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' @keywords internal runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, genoSource=c("snp-pileup", "generic"), + chrInfo, syntheticRefDF, genoSource=c("snp-pileup", "generic", "VCF"), studyType=c("DNA", "RNA"), np=1L, blockTypeID=NULL, verbose=FALSE) { diff --git a/man/runWrapperAncestry.Rd b/man/runWrapperAncestry.Rd index f2b49db29..7cd17c151 100644 --- a/man/runWrapperAncestry.Rd +++ b/man/runWrapperAncestry.Rd @@ -16,7 +16,7 @@ runWrapperAncestry( fileReferenceAnnotGDS, chrInfo, syntheticRefDF, - genoSource = c("snp-pileup", "generic"), + genoSource = c("snp-pileup", "generic", "VCF"), studyType = c("DNA", "RNA"), np = 1L, blockTypeID = NULL, @@ -70,14 +70,16 @@ subcontinental population assigned to the sample. } super-population assigned to the sample. } }} -\item{genoSource}{a \code{stirng} with two possible values: -snp-pileup and generic. It specifies if the genotype files -have been generated by snp-pileup (Facets) or are in a generic format csv -with at least the columns: -Chromosome,Position,Ref,Alt,Count,File1R,File1A -where Count is the deep at the position, -FileR is the deep of the reference allele, and -File1A is the deep of the specific alternative allele} +\item{genoSource}{a \code{character} string with two possible values: +'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +are generated by snp-pileup (Facets) or are a generic format CSV file +with at least those columns: +'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +The 'Count' is the depth at the specified position; +'FileR' is the depth of the reference allele and +'File1A' is the depth of the specific alternative allele. +Finally the file can be a VCF file with at least those genotype +fields: GT, AD, DP.} \item{studyType}{a \code{character} string representing the type of study. The possible choices are: "DNA" and "RNA". The type of study affects the From 697c5f4d0a55ad936fe886cf163b35700cd29aec Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 27 Sep 2023 22:41:52 -0400 Subject: [PATCH 248/385] Add to runExomeAncestry and runRNAAncestry the genoSource VCF --- R/processStudy.R | 40 ++++++++++++++++++++++------------------ man/runExomeAncestry.Rd | 20 +++++++++++--------- man/runRNAAncestry.Rd | 20 +++++++++++--------- 3 files changed, 44 insertions(+), 36 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 1aaf897c3..6badaeed4 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -1911,14 +1911,16 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' super-population assigned to the sample. } #' } #' -#' @param genoSource a \code{stirng} with two possible values: -#' snp-pileup and generic. It specify if the genotype files -#' are generate by snp-pileup(Facets) or generic format csv -#' with the column at least the columns: -#' Chromosome,Position,Ref,Alt,Count,File1R,File1A -#' where Count is the deep at the position, -#' FileR is the deep of the reference allele, and -#' File1A is the deep of the specific alternative allele +#' @param genoSource a \code{character} string with two possible values: +#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +#' are generated by snp-pileup (Facets) or are a generic format CSV file +#' with at least those columns: +#' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +#' The 'Count' is the depth at the specified position; +#' 'FileR' is the depth of the reference allele and +#' 'File1A' is the depth of the specific alternative allele. +#' Finally the file can be a VCF file with at least those genotype +#' fields: GT, AD, DP. #' #' @param np a single positive \code{integer} specifying the number of #' threads to be used. Default: \code{1L}. @@ -2045,7 +2047,7 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic"), np=1L, + genoSource=c("snp-pileup", "generic", "VCF"), np=1L, verbose=FALSE) { ## Validate parameters @@ -2121,14 +2123,16 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' super-population assigned to the sample. } #' } #' -#' @param genoSource a \code{stirng} with two possible values: -#' snp-pileup and generic. It specify if the genotype files -#' are generate by snp-pileup(Facets) or generic format csv -#' with the column at least the columns: -#' Chromosome,Position,Ref,Alt,Count,File1R,File1A -#' where Count is the deep at the position, -#' FileR is the deep of the reference allele, and -#' File1A is the deep of the specific alternative allele +#' @param genoSource a \code{character} string with two possible values: +#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +#' are generated by snp-pileup (Facets) or are a generic format CSV file +#' with at least those columns: +#' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +#' The 'Count' is the depth at the specified position; +#' 'FileR' is the depth of the reference allele and +#' 'File1A' is the depth of the specific alternative allele. +#' Finally the file can be a VCF file with at least those genotype +#' fields: GT, AD, DP. #' #' @param np a single positive \code{integer} specifying the number of #' threads to be used. Default: \code{1L}. @@ -2261,7 +2265,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic"), np=1L, + genoSource=c("snp-pileup", "generic", "VCF"), np=1L, blockTypeID, verbose=FALSE) { ## Validate parameters diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index d9363540a..2bfb4771a 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -16,7 +16,7 @@ runExomeAncestry( fileReferenceAnnotGDS, chrInfo, syntheticRefDF, - genoSource = c("snp-pileup", "generic"), + genoSource = c("snp-pileup", "generic", "VCF"), np = 1L, verbose = FALSE ) @@ -69,14 +69,16 @@ subcontinental population assigned to the sample. } super-population assigned to the sample. } }} -\item{genoSource}{a \code{stirng} with two possible values: -snp-pileup and generic. It specify if the genotype files -are generate by snp-pileup(Facets) or generic format csv -with the column at least the columns: -Chromosome,Position,Ref,Alt,Count,File1R,File1A -where Count is the deep at the position, -FileR is the deep of the reference allele, and -File1A is the deep of the specific alternative allele} +\item{genoSource}{a \code{character} string with two possible values: +'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +are generated by snp-pileup (Facets) or are a generic format CSV file +with at least those columns: +'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +The 'Count' is the depth at the specified position; +'FileR' is the depth of the reference allele and +'File1A' is the depth of the specific alternative allele. +Finally the file can be a VCF file with at least those genotype +fields: GT, AD, DP.} \item{np}{a single positive \code{integer} specifying the number of threads to be used. Default: \code{1L}.} diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index 518836e3d..8b374fe96 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -16,7 +16,7 @@ runRNAAncestry( fileReferenceAnnotGDS, chrInfo, syntheticRefDF, - genoSource = c("snp-pileup", "generic"), + genoSource = c("snp-pileup", "generic", "VCF"), np = 1L, blockTypeID, verbose = FALSE @@ -70,14 +70,16 @@ subcontinental population assigned to the sample. } super-population assigned to the sample. } }} -\item{genoSource}{a \code{stirng} with two possible values: -snp-pileup and generic. It specify if the genotype files -are generate by snp-pileup(Facets) or generic format csv -with the column at least the columns: -Chromosome,Position,Ref,Alt,Count,File1R,File1A -where Count is the deep at the position, -FileR is the deep of the reference allele, and -File1A is the deep of the specific alternative allele} +\item{genoSource}{a \code{character} string with two possible values: +'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +are generated by snp-pileup (Facets) or are a generic format CSV file +with at least those columns: +'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +The 'Count' is the depth at the specified position; +'FileR' is the depth of the reference allele and +'File1A' is the depth of the specific alternative allele. +Finally the file can be a VCF file with at least those genotype +fields: GT, AD, DP.} \item{np}{a single positive \code{integer} specifying the number of threads to be used. Default: \code{1L}.} From ccea700ad8e4218f4af232a7421f89edd5fa18f9 Mon Sep 17 00:00:00 2001 From: belleau Date: Thu, 28 Sep 2023 17:20:27 -0400 Subject: [PATCH 249/385] Update the vignette Create_Reference_GDS_File --- vignettes/Create_Reference_GDS_File.Rmd | 34 ++++++++++++++++++++----- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 0d764246c..656590a2a 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -66,10 +66,10 @@ also used to generate the PCA on which the samples of interest are going to be projected. The *Population Reference GDS file* is a GDS object of class -[SNPGDSFileClass](https://www.bioconductor.org/packages/release/bioc/vignettes/SNPRelate/inst/doc/SNPRelate.html#data-formats-used-in-snprelate) from [SNPRelate](https://www.bioconductor.org/packages/release/bioc/html/SNPRelate.html) +[SNPGDSFileClass](https://www.bioconductor.org/packages/release/bioc/vignettes/) from [SNPRelate](https://www.bioconductor.org/packages/release/bioc/html/SNPRelate.html) package [@Zheng2012]. -Beware that only unrelated samples should be present in the GDS files. +Beware that related profiles should be flagged in the *Population Reference GDS file* files. ```{r runRefGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# @@ -121,11 +121,25 @@ The mandatory fields are:
This following example shows how to create a *Population GDS Reference file*. -This example is for demonstration purpose only. A working -*Population GDS Reference file* would have to contain multiple samples from +This example is for demonstration purpose only and use hard coded values. +A working *Population GDS Reference file* would have to contain multiple +samples from each continental population and would also have to contain the SNVs from the entire genome. +To generate a real *Population GDS Reference file*, the pipeline to process +the information would depend of the selected source. +If the source files are in VCF format, you can use Bioconductor +[VariationAnnotation](https://bioconductor.org/packages/release/bioc/html/VariantAnnotation.html) +package to extract the genotypic information (beware it may use a lot of +memory). +Often, you will need to parse metadata files to get information such as the +sex and population of the profiles. In addition, the Bioconductor +[GENESIS](https://bioconductor.org/packages/release/bioc/html/GENESIS.html) +package can +be used to compute kinship coefficients to identify the unrelated profiles. + + ```{r createRefGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# ## Load required packages @@ -270,8 +284,16 @@ unlink(fileNewReferenceGDS, force=TRUE) The *Population Reference Annotation GDS file* contains phase information and block group information for all the SNVs present in -*Population Reference GDS file*. A block can be a linkage disequelibrium block -relative to a population or a gene. +*Population Reference GDS file*. +If the source files are in VCF format, you can use Bioconductor +[VariationAnnotation](https://bioconductor.org/packages/release/bioc/html/VariantAnnotation.html) +package to extract the phase information (beware it may use a lot of +memory). +A block can be a linkage disequelibrium block +relative to a population or a gene. A bioconductor package like +[GENESIS](https://bioconductor.org/packages/release/bioc/html/GENESIS.html) +can be used to get the block information. + ```{r runRefAnnotGDS, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# From 91eaa507012f3702f664810c8bff38ae07434185 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 28 Sep 2023 20:51:28 -0400 Subject: [PATCH 250/385] Tar vcf chromosome files and adapt doc accordingly --- R/tools.R | 34 ++++++++++++------ .../demoGenoChr/chr1/NA12003.chr1.vcf.bz2 | Bin 69 -> 0 bytes .../demoGenoChr/chr1/NA12004.chr1.vcf.bz2 | Bin 79 -> 0 bytes .../demoGenoChr/chr1/NA12005.chr1.vcf.bz2 | Bin 80 -> 0 bytes .../demoGenoChr/chr10/NA12003.chr10.vcf.bz2 | Bin 73 -> 0 bytes .../demoGenoChr/chr10/NA12004.chr10.vcf.bz2 | Bin 75 -> 0 bytes .../demoGenoChr/chr10/NA12005.chr10.vcf.bz2 | Bin 74 -> 0 bytes .../demoGenoChr/chr11/NA12003.chr11.vcf.bz2 | Bin 73 -> 0 bytes .../demoGenoChr/chr11/NA12004.chr11.vcf.bz2 | Bin 81 -> 0 bytes .../demoGenoChr/chr11/NA12005.chr11.vcf.bz2 | Bin 69 -> 0 bytes .../demoGenoChr/chr12/NA12003.chr12.vcf.bz2 | Bin 61 -> 0 bytes .../demoGenoChr/chr12/NA12004.chr12.vcf.bz2 | Bin 66 -> 0 bytes .../demoGenoChr/chr12/NA12005.chr12.vcf.bz2 | Bin 65 -> 0 bytes .../demoGenoChr/chr13/NA12003.chr13.vcf.bz2 | Bin 73 -> 0 bytes .../demoGenoChr/chr13/NA12004.chr13.vcf.bz2 | Bin 74 -> 0 bytes .../demoGenoChr/chr13/NA12005.chr13.vcf.bz2 | Bin 72 -> 0 bytes .../demoGenoChr/chr14/NA12003.chr14.vcf.bz2 | Bin 61 -> 0 bytes .../demoGenoChr/chr14/NA12004.chr14.vcf.bz2 | Bin 61 -> 0 bytes .../demoGenoChr/chr14/NA12005.chr14.vcf.bz2 | Bin 61 -> 0 bytes .../demoGenoChr/chr15/NA12003.chr15.vcf.bz2 | Bin 73 -> 0 bytes .../demoGenoChr/chr15/NA12004.chr15.vcf.bz2 | Bin 65 -> 0 bytes .../demoGenoChr/chr15/NA12005.chr15.vcf.bz2 | Bin 68 -> 0 bytes .../demoGenoChr/chr16/NA12003.chr16.vcf.bz2 | Bin 64 -> 0 bytes .../demoGenoChr/chr16/NA12004.chr16.vcf.bz2 | Bin 70 -> 0 bytes .../demoGenoChr/chr16/NA12005.chr16.vcf.bz2 | Bin 62 -> 0 bytes .../demoGenoChr/chr17/NA12003.chr17.vcf.bz2 | Bin 60 -> 0 bytes .../demoGenoChr/chr17/NA12004.chr17.vcf.bz2 | Bin 64 -> 0 bytes .../demoGenoChr/chr17/NA12005.chr17.vcf.bz2 | Bin 68 -> 0 bytes .../demoGenoChr/chr18/NA12003.chr18.vcf.bz2 | Bin 60 -> 0 bytes .../demoGenoChr/chr18/NA12004.chr18.vcf.bz2 | Bin 62 -> 0 bytes .../demoGenoChr/chr18/NA12005.chr18.vcf.bz2 | Bin 61 -> 0 bytes .../demoGenoChr/chr19/NA12003.chr19.vcf.bz2 | Bin 74 -> 0 bytes .../demoGenoChr/chr19/NA12004.chr19.vcf.bz2 | Bin 61 -> 0 bytes .../demoGenoChr/chr19/NA12005.chr19.vcf.bz2 | Bin 63 -> 0 bytes .../demoGenoChr/chr2/NA12003.chr2.vcf.bz2 | Bin 61 -> 0 bytes .../demoGenoChr/chr2/NA12004.chr2.vcf.bz2 | Bin 61 -> 0 bytes .../demoGenoChr/chr2/NA12005.chr2.vcf.bz2 | Bin 61 -> 0 bytes .../demoGenoChr/chr20/NA12003.chr20.vcf.bz2 | Bin 64 -> 0 bytes .../demoGenoChr/chr20/NA12004.chr20.vcf.bz2 | Bin 65 -> 0 bytes .../demoGenoChr/chr20/NA12005.chr20.vcf.bz2 | Bin 60 -> 0 bytes .../demoGenoChr/chr21/NA12003.chr21.vcf.bz2 | Bin 72 -> 0 bytes .../demoGenoChr/chr21/NA12004.chr21.vcf.bz2 | Bin 71 -> 0 bytes .../demoGenoChr/chr21/NA12005.chr21.vcf.bz2 | Bin 65 -> 0 bytes .../demoGenoChr/chr22/NA12003.chr22.vcf.bz2 | Bin 77 -> 0 bytes .../demoGenoChr/chr22/NA12004.chr22.vcf.bz2 | Bin 61 -> 0 bytes .../demoGenoChr/chr22/NA12005.chr22.vcf.bz2 | Bin 79 -> 0 bytes .../demoGenoChr/chr3/NA12003.chr3.vcf.bz2 | Bin 74 -> 0 bytes .../demoGenoChr/chr3/NA12004.chr3.vcf.bz2 | Bin 71 -> 0 bytes .../demoGenoChr/chr3/NA12005.chr3.vcf.bz2 | Bin 76 -> 0 bytes .../demoGenoChr/chr4/NA12003.chr4.vcf.bz2 | Bin 64 -> 0 bytes .../demoGenoChr/chr4/NA12004.chr4.vcf.bz2 | Bin 68 -> 0 bytes .../demoGenoChr/chr4/NA12005.chr4.vcf.bz2 | Bin 69 -> 0 bytes .../demoGenoChr/chr5/NA12003.chr5.vcf.bz2 | Bin 71 -> 0 bytes .../demoGenoChr/chr5/NA12004.chr5.vcf.bz2 | Bin 69 -> 0 bytes .../demoGenoChr/chr5/NA12005.chr5.vcf.bz2 | Bin 71 -> 0 bytes .../demoGenoChr/chr6/NA12003.chr6.vcf.bz2 | Bin 72 -> 0 bytes .../demoGenoChr/chr6/NA12004.chr6.vcf.bz2 | Bin 70 -> 0 bytes .../demoGenoChr/chr6/NA12005.chr6.vcf.bz2 | Bin 69 -> 0 bytes .../demoGenoChr/chr7/NA12003.chr7.vcf.bz2 | Bin 70 -> 0 bytes .../demoGenoChr/chr7/NA12004.chr7.vcf.bz2 | Bin 69 -> 0 bytes .../demoGenoChr/chr7/NA12005.chr7.vcf.bz2 | Bin 72 -> 0 bytes .../demoGenoChr/chr8/NA12003.chr8.vcf.bz2 | Bin 77 -> 0 bytes .../demoGenoChr/chr8/NA12004.chr8.vcf.bz2 | Bin 75 -> 0 bytes .../demoGenoChr/chr8/NA12005.chr8.vcf.bz2 | Bin 78 -> 0 bytes .../demoGenoChr/chr9/NA12003.chr9.vcf.bz2 | Bin 62 -> 0 bytes .../demoGenoChr/chr9/NA12004.chr9.vcf.bz2 | Bin 68 -> 0 bytes .../demoGenoChr/chr9/NA12005.chr9.vcf.bz2 | Bin 67 -> 0 bytes inst/extdata/demoGenoChr/demoGenoChr.tar | Bin 0 -> 3732 bytes man/groupChr1KGSNV.Rd | 34 ++++++++++++------ 69 files changed, 46 insertions(+), 22 deletions(-) delete mode 100644 inst/extdata/demoGenoChr/chr1/NA12003.chr1.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr1/NA12004.chr1.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr1/NA12005.chr1.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr10/NA12003.chr10.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr10/NA12004.chr10.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr10/NA12005.chr10.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr11/NA12003.chr11.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr11/NA12004.chr11.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr11/NA12005.chr11.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr12/NA12003.chr12.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr12/NA12004.chr12.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr12/NA12005.chr12.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr13/NA12003.chr13.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr13/NA12004.chr13.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr13/NA12005.chr13.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr14/NA12003.chr14.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr14/NA12004.chr14.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr14/NA12005.chr14.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr15/NA12003.chr15.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr15/NA12004.chr15.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr15/NA12005.chr15.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr16/NA12003.chr16.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr16/NA12004.chr16.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr16/NA12005.chr16.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr17/NA12003.chr17.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr17/NA12004.chr17.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr17/NA12005.chr17.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr18/NA12003.chr18.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr18/NA12004.chr18.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr18/NA12005.chr18.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr19/NA12003.chr19.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr19/NA12004.chr19.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr19/NA12005.chr19.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr2/NA12003.chr2.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr2/NA12004.chr2.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr2/NA12005.chr2.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr20/NA12003.chr20.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr20/NA12004.chr20.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr20/NA12005.chr20.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr21/NA12003.chr21.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr21/NA12004.chr21.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr21/NA12005.chr21.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr22/NA12003.chr22.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr22/NA12004.chr22.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr22/NA12005.chr22.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr3/NA12003.chr3.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr3/NA12004.chr3.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr3/NA12005.chr3.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr4/NA12003.chr4.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr4/NA12004.chr4.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr4/NA12005.chr4.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr5/NA12003.chr5.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr5/NA12004.chr5.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr5/NA12005.chr5.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr6/NA12003.chr6.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr6/NA12004.chr6.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr6/NA12005.chr6.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr7/NA12003.chr7.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr7/NA12004.chr7.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr7/NA12005.chr7.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr8/NA12003.chr8.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr8/NA12004.chr8.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr8/NA12005.chr8.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr9/NA12003.chr9.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr9/NA12004.chr9.vcf.bz2 delete mode 100644 inst/extdata/demoGenoChr/chr9/NA12005.chr9.vcf.bz2 create mode 100644 inst/extdata/demoGenoChr/demoGenoChr.tar diff --git a/R/tools.R b/R/tools.R index 90f546264..3ed733651 100644 --- a/R/tools.R +++ b/R/tools.R @@ -160,27 +160,39 @@ snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { #' #' ## Path to the demo vcf files in this package #' dataDir <- system.file("extdata", package="RAIDS") -#' pathGeno <- file.path(dataDir, "demoGenoChr") +#' pathGenoTar <- file.path(dataDir, "demoGenoChr", "demoGenoChr.tar") #' -#' ## Path where the output vcf file will be created -#' pathOut <- tempdir() +#' ## Path where the chromosomes files will be located +#' pathGeno <- file.path(tempdir(), "tempGeno") +#' dir.create(pathGeno, showWarnings=FALSE) +#' +#' ## Untar the file that contains the VCF files for 3 samples split by +#' ## chromosome (one directory per chromosome) +#' untar(tarfile=pathGenoTar, exdir=pathGeno) +#' +#' ## Path where the output VCF file will be created is +#' ## the same where the split VCF are (pathGeno) #' #' ## The files must not exist -#' if (!file.exists(file.path(tempdir(), "NA12003.csv.bz2")) && -#' !file.exists(file.path(tempdir(), "NA12004.csv.bz2")) && -#' !file.exists(file.path(tempdir(), "NA12005.csv.bz2"))) { +#' if (!file.exists(file.path(pathGeno, "NA12003.csv.bz2")) && +#' !file.exists(file.path(pathGeno, "NA12004.csv.bz2")) && +#' !file.exists(file.path(pathGeno, "NA12005.csv.bz2"))) { #' #' ## Return 0 when successful #' ## The files "NA12003.csv.bz2", "NA12004.csv.bz2" and #' ## "NA12005.csv.bz2" should not be present in the current directory -#' groupChr1KGSNV(pathGenoChr=pathGeno, pathOut=pathOut) +#' groupChr1KGSNV(pathGenoChr=pathGeno, pathOut=pathGeno) +#' +#' ## Validate that files have been created +#' file.exists(file.path(pathGeno, "NA12003.csv.bz2")) +#' file.exists(file.path(pathGeno, "NA12004.csv.bz2")) +#' file.exists(file.path(pathGeno, "NA12005.csv.bz2")) #' -#' ## Remove temporary VCF file -#' unlink(file.path(tempdir(), "NA12003.csv.bz2"), force=TRUE) -#' unlink(file.path(tempdir(), "NA12004.csv.bz2"), force=TRUE) -#' unlink(file.path(tempdir(), "NA12005.csv.bz2"), force=TRUE) #' } #' +#' ## Remove temporary directory +#' unlink(pathGeno, recursive=TRUE, force=TRUE) +#' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom utils write.csv2 read.csv2 #' @encoding UTF-8 diff --git a/inst/extdata/demoGenoChr/chr1/NA12003.chr1.vcf.bz2 b/inst/extdata/demoGenoChr/chr1/NA12003.chr1.vcf.bz2 deleted file mode 100644 index 5a9e113810de19334e580365ec025e181925c408..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69 zcmZ>Y%CIzaj8qGb{J2I=kAY!^PXmKM1%m=31B(Jfh>9f;T4*^jL0KkKSzS_OjQ{|cOn?9obO0a$00bZaa6f diff --git a/inst/extdata/demoGenoChr/chr1/NA12005.chr1.vcf.bz2 b/inst/extdata/demoGenoChr/chr1/NA12005.chr1.vcf.bz2 deleted file mode 100644 index 09d7ec7534134ae459194b24659bdc3717a0e7ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80 zcmV-W0I&Z-T4*^jL0KkKS>2*a4FCX`On?9oasVI!00bZaa6YT diff --git a/inst/extdata/demoGenoChr/chr10/NA12003.chr10.vcf.bz2 b/inst/extdata/demoGenoChr/chr10/NA12003.chr10.vcf.bz2 deleted file mode 100644 index 9559377f6710765ffd26bfe949aa666a92d00630..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73 zcmV-P0Ji@^T4*^jL0KkKSxG%zF#rIVOn?9ocmN;)00bZaP=*8uQ4>iVgjz$8WE8$t fPUk^WL+oDj+q$brQUxf|#rV6DDZ+$;N$Tl{280^O diff --git a/inst/extdata/demoGenoChr/chr10/NA12004.chr10.vcf.bz2 b/inst/extdata/demoGenoChr/chr10/NA12004.chr10.vcf.bz2 deleted file mode 100644 index 9d57ad3073ba252e7c4f328476b61cb0061f2e0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75 zcmV-R0JQ%?T4*^jL0KkKS-<#`ZU6w7On?9obO0a$00bZaP=*8uQZ+Qp4$GA&6-rS` h(iEN%P0bNbA@(7?_b^c8pv4d3?ntK!5*PmxZNPY%CIzaj8qGbl%FIV&A>3jr-4DBh(UpofklBKppAti$kgOaz?(LY0Fy>Y%CIzaj8qGbTvRya2m`|mp9Thj3I+v61{MW|fHoG6AXAgWa)(m10z?>H^&5kW dLxa1&v3Uzr$C+Fldgh=iY|{eI{++J7_k5V diff --git a/inst/extdata/demoGenoChr/chr11/NA12004.chr11.vcf.bz2 b/inst/extdata/demoGenoChr/chr11/NA12004.chr11.vcf.bz2 deleted file mode 100644 index 5a88d80958f1618b8d595be2bfe7c13e8374708d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81 zcmZ>Y%CIzaj8qGb{H8tcG6Ta5p9Thj5(WiE1{MW|BB`obJR(zieJu~=%zNB3JM6-( lX!R@0D{loK{N23o?{oGZ-bJ^zNqaC&5ifGJ2$%pe0sz0}A)WvL diff --git a/inst/extdata/demoGenoChr/chr11/NA12005.chr11.vcf.bz2 b/inst/extdata/demoGenoChr/chr11/NA12005.chr11.vcf.bz2 deleted file mode 100644 index 6055efe7dedad2e472568eff91e757ba3215649b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69 zcmZ>Y%CIzaj8qGbG%XIf%D^zgr-4DBh(UpofklBK#H@pn%ONcwsFmyT4sivWt~uwl ZmNh3u)&@9eN!RH;=_**Lko9ckDgd+27YhIY diff --git a/inst/extdata/demoGenoChr/chr12/NA12003.chr12.vcf.bz2 b/inst/extdata/demoGenoChr/chr12/NA12003.chr12.vcf.bz2 deleted file mode 100644 index 57cf24de4e2223a95bf0c15d1819d26400d975a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61 zcmZ>Y%CIzaj8qGbTx)mKk%3``PXmKM1%m=31B(KKArA*vsNu>v7q)+L57->(bpPkM QXDi~wi(D-NCV-R!07ZKh-T(jq diff --git a/inst/extdata/demoGenoChr/chr12/NA12004.chr12.vcf.bz2 b/inst/extdata/demoGenoChr/chr12/NA12004.chr12.vcf.bz2 deleted file mode 100644 index 6fdeed51dbb452c70e6cf581a440fabdf0127139..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66 zcmV-I0KNZ0T4*^jL0KkKS>Z%McmM#HOn?9obO0a$00bZaR5qZ<3Q9n8k(!N&*jpX% YrB6BK3#BIWut^>+~+5i9m diff --git a/inst/extdata/demoGenoChr/chr12/NA12005.chr12.vcf.bz2 b/inst/extdata/demoGenoChr/chr12/NA12005.chr12.vcf.bz2 deleted file mode 100644 index 418994f9c096793d4a2f7b16d827a14ff486f95c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65 zcmZ>Y%CIzaj8qGbJS2Chgn?m(PXmKM5rYCF1B(JfKpP83SBh?tYL^hh39iaevsVot VtarX$#r&~cCAgK7NAZoi0|0h)6!!oC diff --git a/inst/extdata/demoGenoChr/chr13/NA12003.chr13.vcf.bz2 b/inst/extdata/demoGenoChr/chr13/NA12003.chr13.vcf.bz2 deleted file mode 100644 index f0ff41dd323a335decb81dfe41db387ba443b317..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73 zcmV-P0Ji@^T4*^jL0KkKSz{m+(EtFLOn?9ocmN;)00bZaP=*8uQZ+Qp5`?7+QKUO$ f1p(kx+|&W${f774#Yd6>NPaHlig2MI#y}~eAL|+1 diff --git a/inst/extdata/demoGenoChr/chr13/NA12004.chr13.vcf.bz2 b/inst/extdata/demoGenoChr/chr13/NA12004.chr13.vcf.bz2 deleted file mode 100644 index 0d5fc433f26196d3afe6433d10f070197f0c359b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74 zcmV-Q0JZ-@T4*^jL0KkKSv#c2pa1}vOn?9obO0a$00bZaR5sO6&=D!=G(`}|1LXnl gF;O-Hx7O4oLQS?TRBT0}FjwO4NT&)C2XvVf0Cd|J`~Uy| diff --git a/inst/extdata/demoGenoChr/chr13/NA12005.chr13.vcf.bz2 b/inst/extdata/demoGenoChr/chr13/NA12005.chr13.vcf.bz2 deleted file mode 100644 index 474e86cb55275409e8819fef97e3b7cf340f6f5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72 zcmZ>Y%CIzaj8qGbR9bN1F9X92p9ThjA_fIU1{MW|fHoG6kjudyA#WO<{BS6r)im=v b%e~*mY*Q9;u`bc%P_P#-aY%CIzaj8qGbv<;cJih*H diff --git a/inst/extdata/demoGenoChr/chr14/NA12004.chr14.vcf.bz2 b/inst/extdata/demoGenoChr/chr14/NA12004.chr14.vcf.bz2 deleted file mode 100644 index c19eee1968b4a3feefd352063e1590a0de980ec4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61 zcmZ>Y%CIzaj8qGbeD7eM#=tPcr-4DBgh7FkfklDAkcUGsSZd}JuIUdiGENm?`){18 R!Oy)@X^w_R`2y+93;_LT5o`be diff --git a/inst/extdata/demoGenoChr/chr14/NA12005.chr14.vcf.bz2 b/inst/extdata/demoGenoChr/chr14/NA12005.chr14.vcf.bz2 deleted file mode 100644 index 509cb2d287b439986803041e874d5ed59de20696..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61 zcmZ>Y%CIzaj8qGb?C7y|XJDA&)4(85#Gt^)z@orl$ipERe4@=EWRE-t-&q0an>$~# Ru>FZWDe}Y%CIzaj8qGb+@#~}$G|Ydr-4DBgh7FkfklBKppAv2(?pj+MI@zC`~dTI2X?vZ Vd%guQ9)I-CV>y?Qm}_U|0RT9_6W;&; diff --git a/inst/extdata/demoGenoChr/chr15/NA12005.chr15.vcf.bz2 b/inst/extdata/demoGenoChr/chr15/NA12005.chr15.vcf.bz2 deleted file mode 100644 index f48cd254721a3d20ae0bbb2e22ff7a8923671bf2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmZ>Y%CIzaj8qGbJhhP}ih*Hy+1d7&Tl-a8h3 Y&-?k^Oy<;L`R<)cb2L0sBbsy>0Mfq~Z2$lO diff --git a/inst/extdata/demoGenoChr/chr16/NA12003.chr16.vcf.bz2 b/inst/extdata/demoGenoChr/chr16/NA12003.chr16.vcf.bz2 deleted file mode 100644 index aca1b7a8763b55eae5eaa9badb352c55b5b4654c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64 zcmZ>Y%CIzaj8qGb6ueN_%fK+hr-4DBfY%CIzaj8qGbw7zJN$iOher-4DBgh7FkfklBKppAtih}ke~itnj;4sz*&!R`gs a`?JM^E-<<>OcDK9t`gkJ$-GyXO#lF)8xyYp diff --git a/inst/extdata/demoGenoChr/chr16/NA12005.chr16.vcf.bz2 b/inst/extdata/demoGenoChr/chr16/NA12005.chr16.vcf.bz2 deleted file mode 100644 index 9a94357479918d368949f05dd4ed46bbf919c277..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62 zcmZ>Y%CIzaj8qGb{AJO>$-pqfr-4DBh(UpofklDAkcUIi*GHu@L}9v95yO+Cj30N` SPIRc#d(u^~Q1MHlfDiy1=o6a& diff --git a/inst/extdata/demoGenoChr/chr17/NA12003.chr17.vcf.bz2 b/inst/extdata/demoGenoChr/chr17/NA12003.chr17.vcf.bz2 deleted file mode 100644 index 5491587438a9b77ea1ec3174c21bfc8bc23f1a3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60 zcmV-C0K@-6T4*^jL0KkKSzcJzO8@|vOn?9ocmN;)00bZaF$@R_l)@QH;3tqxtwArf Sx$C47{x0N-aG@Z)v96XGv=w;( diff --git a/inst/extdata/demoGenoChr/chr17/NA12004.chr17.vcf.bz2 b/inst/extdata/demoGenoChr/chr17/NA12004.chr17.vcf.bz2 deleted file mode 100644 index 7040e9d70815f4c4d99550ed0911b29f2d032fc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64 zcmZ>Y%CIzaj8qGbTxP+>%)l_ir-4DBgh7FkfklBK#F>dDY%CIzaj8qGbe0eV^n1Nx2PXmKM5rYCF1B(JfKpP83r-`mg2%iJDioe#fyP`gP YSMF77EJ|TwKYC}PpNNW8`HU$C0G=EbX8-^I diff --git a/inst/extdata/demoGenoChr/chr18/NA12003.chr18.vcf.bz2 b/inst/extdata/demoGenoChr/chr18/NA12003.chr18.vcf.bz2 deleted file mode 100644 index 7069651ccca44b73369f772179a4836f6c97bdca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60 zcmV-C0K@-6T4*^jL0KkKSs03~`Tzi!On?9ocmN;)00bZaF$@S1Q`EsC0N1oYZd!o< SGPdG?@Vk;J!i0dtRd3KZ;}(?w diff --git a/inst/extdata/demoGenoChr/chr18/NA12004.chr18.vcf.bz2 b/inst/extdata/demoGenoChr/chr18/NA12004.chr18.vcf.bz2 deleted file mode 100644 index 719c31374402d15473af9f6aa9e1f05ec728040e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62 zcmZ>Y%CIzaj8qGb6rK>4&A>3jr-4DBgh7FkfklDAkcUIi*GHveZD5H)5yO+Cj30N` SPIRc#d(u^~P(fW`%{2fF!V|*) diff --git a/inst/extdata/demoGenoChr/chr18/NA12005.chr18.vcf.bz2 b/inst/extdata/demoGenoChr/chr18/NA12005.chr18.vcf.bz2 deleted file mode 100644 index 2928cf343b3de3cfc9b02ab5591bbbe5f0565bd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61 zcmZ>Y%CIzaj8qGbTt8`52m`|mp9ThjA_fIU1{MVdLmm!6&ljpp;$G`D_^OVuXQz9z Rus?d|v7Adt^i!x;0{{W<5v2eC diff --git a/inst/extdata/demoGenoChr/chr19/NA12003.chr19.vcf.bz2 b/inst/extdata/demoGenoChr/chr19/NA12003.chr19.vcf.bz2 deleted file mode 100644 index 9733612b48f20530a35a146725c79fd65f8576f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74 zcmZ>Y%CIzaj8qGbl%A+t%D^zgr-4DBfY%CIzaj8qGb+`QxGUj~L5J`D^4B@7CT3@i!^hCCdCo-b6nrhD{j@KqgQ&rbJb RVSn__V>y?QSh>9Y0sugv5|jV{ diff --git a/inst/extdata/demoGenoChr/chr19/NA12005.chr19.vcf.bz2 b/inst/extdata/demoGenoChr/chr19/NA12005.chr19.vcf.bz2 deleted file mode 100644 index eaf2103ed782a850bd94b12be9fba925b24cb20f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63 zcmV-F0Kor3T4*^jL0KkKS@9Cx?f?LoOn?9oasVI!00bZaF$@S1Q`Fj;NT`{_oJ~L* VDuDF$&9Oj!F64@Ep&{ZWyWF4h7?A(~ diff --git a/inst/extdata/demoGenoChr/chr2/NA12003.chr2.vcf.bz2 b/inst/extdata/demoGenoChr/chr2/NA12003.chr2.vcf.bz2 deleted file mode 100644 index 68b8d8cb510a5cc5f076d3cb620430d19b27abb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61 zcmV-D0K)%5T4*^jL0KkKS&8v8tpEU+On?9ocmN;)00bZaF$@R_l4Q|9%8)%Eo#r5$ TTYkH=6XNbjrwS4gJ|=abL&Fqt diff --git a/inst/extdata/demoGenoChr/chr2/NA12004.chr2.vcf.bz2 b/inst/extdata/demoGenoChr/chr2/NA12004.chr2.vcf.bz2 deleted file mode 100644 index 29710f3b9dbcd8e721954cda2aecc34e3a1c25d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61 zcmZ>Y%CIzaj8qGbY};qHje%i?PXmKM34;P71B(KKArFUO@Rfr~TH%vj*q*N7|E!&- R!Oy)@X^w`6bG&pk0{|6a5nliR diff --git a/inst/extdata/demoGenoChr/chr2/NA12005.chr2.vcf.bz2 b/inst/extdata/demoGenoChr/chr2/NA12005.chr2.vcf.bz2 deleted file mode 100644 index e7207c85e5ae7ccf39b0f6997580201d6cf7e7dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61 zcmZ>Y%CIzaj8qGb4E!|Dn}K15PXmKM5rYCF1B(KKArFUO@CB95I#)jdnHdVEoAXz3 R@Yckh6nW_6=zgkF2LKA55;Fh* diff --git a/inst/extdata/demoGenoChr/chr20/NA12003.chr20.vcf.bz2 b/inst/extdata/demoGenoChr/chr20/NA12003.chr20.vcf.bz2 deleted file mode 100644 index e46f8375224e977e022627265b2af5636c076dcb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64 zcmV-G0Kfl2T4*^jL0KkKS$xmVaR30AOn?9ocmN;)00bZaP=*8rDNjkGAm$+Yh3}k# W?mNG3?MpEy;_gVN3K9>Q`OYAx#~0fG diff --git a/inst/extdata/demoGenoChr/chr20/NA12004.chr20.vcf.bz2 b/inst/extdata/demoGenoChr/chr20/NA12004.chr20.vcf.bz2 deleted file mode 100644 index 901c941be7eb200a88420fd5ee654bceb4c3f04f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65 zcmV-H0KWf1T4*^jL0KkKSq5#D*#H2TOn?9obO0a$00bZaP=*8ul=PY+ra(~gfcKaH XI~~5ZqLL#Zq49SlQ-uitX4zeko39qb diff --git a/inst/extdata/demoGenoChr/chr20/NA12005.chr20.vcf.bz2 b/inst/extdata/demoGenoChr/chr20/NA12005.chr20.vcf.bz2 deleted file mode 100644 index 0286e12e82e9153a5bff204ccff9efcf587e8631..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60 zcmZ>Y%CIzaj8qGbd~n8R4+Fytp9ThjA_fIU1{MVdLmm#n;45E^A{JOJu$$^oY`sl` Q|LC2Gej+Ls#=`mx04{_QLjV8( diff --git a/inst/extdata/demoGenoChr/chr21/NA12003.chr21.vcf.bz2 b/inst/extdata/demoGenoChr/chr21/NA12003.chr21.vcf.bz2 deleted file mode 100644 index 1b8e8a4b8d568c1d8b4e0fd2f85e6be982ba1426..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72 zcmV-O0Jr}_T4*^jL0KkKS!&mNHvj;bOn?9ocmN;)00bZaR5npG!3scTBSNJExX4-x eJc^voDyD<=CVOt61+WE*@Vk;J!i0lXyVuTcBp=*j7=RI*7|;L! diff --git a/inst/extdata/demoGenoChr/chr21/NA12005.chr21.vcf.bz2 b/inst/extdata/demoGenoChr/chr21/NA12005.chr21.vcf.bz2 deleted file mode 100644 index 175df8b9f9efeaa9b17855e14c551876a3ba54ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65 zcmZ>Y%CIzaj8qGboEggy!@w}Zr-4DBh(UpofklBKppAvqtIF3`SK+;i_wfb3yP1+- V-TSS>*?;uTL_ZM~wQvV<1^`+#6ej=x diff --git a/inst/extdata/demoGenoChr/chr22/NA12003.chr22.vcf.bz2 b/inst/extdata/demoGenoChr/chr22/NA12003.chr22.vcf.bz2 deleted file mode 100644 index df8ed4e019624a1f61ceece31539d9ab6a9891b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77 zcmV-T0J8r=T4*^jL0KkKS#5?nnE(KoOn?9ocmN;)00bZaP=*8uQZ+Qp0)~`mM!OC{ jLiiOoG(|YSVjJIc1mqz|r7c91#rV6DDZ+$Y%CIzaj8qGbREg%vW?-1%)4(85!l1y&z@orl$ipERd_kpSWu2dZ%nSw7&H1Z1 Rcxz%$iad03n3!X@1_0N85rqH% diff --git a/inst/extdata/demoGenoChr/chr22/NA12005.chr22.vcf.bz2 b/inst/extdata/demoGenoChr/chr22/NA12005.chr22.vcf.bz2 deleted file mode 100644 index 45979aa6b045b5726b6e9cf33838efbf1f1c79b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79 zcmV-V0I>f;T4*^jL0KkKS=~j3P5=OyOn?9oasVI!00bZaY7%;>03t-wIm;Nf#84I6 la%iv+WMc?uC}m&(+NbHyZPRf8B&sWZF64@Ep&`1944mv%9E1P> diff --git a/inst/extdata/demoGenoChr/chr3/NA12003.chr3.vcf.bz2 b/inst/extdata/demoGenoChr/chr3/NA12003.chr3.vcf.bz2 deleted file mode 100644 index e1d4d9c329f447a3e1aa3aadfbc8e8c579211565..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74 zcmZ>Y%CIzaj8qGbRDLk~4g35KE14bprqvq!wfV diff --git a/inst/extdata/demoGenoChr/chr3/NA12004.chr3.vcf.bz2 b/inst/extdata/demoGenoChr/chr3/NA12004.chr3.vcf.bz2 deleted file mode 100644 index b14a26a07fd993ef67ce204c524308107f1f8166..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71 zcmZ>Y%CIzaj8qGb{M%b-!oV=Yr-4DBgh7FkfklBKppAti$kgPFwVuihSg7~PVY%q!9vB~QjanK1)~^p diff --git a/inst/extdata/demoGenoChr/chr3/NA12005.chr3.vcf.bz2 b/inst/extdata/demoGenoChr/chr3/NA12005.chr3.vcf.bz2 deleted file mode 100644 index ae85583170d06015e9ee70ef602924e594efb7b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76 zcmV-S0JHx>T4*^jL0KkKSz^wpWdHz}On?9oasVI!00bZaP=*8uQZ+QpS_SNx3Q*M| iQQ%bE)fD3WfNy=wK;(l;lmkQ`i@744C`d79R5F0KjvGAy diff --git a/inst/extdata/demoGenoChr/chr4/NA12003.chr4.vcf.bz2 b/inst/extdata/demoGenoChr/chr4/NA12003.chr4.vcf.bz2 deleted file mode 100644 index c01c61b9054eb33400ed878443d08e14fb757018..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64 zcmZ>Y%CIzaj8qGb><&4U!oV=Yr-4DBfdDIG9tRJA^x&a!2uK)m;On?9obO0a$00bZaR3$XfVG&G)pfU*{p$Mi$ aJSv-XKzNzRzCH$rxt< diff --git a/inst/extdata/demoGenoChr/chr4/NA12005.chr4.vcf.bz2 b/inst/extdata/demoGenoChr/chr4/NA12005.chr4.vcf.bz2 deleted file mode 100644 index bfa295fde0b375b71d628bf7e0d1cb991c664347..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69 zcmZ>Y%CIzaj8qGbJn&gy3j@Opp9ThjA_fIU1{MW|fHoG6Kp#(Wg(#MNNBJ4}jk{K^ XFR=c;y+k8)sg%8Vk*h_(1duiWy($(p diff --git a/inst/extdata/demoGenoChr/chr5/NA12003.chr5.vcf.bz2 b/inst/extdata/demoGenoChr/chr5/NA12003.chr5.vcf.bz2 deleted file mode 100644 index e812d8fbd60b98fd1b6c8cb4065875624542c75e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71 zcmV-N0J#4`T4*^jL0KkKS(ZyFmjD2mOn?9ocmN;)00bZaP=*8uQkzpV1DS~u6aqvP dAxx3fMBLQ@_+R&(+)y72xgwk>NJ}M@%Ye$@7Ulo| diff --git a/inst/extdata/demoGenoChr/chr5/NA12004.chr5.vcf.bz2 b/inst/extdata/demoGenoChr/chr5/NA12004.chr5.vcf.bz2 deleted file mode 100644 index b978498b0bc2b086501a8b42a35cf3682723d844..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69 zcmV-L0J{G|T4*^jL0KkKStq(3IRF5dOn?9obO0a$00bZaP=*8uQkzpV7MGEd(ya?Y bK%E6m%}^hg{pWWS2g2@1rwS4T_d};3syP;C diff --git a/inst/extdata/demoGenoChr/chr5/NA12005.chr5.vcf.bz2 b/inst/extdata/demoGenoChr/chr5/NA12005.chr5.vcf.bz2 deleted file mode 100644 index f60e08d41baf52c399a488ffebd55846de5446e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71 zcmZ>Y%CIzaj8qGbY@K=9k%3``PXmKM5rYCF1B(JfKpP83kg3U;sJLU^UR!ionJPrh bO++pBC%vyd!|JF1=$*%ME+K)i=AZa-cLZ^TS exztqG>>l&mx*3jARN2^ diff --git a/inst/extdata/demoGenoChr/chr6/NA12004.chr6.vcf.bz2 b/inst/extdata/demoGenoChr/chr6/NA12004.chr6.vcf.bz2 deleted file mode 100644 index 1c94aff643f6c77595e5a5ca61015f277eb52048..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70 zcmZ>Y%CIzaj8qGbY%CIzaj8qGbT++PXmKM5rYCF1B(JfKpP83(ClDiQOziaiJ$)O%dY%CIzaj8qGblt^((XJDA&)4(85!l1y&z@oqq(8j_M#BAWOB)sqmY%CIzaj8qGbT=&1pkbz-_PXmKM5rYCF1B(JfKpP83ps=UF$t6w=mNP0tt>?P> c@^7d&y03I_J^Z)<= diff --git a/inst/extdata/demoGenoChr/chr8/NA12003.chr8.vcf.bz2 b/inst/extdata/demoGenoChr/chr8/NA12003.chr8.vcf.bz2 deleted file mode 100644 index 1e1a1581bf5d7434bca805f6833156cbc6d9812e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77 zcmV-T0J8r=T4*^jL0KkKS-SQL?*IUpOn?9ocmN;)00bZaP=*8uQZ+QpDM|>Ej>_Z> jC=?zMP0ayLA@(V~_c2$JEe#?=N8;{CrwS4mUcp`9k$@SB diff --git a/inst/extdata/demoGenoChr/chr8/NA12004.chr8.vcf.bz2 b/inst/extdata/demoGenoChr/chr8/NA12004.chr8.vcf.bz2 deleted file mode 100644 index 9fe74e90bad2a10aab6fd1e26b8aa6b133bb0851..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75 zcmV-R0JQ%?T4*^jL0KkKS+e%$S^xl;On?9obO0a$00bZaP=*8uQZ+QpDM|>Em$GCn h2|~~m2Y^#^Lp*Pn84&;g diff --git a/inst/extdata/demoGenoChr/chr8/NA12005.chr8.vcf.bz2 b/inst/extdata/demoGenoChr/chr8/NA12005.chr8.vcf.bz2 deleted file mode 100644 index 2831fedcc1f292179f383b10502155bb331cf47d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 78 zcmZ>Y%CIzaj8qGbtTy_@$-pqfr-4DBh(UpofklC#NU@Pgq}SJ&E2ybymQ(ZQNg^Bp im8|9_tQP7wmVLi-)X#yJ!P&oir_vk^58IiQEDZoY%CIzaj8qGb%*>v!gn?m(PXmKM1%m=31B(KKArFV3=1UVt#*_1r)ogc<4p diff --git a/inst/extdata/demoGenoChr/chr9/NA12005.chr9.vcf.bz2 b/inst/extdata/demoGenoChr/chr9/NA12005.chr9.vcf.bz2 deleted file mode 100644 index 64b3334102c94adbd7fbd23f4862ef4624def35a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67 zcmV-J0KES~T4*^jL0KkKS>@Wq2><|?On?9oasVI!00bZaR3wcw1StUnlBu}^AZVoW Zs&hCXIu7K{ZHNWp?ntK!5*)i&fgrR`79{`x diff --git a/inst/extdata/demoGenoChr/demoGenoChr.tar b/inst/extdata/demoGenoChr/demoGenoChr.tar new file mode 100644 index 0000000000000000000000000000000000000000..e17204e307ace2b5dd6f1a9e328c0708fc6fb631 GIT binary patch literal 3732 zcmV;F4r}rKH+ooF0004LBHlIv03iVu0001VFXf}*H~$V;T>uvg$meP%G9vwPFG)}8 z-jZ5w3@9TEvRViF?#QALWrUvCrKlso9)V&rgf)e&zKh!{bpOQ9QenOCIGTX>o@p z0`A&e!1wJQ8^3XOPveLT66**!pjC3BKqDM~f{mCPaXhG~yt`)td);VNO!Z!P(C+6i z{x_&Uc2NNPm~r2`%FtSGQyqY(VrFHJZhJn0bXIE|aaK`8Q~JtW%TS_#?U{x4%GxAT z4980A31bq+4zkHPZPS9&9p}Qa&1OC{0KPOD>vl%w3!nL2`sAPX^b&LXg~Pj=~Ti<XZACGpyfetdMLQ4QQBXxYR<&1D3cpx3BMkqu}?%n}jdncvA8^ zVrIIw=a5|`@TDi`_-%nwY1SjW7wn`G(ZE6~Jypkr8fTnkkYSk6h0l`{fGck!3 z0C&(H@pCmm6LIE7(h*g0ZRy$Bi+sx$ogHf{slke@0~#0mHOJ=>@nAOK%#sr*=U55; zpwriNKr2Jp14w@5;E5`x;qEJhZ;bOwwg9q7>t0tN_-aCmbCF|6MK+Y;)abETtk3un z;p>?OhH}Yelg?01Bok0?%hYtBG*Wwlv=LTVum30BsQo?zyj$?h_Of|+zA4J=wPW%- z2M>Q7GA{x^_}17_0sz|M-lZvzTne!0FMi53GQfFfwA3W#V&ZYU`WqP)Z4b1R(p_!% z?i;QD{Rg?tBc>3{Ez;|^J^xVG+jzT5Y|(~~CCR}KO=xs8-bJH(nT<{%JI@#i$OWN) z<)d@3@j%yCH|E<NPMn(;f~ywUSJic&RM&=uY&{<1vXQADNyG* zv6pfr0f#0&mIz`VXZIOE{I0b`@3Jj4RlM2sID5Ff5Xi{#aAl5+In zN=`WgKI|#Vjn_Vy;ml|ELvEIFFj>b#iSfe#NS{y=CHS2fsbVEi3+3$S2aVp1brs%) zO4&>5mX*s#Z+$BAv!e}js_1OY0TgM5t`{GxB18#Q%ld<8SzIdlXK%rrEMdl_5SD{t zb2-r?x(X#cIP%1NeUMrD7BJsvQ~k5=-|Rx`{%P&q69a21jLFtxyM`yEeVVnfH7t9* zsLD7s5?%m~@;)v|MW-_%(@$nudW7;NVsiI*)M_=o%=qf>$s0>*ZKc-&Lpy2KK?Rh_ z-->~@(ex7H)9jI<$ul#!+x3btZ#Z*dggWN$5Od;myvDg$KkR@FGjgml6_tZ?G`FEH z{ll;?pj6}zM`p%n6gk?R-}BnlcA6k7m?m;4H=w}&hj1-}&flQ%X)W%76;N8{J9R_O z8RYO{j>-IY5j7WTfJDh5XV8pw>AZ1f);zUB4FRfuC3IQ*Nw%fahg@1rr&S^s6Zq%?3Tz&zNYxVWk6g68z_dVMuUiZ= zg#OvFdBe%->>-bXO?^UP73fnKX9%+lou9`}S{FBMIJS-kvz5@Y{BLrCZ;rS*{n_3- zsM3%o3tIsSAmk!Y{n(Opr-+l^6{im{AJ?nY7Me zJB$V|fGAkbjg&j6Ol|OmpR}~H<|~DHrLrqd(6wWgrJ;1uH_jlo>1dX8?4M~fOvZ}F(NSz zG?v!&&y@57Jp|Ct%g%0DAc)Z;W<`B3Q0vrk$T$=mYjK6J!mRs5loE0mzK1U3g`n89 zoIxqwT2z9DF&2~G!Dca^@dqUKH-e&n?uS=eb?_8sSxg12N*)AIT z71i8xbanOE&s<`@kSe_(xb_2zVctI5eH6W{wW5-NFM|NSNe2?f z8t65`s%u=(tn!|5uq>b)j@KsJD}wGDl@3EC?>keL2P65B8_{jB8HE7U{Swqmo$v47 zPrK4M-Oj+VXl*rtgcs%qkvWXz2(I3G=884oaD4^@gQmDN*pLq%9deCi zYTjwyM%_Y0In^b(I!sk`Srp!6{h~t@ozcHJ`Yl*KWhq?)4J0qemY{N85qUIKi!$d1 z23axcbEm=XC!3|2)zzLMSS&f;w2)=U@YDksLk(>$)8aPs9u?vXg++QSpT;jn&A=`Q z=55jn_6cLs)jz52Drt+;dPnT%iAVBHj=4&d(24_k}?MWs}*ept$_ zzBNOtZJKm`RRm}_JJV)Pp0K6JM))Yu9OsK=kBCoWNPT6Lydn_GCYze+PVH= z-qCOkx}1^StBFA8DWC-O?OSP_DQ4iWcbSP=|IA{1zloyP4&Rb_&+(ZF=11{%R!@)V z5g!JS&EKI&cl>x*dPLLO394eSUX^C%gUw*`XRMpW?t~7HlzBl8DCb(e*&1a9{9flZ zMMko8Je{D3rF%TirUEbnuaD-;W@V6`!-tWNo~BEppX7JuUBs`BbNJafm`jy{1n%Zg z93ih6mnn;CzU8YXrfQ%(DjeA1)|SRC7+xW_wMNeau>0yf1s&H@zEhn*x@dJfQsWc? zC?Udps_BB4WVy~PQ_=zF0wWj?A13wlUYc}GgRI$>#pnt;0xZu2gc;57!YjJ|hfRbJ~l+CZjo}S<(+^?mHmucT~G7f`qGLtfr-FvI4gx zceSgJ(y@yvmWC=hg5^qO>}Zt(xn2bc ze+5ntOKEq%j`cHg=`BxeEf1jP7eI-QCPZ8Up?54_z!|a$&LCd2`pZz+uL6U_^LGMO zgnz~BmT28@m7RSC;wG1dOPNnS6*s)lMcuwi*Dube&Yzb&$9j%AVk!ghrkKO*998G2 zvGjp>Kyjk^(Gd$riOLAg{o%bD;bVxpTRdPs9`ROb!z&*|g~|S_Bk)MbLKfnS`sL9z z5z7}#;}X1wN*{=qdK70OM|ls4_AW+l9eX5Db}8b>b`TcQp}2~v;8L#g+0}ms4G_N> y?_6sB7n`W}8>JU?>^(1SJOBU$Oq|>R0q`7v@B{#;wR=~ literal 0 HcmV?d00001 diff --git a/man/groupChr1KGSNV.Rd b/man/groupChr1KGSNV.Rd index dfbf884a6..82a9f806f 100644 --- a/man/groupChr1KGSNV.Rd +++ b/man/groupChr1KGSNV.Rd @@ -32,27 +32,39 @@ files for all samples present in the input directory. ## Path to the demo vcf files in this package dataDir <- system.file("extdata", package="RAIDS") -pathGeno <- file.path(dataDir, "demoGenoChr") +pathGenoTar <- file.path(dataDir, "demoGenoChr", "demoGenoChr.tar") -## Path where the output vcf file will be created -pathOut <- tempdir() +## Path where the chromosomes files will be located +pathGeno <- file.path(tempdir(), "tempGeno") +dir.create(pathGeno, showWarnings=FALSE) + +## Untar the file that contains the VCF files for 3 samples split by +## chromosome (one directory per chromosome) +untar(tarfile=pathGenoTar, exdir=pathGeno) + +## Path where the output VCF file will be created is +## the same where the split VCF are (pathGeno) ## The files must not exist -if (!file.exists(file.path(tempdir(), "NA12003.csv.bz2")) && - !file.exists(file.path(tempdir(), "NA12004.csv.bz2")) && - !file.exists(file.path(tempdir(), "NA12005.csv.bz2"))) { +if (!file.exists(file.path(pathGeno, "NA12003.csv.bz2")) && + !file.exists(file.path(pathGeno, "NA12004.csv.bz2")) && + !file.exists(file.path(pathGeno, "NA12005.csv.bz2"))) { ## Return 0 when successful ## The files "NA12003.csv.bz2", "NA12004.csv.bz2" and ## "NA12005.csv.bz2" should not be present in the current directory - groupChr1KGSNV(pathGenoChr=pathGeno, pathOut=pathOut) + groupChr1KGSNV(pathGenoChr=pathGeno, pathOut=pathGeno) + + ## Validate that files have been created + file.exists(file.path(pathGeno, "NA12003.csv.bz2")) + file.exists(file.path(pathGeno, "NA12004.csv.bz2")) + file.exists(file.path(pathGeno, "NA12005.csv.bz2")) - ## Remove temporary VCF file - unlink(file.path(tempdir(), "NA12003.csv.bz2"), force=TRUE) - unlink(file.path(tempdir(), "NA12004.csv.bz2"), force=TRUE) - unlink(file.path(tempdir(), "NA12005.csv.bz2"), force=TRUE) } +## Remove temporary directory +unlink(pathGeno, recursive=TRUE, force=TRUE) + } \author{ Pascal Belleau, Astrid Deschênes and Alexander Krasnitz From 3751711a48d03523508a12fd69d34dcd46d9f4de Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 02:30:29 -0400 Subject: [PATCH 251/385] Remove duplicated demo Ref GDS files and adapt examples --- R/RAIDS.R | 6 ++--- R/allelicFraction.R | 2 +- R/allelicFraction_internal.R | 12 +++++----- R/gdsWrapper_internal.R | 4 ++-- R/process1KG.R | 2 +- R/process1KG_internal.R | 4 ++-- R/processStudy.R | 22 +++++++++--------- R/processStudy_internal.R | 12 +++++----- R/synthetic.R | 4 ++-- .../ex1_good_small_1KG.gds} | Bin .../ex1_good_small_1KG_Annot.gds} | Bin .../tests/ex1_good_small_1KG_Annot_GDS.gds | Bin 163611 -> 0 bytes inst/extdata/tests/ex1_good_small_1KG_GDS.gds | Bin 849907 -> 0 bytes man/add1KG2SampleGDS.Rd | 2 +- man/addGeneBlockGDSRefAnnot.Rd | 2 +- man/computeAllelicFractionDNA.Rd | 2 +- man/computeAllelicFractionRNA.Rd | 4 ++-- man/computeAllelicImbDNAChr.Rd | 2 +- man/computeAncestryFromSyntheticFile.Rd | 4 ++-- man/computeLOHBlocksDNAChr.Rd | 2 +- man/createStudy2GDS1KG.Rd | 2 +- man/demoPedigreeEx1.Rd | 6 ++--- man/estimateAllelicFraction.Rd | 2 +- man/generateGeneBlock.Rd | 4 ++-- man/getBlockIDs.Rd | 4 ++-- man/getTableSNV.Rd | 2 +- man/pruningSample.Rd | 2 +- man/runExomeAncestry.Rd | 6 ++--- man/runProfileAncestry.Rd | 6 ++--- man/runRNAAncestry.Rd | 6 ++--- man/runWrapperAncestry.Rd | 6 ++--- man/syntheticGeno.Rd | 4 ++-- tests/testthat/test-gdsWrapper_internal.R | 8 +++---- vignettes/Create_Reference_GDS_File.Rmd | 4 ++-- vignettes/RAIDS.Rmd | 22 ++++++++++-------- 35 files changed, 86 insertions(+), 84 deletions(-) rename inst/extdata/{example/gdsRef/ex1kg.gds => tests/ex1_good_small_1KG.gds} (100%) rename inst/extdata/{example/gdsRef/exAnnot1kg.gds => tests/ex1_good_small_1KG_Annot.gds} (100%) delete mode 100644 inst/extdata/tests/ex1_good_small_1KG_Annot_GDS.gds delete mode 100644 inst/extdata/tests/ex1_good_small_1KG_GDS.gds diff --git a/R/RAIDS.R b/R/RAIDS.R index 34529e684..f8d12a6d9 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -660,10 +660,10 @@ NULL #' ## Note that the 1KG GDS file used for this example is a #' ## simplified version and CANNOT be used for any real analysis #' ################################################################# -#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' path1KG <- file.path(dataDir, "tests") #' -#' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") -#' fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +#' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +#' fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") #' #' ################################################################# #' ## The Sample SNP pileup files (one per sample) need diff --git a/R/allelicFraction.R b/R/allelicFraction.R index c4ae67d90..e41b22ae0 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -90,7 +90,7 @@ #' #' ## Path to the demo 1KG GDS file located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") -#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG.gds") #' #' ## Profile GDS file for one profile #' fileProfile <- file.path(tempdir(), "ex1.gds") diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 69ff8c63c..f0166f1f0 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -60,7 +60,7 @@ #' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") -#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG.gds") #' #' ## Temporary Profile GDS file for one profile in temporary directory #' fileProfile <- file.path(tempdir(), "ex1.gds") @@ -308,7 +308,7 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' #' ## Path to the demo Reference GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") -#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG.gds") #' #' ## Open the Reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileGDS) @@ -712,7 +712,7 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { #' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") -#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG.gds") #' #' ## Temporary Profile GDS file for one profile in temporary directory #' fileProfile <- file.path(tempdir(), "ex1.gds") @@ -928,8 +928,8 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' #' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") -#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") -#' fileAnnotGDS <- file.path(dataDir, "ex1_good_small_1KG_Annot_GDS.gds") +#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG.gds") +#' fileAnnotGDS <- file.path(dataDir, "ex1_good_small_1KG_Annot.gds") #' #' ## Temporary Profile GDS file for one profile in temporary directory #' fileProfile <- file.path(tempdir(), "ex1.gds") @@ -1103,7 +1103,7 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, #' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") -#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG.gds") #' #' ## Open the reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileGDS) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 99eec9113..780a6151d 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -1165,8 +1165,8 @@ addUpdateLap <- function(gdsProfile, snpLap) { #' ## Path to the demo 1KG Annotation GDS file located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' -#' path1KG <- file.path(dataDir, "example", "gdsRef") -#' fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +#' path1KG <- file.path(dataDir, "tests") +#' fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") #' #' gdsRefAnnotation <- openfn.gds(fileAnnotGDS) #' diff --git a/R/process1KG.R b/R/process1KG.R index a7a522d7f..380c81807 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -808,7 +808,7 @@ getRef1KGPop <- function(gdsReference, popName="superPop") { #' #' ## GDS Reference file #' fileReferenceGDS <- file.path(dataDir, "tests", -#' "ex1_good_small_1KG_GDS.gds") +#' "ex1_good_small_1KG.gds") #' #' ## Open the reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileReferenceGDS) diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index 56c70ab3f..ac467ea65 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -189,10 +189,10 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, #' ## Making a "short cut" on the ensDb object #' edb <- EnsDb.Hsapiens.v86::EnsDb.Hsapiens.v86 #' -#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' path1KG <- file.path(dataDir, "tests") #' #' ## Reference GDS file -#' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") +#' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") #' #' ## Open the reference GDS file (demo version) #' gds1KG <- snpgdsOpen(fileReferenceGDS) diff --git a/R/processStudy.R b/R/processStudy.R index 88c4561d6..84b2d8d00 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -73,7 +73,7 @@ #' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") -#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG.gds") #' #' ## The data.frame containing the information about the study #' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" @@ -273,7 +273,7 @@ createStudy2GDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' #' ## Path to the demo Reference GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") -#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG.gds") #' #' ## The data.frame containing the information about the study #' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" @@ -473,7 +473,7 @@ pruningSample <- function(gdsReference, #' #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata/tests", package="RAIDS") -#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") +#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG.gds") #' #' ## The data.frame containing the information about the study #' ## The 3 mandatory columns: "studyID", "study.desc", "study.platform" @@ -1732,10 +1732,10 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, #' data(demoKnownSuperPop1KG) #' #' ## The Reference GDS file -#' path1KG <- system.file("extdata/example/gdsRef", package="RAIDS") +#' path1KG <- system.file("extdata/tests", package="RAIDS") #' #' ## Open the Reference GDS file -#' gdsRef <- snpgdsOpen(file.path(path1KG, "ex1kg.gds")) +#' gdsRef <- snpgdsOpen(file.path(path1KG, "ex1_good_small_1KG.gds")) #' #' ## Path to the demo synthetic results files #' ## List of the KNN result files from PCA run on synthetic data @@ -1974,10 +1974,10 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' ## Note that the 1KG GDS file used for this example is a #' ## simplified version and CANNOT be used for any real analysis #' ################################################################# -#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' path1KG <- file.path(dataDir, "tests") #' -#' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") -#' fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +#' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +#' fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") #' #' ################################################################# #' ## The Sample SNP pileup files (one per sample) need @@ -2188,10 +2188,10 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ## Note that the 1KG GDS file used for this example is a #' ## simplified version and CANNOT be used for any real analysis #' ################################################################# -#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' path1KG <- file.path(dataDir, "tests") #' -#' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") -#' fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +#' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +#' fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") #' #' ################################################################# #' ## The Sample SNP pileup files (one per sample) need diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 94203bc82..d4f6cd03e 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2045,10 +2045,10 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' ## Note that the 1KG GDS file used for this example is a #' ## simplified version and CANNOT be used for any real analysis #' ################################################################# -#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' path1KG <- file.path(dataDir, "tests") #' -#' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") -#' fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +#' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +#' fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") #' #' ################################################################# #' ## The Sample SNP pileup files (one per sample) need @@ -2352,10 +2352,10 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' ## Note that the 1KG GDS file used for this example is a #' ## simplified version and CANNOT be used for any real analysis #' ################################################################# -#' path1KG <- file.path(dataDir, "example", "gdsRef") +#' path1KG <- file.path(dataDir, "tests") #' -#' fileReferenceGDS <- file.path(path1KG, "ex1kg.gds") -#' fileAnnotGDS <- file.path(path1KG, "exAnnot1kg.gds") +#' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +#' fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") #' #' ################################################################# #' ## The Sample SNP pileup files (one per sample) need diff --git a/R/synthetic.R b/R/synthetic.R index 5ab17de9b..53a942fb8 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -402,9 +402,9 @@ prepSynthetic <- function(fileProfileGDS, listSampleRef, #' #' ## The 1KG files #' gds1KG <- snpgdsOpen(file.path(dataDir, -#' "ex1_good_small_1KG_GDS.gds")) +#' "ex1_good_small_1KG.gds")) #' gds1KGAnnot <- openfn.gds(file.path(dataDir, -#' "ex1_good_small_1KG_Annot_GDS.gds")) +#' "ex1_good_small_1KG_Annot.gds")) #' #' ## Generate the synthetic profiles and add them into the Profile GDS #' syntheticGeno(gdsReference=gds1KG, gdsRefAnnot=gds1KGAnnot, diff --git a/inst/extdata/example/gdsRef/ex1kg.gds b/inst/extdata/tests/ex1_good_small_1KG.gds similarity index 100% rename from inst/extdata/example/gdsRef/ex1kg.gds rename to inst/extdata/tests/ex1_good_small_1KG.gds diff --git a/inst/extdata/example/gdsRef/exAnnot1kg.gds b/inst/extdata/tests/ex1_good_small_1KG_Annot.gds similarity index 100% rename from inst/extdata/example/gdsRef/exAnnot1kg.gds rename to inst/extdata/tests/ex1_good_small_1KG_Annot.gds diff --git a/inst/extdata/tests/ex1_good_small_1KG_Annot_GDS.gds b/inst/extdata/tests/ex1_good_small_1KG_Annot_GDS.gds deleted file mode 100644 index e977787ff9c49c51fda7f5e4de3b380cac1e3fbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163611 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%0APO{9I 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
P!mq)l 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%0Dm%|NV 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 z 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�O?lEY^kqi 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

D|RH+O>Di9rEv@*w+NzlM31|sKo^oo*wJ`JTHbK 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%0AXH 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 Date: Fri, 29 Sep 2023 12:26:46 -0400 Subject: [PATCH 252/385] README for the examples data --- inst/extdata/README | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 inst/extdata/README diff --git a/inst/extdata/README b/inst/extdata/README new file mode 100644 index 000000000..c089a6f66 --- /dev/null +++ b/inst/extdata/README @@ -0,0 +1,54 @@ +The files in the examples extdata/demoGenoChr.tar +are for each chromosome the first 100 genotype of the profiles NA12003, NA12004 and NA12005 extract from the 1KG VCF files from + http://ftp.1000genomes.ebi.ac.uk/vol1/ftp/data_collections/1000_genomes_project/release/20181203_biallelic_SNV + +The files +tests/ex1_good_small_1KG.gd +tests/ex1_good_small_1KG_Annot.gds +are base on subset of the genotype from 1000 genomes describe in +https://wellcomeopenresearch.org/articles/4-50/ +500 SNV from each chromosome are used (11000 for the 22 autosomal chromosomes). +For each of the 26 sub continentales population in this version of 1000 genomes, 6 profiles are randomly selected (156 profiles) to generate those gds. + + + +The files : +example/snpPileup/ex1.vcf.gz +example/snpPileup/ex1.generic.txt.gz +example/snpPileup/ex1.txt.gz +example/snpPileupRNA/ex1.generic.txt.gz +example/snpPileupRNA/ex1.txt.gz +demoAncestryCall/ex1.gds +demoKNNSynthetic/ex1.gds + +The genotype are synthetic data between a profile in 1000 genome randomly selected with an AFR +ancestry and not in the sample used in tests/ex1_good_small_1KG.gd and one exome from Tiriac et al. 2018. +(the exome is restricted access, it is only use to get the total read deep at the SNV position +and an estimate of allelic fraction of the regions). +Only 500 SNVs per chromosome are kept. +The pipeline to generate the synthetic data are describe in Belleau et al 2023. + +The files : +HG00*.csv.bz2 +are the first 10 SNV from chromosome 1 in 1000 genomes describe in +https://wellcomeopenresearch.org/articles/4-50/ + +The file : +matFreqSNV_Demo.txt.bz2 +is the csv file with the frequency for the 5 super population of the 10 first SNV from +chromosome 1 in 1000 genomes describe in +https://wellcomeopenresearch.org/articles/4-50/ + +The file: +listSNPIndexes_Demo.rds +mapSNVSelected_Demo.rds +are create from matFreqSNV_Demo.txt.bz2 +listSNPIndexes_Demo.rds: is an index of the variant where the frequency of at +least one 1000 genomes superpopulation is bigger than 1%. +mapSNVSelected_Demo.rds: subset matFreqSNV_Demo.txt.bz2 of the SNV selected +in listSNPIndexes_Demo.rds + +The file: +unrelatedPatientsInfo_Demo.rds +list of unrelated patient from 1000 genome describe in +https://wellcomeopenresearch.org/articles/4-50/ From b90533f252e6111ef5fc4c9be021ef0ba4212011 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 29 Sep 2023 12:55:46 -0400 Subject: [PATCH 253/385] Updated the example unrelatedPatientsInfo_Demo.rds --- inst/extdata/unrelatedPatientsInfo_Demo.rds | Bin 108 -> 126 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/inst/extdata/unrelatedPatientsInfo_Demo.rds b/inst/extdata/unrelatedPatientsInfo_Demo.rds index 75014a6da7896cd682e054d2648497087057065f..3543aba0e54ee7d17ac8cac2e55f919f8cf430d2 100644 GIT binary patch literal 126 zcmb2|=3oE==I#ec2?+^l35iKb32CfGk`d0%cS>|6BxbZU%BU%bF>o4fFeqTkEaNX{ zW_D%{4p}FubzNp^cH^n7NAi|1YF!tYn%#2B)a~gk1BSc&PmG*eBR>lj2X`<0X5h#g d*%egWwJ>MfB^!hO#)t9@j~q8}GcYnR008oIEEE6$ literal 108 zcmb2|=3oE=w(bW>2?+^l35iUT);Op!XJ>TGUdPJJJlS9Zvq-7{!(|D<4sXkjKws_|GpeeJ0c~Un|eb!jX!}FhE LpOTW*QlKRO7|$r> From 87c14221fc7594f58e03415f2b3b2fa3504663de Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 29 Sep 2023 13:28:09 -0400 Subject: [PATCH 254/385] Update the man for pathGeno --- R/gdsWrapper_internal.R | 11 ++++++++--- R/processStudy.R | 15 ++++++++++++--- R/processStudy_internal.R | 5 ++++- inst/extdata/README | 2 +- man/createStudy2GDS1KG.Rd | 5 ++++- man/generateGDS1KGgenotypeFromSNPPileup.Rd | 11 ++++++++--- man/runExomeAncestry.Rd | 5 ++++- man/runRNAAncestry.Rd | 5 ++++- man/runWrapperAncestry.Rd | 5 ++++- 9 files changed, 49 insertions(+), 15 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 780a6151d..4b2803d21 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -246,9 +246,14 @@ appendGDSgenotypeMat <- function(gds, matG) { #' profile into the Profile GDS file. The genotype information is extracted #' from a SNV file as generated by SNP-pileup or other tools. #' -#' @param pathGeno a \code{character} string representing the path to a -#' directory with the genotype files for the profiles, as generated by -#' snp-pileup. The path must exist. +#' @param pathGeno a \code{character} string representing the path to the +#' directory containing the VCF output of SNP-pileup for each sample. The +#' SNP-pileup files must be compressed (gz files) and have the name identifiers +#' of the samples. A sample with "Name.ID" identifier would have an +#' associated file called +#' if genoSource is "VCF", then "Name.ID.vcf.gz", +#' if genoSource is "generic", then "Name.ID.generic.txt.gz" +#' if genoSource is "snp-pileup", then "Name.ID.txt.gz". #' #' @param listSamples a \code{vector} of \code{character} string corresponding #' to the sample identifiers that will have a Profile GDS file created. The diff --git a/R/processStudy.R b/R/processStudy.R index 84b2d8d00..e7630f6bb 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -11,7 +11,10 @@ #' directory containing the VCF output of SNP-pileup for each sample. The #' SNP-pileup files must be compressed (gz files) and have the name identifiers #' of the samples. A sample with "Name.ID" identifier would have an -#' associated SNP-pileup file called "Name.ID.txt.gz". +#' associated file called +#' if genoSource is "VCF", then "Name.ID.vcf.gz", +#' if genoSource is "generic", then "Name.ID.generic.txt.gz" +#' if genoSource is "snp-pileup", then "Name.ID.txt.gz". #' #' @param filePedRDS a \code{character} string representing the path to the #' RDS file that contains the information about the sample to analyse. @@ -1884,7 +1887,10 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' directory containing the VCF output of SNP-pileup for each sample. The #' SNP-pileup files must be compressed (gz files) and have the name identifiers #' of the samples. A sample with "Name.ID" identifier would have an -#' associated SNP-pileup file called "Name.ID.txt.gz". +#' associated file called +#' if genoSource is "VCF", then "Name.ID.vcf.gz", +#' if genoSource is "generic", then "Name.ID.generic.txt.gz" +#' if genoSource is "snp-pileup", then "Name.ID.txt.gz". #' #' @param pathOut a \code{character} string representing the path to #' the directory where the output files are created. @@ -2094,7 +2100,10 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' directory containing the VCF output of SNP-pileup for each sample. The #' SNP-pileup files must be compressed (gz files) and have the name identifiers #' of the samples. A sample with "Name.ID" identifier would have an -#' associated SNP-pileup file called "Name.ID.txt.gz". +#' associated file called +#' if genoSource is "VCF", then "Name.ID.vcf.gz", +#' if genoSource is "generic", then "Name.ID.generic.txt.gz" +#' if genoSource is "snp-pileup", then "Name.ID.txt.gz". #' #' @param pathOut a \code{character} string representing the path to #' the directory where the output files are created. diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index d4f6cd03e..693304f59 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2255,7 +2255,10 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' directory containing the VCF output of SNP-pileup for each sample. The #' SNP-pileup files must be compressed (gz files) and have the name identifiers #' of the samples. A sample with "Name.ID" identifier would have an -#' associated SNP-pileup file called "Name.ID.txt.gz". +#' associated file called +#' if genoSource is "VCF", then "Name.ID.vcf.gz", +#' if genoSource is "generic", then "Name.ID.generic.txt.gz" +#' if genoSource is "snp-pileup", then "Name.ID.txt.gz". #' #' @param pathOut a \code{character} string representing the path to #' the directory where the output files are created. diff --git a/inst/extdata/README b/inst/extdata/README index c089a6f66..b46f1a9ec 100644 --- a/inst/extdata/README +++ b/inst/extdata/README @@ -50,5 +50,5 @@ in listSNPIndexes_Demo.rds The file: unrelatedPatientsInfo_Demo.rds -list of unrelated patient from 1000 genome describe in +list of unrelated (the file does not represent real relation between) patient from 1000 genome describe in https://wellcomeopenresearch.org/articles/4-50/ diff --git a/man/createStudy2GDS1KG.Rd b/man/createStudy2GDS1KG.Rd index b175459d4..e8f1d8f60 100644 --- a/man/createStudy2GDS1KG.Rd +++ b/man/createStudy2GDS1KG.Rd @@ -25,7 +25,10 @@ createStudy2GDS1KG( directory containing the VCF output of SNP-pileup for each sample. The SNP-pileup files must be compressed (gz files) and have the name identifiers of the samples. A sample with "Name.ID" identifier would have an -associated SNP-pileup file called "Name.ID.txt.gz".} +associated file called +if genoSource is "VCF", then "Name.ID.vcf.gz", +if genoSource is "generic", then "Name.ID.generic.txt.gz" +if genoSource is "snp-pileup", then "Name.ID.txt.gz".} \item{filePedRDS}{a \code{character} string representing the path to the RDS file that contains the information about the sample to analyse. diff --git a/man/generateGDS1KGgenotypeFromSNPPileup.Rd b/man/generateGDS1KGgenotypeFromSNPPileup.Rd index b60489397..d18b8579f 100644 --- a/man/generateGDS1KGgenotypeFromSNPPileup.Rd +++ b/man/generateGDS1KGgenotypeFromSNPPileup.Rd @@ -23,9 +23,14 @@ generateGDS1KGgenotypeFromSNPPileup( ) } \arguments{ -\item{pathGeno}{a \code{character} string representing the path to a -directory with the genotype files for the profiles, as generated by -snp-pileup. The path must exist.} +\item{pathGeno}{a \code{character} string representing the path to the +directory containing the VCF output of SNP-pileup for each sample. The +SNP-pileup files must be compressed (gz files) and have the name identifiers +of the samples. A sample with "Name.ID" identifier would have an +associated file called +if genoSource is "VCF", then "Name.ID.vcf.gz", +if genoSource is "generic", then "Name.ID.generic.txt.gz" +if genoSource is "snp-pileup", then "Name.ID.txt.gz".} \item{listSamples}{a \code{vector} of \code{character} string corresponding to the sample identifiers that will have a Profile GDS file created. The diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index 857791deb..8ce35a189 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -42,7 +42,10 @@ Default: \code{NULL}.} directory containing the VCF output of SNP-pileup for each sample. The SNP-pileup files must be compressed (gz files) and have the name identifiers of the samples. A sample with "Name.ID" identifier would have an -associated SNP-pileup file called "Name.ID.txt.gz".} +associated file called +if genoSource is "VCF", then "Name.ID.vcf.gz", +if genoSource is "generic", then "Name.ID.generic.txt.gz" +if genoSource is "snp-pileup", then "Name.ID.txt.gz".} \item{pathOut}{a \code{character} string representing the path to the directory where the output files are created.} diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index 5c8499898..4a8ce485d 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -43,7 +43,10 @@ Default: \code{NULL}.} directory containing the VCF output of SNP-pileup for each sample. The SNP-pileup files must be compressed (gz files) and have the name identifiers of the samples. A sample with "Name.ID" identifier would have an -associated SNP-pileup file called "Name.ID.txt.gz".} +associated file called +if genoSource is "VCF", then "Name.ID.vcf.gz", +if genoSource is "generic", then "Name.ID.generic.txt.gz" +if genoSource is "snp-pileup", then "Name.ID.txt.gz".} \item{pathOut}{a \code{character} string representing the path to the directory where the output files are created.} diff --git a/man/runWrapperAncestry.Rd b/man/runWrapperAncestry.Rd index 78a84f011..f1024f8d3 100644 --- a/man/runWrapperAncestry.Rd +++ b/man/runWrapperAncestry.Rd @@ -44,7 +44,10 @@ Default: \code{NULL}.} directory containing the VCF output of SNP-pileup for each sample. The SNP-pileup files must be compressed (gz files) and have the name identifiers of the samples. A sample with "Name.ID" identifier would have an -associated SNP-pileup file called "Name.ID.txt.gz".} +associated file called +if genoSource is "VCF", then "Name.ID.vcf.gz", +if genoSource is "generic", then "Name.ID.generic.txt.gz" +if genoSource is "snp-pileup", then "Name.ID.txt.gz".} \item{pathOut}{a \code{character} string representing the path to the directory where the output files are created.} From 15f3a255b90d4a669bf41de3554d33820e9e2c81 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 13:57:47 -0400 Subject: [PATCH 255/385] Move genotypes CSV files to sub-directory in inst/extdata and adapt documentation accordingly --- R/RAIDS.R | 2 +- R/allelicFraction_internal.R | 16 +-- R/gdsWrapper.R | 14 ++- R/process1KG.R | 21 ++-- R/processStudy.R | 4 +- R/processStudy_internal.R | 4 +- .../HG00100.csv.bz2 | Bin .../HG00101.csv.bz2 | Bin .../HG00102.csv.bz2 | Bin .../HG00103.csv.bz2 | Bin .../HG00104.csv.bz2 | Bin .../HG00105.csv.bz2 | Bin .../HG00106.csv.bz2 | Bin .../HG00107.csv.bz2 | Bin .../HG00108.csv.bz2 | Bin .../HG00109.csv.bz2 | Bin man/appendGDSgenotype.Rd | 7 +- man/demoPedigreeEx1.Rd | 2 +- man/generateGDS1KG.Rd | 5 +- man/generateGDSgenotype.Rd | 5 +- man/generatePhase1KG2GDS.Rd | 7 +- man/prepPed1KG.Rd | 5 +- man/runExomeAncestry.Rd | 2 +- man/runRNAAncestry.Rd | 2 +- vignettes/RAIDS.Rmd | 96 +++++++++--------- 25 files changed, 111 insertions(+), 81 deletions(-) rename inst/extdata/{ => demoProfileGenotypes}/HG00100.csv.bz2 (100%) rename inst/extdata/{ => demoProfileGenotypes}/HG00101.csv.bz2 (100%) rename inst/extdata/{ => demoProfileGenotypes}/HG00102.csv.bz2 (100%) rename inst/extdata/{ => demoProfileGenotypes}/HG00103.csv.bz2 (100%) rename inst/extdata/{ => demoProfileGenotypes}/HG00104.csv.bz2 (100%) rename inst/extdata/{ => demoProfileGenotypes}/HG00105.csv.bz2 (100%) rename inst/extdata/{ => demoProfileGenotypes}/HG00106.csv.bz2 (100%) rename inst/extdata/{ => demoProfileGenotypes}/HG00107.csv.bz2 (100%) rename inst/extdata/{ => demoProfileGenotypes}/HG00108.csv.bz2 (100%) rename inst/extdata/{ => demoProfileGenotypes}/HG00109.csv.bz2 (100%) diff --git a/R/RAIDS.R b/R/RAIDS.R index f8d12a6d9..f263e61ad 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -706,7 +706,7 @@ NULL #' ## chr23 is chrX, chr24 is chrY and chrM is 25 #' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] #' -#' \dontrun{ +#' \donttest{ #' runExomeAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, #' pathGeno=pathGeno, pathOut=pathOut, diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index f0166f1f0..3b8993fff 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -394,8 +394,7 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, homoBlock$LOH <- rep(0, nrow(homoBlock)) homoBlock <- lapply(seq_len(nrow(homoBlock)), - FUN=function(i, homoBlock, blcSNV, - listAF,snpPos){ + FUN=function(i, homoBlock, blcSNV, listAF, snpPos){ blcCur <- blcSNV[blcSNV$block == i, ] snvH <- snpPos[blcCur$snv, ] lH1 <- 0 @@ -408,12 +407,13 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, == 1)] homoBlock$nbNorm[i] <- length(listCount) if(homoBlock$nbNorm[i] > 0){ - lH1 <-sum(log10(apply(snvH[which(snvH$normal.geno == 1), - c("cnt.ref", "cnt.tot"), drop=FALSE], - 1, FUN=function(x){ - return(dbinom(x[1], x[2], 0.5)) - # genoN1 * dbinom(x[1], x[2], 0.5) + genoN - }))) + lH1 <-sum(log10( + apply(snvH[which(snvH$normal.geno == 1), + c("cnt.ref", "cnt.tot"), drop=FALSE], + 1, FUN=function(x){ + return(dbinom(x[1], x[2], 0.5)) + ## genoN1 * dbinom(x[1], x[2], 0.5) + genoN + }))) lM1 <- sum(log10(apply(snvH[which(snvH$normal.geno == 1), c("cnt.ref", "cnt.tot"), drop=FALSE], diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 6e936e774..6ad0b053c 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -125,6 +125,9 @@ generateGDSSNPinfo <- function(gdsReference, fileFreq, verbose) { #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' +#' ## Path where the demo genotype CSV files are located +#' pathGeno <- file.path(dataDir, "demoProfileGenotypes") +#' #' ## The RDS file containing the pedigree information #' pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") #' @@ -153,7 +156,7 @@ generateGDSSNPinfo <- function(gdsReference, fileFreq, verbose) { #' verbose=FALSE) #' #' ## Add genotype information to the Reference GDS -#' RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, +#' RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=pathGeno, #' fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS, verbose=FALSE) #' #' ## Close file @@ -249,6 +252,9 @@ generateGDSgenotype <- function(gds, pathGeno, fileSNPsRDS, listSamples, #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' +#' ## Path where the demo genotype CSV files are located +#' pathGeno <- file.path(dataDir, "demoProfileGenotypes") +#' #' ## The RDS file containing the pedigree information #' pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") #' @@ -277,12 +283,12 @@ generateGDSgenotype <- function(gds, pathGeno, fileSNPsRDS, listSamples, #' verbose=FALSE) #' #' ## Add genotype information to the Reference GDS for the 3 first samples -#' RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, +#' RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=pathGeno, #' fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS[1:3], #' verbose=FALSE) #' #' ## Append genotype information to the Reference GDS for the other samples -#' RAIDS:::appendGDSgenotype(gds=newGDS, pathGeno=dataDir, +#' RAIDS:::appendGDSgenotype(gds=newGDS, pathGeno=pathGeno, #' fileSNPsRDS=snpIndexFile, #' listSample=listSampleGDS[4:length(listSampleGDS)], #' verbose=FALSE) @@ -302,7 +308,7 @@ appendGDSgenotype <- function(gds, listSample, pathGeno, fileSNPsRDS, verbose) { # File with the description of the SNP keep - listMatRef <- dir(pathGeno, pattern = ".+.csv.bz2") + listMatRef <- dir(pathGeno, pattern=".+.csv.bz2") listSample1k <- gsub(".csv.bz2", "", listMatRef) listSNP <- readRDS(file=fileSNPsRDS) diff --git a/R/process1KG.R b/R/process1KG.R index 380c81807..8d3a449b1 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -42,12 +42,15 @@ #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' +#' ## Path where the demo genotype CSV files are located +#' pathGeno <- file.path(dataDir, "demoProfileGenotypes") +#' #' ## Demo pedigree file #' pedDemoFile <- file.path(dataDir, "PedigreeDemo.ped") #' #' ## Create a data.frame containing the information of the retained #' ## samples (samples with existing genotyping files) -#' prepPed1KG(filePed=pedDemoFile, pathGeno=dataDir, batch=0L) +#' prepPed1KG(filePed=pedDemoFile, pathGeno=pathGeno, batch=0L) #' #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz @@ -96,8 +99,8 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), ## NOTE: could be done when the data.frame is created pedAll$sex <- as.character(pedAll$sex) - ## Only retained samples with existing genotyping file - listMat1k <- dir(pathGeno, pattern = ".+.csv.bz2") + ## Only retained samples with existing genotyping files + listMat1k <- dir(pathGeno, pattern=".+.csv.bz2") listSample1k <- gsub(".csv.bz2", "", listMat1k) pedAll <- pedAll[listSample1k, ] @@ -274,6 +277,9 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' +#' ## Path to the CSV genoytype files +#' pathGeno <- file.path(dataDir, "demoProfileGenotypes") +#' #' ## The RDS file containing the pedigree information #' pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") #' @@ -287,7 +293,7 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { #' tempRefGDS <- file.path(tempdir(), "1KG_TEMP.gds") #' #' ## Create a temporary Reference GDS file -#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +#' generateGDS1KG(pathGeno=pathGeno, filePedRDS=pedigreeFile, #' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, #' fileNameGDS=tempRefGDS, listSamples=NULL) #' @@ -373,6 +379,9 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' ## Path to the demo pedigree file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' +#' ## Path where the demo genotype CSV files are located +#' pathGeno <- file.path(dataDir, "demoProfileGenotypes") +#' #' ## The RDS file containing the pedigree information #' pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") #' @@ -386,7 +395,7 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' fileReferenceGDS <- file.path(tempdir(), "1KG_TEMP_02.gds") #' #' ## Create a temporary Reference GDS file containing information from 1KG -#' generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +#' generateGDS1KG(pathGeno=pathGeno, filePedRDS=pedigreeFile, #' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, #' fileNameGDS=fileReferenceGDS, listSamples=NULL) #' @@ -403,7 +412,7 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' if (FALSE) { #' generatePhase1KG2GDS(gdsReference=gdsRef, #' gdsReferencePhase=gdsPhase, -#' pathGeno=dataDir, fileSNPsRDS=filterSNVFile, +#' pathGeno=pathGeno, fileSNPsRDS=filterSNVFile, #' verbose=FALSE) #' } #' diff --git a/R/processStudy.R b/R/processStudy.R index 84b2d8d00..5aca5d60a 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2020,7 +2020,7 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' ## chr23 is chrX, chr24 is chrY and chrM is 25 #' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] #' -#' \dontrun{ +#' \donttest{ #' #' runExomeAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, @@ -2234,7 +2234,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ## chr23 is chrX, chr24 is chrY and chrM is 25 #' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] #' -#' \dontrun{ +#' \donttest{ #' #' runRNAAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, #' pathProfileGDS=pathProfileGDS, diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index d4f6cd03e..b5d46b4cf 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -907,8 +907,8 @@ validateComputePCARefSample <- function(gdsProfile, currentProfile, studyIDRef, #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @encoding UTF-8 #' @keywords internal -validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, currentProfile, - studyID) { +validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, + currentProfile, studyID) { ## The gds must be an object of class "gds.class" validateGDSClass(gds=gdsReference, name="gdsReference") diff --git a/inst/extdata/HG00100.csv.bz2 b/inst/extdata/demoProfileGenotypes/HG00100.csv.bz2 similarity index 100% rename from inst/extdata/HG00100.csv.bz2 rename to inst/extdata/demoProfileGenotypes/HG00100.csv.bz2 diff --git a/inst/extdata/HG00101.csv.bz2 b/inst/extdata/demoProfileGenotypes/HG00101.csv.bz2 similarity index 100% rename from inst/extdata/HG00101.csv.bz2 rename to inst/extdata/demoProfileGenotypes/HG00101.csv.bz2 diff --git a/inst/extdata/HG00102.csv.bz2 b/inst/extdata/demoProfileGenotypes/HG00102.csv.bz2 similarity index 100% rename from inst/extdata/HG00102.csv.bz2 rename to inst/extdata/demoProfileGenotypes/HG00102.csv.bz2 diff --git a/inst/extdata/HG00103.csv.bz2 b/inst/extdata/demoProfileGenotypes/HG00103.csv.bz2 similarity index 100% rename from inst/extdata/HG00103.csv.bz2 rename to inst/extdata/demoProfileGenotypes/HG00103.csv.bz2 diff --git a/inst/extdata/HG00104.csv.bz2 b/inst/extdata/demoProfileGenotypes/HG00104.csv.bz2 similarity index 100% rename from inst/extdata/HG00104.csv.bz2 rename to inst/extdata/demoProfileGenotypes/HG00104.csv.bz2 diff --git a/inst/extdata/HG00105.csv.bz2 b/inst/extdata/demoProfileGenotypes/HG00105.csv.bz2 similarity index 100% rename from inst/extdata/HG00105.csv.bz2 rename to inst/extdata/demoProfileGenotypes/HG00105.csv.bz2 diff --git a/inst/extdata/HG00106.csv.bz2 b/inst/extdata/demoProfileGenotypes/HG00106.csv.bz2 similarity index 100% rename from inst/extdata/HG00106.csv.bz2 rename to inst/extdata/demoProfileGenotypes/HG00106.csv.bz2 diff --git a/inst/extdata/HG00107.csv.bz2 b/inst/extdata/demoProfileGenotypes/HG00107.csv.bz2 similarity index 100% rename from inst/extdata/HG00107.csv.bz2 rename to inst/extdata/demoProfileGenotypes/HG00107.csv.bz2 diff --git a/inst/extdata/HG00108.csv.bz2 b/inst/extdata/demoProfileGenotypes/HG00108.csv.bz2 similarity index 100% rename from inst/extdata/HG00108.csv.bz2 rename to inst/extdata/demoProfileGenotypes/HG00108.csv.bz2 diff --git a/inst/extdata/HG00109.csv.bz2 b/inst/extdata/demoProfileGenotypes/HG00109.csv.bz2 similarity index 100% rename from inst/extdata/HG00109.csv.bz2 rename to inst/extdata/demoProfileGenotypes/HG00109.csv.bz2 diff --git a/man/appendGDSgenotype.Rd b/man/appendGDSgenotype.Rd index 4e7274f9e..93a55370a 100644 --- a/man/appendGDSgenotype.Rd +++ b/man/appendGDSgenotype.Rd @@ -45,6 +45,9 @@ library(gdsfmt) ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") +## Path where the demo genotype CSV files are located +pathGeno <- file.path(dataDir, "demoProfileGenotypes") + ## The RDS file containing the pedigree information pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") @@ -73,12 +76,12 @@ RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, verbose=FALSE) ## Add genotype information to the Reference GDS for the 3 first samples -RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, +RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=pathGeno, fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS[1:3], verbose=FALSE) ## Append genotype information to the Reference GDS for the other samples -RAIDS:::appendGDSgenotype(gds=newGDS, pathGeno=dataDir, +RAIDS:::appendGDSgenotype(gds=newGDS, pathGeno=pathGeno, fileSNPsRDS=snpIndexFile, listSample=listSampleGDS[4:length(listSampleGDS)], verbose=FALSE) diff --git a/man/demoPedigreeEx1.Rd b/man/demoPedigreeEx1.Rd index 94f24b4da..bd85ba63e 100644 --- a/man/demoPedigreeEx1.Rd +++ b/man/demoPedigreeEx1.Rd @@ -113,7 +113,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && ## chr23 is chrX, chr24 is chrY and chrM is 25 chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] - \dontrun{ + \donttest{ runExomeAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, diff --git a/man/generateGDS1KG.Rd b/man/generateGDS1KG.Rd index 26c9e3597..fff2a4c71 100644 --- a/man/generateGDS1KG.Rd +++ b/man/generateGDS1KG.Rd @@ -67,6 +67,9 @@ https://bioconductor.org/packages/gdsfmt/ ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") +## Path to the CSV genoytype files +pathGeno <- file.path(dataDir, "demoProfileGenotypes") + ## The RDS file containing the pedigree information pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") @@ -80,7 +83,7 @@ filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") tempRefGDS <- file.path(tempdir(), "1KG_TEMP.gds") ## Create a temporary Reference GDS file -generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +generateGDS1KG(pathGeno=pathGeno, filePedRDS=pedigreeFile, fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, fileNameGDS=tempRefGDS, listSamples=NULL) diff --git a/man/generateGDSgenotype.Rd b/man/generateGDSgenotype.Rd index 2ad46abd0..a9bfa0cf0 100644 --- a/man/generateGDSgenotype.Rd +++ b/man/generateGDSgenotype.Rd @@ -45,6 +45,9 @@ library(gdsfmt) ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") +## Path where the demo genotype CSV files are located +pathGeno <- file.path(dataDir, "demoProfileGenotypes") + ## The RDS file containing the pedigree information pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") @@ -73,7 +76,7 @@ RAIDS:::generateGDSSNPinfo(gdsReference=newGDS, fileFreq=filterSNVFile, verbose=FALSE) ## Add genotype information to the Reference GDS -RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=dataDir, +RAIDS:::generateGDSgenotype(gds=newGDS, pathGeno=pathGeno, fileSNPsRDS=snpIndexFile, listSamples=listSampleGDS, verbose=FALSE) ## Close file diff --git a/man/generatePhase1KG2GDS.Rd b/man/generatePhase1KG2GDS.Rd index a6153342e..18f090804 100644 --- a/man/generatePhase1KG2GDS.Rd +++ b/man/generatePhase1KG2GDS.Rd @@ -50,6 +50,9 @@ library(gdsfmt) ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") +## Path where the demo genotype CSV files are located +pathGeno <- file.path(dataDir, "demoProfileGenotypes") + ## The RDS file containing the pedigree information pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") @@ -63,7 +66,7 @@ filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") fileReferenceGDS <- file.path(tempdir(), "1KG_TEMP_02.gds") ## Create a temporary Reference GDS file containing information from 1KG -generateGDS1KG(pathGeno=dataDir, filePedRDS=pedigreeFile, +generateGDS1KG(pathGeno=pathGeno, filePedRDS=pedigreeFile, fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, fileNameGDS=fileReferenceGDS, listSamples=NULL) @@ -80,7 +83,7 @@ gdsRef <- openfn.gds(fileReferenceGDS) if (FALSE) { generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, - pathGeno=dataDir, fileSNPsRDS=filterSNVFile, + pathGeno=pathGeno, fileSNPsRDS=filterSNVFile, verbose=FALSE) } diff --git a/man/prepPed1KG.Rd b/man/prepPed1KG.Rd index a409d4cd7..6921ff137 100644 --- a/man/prepPed1KG.Rd +++ b/man/prepPed1KG.Rd @@ -52,12 +52,15 @@ sample be available in a specified directory. ## Path to the demo pedigree file is located in this package dataDir <- system.file("extdata", package="RAIDS") +## Path where the demo genotype CSV files are located +pathGeno <- file.path(dataDir, "demoProfileGenotypes") + ## Demo pedigree file pedDemoFile <- file.path(dataDir, "PedigreeDemo.ped") ## Create a data.frame containing the information of the retained ## samples (samples with existing genotyping files) -prepPed1KG(filePed=pedDemoFile, pathGeno=dataDir, batch=0L) +prepPed1KG(filePed=pedDemoFile, pathGeno=pathGeno, batch=0L) } diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index 857791deb..07a63d5a3 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -177,7 +177,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && ## chr23 is chrX, chr24 is chrY and chrM is 25 chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] - \dontrun{ + \donttest{ runExomeAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, pathProfileGDS=pathProfileGDS, diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index 5c8499898..2fb139add 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -182,7 +182,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && ## chr23 is chrX, chr24 is chrY and chrM is 25 chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] - \dontrun{ + \donttest{ runRNAAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, pathProfileGDS=pathProfileGDS, diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index c323b5f56..f387696a5 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -300,40 +300,40 @@ closefn.gds(gds1KG) if (requireNamespace("GenomeInfoDb", quietly=TRUE) && requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { - ## Chromosome length information - ## chr23 is chrX, chr24 is chrY and chrM is 25 - chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] - - ############################################################################# - ## The path where the Sample GDS files (one per sample) - ## will be created needs to be specified. - ############################################################################# - pathProfileGDS <- file.path(tempdir(), "exampleDNA", "out.tmp") - - ############################################################################# - ## The path where the result files will be created needs to - ## be specified - ############################################################################# - pathOut <- file.path(tempdir(), "exampleDNA", "res.out") - - ## Example can only be run if the current directory is in writing mode - if (!dir.exists(file.path(tempdir(), "exampleDNA"))) { - - dir.create(file.path(tempdir(), "exampleDNA")) - dir.create(pathProfileGDS) - dir.create(pathOut) + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + ########################################################################### + ## The path where the Sample GDS files (one per sample) + ## will be created needs to be specified. + ########################################################################### + pathProfileGDS <- file.path(tempdir(), "exampleDNA", "out.tmp") + + ########################################################################### + ## The path where the result files will be created needs to + ## be specified + ########################################################################### + pathOut <- file.path(tempdir(), "exampleDNA", "res.out") + + ## Example can only be run if the current directory is in writing mode + if (!dir.exists(file.path(tempdir(), "exampleDNA"))) { + + dir.create(file.path(tempdir(), "exampleDNA")) + dir.create(pathProfileGDS) + dir.create(pathOut) - ######################################################################### - ## The wrapper function generates the synthetic dataset and uses it - ## to selected the optimal parameters before calling the genetic - ## ancestry on the current profiles. - ## All important information, for each step, are saved in - ## multiple output files. - ## The 'genoSource' parameter has 2 options depending on how the - ## SNP pileup files have been generated: - ## "snp-pileup" (snp-pileup software) or "generic" (other software) - ######################################################################### - runExomeAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, + ####################################################################### + ## The wrapper function generates the synthetic dataset and uses it + ## to selected the optimal parameters before calling the genetic + ## ancestry on the current profiles. + ## All important information, for each step, are saved in + ## multiple output files. + ## The 'genoSource' parameter has 2 options depending on how the + ## SNP pileup files have been generated: + ## "snp-pileup" (snp-pileup software) or "generic" (other software) + ####################################################################### + runExomeAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, @@ -342,23 +342,23 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && chrInfo=chrInfo, syntheticRefDF=dataRef, genoSource="snp-pileup") - list.files(pathOut) - list.files(file.path(pathOut, demoPedigreeEx1$Name.ID[1])) - - ######################################################################### - ## The file containing the ancestry inference (SuperPop column) and - ## optimal number of PCA component (D column) - ## optimal number of neighbours (K column) - ######################################################################### - resAncestry <- read.csv(file.path(pathOut, + list.files(pathOut) + list.files(file.path(pathOut, demoPedigreeEx1$Name.ID[1])) + + ####################################################################### + ## The file containing the ancestry inference (SuperPop column) and + ## optimal number of PCA component (D column) + ## optimal number of neighbours (K column) + ####################################################################### + resAncestry <- read.csv(file.path(pathOut, paste0(demoPedigreeEx1$Name.ID[1], ".Ancestry.csv"))) - print(resAncestry) + print(resAncestry) - ## Remove temporary files created for this demo - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) - unlink(file.path(tempdir(), "exampleDNA"), recursive=TRUE, force=TRUE) - } + ## Remove temporary files created for this demo + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + unlink(file.path(tempdir(), "exampleDNA"), recursive=TRUE, force=TRUE) + } } From f6b0ea98b4fd6114025da99a6ec9b991854871d0 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 14:44:16 -0400 Subject: [PATCH 256/385] Cange extension of README file and update content --- inst/extdata/{README => README.txt} | 33 +++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 9 deletions(-) rename inst/extdata/{README => README.txt} (55%) diff --git a/inst/extdata/README b/inst/extdata/README.txt similarity index 55% rename from inst/extdata/README rename to inst/extdata/README.txt index b46f1a9ec..86f771a14 100644 --- a/inst/extdata/README +++ b/inst/extdata/README.txt @@ -1,14 +1,29 @@ -The files in the examples extdata/demoGenoChr.tar -are for each chromosome the first 100 genotype of the profiles NA12003, NA12004 and NA12005 extract from the 1KG VCF files from +######################################################################################## +## README file +## +## This file describes the objects present in the inst/extdata directory. +######################################################################################## + + +######################################################################################### +## extdata/demoGenoChr.tar +######################################################################################### +The files present in the extdata/demoGenoChr.tar files are the first +100 genotypes of 3 reference profiles (NA12003, NA12004 and NA12005) for each chromosome. +The genotypes are directly extracted from the 1KG VCF files that is available at: http://ftp.1000genomes.ebi.ac.uk/vol1/ftp/data_collections/1000_genomes_project/release/20181203_biallelic_SNV -The files -tests/ex1_good_small_1KG.gd -tests/ex1_good_small_1KG_Annot.gds -are base on subset of the genotype from 1000 genomes describe in -https://wellcomeopenresearch.org/articles/4-50/ -500 SNV from each chromosome are used (11000 for the 22 autosomal chromosomes). -For each of the 26 sub continentales population in this version of 1000 genomes, 6 profiles are randomly selected (156 profiles) to generate those gds. + +######################################################################################### +## tests/ex1_good_small_1KG.gds and tests/ex1_good_small_1KG_Annot.gds +######################################################################################### +Both files are based on subset of the genotypes from 1000 Genomes described in: + https://wellcomeopenresearch.org/articles/4-50/ + +The 500 SNVs from each chromosome habe been retained (11000 for the +22 autosomal chromosomes). For each of the 26 sub-continental populations in this +version of 1000 Genomes, 6 profiles have been randomly selected (total of 156 profiles) +to generate those reference GDS files. From f95b316479d151a9bca8a48ae919e2b215220068 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 29 Sep 2023 15:01:10 -0400 Subject: [PATCH 257/385] Update the vignette with VCF --- R/tools_internal.R | 7 +- inst/extdata/example/snpPileupRNA/ex1.vcf.gz | Bin 0 -> 104850 bytes man/readSNVVCF.Rd | 4 +- vignettes/RAIDS.Rmd | 68 +++++++++++++------ 4 files changed, 56 insertions(+), 23 deletions(-) create mode 100644 inst/extdata/example/snpPileupRNA/ex1.vcf.gz diff --git a/R/tools_internal.R b/R/tools_internal.R index 78bc5d7cd..cad972cc2 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -332,6 +332,9 @@ readSNVFileGeneric <- function(fileName, offset = 0L) { #' the path, of a VCF file containing the SNV read counts. #' The VCF must contain those genotype fields: GT, AD, DP. #' +#' +#' @param profileName a \code{character} with Name.ID for the genotype name +#' #' @param offset a \code{integer} representing the offset to be added to the #' position of the SNVs. The value of offset #' is added to the position present in the file. Default: \code{0L}. @@ -370,10 +373,10 @@ readSNVFileGeneric <- function(fileName, offset = 0L) { #' @importFrom GenomicRanges seqnames start width #' @encoding UTF-8 #' @keywords internal -readSNVVCF <- function(fileName, genome = "hg38", +readSNVVCF <- function(fileName, profileName = NULL, offset = 0L) { - vcf <- readVcf(fileName, genome) + vcf <- readVcf(fileName) gtCur <- geno(vcf) genoPos <- 1 diff --git a/inst/extdata/example/snpPileupRNA/ex1.vcf.gz b/inst/extdata/example/snpPileupRNA/ex1.vcf.gz new file mode 100644 index 0000000000000000000000000000000000000000..55101e0916c186b799d67802350dfba1eb61024f GIT binary patch literal 104850 zcmV)FK)=5qiwFb&00000{{{d;LjnMjGwprZa~!#m_cQme=omljI6_U~KD3`Ug4Shu zb&W(%>^?D?>>}AaWH;T1G;;Wl|1ts8l_&{l?e3dr#^X^}{eS|HcP4;8{NZ|a*IaM5 z_ly10U!T4FtWL$h{NWETU%xqj@$u>Zd;R?B%d^*S9zAb%SKHOYezjRY{psambvN7J zHnZJo-^^Cmv&G#V{;#=fcC%}IczM{*pv~EGb$#7zoArLSZ5F%DdUyKMzmHr0aQ5lb zxb;ui=+$PuU#!-<*t*}|m@N3*NJP6?hnlT7``K;-1i8ARP2Vma?l$|c52Wp17hCwQ{cPPV zwuvNQ;Gfg4oAqqBxNl}1IHSV5&6kTfffq2gt8wFJac1!W{(#?l*#Kg;duXm!*DL60 ze+#pHySZD^hVK^-6J*%UXgi_s+QVvn^DTP3KiutC;rmus6U@>L__DcL9DuC%n+-I% z{yHFxU0|3Q<$W|ynQZnkXp%~c|DWWDT#`_=FJ!?u~-ZbJYq4x5iex}F6D&PYOJEpFh=?6cDtl=wFj;%o=7_3{GO z<{RRH2(&Bs&@@A+0&sd@BDYQIdwrL23v{sp>WV$pbprE-LT4y7VV*8GFr{5z*`j=D z7QbDza(LX&+e4zk<)(>E-!~12%hhkd!nd1ECNbWBe0z2tT0MLI=-uJ|ve`cU_~;yD z)zjDTIUpM+R(*99mwgw8gXE8b1qMCh`=pdM+hwzzMRLyieA)JS7W;g8w^>ZnSt|v1 ziHMsmsI7)}Hqd~5FV8=;z3}gi?BQX%`F(Ydt;WR;l>Kwyi`kbI{P){mo(ipDMDdT8 z@X~$IC!pgxO8q14{w4n?YNqzt=72gQaUzZgk-+(@?MS@r4i67N^(eNR#no+^f~;5Z zk^f+?fc)WJ>!_&fv{mT4Z?u0(J9za=&04-{)znCDDELDa z`orzl9atN8vxnQo4oB4)0WinW>_u@6RED6-@CL|FB;uU9k-o5;p*3<$MR@fqCgAXcT%k zi8x?l(HOV}`>`{_!JBFAl&gVhJ@}SSHAMU&4QB@e{AcJ3XZ9{y8?ClS7Q#PYueQ5R zt+$^6xJ(v(`cvDp`d-h?cAl02wBQ5K7__=WL9heU7-sx-1uKY;wkx#yptF~&9jxuY z?q)B32RS`EZ{T|Zd7+s!iz+b~Mvec!A{Mq>#{MWPdi$9C= zcYk^Q=|APg8^+`XWBj5O->09iu1|0N4vmkzqxpUTX3&iDzNgXii}3uI4oC3Q*gTA= z7rAqsu6b*;&S9=M+ue*=*?z$>y+ONg(GrD@wsCkZwfta%hcz(u)$MS?zz9H}8?2ni zH`~?n@&53+0pI)acDdLu9wW!xH;-REfA;v*$7i?Foi6$5XZYXs05+-1d_W3Nd5}tstxkSwP=f&^y=yF4w^JrhrM0x>^6H@C@~8dcr~%>v=TG=gIk+C+BN6=i}!XDd-*wmikK%Tg^F-uJF8#c);v) z27is43Lnu)4W61>&w~>+d%eEKx%!$g!4jB1pb&_B+cuVl**T;vEWwyhfbpXZ6(8Ph zZsxo7=SaOULV4=A)|_c=y-~vI^bYvu&0Y7FIpy3juZ@O(IVsXhV_ule#i?XMJ9tTW zub49MUi6RV4?y2{umZ!i2eM5AX&sIpddhr#taoU=H(b^Gb5 zrAT)mNuc{VNZ|SQ0DS$|cdy^S8$NkhESD(T+3-j3aqkX0oW#k;_s#YO$tARS_U29C zI9OJAwpzx?-vy-%MDTU?>Ghiz@6O?!9jM7QtS2zdm!^TXx0@T7limFAunfj4k1GY^ zL>UC{1Lfj)m#eVK3*f50i;gF*pznQ?BruTbeVB*eXZ!78`tkize*>H((f1l?Ul}%n z6x@2Uky>vT+eoai7$`=&S7AEamO!t?DS-cv7DU_Q;3W`gK-NL|%rP|7ebn9N0DOdk z4rJf_@_;-yQ>=RwhLF85=Y#p}rfPl#b`Y*|`<3YH@8;-Ph7U-}t$lji+&y%E09m&i zt_G0!mp`wT;1LdAxkQHlI(z-@<$L(ym%qM#ao#;XfNc5i<{0>mbIZ5rY;^UZaVKf96&1f%Nl&0_zX>dXnnrMZBgdwts4m>{^< zkvLj9?4Go-OZqtd3VgmfY`?FNmzSU3eRzBW|Gii~UR+1|i+?=5y#Y1deGfjoPD)@0 z1Kme$n7V*9doee?QTD%QSFF~dJ;^SBVHbDDv=#uXOBCnJQ{cS+p_LNIrq$kmn`zel z1~YN_x5yIl2Vj&KKoCh6f6L|o6${E2g__WOz znEQ2WyyEN0;JxnNS|9G)Z%8iUZq`~=%f^V4q_r^tHh!1e+8( z=*+CpeNTMg=(*HaI}ai#?(yVw1mA48sFIR38i=-iC2&b+8%`OL-6)%8nIrtE;7lqe zE%(-Nr_$#i)`)ACon_KmimUZ+@GEfe<@T`p@AVuEkcZoRosqnON#NtVNoXhUYxj1u z4lmy|H;b#Uv8A}0^XP96ErVrqc>v3Kw`=Y%@4k|sBNUDNT^FV4m*Wbi^#FX=g6EiG z#UD_R4hbSi?69IhW?{{`H3q6iX_ST#Eupw9V0xthcd+d@%O!a915af1R+JcHs!xtj zv^v0?pv^`WKw^n`(m1;Ce!#OZ~v{bunHT&LCg5G5-}0Pq*TMn-P)DDeHeFuj3{`@sUi zgfDGFOi18j*!&84^S%q;zC8PM{^Ha5#o4cCuiu>g>CKCgv=2$D*|YcWKE3$(>)HA1 zU&G@;{A+%5x48tO41I@Bimq$mEv1LAc_2I>*A>T*I*_9ab2gZ)4TWYUbNwZ^+V^<2FVTccGU!>J#S-R^S-7c zxfksR&QV9Sp8~u+QXi<2Kk~XrCSSj@~I34W_?AwsAVCnv4&wC@gq{dD~FQxr;?y zXAci|Uw{4O)5p`jOR%AN8 z9$x9IO+pz>ssxCt0zV?8kFYAOO<0XqZ;z$9i!RxX{679XaAVGCmB>V0(I~y&xgc@f z2NhaadVysKgZi^^$!yo}|D??5->~kqNwadl_&U2?00mt(D2kF%KJM(rvv;%#r7+{E zW;hfFtag1l%DCNEFFwAlDzTZEzOQuhcHQi?5$Ue{${IhkNHkgT>H&NKfM1`!#uQ@lNN7|TYY!-=Kb?>b=|w>COB)eyA9ft zvk->C3cD0%MS6)&d}P*8&%7Xo$&1~f@UH)YP~}xaOIaIzZJbkNm z!-}7r1~n*u+_sg)%N5Z7YKcWsSkQM1bBTo8)%A>fegEw3aomP&B^h_S*@gOGusav1 z1CnhVN;KF1x}OE-Cye*%unooXAuM!5r0$3J@7hmb?YI|2IfQEAYc%PHPI#^L#5<~ghk<(nFXiv(?j6UqbYiL<)4gMv zW7^w^cWn2L_ENz+GJnT)?P{2k8vm!$P}auPZ3U((DOGx?Gj zv?Q#SY+`7{9kZxP9zLQN_ld6a(40x{(XA#{KHdePhOorIeY%(?B$c^A5Qo` z_!IU>+9&*pv^`7-2d_WtVVsR%r~f#80%XjdF!;X?=B3pEcHY6{2*&;a@5>021DLY} zW^$N`Fw?^{6Y%*~6ee7N2{(WV(wh_+Oo{-LqK8?Duvajb?ML$bBYFJDZUHP; z-i{Zb4yKJB_a<_fh%hmL8SV%yUjPvoK*#}1@-QVmEMEW-7eI6i0JNn{7~8WJrt+Co zaVC}MVM?;`y2-pZ8GDm`Z^~H_#@6*#LzC7z?*pt`Zo%@gMVRPejww!NQspoeVXB95 z>j{+WvNnk#Q`3Um^SRm!|ekMi!ks^Mi7<{DBj7&)l z%o{<7tLh`Y)06`$xEq#D`X7RM!re9e<^kr$G%50R6LH;y?qOOQB7$<5j4(NX!Dk-7 z+z6vISq1ZsjX$zxxxLU*5m?0ncmc|J{E;RX3ML8#V+JtC$GsVw!)%1v9tOtSSOir~ ziPV$>YDAEipvA}9bV39{Z=i`!nI1?X(5H&5fy!q^#aU7PtVnN&9@aU1X%#yJ!+G$x zc%plP13AHdU{S!JbA$wHm5Ua!g28U}6Vr2-@rta7%IRH2dRINYTglm23F@3F zb!1BI2CzW5gWhyLSd|DDD5oE<1ux@x_35pq^j>2vd251%dv=^{=0OjtF|2Az(FLS`lBE3zmxS=cVxgZiwa^Vim~}j+Q>V$ok`7@ z<%A|HR1CnJA{)aw`}|gN+qL&_Lw6TzI+ok&X>u-j1il=8R(_<5=Cpv?a@3A(#Q?4K?XOb=jE5xcXdH_n(M zQd#HL1N0V6CF?YJ^dkP-KhdUdM+ci{Xi?^-p?xHw8QI&0fU}mU*eMfBk4-FqIY!*m z3Nu85IYH%g4Y_fy9f4J71$W;+=8&`yuXR^fO6%xYreR>b2Fmb|0BH$5?vT*FNE ztOOoABj!|vA&xLjBbz!W;1N_MLB@NfM@%Dx??B1;?-FwmG*q3m8>f5U`KhSD)M2*N__Yd|(KSMM@T zt#myM21^()hnZ*?@s*O~H5m6Hy;lUt5vD8=Z52}_F_lJ^KVJ~g($Tm81*SA6 z-vkhVeqwpwju1p>Rm3U)CKU;eRYbV}rf8T^<#VLs94R?~2|bo|Drd-6+p7W05%!-l zz@paZ>@BoNEm=tGCm7OtU`RU{n^S~ED(ogBVgBuS0bKr(E`FrzKT^o7x3b5HFq#jm zFo28%e~0pMInx0!Mcv}5k>FxdWkO221C_ z<|V3A=Hf&~aUy*W)10h$g~f%i)LRcLyDA7Xw6_Yq;DlG6OlH}|H4dzKHzt&d3@E}R z5zNyp7vri@XzjQJV^TS%20ZAQrfI_ps}x{1Dg55ND2MeC=4m#d9QOp6qsgusV+LR} z>Qe>dOwm+!g%AXoHz&u&DvWpFQ%2Ks$ma%__W!03*Uw<%&YZ^;f)yNkMZ@d2c)#c-#$P zG__imZ2-&j_GKr;3d^a@TOp(Xrp57jdyDoxO|6z0&n|BMG_RIxQXMs^_8knffn%1a zp*Ap;XfLU4;RFRwkm@|Zwr?V_0Cm&(SS^RG1&y6#G0Y-?cB4G$H?}%qq zVU<~jCS24P;EjA|}x3>9Ogim};a(vtww;s-TK4RkM)B)-QmE?uda=vD{$Zq>`*&D3pV07VCiJ7$){Mo|aTMk;%Rx-O-gd*~r}@GPA_arf6Z>Y$2s3R8 z7xb#bw7cg*xPevXz)+?JPdN^QrMrfjSLNClgjwp}Oh&ZAS4(hf95YID!*R|!x^jwX zS{zY9S59#nKCNLjr##JP)L7RJ!~yj{DjXMpQD3e`);VJhS;vY3e}qwioJH?AYWv{0 z;HDm4BK!8S#hgTtO9SS6>T+8+b!Z;1!mbIhK{$OR7AW<^RTjZm zXQXMGy@Hgb7mTVeyt3SNN;$>|(^ag3!i>c6gb7-P zlf|o{Fx;U-Bty-VfF10Jtx{p)IAfTnlA+=wVby5acMTgD>l~?VsBi@V<~0c`)et7Q z;)XI^1(hI-L^Wz*RH@g%yrRL7ss#WT&Fkb<{_2s%?2{b*J&@D}>=5FZOht#?I64e4 zBWSL3f`3K)PR_f5t7IVC!@_j;M$51 zCUArGv_>qq1jQpvBD&rb1YA^lXGa;H&ND_0&kCaoVIhDpWZOv}FB;h(X2Az=Mlb{8 z>y34X+s~=6sjw$JvxXS36{Sr8^Gb~8$mDa>)`a$R#M^{T2O~k2SQ4Ruk@_Hu!~F$h zj%wtu2N6YJdTM8}#+}7I-FRVXm1aea62QD8+i0h@YS`At6ABBqBoAxa@7(};5S$de zmvt0)?x~LNC|QTFTtpT*Sy_%p84$aqC^r!19aT2PeYFAR$%)IABKPxP>(o3e|0kittd|SJC!FEVS*9kvks;N zW$dCn2r#;Xy3CLPR+D%iXFUSUll>QUAL+Aw_PG^l9!-^1^S*PS?FvCb{x{9qZp)_9oa#Se5 z(l(YOs(2A*GZHQ4g%IYmBL#{9UhS+DoC@s#hr?a)psGIF)1-gd8UvVSjQAckq6T2Jpr!0XL>O8A>58IQtOv``|7+O0 zWu6{8Q`5T@w8F5QIYpSH+Z?9WktfH83q4p($Fhm4;Y#O3W;Rqv9EWkZ<0l4vD?;$) z(o5}`vXT}OmkAtUw5p{-2H-g#o=i#EN=2BaHFOmsA7+HpYNVQv1c9SzthQn%!L*^3 zmgVrZ#uL%#PUWd0>9pNT4Pc%UblFY-n4r50YL**`gl?QFlX8H4KPH(r&I#N&*TY;J zradBCfiTYLCg6!IyBTHK5hiF|*EB4O20Q#`)Qn8wrX$RD!<6=Pv(dzn5;{^%d!7Wq z@-4{a1u;x>scE%DF>a2qxRL6pJt+ut^w6%FDFG7AqP-O#39#ccGZE&;wo@g{(UR4g zu}PDi=~DEQ4FgSL$$p!%D~T|n=>GPi;tH@VgFj)I^O0c=FwF(61SytdB1~|4G)l3^ z0%4NTyzA74CypDQ+DvGGak>B%%Z;$3YatM3JQ-Wnx@ngp2S*e!1ehbbyd0JXm=W2A zr=rz~FiF>~yekV~ie`Dso)N-ymZz#=9FrYxShd_X+o)C}Ucok|Rr6&NAi!#l56Py) zb9z`w4RLuUY2{VTlz5emt%kcjuqi!yt3q|){(eG}StNo#ak2Kqbg>8o`m_zNmz2dr zvjAqfrfHap1@~5kZSX@=u~^9*U|E4!1)X?s*QpRH#=QXMbO@LX&)S;Ey4X?H1!2a} zTv5@7HJlkCNU2FBEIUlGSRxr0Ff-r7roTaR)IOm@3x~y3@JimjUA5j)UTyU8kyi(>jfN4c{MU)u_%#yglZ%E1$ zSq>Y5K_L0@;OzF_17Z_0+Oq|2mt$_nJdh-3-4UuunL&n`!TzJQ$<7lf2K5l;vTZ6A z%P)YmY1*lRM!`_bYK?1_-!XplUR{J`mP$DeV1Ps=-Ck57H#r{rOvY9&hz6JzG!auH zlJFpIGPVkH3Sjw0t%{jcU>8v|n*ZDVLFQ4NU^f zQ&_RI5@4Ru$l}yKp*9mA%VR|>mlfT{A#6v`6LqGw^mIF|+U6PzJQ~j66VgV2!0U}k zgway>a$pEx;9-(;U}}~KVA)3PV(JHBiaMs{^CJ+Z4asqqcWxrg7;2VJc+Ya|J%fhI z>QQSHDZuEKpc?YiT4z;GRWKueK-_C@vQuV?k+}fNYq`rDX{^tjw~F2XW=YheW=f1> zp5`@*yDbpLIq@8(oNhLDy15rlQROmGTAl3Oj=Qmhho09{0|UF2`g|4U7R)0xcrq;! zszc)5<&oVa25Q4w$7qPBm{$%k8ACirq@w}mHKV5km8}H9j8gPwf-;d}X&e{hkF0Q~ z1+&6_|8VCi+6I`SLCy-B1Pl_FCEIGI#ATwaT>1boOb?wLYo-CrFq&p7yMTf-DQM+W zS#tqQQLnh1WgLld*D8OjNTFsQm_MF3Gg41|g6C>Gy3WHY&kU%ueRy_F#VVnl1%ZYr1iHy68 zDMTYA$SyJ^6+sYyaaxXDLnQ#qQiv4`fG~P!ZaMBNq!jM>go(hS5mNj;mHOqQ)Gxxc zrMps#$yk8t%;l>H^8-xK+iA>HJi%Z*!LR|0rqwE}U@-56B1h%d$P&%CB{|&kF|rXx zZ0_h1~)AJ4w@^xBJZm>-Y*qQ^|R9M*1U>|tPn(F3?E zhzr~hOK+#CU{j+ktz4?Hf*fa#FiwU0D4ejzAN6LyQ+CwDpMnVr(~NFloscDdEJ`Gp zlbjr1F)d2cnP%X9=aj<;-aPqXOx9GP&4 zsY9rGuOizn*BtTNy-;r=SI|n^q zKNHt4-iMNKhK_IQh}GDi9row5LdSv%YjHG^Q>y5SIL~Nsr6gwp4t$cVWV{N;nI=0% zOTstejAKV8kR#4ADxylKh$bBO)a5RSwt$mNWG8zTBx%HPmmR89!$%Sskcg#11h2)> zEkGq(HR6Pz6}2UUF5#Sx$(L{M<{@52#3^>{A z;uNVBDeb9CxOmR+5$UBC=V&ENpk{ z%Z~WUX-&_Xu8|wkIcflx)P2AKxzeiaD!BnTOQK#?a#1^xZKbM_H`?j61+<%&(y3kv zm+b+p(leMOafJU1;evoOxHEEWUsUNsz|r$(ru03d`ra@uh<+-S79^YysP-MjsDw zR?ZCmv1toqYAE06H4)elgTO|M%j#7pOxQFf;DzH^?GB5hjZ;IL*5I`k@Dndg4WmwQG&`G-oAYwAI&9C&*2MVK(0VAG1(9%^=8{XvrG$$oybbxN z5Lt{k&>SRcXLD_Cql~j|fU}k;;ZlMx;GANXq*!aLMm%OOtHi4C0strIR{AQsc1qFm zv{F%3!fBdjud)6B=Op2W(%oGVhv$m@fIRbpDN|lQOV`f}PA^2R;&(9R6sfMRSqI02 zr>9fY@U3I%B)RVuZcfNu$CRKKHP^@`y!D*&Uk!aC&c!YDlvN6&hw!lBi0QZzYf z)D(}9=VYgFjW+~1?#a6QoZo%qch3hnDe1`o6;V@%WxkXjD(Dl83Cn4ky+STIyxM_o zCaT~+z{Q)1jyTpY;j+`+Yoae${%U9xvm#pOFx5!C;6lz8Z~`yB%hEa%_7Wf4ONh&N z>y-HjaV9&q z3YaUre8fpZZ`Ul_ONdkStc(hNK%Ax5sa8ajghk3e@_@yJlbp!i(j~(IhxAD{y}Mlh zxkxY04RAWUQxa%3^;Y6HH5H60^cTCyWDu!xQZ(<|V(<9GHomdWXUd-(rs1|XBjOmtq{G4%PMqy-k*>C z`My7}m8oeyW!k0f`hAUjIGVb*^`Ifovm44M&%TTadTu2!6;o1KCrsK0n;Mdm8V_Y+ z1dEDEdZCobDZ{k4VH$}ydJBW4^UOUle9(|mBvxG!8PfuQf*u)Cwq6j&vl_^Pt@tRXdE*&b4kUVy;;TY7XUxlEf%V?*E%67g2SQ;0LPOr;{Jr}3gG zdfZ9XL?MoRXC+Q58cr*VQ^dt{Ifv@EW?=x89bQ>DD>dRQqlNub?gSgV6NnS^O4W++ z2u!9h^lA&Aub+?W=luW|ulyPkY&oo=C4&y>&Cg{wOG{xrBkryluS2TrQ&`!jdYohQ zZnzo=1USWs%&%~>z^7v>Gw&_>9(VU zv-AQYn~%@N@!5WS;1wuxgsPb02Z8(`)Bq@B^3^idX;@MJ9-o zH0)4=1Lu>cr1tqS>xa0^#;eeO3UkavUT4L;98+jAC}4*hN3<58Hytyny0>jeMGK(+ zfO6bJD-NCzy}zOy@6zaP)0?AJF2LIhv)lj|;}=I9-5+qq+AQ8xVNt1YyYHB>Y6Ljo z6eomUHJ_l?sDEF&zdPZgpFR}C6#@WFW=pCds|X#>@TLl*LcoC;BrUzZwwyl$oR8I- z!*wqdO(&cZWF1O{{uE3pmfoWu4P^#f_H}agqcerqi=g{tOQVcBYT#LPL167}0|j0uXT0(qpE|c}Z}7 zWLp(}l>LL-GU&ooFMD|H4}yAb5^jyCrVg5k;8hZ%xu9L*@3w14x0+u zh`8+Jh6>q%IB&;mT44*~RXZ`)T<|SO{c6BbpQ~bgfWtkwW16j~T{CFZiQ{WF3@95; zWk7}O0Gwis*5{UeZNv$ECc(IslH|&s8B)EuObSgVq)67jTLOb<4SJJo#K? zH@lTZA>x#yJ8R0m7~(WNO<<}&5p{+&UdaC6;}6j30<2@a2QUDb%`W(;SQyQfaz}1C zPdF{aLILX$SG`=IQEDAU>XRK5RI1A1mBl5-N>)_%# zI5oh>8dbfEnWrUk3708;dmC@su>@+vYPTk4gYEH>AAZVh9&O#5UJ?=n4&b? z^I=kP?sw%GC-TgKc%heBSMjYeO4I6+3Ox-tYp6p}VF=-dYI=uxMG>k60mD3{v$7+C zIBpf0&k8wjapN2(>sLdcR;cW9+?si@!fLYFr*zM3#L4U+t-AiCq}K&ZU(-(KQ;F=( zmXC_g%>004PKtd{w zR&DqX+ZPXqhUonzQ~7<}Zmu_2d1gG=$iVA;!XF!oGjQaLd%VMzB+@IYdl9E-q7IG4 zZ0cB|MJ5JNZE4bLYS!CnAI>`nMrv7>>mL!9h3Ea$Nqioq5WL5@7^G~tY*8mgSGa##;h6S^|v(3Oh?5M+E41)kiuJ@#E1 z#*e*PFyRDs4t%a7+7eba#949_enq)F;$*rEVRmIL4hj&jHdYM4N`H~3gTqu#ZIKgc*>1&!-r5>en}5oi8PRAr<43HUX@NQ ztqBR&%2Yo5U`ubWtuRIq=R7Hbp0I+oZ?~t6kHRto`Zb=O{y$ZP9a+>5D8jP*2(1Yo zO%YeF1|*C-KPU-L47wv>IfSP59YnPzNH}fs<8t`H!jkHT3S$XyUZiukkJ(l4rIwkw zSP>`;IC@@m>4MvY<8(nP1W~|w@|_i@Zy+vKUkx0(sj~5OmgVp}+XI=7ISm7Gj*-Mb zg<0l7l_*hhDFZpP4RJaFRH*LKqb&C3~Kz<~vMyshK0*g??K8_Mps$K%4X%MB~| z7Vkx-I~FSfM&9EF46+-zA|njAbaB~nRkq&4@KOM$FS9GV_lUEMZiC5j{~wdrUn>Cr z001A02m}BC000301^_}s0su@YrJc#LCAn>e*VoTd(ZLyDMR?I6g|*c}Z{UsBUhClv zkj$IRpVCzm%ahxX)JJh&DH*W$*NrqBDEkk|A2`Mf@# z*Ke+I?SuQr#nH(T4~}k*awFyb@%88T^V0dE^6%yo)BUPcOG+>_e3J8#kvFc^@O)&e z=g`zSH1+0~8_WOypZ6!m@bao*y=u5$l|zs5IXaO}k|szumvTxnqmP-Cq>J8eHy zGCyBDoiC8)+DrQj6sm)}7tlGOF|AE zleZtMt;3I%mysx8N$z_ra*i29a5@)Fnwuig#^td{ce!?sVO(R_QvDg*4ioI)w_#hO zb`P4Y%O&@}$Ge;_TjtA_?PUwK2>RkVJb(QAkDuX3l&6VE+_;WhIp?TMNmK6m$dm%Z ze7p=!o8NbjO9?b4W8VnpG^T(Hx`ZCub6o0kJmbG*9)8p!-&gPPEHQ9K@~1`qrAC|M5=rNsZZ3=12LW*kB%bfd z@#acQ^n6b`*C);ON!#;E8uPv@`%_c2DacyCxta*<8IRypj$wVK@-i+-*GnolN4dcK z;pshRT5)m+AYzt@XnKgcGE4D;X-PQoRQV?6Ku=UAU9<&;3vd-g+0rFI(6yXA{% z{|>G(?4xo%ugvF_`+2!D<>&W#6tr-?g3>AH{FOO><(|J1AP`N2Ijes@;RP)j%U8dv$hm)eLCb>s+=0=zjQhU zX*vaozquxw6AdNLyf=}cAYW|DUO3rCsla%8_K{lJ6`tpj*In!@`i*%PZz+H$VLMqO zR0O@aM>74Dg2=E35tm>(b*92v-w$zb>u@v64UEkfl&TkD#6c zyw2y3pP|=uy2vNT|%muVBg!B8Zg_m}2xW2}M4QnAJku;$d+5BR#Z3|d`r@{Do z7QS#XV06Ku$d#)oNS@DIhFDZX?D4z?>-9wd)gM(pw{8+hmK~?~{6ITKpj;QH5*A)~ zQRU&1c@GrVPz*0pHY_n4XhUO4&t=rlWz?rU>3!pJg-C%%?zN=02Z#ZO-6&ki;Bb5N zh;j|=VvqP};^=aH+DGl&CT(uZmNu?e@Z0DV12pH5!p`-NgKo-+bcA{EY$xGrfykLh zzY0gOJjK9^yT82svU9ycyuxGOw#+$z-m)WglcQ>jxddWPxT$V-@${l68T6!Z;+ev( zKfjOW{L%h>jXQOa z)aUTc5w&)Ns(!r%7sm;w(DR{W&gaj!ViLmm@v5ZatTFofbpwH`m*U7w%iv*n$_gg5~az%i?H- z+U|8`Y~8_$1Kp>k=uQSqPKEE+M=tx~YL1{<3=3>j*I7Bov&``<>A}IgTOr8F^?=EMiqBJ1>qk-9M9ihdn%CcA>25zH#sX|C!b+ii46T{ZTZYd5yhH>(!<#K$H(UJTdVb1PD<-};#$1+X`wx#Fas_;HJUQOD z+$nuN4_Tc4ICBhcpW)&P=qZn3EL_1Dr}KH7K*3s}kio?`lh)h!9Wl|1?$?#wR6V;7l+ZR`#-}%c*~dMEnhM?akD6XeH;}ME=Sy0 z4zD{?hE-XDcs;-Vz7>Z^8iz;^4&x;b2`h>~&+tMf9E|4P8UDnwbGB|?7A6ZR0Uu2KbeN#@{0ZD-gI9>Lgii3!4^o-m+t1;*3$ zeZpa0?=XZ$cqXb(-ZooE(4KHHzHllC|ov(I&Uz^|8w(sM- z&S|-;R2EkWGaC-oGB^-14x3bS@(BZ!RyF71GTOk7z@Kt8V3C=v0!NL*QN>}~z`}7r z+tMM@l&b-Ac(!RUI6_<27QM=~jL{c6@~<2fjJkQ|T@RMvkw@EP8eBipzGf6mxrkN6 zu6fsb(a-m-)*M8f2jBD3RpRi=Qj;a;x98Owq3X`6W?Njt%)KK6Gq{Q+2QR0rmR{Mu zuO5kF-?+4?;y;xysm%nz$KTfy7HYnX=Q?e(k7sKEOHEws`n$UGlaiRh5!eNeSkB-W z#Lbpp+6tb+U7ibCMQH|28faPI8oGCkl-pt5p&wadxuw>BLlfjy>Z-x` zBxo|Y1~pKQ{Izn8KQD%knPkPH=jE_8h3f?^MmsVPiw-9iiQB=CSZksDc|Cw~SLEX( zja;jELiM>`9Hk*q+eK8!3wy>>IsSD3i$HY0J-|AK#Ci;A=VHbn+gmm+>G7o$cMh8* zIHL1|!;S2lzn<{>-a3a&0nqEliRk|_&lj#n8s7q^%6{ljqvx83R+zvt;`4b|Fn)ht z$7U7%9G5=jL{B?cK)&>IefGIN`#pcH2DBXb6#Q2ofN*o7M^TH5h1D+&AC#Fx*EYhT3eLpjZ~)rSKsep^RP{MPYh z3Vd!imtp{u)8o3eP*OpG;n4ib;i({xzz{Cu!LGL=&DEl4e_qXy1>m%vRoJy!7&K#e$HQ?3cK^h&4X*Z zV0+>CVAaZQ!OgO#2TK`SMo3+)McDt8qA zIV@r2utANBqZn~qTylcqQ4slNP_DwU{QR?7nDRrJG3M&9z)0(=@W8yo1snaa(4uu% z`Wz_YaXU{=KsY{Jo7cnDtGk(I)hcyacd4eF+jZP}{uoC*Uh0u1%3;9KW9|r-8u*W% zK!R{Nf}i^?O;$s<6p9u)8XTuDP%@EQBm$w~s+( zFcm$)Xx4LuqXY1og_5fxxnir6K` zVMMVi4OlWBYhO!Y3bZ{u=0V$w{YXLERFts&C+-td)a(E)f&(>c4~qU!exBJ(_sEr2 zBSbFWtGkBaNLhAg{r-F3MWr=#>>Z^7$`MT|;cjd&I5E@{9B%RibcD;taZ0;XK)H%i z$x+ZAnbem3rG2pi2~`6Lb>k9-zTXaub=>NdTfnkVhh3r^hUi@yi!zlD8_Nwf|Q zSPdE{moxSy@zLwn&HIooUmr)1wFf7*g7v*;4Fyw&9udg3VwtpSKd^>azCKQM zF*m{nf4=95PmkrYuJzJ-`i;~t_n5KEfG1EX+}sZza-vUWfNWPqIPXI;lL*w@xFjJ` z%Ta95Z5`-Y(Fo?RCzGHYRzG?Ig2HitdGYN3J_Ios+|u3^gBQ6i=s zRgjAg_eIRKS}_ykmrQKyK26Nvajy`X+tX>)ABVrQIrl5`})FpMKoG3`#_+eVUq3s3bfQ3JHjl6I~`SXJ3$-$u`hXa~o51AlW;W#^> z9IXx}oAvzG-9`TGNEqHjBO3Ia-4{u^B3-e>9nIJ{$GHi_EW+L;4$ppY4U;(zwXNLY z+1qYO%8A43CGtsdM!BQsiAQZKcO1rXm@~rVhVsZE;zf$pV_Y0+w1{5;)L zckOSVadoEscDM31oIk#ARcg&B0Plf_?6eCed|AzftQZl*P?s z*n8C9A-I*pzW)yQUbudRAwF?qQ!OE_I)P6u0YNji^Le{`Wo7>8=G2b-`qaZ$j?g*YDjnl^Uh_#QN@uV8C z9a=lNtL5*5!`8%(;%DJRb;7!KtusAPjFA=3JaD9lC3c?m!fEym-M{agzh$J~HhNVz z1Lol^?^d6AH|07;9vm%jl3t{6wCZt~Ov3d9$t90UYI>U!M%3(Nk8(4&`dNvja4jDm zpTo3k;=Eu!(vhqi9D37-$)qU;tvw8XRB^tye>NLxbVSDz1;>V@TpKP}N9l%eEq6E# z>sbiGwT`F%?39yogty5#N_~W*iq-nQanaa3jLW%zt}6q+7Z4ROyCD~ET{W<{%6R(0 zVM7fLd^<svjIag>bP$UrOJ5axQ3K*rlL}#Koo$Z^yhi-0!aW6W1Jzn>?{2 z)+>qd@XsmdJBWF~D%yE(_DltPMz~g>gP14g$bl+~7e^*6Y0X!~KK6FOnsOQYZ+kLY z9K*~M|N3w$)>kQ)F*D`p>M5L<31D}J)l#{Ef^l@d+LJRIwEgU@2~ZO$q#ir>E-DEC0y@ExXR)Fa0&r00(+~G z>px;2S2^7tkf0G8k2@+yg(J#P8}CUnupZlnp>edD(^Nsg2%yJNVlBnT&PX0jL8%ht ztv!Z4i-(R)Ty=oY<#)MeVM7_u!M)!w{oJ2job-s@`(A=N8G<@pbs?7Lz2pljdB)h*I?>BzKe2ruJFxw zA@E&Mt|vWvoP)@#x-Hl^>$~=- zwZj=zuHv3_L=*L{1B@bjf*w8eie3LaV!Uhfdb}Rb;oJ*HtG??aBd@De;Vb!L6ky;TujX7=U8Tp~(b`DRt zwkJ`{*!#n?V1>hiNKcfm>lMq8zVKwKmFqKl`AH$8aD^(~uHvxTm20q(9mh_R7*+W< z4t@@8k*3oXUVttCmLYUioQ_oj*V#__3l3Gf=244Dl{tjc~8teG^#CpS9u-{s& z7HzRwzQ-tvi+~wPqbO%$9cwzQM6_b#mgpyDh2aLa(sldL8ZBxj783@kjBK4^S@X%C zsh@>aD64T`)LQA#BGpoo7v|`~vWw!0^$2+uE5SZ6I#$VhK6tL}s6Ep{>%z$rUkT#* zI~fmVT4CRbHJnJRt*c;qcNMlEwStrr%Wn3f5{F-tE7!Cx!bJg^e6>%0}an^-!^mJI7`VW^`# zm?-25oxeScCbx{O0~{(!F|-67Dr#Wp@w^zweai|i3bHtyp<%_mFZp zuGO)#CzFf?jqBIj{nkf@dpjdJw@oJ^X$M58@PW0R^r;%$}SgfGnjgG?us{tD^ zdz8CY>cX<4(^R6l=xCWrdeUKD4EyUs1##wsp5+M_MsyjS?s|%e<$(8O7-eM(J8V^4 zHt}blPQbVKUSgn(9T9CeT(LsfapH-suu~ghr?mYiZ$G0q+Cfd*oBW`M{1_OjU#qra zV)NqDU0Ru@^1uiR{jB7`!aBGCwyCTb5vJiyr6HJ}+zRr%jkKZ(_VnvkpD$4u#f~$i9*mjzWB<9t z{&MvAyiM!dx{fy&3q%w>Z`rA0u+Ae~1Vek*j)N%15tDyLCI7-O5M}G2fnjfF&-U&b z4FehU)=4&NC)vxCEMkCUJcVJ$W)&+Ht0#=C$;4`f#!^7|EY zRe5GzFoIyGmGT;xc98-xYZ_yUB`oc*%9;m8gfY?=2}VE4=%=#(DYrb6Uzs-vJWRTm z5X!f&^u5N#0f|tVU`NddMwlOdePDZeAO`Be%Z~R9;p(=a>a16 zZ4$@|pMCT8V-!YWS24=vtfVt72|ZmxP>gBEHWVX_LppT(ID65b`_MBaYDi#LdozAK zF$T;b52<9lEv=rJ;Opk!uwfNTtc+5kg`xVhDwifU{f0ezWSk0I7~`3Q7Z*G}TyVkq zm4|U3i(goVW>0niU$GV-cI>b>M}hE%J?SUL=*(IbJPSLHJ36+hh!VV7?XWlFxP~`l( zx$ylv;>$yMmUS`8#3Dg%{4IZ&t~QKfu5r|8N?|VF2}S*#)KCDKi2}ur_OT9`oI^XB zLRht76H7;nJKJg$EU(;lGTkOIRZA)A5D6QjZMHT{9B|9{WU`K7} z+lHj)h8!4fe_LV;))2Ffi%yJ=&O^3ICgwoEw&e~VM_t?4p2Eg60ZGH8u%T?xCK%&w zNRFkfts@iIjgBCVc$w|Es>00o4Q!P@e~>vH7}g6qc0kFcVZ6(;lyf15{FEa|qn9xh zFm4@z;*zOh3KaZq)tj=ElSVf3B>F>N(gA6SYNnjbr!#;hJ9G=G62PL#r~XTELgFE-u3(G zvgsy=M~|E5?{o;I*cMO?HFCns5=`Tw#L%+U$I%kx+_k5Xk+7u zU2*L|sbVQY^4d;VD0Un^dArtc4hi=gt0<)2>N(aK656oi2!Xwmau)BrfRr$;GQ|?s z^Vk75#f}c5c6d**a`-o9<$29rj572~O%r5bgb6>>2Amj{f4QC(@ooagniMQY?DJ!K zQv*9X{u@`l3Z`8dF$iY06&y@q5Qst?~J9moFO z1EYK1Wnd_&9cF-H4WcX#Ge9vs;OP~NZxy@~BoWLYw8S`Q!PziSZ}hrqx<30AHj%^3l1FHz4JUH{@2;r)oeX$eP-Sq)6Mm0ac4V1+FBS7AbK#;h}qYtMyFy8vl@<_L@i<|TsbS2!;eCGD4K5U zFyB3ki%Y?VDV|lL7w}cVY+Cr%)%j)1S32#obLx0Lkm<%c-eqOizYUDQ=(G!>w7Rt6 z$x(-@ROy1s%j&x^ur{0CesJ%hVmZz;VtWr^GaN5i3RpB@7t2=B$~mJ$WtN{PR`703 z&qxY(s7l+%R4n67Y3J#A(L&llB~!gk0YO{Asx;%W_lX^y-<=8|7Dc5ACf`WSt%@h+jtND(${o73$yHkZBeJw6I5T z2!`=s`$T|XdND6pPj(DPLorydRhbzHnHv9uszX@ywgvBNo0aF9#jJ)=R2z*NbNh^wpnZPl>#|WW<*g=M>L{okt~8 zoVR6{+hC%=hgE;rkWn8vjy;N>5=8~pz(ld<+o+WPE8^|gj#PqTcng+e%L|qglqJ}C zYQ-|%p=5X3Qmo)f2S+$euu5O#jsZXrA)XFarRvxJW6%=j`fdj z))<~Xg<_wz#%elziyT2~fOx+{#V8iRhPIEQjsl-UGdb2<&IwHihd33i5(oi@7fB@& z-ctd-&yrM0B~{un5T_0=QZY0!9G({GEm7DX#!l}jhL^E8Voic&l){d{ieeQ?MVwg2 zl)!7ScUWDcwocp-Ze4?0cl4JE2kfZ=_WSUC^EhRiX#a0RRU?_0U(?^Mi@+4*+G8b;piK)ZNlv#Z(%Z8#@J2@0MZc9LSu zPsRD>6Rh6-Nt9KqBA-iX9Qy4f$nS7~>kh4Uy9?{kEW*06Wn#U6Tydntsg|SU*HLdn zoCymjJm01_5rdiLNb3y@^Y(T&NH7jCBpysOJLZ2K0XxCk(frGHB?aT-q6XWamthRY zMTKUQhk;>%vFjx%V!+P#v`9E4cD;pQxj^3wk7n&$uv?3LGElKvU?e^2zcXP8ihXE# zVvb{{&kmhc1PNoIqNAFQwRj86O}GwboqE)ZmTUXQ(sg0yCpHR;13;fANHiOlF-2^f zZGs)ARUO8yV4OZTZ8+-3!J2enDYk?i!R@827~UG>SjvK(tHjpItbHRfL*aSJ5?872 zCmTnwf>)ke7eP$y=&kPX(-gzAu?`);dH^5l53KuKC&qYdT0bYC&k5*d#~c?xJj;*; ztMk6^&AxFI1}c`p2DBSJDV8yw;JDRgl41@&EgIKpJtZre8IBMo>%FWH40iaBg3)nL zxE*L=y)+HW18sYOlZaW!LON_A!H%+Chk2+N>K#XbOt9L(I&o+@!5ZF6Q{U3bQ}2Aw zTW%36)E#A4f+Y+!dL|&ZdK8^F6o}Z_1&(YxqIh~AO~9MkZ2O!`j0wv+%|rT%Wjsph zF*8am4NlwJ=U5c0$I)2ZhUJn&#ae$mF)LWamg=o5P{_1v*mP z4xL(KKDt{vMp6qLKoxuJh0&cJp60OgYKsB#q>du5fkBD*+u`z+I!+swVU;)%)rv73 z?Rd+|mS=RbF#qtka7`(OXh-#I!!It>b_y?%w(>Q zZS?q^TpTwg=BL{vSjBd4*0oO)YZ1!Vt$SJ*R-weZpQ86VMxJksFg$LbJ|9>G1?_O< z1!GK@^IP9G)&wShuRiXTj>}+QDwD4Zv^S8j--ja(Jv#Ac(I5BdU4tYfy% zI?JsXhkyZMtGY_CQId%*Q;lTP!tkawtB_}6S7-RUc+#+vCsr`T$mdJ)d`aG3vf){7 ztEhZpgeB}&8%o9WwgN1ecT9j_Sh@${)7d^d>6YWYupsaXr_P^=$5mT~NqAxCZW>=xIs$xL%IpAR{?7xEfLf9a+z1ROd3PZR3sxdoMAu6%lA* z;|SY(TLFm4RmO#2If)mC)x7rJ9$e4RanY&(m|UCvJT}|ZI#{&0j3)wp-^T%KK5XeB zTnlvc9Wi{oizDciZdEibuGbIi+9wyo(GS$r;Dc)k>qU$Z#>JruvBCitSF!(=XPq@| z%L?+?@HQ`wu#Cnv?>S=X!g3TBmyf`O5#9XeFiPX&3YsataVcEzYF{JdF*p{v5AK@P z`Ezj%4V?F2#aL(eJaGCyA?0lW0RI30ABzYC000000RIL6LPG)o|0kWD%Z@EKuBOM? z&te$5lF|mwpl}N9=^6M9deY+_*TXj{X=NyW#Wopf8@o_d{#Hcj!n>##>(`%O|NZs1 z{Q2kCzyIgIV)**&?_dA=_pg8b?_dA^pRYgv^XIP^{s_N<{KxVU~aYFBzH7d-n4^+aK{)_%q~ETH-2$5~y|l zmHPJ&_0U3q4{lFCG(Na}xLh;$1TWy2n9Pks8x#6HG4bT$?-g%Q)naV__8s^|CC z`Mve~drQc<&yDuiJB~Uxcu&W?lo)GD@Sb!&kLL4e=eUpOea}k?Pvfgx2^&Ya@IB*M zFda)`ZyoI3Y^n)^SMixbJg?-iX2+K^#f_$shN5$mjRvxn6SKxK!hNxg^t2Bg(;3uhcp3HS8Q3sC14e&GDqT zaV>%U#OHhRd{5rrvvsfw=v>z{=bh5V^`*zY$A!=Da zbQsdYr9xk?4Su2`TjIW6T=PJMa3Arx|9I{{=AC1Z*B*T<94D|t=#*zPe({Bhj4-a$^#`JOc2ldks^@e=sH zA6)a$GNlA^(6g?EJLHl>k101C#J}I^72){MD;_y7TtUvE|AcD+{Vd1xxU^V*U|$QD z3)+$Qd02L2Qakc{9+*PU_3P$8c>F;o`NsbB+Ro~niNG!|=lqp9f2D35NAMrYxz0ZN zJ?-4m)0f^nzc0`4%YEb82w?2J&a3kGA_C8T!n34&h=8}dMV%QC5p9NVV!yA zJ!LUuU|b%;S|YY**sxxqt-&&^8HdXgbD@my>IkL9ET(n`5$q88%26UPo$L_D;0o-) zroC<~77;UC!FMK?aN_gKHTou0p`!7;c5<$PY5&nw^0D=`HePtTqgf37ujCG60Ma58;p8rms_SX+~U`4QI$Tsntq zrd*HUnpOP1sOvg4+4QBylv?1R0sh>7)$4;>5BLI4zFN8aYLUf~8aB$y4bp{LG2_d~ zcv3c5mCYsml_RiCJqu5`6xw|O)pKI%oR}Inj%fOnuat&xTv2d11eI_t%nkWUDGJwD zjQWiYovFvxAO_*^WyG;48DoHsg|6H*zV-!c=ZFS}F^H#_alOZkg%bq@v1Z5oDJL57 z>utUMi(hh~_FoFjc!8!18va-SW zav0Cb#R&74&T&a|T+%fzA|(ns2cB^ej;8VaJ0I^U=BQjReCM1-+hifm;xN91i-{ob zmQQ0ZPh;=fpj9q&0As;+xP;?UA%EtOg@fz(eed(&@;g0OTzj59A{?jt_c|OK<*1df zw{g16xpD^C;V>EpSJIETb{H$3dCB70fHCIUTe5l@=HXoL$)~em8@EEmSs3&CxXbgN ztSK!=>T+sqBULyVm~#IG2~T_eH7Iu6(c|V z$+^cIN-o?Ig}!er@p2LtV0ad6kDcZ~U7Q`r*6OmvXgqi}au?$r-qYc24vzBuJsr^r z;YuuMgxe8U^)Nz&LJH4#Du)qJhnG4zh}w7rs&J`7RO$%S$6urg8d*QBikFbqpL7N8 z^>;cdWJe*6mJdW!tPcrqTE^M+aQ!o18F2lf)Ic+MtluU!EJGN=QDGw-Gg{kE5-@@U zY$>PMzTRfGgexKc!21*~GG>}=Z+CJSe)@rBD8G|d80%Wl4$UN7ZWtbNXr`8W4bh$# z)J(!LL-fM+yc`l*2p$Vhx%ST)t4GU8xsDZ*KCV;rJ4ayh zc})FQgZNHh5_uMacorSPZH|<#sL#YJJaoOMozl%(0*@Qg6UGvbur$!?wkz8~i#ngl z0o@tT;uEVc5k*FG*kJ`VTIuyYw0o|ZI@e6S){L0n z>-fPdw^F$d<$A97WX-dEy*8tTYw;(-L(Kh(W^WNm0m7@$HTGt+w zom(M~?=p_WO<*XObqRlw{uSJkdUBug?J3_6FaH4RfKsl773{I`FaL6UccnTNMdjXxa%C<<$wyx*JSPPy5bL=DW zN@v;Ku9F-wo8L#<_oWh`JkS&6=qcw4cF0p$wL@4{ zxDr9`^7)?pDWA)A|K}H%+Yf8J}=j&R|*Hb~NgieImd?w&>P!$PP}^@&yM6YGtu zcuvs~ozU$;_HNOZ<@>I9Y1dTs`;Ap%(a7W1TSHd3 zGQGWb_3|ZgXounD!a-=yf*l;aUkJjT zMM}0nEtyuK|34=X&+jAR;~*wK2-L)Cf%DFF6aaQ*vT_X%Bs>*?tOZ*)uCF4cYaZ-G znQ$BmELcZax@Zw?f-t7zfbrn4sI8sz-sZfwYu>rVqtk>P-c>Cc0v<%MEqCP-VWQeT zI5@bD28NwCDkG$j?$3KF`dX2lx^W!xeO#Unq%T8Zdr$5S){Da;)?7e74j|dpsb#p% zXka`%ui*2vN)Xcz4uvmVIS%f61b7dO&vO`-V$RS!fV)R%915|-P6;dZ9r9YaiU)ga zPeF7>h*(|h*+f`hG&gQmhI4xl$Z^0QE_ zc<{_oJgMB#V8appFNI^RP*~(>2q9dem6pBa%R>W^RaAPdPc8|w1|B(4cr`lN*O|j0 zE!z}QFId$vO0fV$qZQ?D?djsxk!am*;MUC-09=dZUBy~+K+o)E5e ztV40=&C=UEcx|lfCyr20+x0-oCG5=g+^}RiB5nUWZH9^bP>mo^kK-DnW6}H}tqg2p z+|P3x*Kv*ULkTS$yBuEA$&4{EM-EZ5$0Y&hDBD+#8kDMeG;0ma9YYLuE=jqDM|(Xp zEL=y;D!TR@n6PAe*oL&FmG1mr9R1vEeQvf+8hEXCh;^e=` z|8x5>46XE2L-e^LdfvDiz`}Nvf){a&J4$-b4y-aec)Z24{z#|{>)m5%QP6fE_d#~# zh6jg*SB@N^a`9;0W>>l?mk7@NIdTocacYiUe5i3rn;4)4?m>12H|nBpJ;x4$*b_qF7$ZSQ&EpyS18hE7t%gQFgGgJjom`V!TJNR6NfU4t+LH zjEze_d`sW+dW=xbU0OgVfrNrkxKKKm-dw7E#5fP#()c#A3%L zcdm6Nk`WIbc`RGjlhh~xJR7SsAM@a_s91bb^Z-4{>BegH!+YBER|V<;*LD2u^S-$n z0v*k7Z9z4-((mick%Li=8_E}ZJcV0_1@~CQL(FR>8*@sso~hJGG4(43rmLK>A%er> zs3P1N9$0qlf8koFs37h2s@##=bSUJ(F>IsQ&2SZENBUa@*4#g^$ zFrx9)ymb|aefE(^9NiG0?``=eoSw;eEhnhxr3B!xIdVtJ&HeW-GND{+7>RSNm*Ikg zozTvCXmcJ~-8sxnKSj>+J#wZTVROuLHFU*>9Z&Y?sxIXFp~A~R)gNjY zOLmlD3fBXk{(dr4Rt&nfma+_yc#ACTWw}rhd#%iEM(Gl)v0xyVauYM zTu(<8h|z~_aSb)A6@&h84ZqK@1P50s5!Az5uKePTw&+$2cX2&qm5brZPmaTC|KRR} zI5<&Q8QXDt-cz{pGUPD0rfcoXY^T1mHgx-omxy0KG);mRJ((s~+Yt*g%3i)X=&@tP z^1eB2IB2BnCr1(cqdaA$=7d(>xefzt^%GcJ#x&g1fsy*@PrCn|)(Mi&524LvRd_G1 zpl@hJ_ZL^OGpc3VFOD#q^~9x<`!r~AXJPzy3>d6tMGlwHRyL?#Y!fZ zX9w5)Jq=C1xVmCb?tT}OD+PnyzHuo%VzWBKN1mLXJ%RaitTW*TJCAK(5Tic2qPOdQ~aXf-wxeh+7Rc|#onRZ++u6ZcE^q1`{ z7FUn1ufFHijD1`@>#W9DAxq8Yd-8lw?i-f~va!}hI*Th41;%bAukw@h+^^P50tdhrX4oh-99M_B`Y#!U0wO16HFrIM{&mdqP z)nPITS27;*HI8~LuF}g+FoSC)V`;lh9S&5BXWzCcBZKK($2t@4b4QyyO*1$y z1$}JmXwc#a!>As)s~p4kdE|?5ozPTv$d{(=gwdpTmQ;oH* zwFyMr#)TvHJ+=yG7neHd6_1`4?&$0MEGJgQZz`i7U>qeBo8ZtNst_Ht@^yog6^j*# z9s#Z#DpJ<~w{`jG-Yvu7V{3cpf|p)C-Let&mW^!z^%64Jz~$*Zi@s-}jf(-Jn2xAo z6G4oXwyyE)Ef#oBk3j7qal{)o96>#;V!+s#$G7W&4n^bfeY*UUpgFW>-n-s&gk7y1 zf}_XOGxqj$2uAHOdNgZwD2y&X{c)p*kyo4?WmJf+c}T5bJ&;EsDu)GS9s#a-cB}~Y zDDJ`GnJtH5()F5jxB$X8o{g~5*2U$Ru?v&OH&>3Z^8B2K6+_tOA=ij`Mc4DhKkL{% z&5?ELwPrjM<1uK&od|dWz$%a(9L0hyMm_pSxQdq|TlGMb%X~DE_v|CmQ_}D}&$?apffE=15w=p=p5zS#I46e@rjk_*-a;e~D)z6ohj)5xi zUKNqH5znRLZS_yL=SICfH*PPGxnNUw+pyKqJrv#3j$zm_+M^+0($FaE8(hpe!;W!y z{L0l1kuyiKL%E}+@Kbxk&)MM8Q_U>aX~|;puYQN)hjPmKeU?Z`h2sQ~I)_IUE7#JnT+BF|uN;e*2zZwFsqJIZwvXSI_2gb&{rBOps^zI7czL$h zd)68{^rN<}X&; z9s5Z1Xys**zloeB(fAGL!BNGQRO27r@Qkzci#sA`4h5W41EXi_Fm;t9PCw#0>LcsK z$cO8A4PQ9H{_#~dQf-6#4zxNbFRo!s!=Z7Nn_V?tk4)-#^SQ$YPkN0tW1~r<@8aZ2 zSZ561n0kX_*trggtz2G}ZM)7(_N{n;P`yeU$4*e6a+oA$`Am5h6I7FQV?MA?3) zPF_DQjk5jtRAY%~9XKMq%4LkSd$hH3c!2GR3lAK2jk8W%F0Q=oruX3*baQq@_LSp> z87tfWm>gDR+W|7YEV%`2&u#l3gF~t9*+;!{#;fBUnHf=Ki3$Dqr+pOF?~EH)=(v>5 z_CJ*42$cek?;G49Uu>yU$kLx0uvp5p9aJjFE+;7iX4WCa)seyKu2Ikxqh^1cD(0E6r}t2IReze(d;Js;$D==@vKEQ1XYCj z8`pS1ZLrm(a&g3X&4kfTdU5mq@ZVqb_P9QCq|ZI>mjh$mH}c`opmDhMIj0yJoP&0_ zg~HW&hG$RVIux*oIL_eKI}F5}N!ua9`m_y1<&JgjFr0;}M;4(MtwB&JM#LYS@AM8><;rdS^_?fk={|6Bo*0O1E zBpqjzCI@=OafU#-SsC|oKX4C6hQc!s+~Zlp>@e`fs%&`p)?-+5Z``qx%Q1hlT5`j) z4vzP1Aydc7mB-$B2gi6;%;QKZN6^&4W5_Cpjkr99m)=f8==eAs`lff)V!t5A`fPe* zIL==ZaCN;ny|xs_)0T3BJ8m4Xy+Y+aRX%UD zuyP%%M114Y10I=itm~S&B!=p){FG14noqsPMYxQei}RD!mep$ewxaaPy@J}tGoD3z zM9g`A6Fye%3|rd!p_WdB*PA=!?%=Tc&{4Oq9AkaDqpC=`jwksXdA!-_9y|Hl=@jjB zU$CmrVFeHF2ldp#amL$RJ^QwX)-r_uec#v4ZjFw8q#RzS?vU47ogN5UKsl^7rE9(PS=auq6_;}5sJpN`SJWC)!7!q0y~G?Ep1bg@7d;AvQLcxmQ@Tf; zgyZysmN$dLyVpGWp{8|((mQ)XxSS$(hqS}v$`uAH-(hDdS3A}{Ipn8sT=1p`ha40I z7%Ns`+hO&=;T2ep^ptWrgWcme5<578P7D3y`sDhJ!+qNy(#mt+_I+F^!+z-Je(zH* z^=rS&*I`=A5hWR1hZ_c5axm)wLYN1;%2m0FEs`95hjN5Yr&xBq(dJ7w*S^?tpO#;f4Go5SC%RM#D%zmNVM zHwq0-(*)rEJ?-~(Q;!yj=TZ`BVQgrd0FWP|jAiw>vEr}xN7Nsx+}DE-1x|Y*?BkRIyOsjw3-lc9*#xWjG?5%FR2uUhW6c9~mRPjz~6*LQK4P#rDjUJMz~K zOKouI5gZn596el`2o60ildeB5lU9qR3m(*TTr{B^VWQDd;GtZPSV3xsMup>mJyjeo zvvM)uk*0@=z*WhVB4_OnS;S#(iLMgC@k8j-Ix1+Co81`SweMAqGTvEb=e7p7+F8HJ z;S8>0H%7-!)8c;AVEL(gS=R1l`}ehgC8ZA2NoF%;yz$`h!JnY&Dd+T9p5KhJZxHfV<~q!xeq06tNqpYy?5gtys~Uz{wmsgri80>RXGySy;Y(Yl<-+jHvI{$ph*_a+#dxA8Bx&#w3pMD^Y1k3eh%dvsQ*=g?g z7eB80b=Laz>uIrL0@*6l9+<3T><(hwm^-mvj|-%qy!ekBA2*UJl1~TSK4khPDdA=J zPXVi?%9g(n8udywtq9imomR1xMtrE)k4pu|dc8ppcs9kMDHN-ao3bkQCl)b~@RYiV zTk2+FwSu={RqjoUFic`Kf>SK6tDTGnnR}m*iIoU_Jgq4E!05QU(Q6mP0!Tb~b!4oJ+;D+8#PNJ5-orc*&;~G+G!#R@Wm6lgM3c zpKtheiskgVo7i1(J+K;%)}ThFVqy^wdV2(~xXc;y8`j-J6RQkb-HP^4jE;FT(xd}p z#%{1yY;j_3ozZs(SO(T&epw^*!7zYr1Y8$}mkxQhY3&WKaIp$~6r&I-Ou$1c>`z~v zuwev3!D>o3vCo~C?u*a{rpMCmYqFjD?Q;)Wy)dp|?R&nB#n%Ky7No#r#Gw7 zga#eStU{HE^@wR(<4Tl)iSLDNF&q;h7$gOg zV%*DALyA@GfbTf;Hc3K%ub=bT=g#PL!x~0(&x$n>yOlKkMf>0M9mCY$VazJU@StSE z(lVi4WW(zSZC|2lT)1F|UZWCYU@Z|;SlQmR$STcZf!r|#e+`uhuXeNwSSQ99s(HHV zX3iy-4I_9-tI4inTF!{wL`}^rnCNS;&pabZdZqpS+w7RjzzF2dlP}RecbSM~pci*1 zksx}P$@e;?TG4T`u9#3v>~Dg~bvul$SV<5swEeAt6+GW!>Qu!l>eMG8o9;qZFFHC- zLzyO&U^!q55IZcQSY%Me{d`)VPwUsydO40pm^Q3p$6b=Po2D3J`oVUu#Skr-p`P0( zy_23;J{qV!WXM)1EPi5PO4fE%z&*H>%O;8+Gi8t+gV{iSnkoB`9i@~A z&-dAZYi%jVN4V8CrxYW+fZY}lg0-Wf%NDhY;n`@1UXc-*Ex2DCRUR0JfCcP#OoJ2c zk0RPA-~YP*3S)f6tldzoqIz%$HSI!+0cktfKCq03h)tJkUY)Xk?(m>u zzl%`HMSiYKzkD0x0OG*naf7m*%o!L~1bU{f$CSageZJ^&kAM%XW5MNvky=*W+uqWz z(PgzJt&gquaeQ)v>yt53B|3hF~>Somj*p zB6colVpxf5uM)vHYz3A7A2hNR8UX(Q03VA81ONa4009360763o0E8)>oyo2xw~>a| zx1XgTFgWu9UKDJ!wqEEBdeiG(`{6r+WS(UHq$(myGRlUf?_?&2V9fmb*T4Tk{_D@b zzJLDf`{#du|Lfmh?mzCE{15jn|Mg%0^S}RBzEW_t5`F#g_1D)={_~G7#)8|h;5ruE z2WyEk|LcE#{qw@8?oX@ZY4yU$w;cIj|HX3Gssko^Srw|9NAUdGpCpc+OkIZ=-J?eo*;#e?*_Yqg&Wi`y>B) zGv_{0AD0EI`v+EjBtOv+H5W_1{`{_=FAhGJu`fQaUia~>V|;5~uA?|?l>5Q|?>Bw(pEp@^d44Z#W6X0B+W2BuDEgW{e}2XrQze)pz+3PO3zVA z`_rzSwmfZ!gXL*yACfelmOew0s5Ji^lDIFRSjTMgc6OCAuR0dVnZDy^MJ4Y%3~kxB zPw{gfgxqQl*MEPPu>4MO{WCtoFz-tur};Z+{o8-%a{mrZ>G+v5zwakMM$v!vQ_7Xx za}>k=8JD~Y3+CaR@%t$Hu?>A&Fx&uP$HKtEjTIJ&3tr4Pz3fZ zjirC!ETFYU(oSbn}_+fSP| zw3X%-EavCa+WwMlykuKmvNX^i8m<}^dih68qCd3AFL(W!zMH>)r+KG8zT)GFl`Qz! zeg4~+k(L)Mfe0seIFj8MCI0V)%&-L7zE0a%r;ToGJAF^@dC6!ODS!Sd>x+jLe!bhq z@jp-h4;HC`zU=qU_2X;({jt$ET!H(flrbsgo)lIZ;9Navun{!al3K{mZDPW5bU2rm zA>r)>mWM?~n{niG#q3Q((n~#KWiUFWW9H z)0M>b5!>>tw}$Vwym}>AiDjRhGA5_olT#Z`4!MIN;N};*x{wXD7^1@$)BIw(zqt8~ zHWKXzC;xwwYzx^6zU^U~envUnB&+2hDR%)|hJY<@!3yYHWnT|v3{Ls1hUQ9*xB?F! zIKS_M#ZcfSH`|d!c6ldCaCFOm==(M$SqUz`;nJsR1cnkIF`-F3&2?O z^rh;d<*A287Fz|*WrI;3n{()|Df0gbj*5_c>PEM8c0Y$W@yhv%T~o41aa ztZl(|adG&#>+3$B$7CZMmDAb$5j5#TQt;`iRh<;{`c%*bD{%4{4y@!nB{0w7)S3RL z@VyvTtZ4g+5?EJ{L_e?Ki7`kf#!B$dJ$`cFgr@^1kr+F$p!bo?Lty8&U=@6xmL*1^ zPG#)&9_#xc`I7sB{<*k2cLO;O13CK@t1#WVAYyFz;n!semd2d#Ci0R#wg%7lwqJcb z7{xp;!{7LDP4c77~U5boV`DY|Fkrpanxk)F7)FD>Nj`XZ?qLA%ua2x?mA~qWepR@seSA$?E(Q zGpGZC1(2QwhhOG>kG_P1n22Kn;ynS03NCToPnhLEfmLE~+-A=^3Ra0h=&~~A0<4m< zV`X6FgGE*v!C0~^<>Y+zoeqesVE^pesbattnhg8n) z#;SWSCt1^R$vtJsL4gQk-ag7gb8K(5=e!wwZq2ot8m_og^k(=wE{w!zdVZThyfQ`s zHeuTJk~H*^R6dw@=ubX)uW71O>2_cXiBo4-mVz}n^$kM z^Yt-=9^_mGt(>f*!asKVBOCun#08;?H^KUX_ahXF zhZ|zWG`#G>+m%4HNx?EGNG=hBI_ijx!g)F zG5U{9#lI6SOZkPlA{Z647uDs>m^hT5Sloqj96~wP1;cRo>0oq^gORb)P~hmf7aa?r zis{yAc0Le+OHlU%cdUVLL=Sy37Q>9~EKbkUT-z0);c##op^u+p-)1j~S_iDZKLG=$*dzt^{1 ziX(C5)sfCva|z=Ax~Ez&Rwr+d#8bMuX|}2YtF#~ z4X3(b5p+=-)-o#0`ixVIcU*J{pUV5mnnm+9%DtPx9?1Yl5SP4xS*o+-0oi#Pu)! zCztT0IdM zqiG$&Bug2F@RYoCWiL@#$SpDA7>b~0C}NNpT|F+9f=h+fy?`m??x4H7sk^&ylO;ke z3LT^vO)*Bd980-W@HXmc9D+3udtFbt>{y0Xq304ZRze+n{kDa4{kdaW3N-)wV;e(3`Lo>jLRZKcoW8Q-Kik=sJO)?e& zx_b3_3&Euf=SwRGG1Ur7skUIl8Szkf&nZen38=YARFZdGW5pxhNlX2=A|^1?DGiVR z-!3XIp%Y4M2{Tf3bDTwoPq+_tEIQ|70ZiXe(Rr6)Lm3od#(ct9sP2GcEEFi3Fqo{Y zMmh|k9xDQ8r2kX@$E42`U{rKtM6}P?;50r~x{Xt=u7CTFuULMEhxhC0a56mJ$40Q` z^ja^*QVpfVs>V|UO9>n~ZJ&`gmUl}xmK!*! zPG0vbo4Zz4Ry>;!mA|dsZg~EkQs7Lr>@F61Tb897s$wjALN~mA6f-uI!B?^993!7t z;W-7uC>N@-iEel^xIJvxB3sT)|pXq~3!2$pDf+#8<8JECo2w_hLm14|Jc_u2#u zEEo4&DB1)Jte}N@ILqpClnIq%YMX2I*C*h>a`NxAnU1j*hi+q~Va32ImiwIzw)-d( ztccD9@>WT98komWyp|9)uz(Q|P37uXPK27ba!gMwU^b3n0t#=^mpPIHD-DK3(+let zYlSIBdMQgT&f}oixGO8}4ksNdd1lH$UbuqVOW4)jcVr4#WirvXh)`SJW_6} zQZP&mbA*Sc7Ur0oM^}{Q9Jo0AKFySvT*MY3y119(^66H5(V%E@$-{W+La}q%zid%7 zIaUpx>sre=zqpEOh6+0I-aURu(b2M3A_9?jJQr zCX^LTSXO;7HfdU$RF|)0?F(n)kQPVN-9atiXeBg^H9yJZd;!0%kqfg4#U08!l*^Be z(Za&*^^*JZt|Hm>dC3je?!6HWf?GKMG7n{Pxqu>ba5R*5#kMNh%9vFhrw z>SjINOKpa^fYQ{qJKE5?){i`Nm>ZK(XoE1AoXd1#s#J_#y#$V>}?SnObR;$eeC+#t+FXe*?-4F@NwyP!5G6@!zD9v0r& z{rprLq+SPW>}}&oqcq~rUrV`)QjX{<4FBZ@3EKvtigvA5^*%W7A{_rlZk%rGcq*ao z$@y&_ltAv}0#?(deLT|;sA(BbA06yJ(`iFezwsLaoR=q7BIkWvu6bX^C3wvI(el|Y zu0j{HQ;(6!E%GG<2il2NWH-4O&>ee-@>7f)Z(w{ z2|4uCqO_pc#bJ|Gt%T*`&?~NW2Qaz{y!)Jco)237#lc z9+_F0IDd$?7P3l3Ia=@t|wb5AYL%gHyGcReWCxvf>RR)jRU)WET#b$prJ)xzqPCtWy?kqIT0_u?XC zxmdXBovY|kJ$N{;ME->%EH^*oxzJ3MZqL7Grc3`JJ~0F6G8Rc99EO=K5|6p!u#(rv zC9EPagv5lyzIS?nS~!2Xx|dd4JGZ8k4lX8-=?|vo#q10*T!JH$xe~wzvFM^Tw6wJd zQ4*^sS1=S~IkA|l=#;bAE}g?#7t1^}R?$IcHmx&OB|L-xPQHpOH#3DA^Yv$3oENq6 z^RWk|JG{A@zJ0g6d)qrh8rG1c7NTRoxQ^nTx+dlI zHNMxfglirWwhjI@soEq5@2RJoNYA}Qv4QN+{Q|=IS+{wQryeF_u9j`BD{USpSFtm+ zmZU$qt?jwi=Ktc_mN>7<9Lbh0gcYXxeh_Yx0S5cGa}~M`7##W}{TdxO<_+OW;X(ud z)4B85!@d_TZT&Q!^Dx7)S;DdT!QnjUXFh!{Y*MlvXS#FbqpA9QRX^N$IQ&EDx@+Z^ z4n7b#B&8@@JYP+K6s~20L&RWjcP_%hJJnxbcgysSb)P?HLH7Kiip||Dl0>+MIrq9D zEnLH%s)o~+*wm{SQZ%iMK!hijKV>3ZsR*7H)DxEKoutVnPHuU^XegMpd$>G`<~14A z+KO%&R)-h?%_t~+q6C7*Eq(sbnu78rr`H#b7$&AeM2e5dE*B#& zsp2v#wSg5VK8-)~6n*rweCdrzC0xodu3EkG2`^7nugAV%6G?O)fd;YX`S3&3e=-^{DH6ChTYN_EM4ScM8M_ZR<6a?N~Et z4Z>y2lQ+l>={y#&?9yO&@~pVH-7}@zWpd}j=A_eo5G1p?)d5(ZCq+znxEbs#;R>q9 zhW(iM1Gi2jhW*$%OgA@iY4pB$QK$RiuuYooWEC#rCAua~0{k!Qi3jH^-kWKf_Z$d2 zhg%eYB*ox34+guMxrQwPwDwYii-hB1+JDS7@TXYzd#)~H_NXELE!-APG{mums}baj zA-KgHYu%8>ZAj=7E@HghkUq>@a1JVR4ZhgUW$+ISZ)zM0YI;-*-Sss5Lq6h#CKksUa|IIt4fP7bHMD6B8Me&viHHTB2Em`DM=jJ< z7!nVK+v)%eiCrXd^8k74S`G2Vp*zFkmME@ztm?M-eVEG$6+b;uRk*9J;vN@0kxaOT z7M#UhQ&_>k1K$wDp~4CV*5OzjxJBG=sJI{eVbiY_qSOhdnmvn+Ru%_YNr@8lr?)Iv zwmWl!i-{~JWRY%9*bm>JX)@Pv;aMblNo7b_#S)H>p6ZqfmGi@c8_|&Z z+&MHk3@NF?`R$sN<1O+1J=f<2Oti9uDuu(^70b!WTt?N?vLRVx_1o<+h7BT|hv!*N z)+(MfSI*nBTi4CPVhds=+F4%)>ISgj9a21MO zE$%xW6#ur{bmxLx;_%#m7I%zD{`woybmrpBS-d&Rx|aM8NHw%5{mi8;ZNzexO3EN! zjcM=})WCm(a%)lkn92^qS(Y$ZWtA9nYEAPV({&^Ft286##%-E!b(5IV*5BKrW5kpl za2B_16(x@% zh09O+U`BmV+Sq_TXxe|wVOw&O{*r>n@^I6+k|ebTtrH@VjZhZ=eeOj#C)_z}?pS(EJcF(rq`eo|8OqA3wNNAKpT86BXf1lY9>Ah_wU%i*5pMyf3x4lh zCKwM&wQ_i;y}@h7TyzeT$#khXIC!2x8}A(6Fl-VAL8959 zCFwC~;Ru`WoG!4PS9LB+v;@=w=`f%)^*LIHR4#@`^suKs=rTGbZs_4NX?`a?J~UzN zJ{`m}P5DfVfMyhn49`z3+f%EHc=IzItW}Dal>Ufm{?vqRyXa61PqP}HKIQO&maSr_ z9()xuCz=2IMr*;FVCW#_DP1ctEohzR?P3rfM!3%YcrN+OlDX6tOUN~{^5E_tV^attXr}*+|nU_`*DhY=WCCwNm<@!KTaj%E{R_7U3X+axddGsL{n-%

S=Di?2WY!mGc)P4c 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 G0002!%Vp94 literal 0 HcmV?d00001 diff --git a/man/readSNVVCF.Rd b/man/readSNVVCF.Rd index 781bfee4a..6aadf71bb 100644 --- a/man/readSNVVCF.Rd +++ b/man/readSNVVCF.Rd @@ -5,13 +5,15 @@ \alias{readSNVVCF} \title{Read a VCF file with the genotypes use for the ancestry call} \usage{ -readSNVVCF(fileName, genome = "hg38", profileName = NULL, offset = 0L) +readSNVVCF(fileName, profileName = NULL, offset = 0L) } \arguments{ \item{fileName}{a \code{character} string representing the name, including the path, of a VCF file containing the SNV read counts. The VCF must contain those genotype fields: GT, AD, DP.} +\item{profileName}{a \code{character} with Name.ID for the genotype name} + \item{offset}{a \code{integer} representing the offset to be added to the position of the SNVs. The value of offset is added to the position present in the file. Default: \code{0L}.} diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index c323b5f56..57f41a93e 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -152,7 +152,7 @@ The wrapper function, called _runExomeAncestry()_, requires 4 files as input: - The **population reference GDS file** - The **population reference SNV Annotation GDS file** -- The **Profile SNP pileup file** (one per sample present in the study) +- The **Profile SNP VCF file** (one per sample present in the study) - The **Profile PED RDS file** (one file with information for all profiles in the study) In addition, a *data.frame* containing the general information about the @@ -181,9 +181,22 @@ as **pathReference**.
-#### **Population SNP pileup file** +#### **Profile SNP file** -The generic **Profile SNP pileup file** format is coma separated and the +The VCF **Profile SNP file** file follow the VCF standard with at least those genotype +fields: GT, AD, DP. The identifiant of the genotype in the VCF must +be (Name.ID). The variants in the VCF must be germline variants +and should include the genotype of the wild-type homozygous +at the selected positions in the reference. One file per +profile are need and must be gzipped. + +Note that the name assigned to the VCF **Profile SNP file** has to +correspond to the profile identifier (Name.ID) in the following analysis. +For example, a SNP file called "Sample.01.vcf.gz" would be +associated to the "Sample.01" profile. + + +The generic **Profile SNP file** format is coma separated and the mandatory columns are: * _Chromosome_: The name of the chromosome @@ -195,12 +208,12 @@ mandatory columns are: * _File1A_: The count for the alternative nucleotide Beware that the starting position in the **population reference GDS File** is -zero (like BED files). The **Profile SNP pileup file** should also start +zero (like BED files). The **Profile SNP file** should also start at position zero. -Note that the name assigned to the **Profile SNP pileup file** has to +Note that the name assigned to the **Profile SNP file** has to correspond to the profile identifier (Name.ID) in the following analysis. -For example, a SNP pileup file called "Sample.01.txt.gz" would be +For example, a SNP file called "Sample.01.generic.txt.gz" would be associated to the "Sample.01" profile.
@@ -272,7 +285,7 @@ studyDF <- data.frame(study.id="MYDATA", stringsAsFactors=FALSE) ############################################################################# -## The Sample SNP pileup files (one per sample) need +## The Sample SNP VCF files (one per sample) need ## to be all located in the same directory. ############################################################################# pathGeno <- file.path(dataDir, "example", "snpPileup") @@ -330,8 +343,10 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && ## All important information, for each step, are saved in ## multiple output files. ## The 'genoSource' parameter has 2 options depending on how the - ## SNP pileup files have been generated: - ## "snp-pileup" (snp-pileup software) or "generic" (other software) + ## SNP files have been generated: + ## SNP VCF files have been generated: + ## "VCF" or "generic" (other software) + ## ######################################################################### runExomeAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, pathProfileGDS=pathProfileGDS, @@ -341,7 +356,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && fileReferenceAnnotGDS=fileAnnotGDS, chrInfo=chrInfo, syntheticRefDF=dataRef, - genoSource="snp-pileup") + genoSource="VCF") list.files(pathOut) list.files(file.path(pathOut, demoPedigreeEx1$Name.ID[1])) @@ -398,7 +413,7 @@ It requires 4 files as input: - The **population reference GDS file** - The **population reference SNV Annotation GDS file** -- The **Profile SNP pileup file** (one per sample present in the study) +- The **Profile SNP file** (one per sample present in the study) - The **Profile PED RDS file** (one file with information for all profiles in the study) A *data.frame* containing the general information about the study is @@ -427,9 +442,21 @@ as **pathReference**.
-#### **Profile SNP pileup file** +#### **Profile SNP file** + +The VCF **Profile SNP file** file follow the VCF standard with at least those genotype +fields: GT, AD, DP. The identifiant of the genotype in the VCF must +be (Name.ID). The variants in the VCF must be germline variants +and should include the genotype of the wild-type homozygous +at the selected positions in the reference. One file per +profile are need and must be gzipped. + +Note that the name assigned to the VCF **Profile SNP file** has to +correspond to the profile identifier (Name.ID) in the following analysis. +For example, a SNP file called "Sample.01.vcf.gz" would be +associated to the "Sample.01" profile. -The generic **Profile SNP pileup file** format is coma separated and the +The generic **Profile SNP file** format is coma separated and the mandatory columns are: * _Chromosome_: The name of the chromosome @@ -441,12 +468,12 @@ mandatory columns are: * _File1A_: The count for the alternative nucleotide Beware that the starting position in the **population reference GDS File** is -zero (like BED files). The **Profile SNP pileup file** should also start +zero (like BED files). The **Profile SNP file** should also start at position zero. -Note that the name assigned to the **Profile SNP pileup file** has to +Note that the name assigned to the **Profile SNP file** has to correspond to the profile identifier (Name.ID) in the following analysis. -For example, a SNP pileup file called "Sample.01.txt.gz" would be +For example, a SNP file called "Sample.01.generic.txt.gz" would be associated to the "Sample.01" profile.
@@ -518,7 +545,7 @@ studyDF <- data.frame(study.id="MYDATA", stringsAsFactors=FALSE) ############################################################################# -## The Sample SNP pileup files (one per sample) need +## The Sample SNP VCF files (one per sample) need ## to be all located in the same directory. ############################################################################# pathGeno <- file.path(dataDir, "example", "snpPileupRNA") @@ -576,8 +603,9 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && ## All important information, for each step, are saved in ## multiple output files. ## The 'genoSource' parameter has 2 options depending on how the - ## SNP pileup files have been generated: - ## "snp-pileup" (snp-pileup software) or "generic" (other software) + ## SNP files have been generated: + ## SNP VCF files have been generated: + ## "VCF" or "generic" (other software) ######################################################################### runRNAAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, pathProfileGDS=pathProfileGDS, @@ -588,7 +616,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && chrInfo=chrInfo, syntheticRefDF=dataRef, blockTypeID="GeneS.Ensembl.Hsapiens.v86", - genoSource="snp-pileup") + genoSource="VCF") list.files(pathOut) list.files(file.path(pathOut, demoPedigreeEx1$Name.ID[1])) From b50aa2245daac1fa9091d21eddad34bfa6d7fded Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 15:17:37 -0400 Subject: [PATCH 258/385] Update README --- inst/extdata/README.txt | 89 +++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 38 deletions(-) diff --git a/inst/extdata/README.txt b/inst/extdata/README.txt index 86f771a14..dd2db1dcd 100644 --- a/inst/extdata/README.txt +++ b/inst/extdata/README.txt @@ -1,58 +1,71 @@ -######################################################################################## +############################################################################### ## README file -## +## ## This file describes the objects present in the inst/extdata directory. -######################################################################################## +############################################################################### -######################################################################################### +############################################################################### ## extdata/demoGenoChr.tar -######################################################################################### -The files present in the extdata/demoGenoChr.tar files are the first -100 genotypes of 3 reference profiles (NA12003, NA12004 and NA12005) for each chromosome. -The genotypes are directly extracted from the 1KG VCF files that is available at: +############################################################################### + +The files present in the extdata/demoGenoChr.tar files are the first +100 genotypes of 3 reference profiles (NA12003, NA12004 and NA12005) for +each chromosome. The genotypes are directly extracted from the 1KG VCF files +that is available at: http://ftp.1000genomes.ebi.ac.uk/vol1/ftp/data_collections/1000_genomes_project/release/20181203_biallelic_SNV -######################################################################################### -## tests/ex1_good_small_1KG.gds and tests/ex1_good_small_1KG_Annot.gds -######################################################################################### +############################################################################### +## tests/ex1_good_small_1KG.gds +## tests/ex1_good_small_1KG_Annot.gds +############################################################################### + Both files are based on subset of the genotypes from 1000 Genomes described in: https://wellcomeopenresearch.org/articles/4-50/ -The 500 SNVs from each chromosome habe been retained (11000 for the -22 autosomal chromosomes). For each of the 26 sub-continental populations in this -version of 1000 Genomes, 6 profiles have been randomly selected (total of 156 profiles) -to generate those reference GDS files. - +The 500 SNVs from each chromosome habe been retained (11000 for the +22 autosomal chromosomes). For each of the 26 sub-continental populations +in this version of 1000 Genomes, 6 profiles have been randomly selected +(total of 156 profiles) to generate those reference GDS files. -The files : -example/snpPileup/ex1.vcf.gz -example/snpPileup/ex1.generic.txt.gz -example/snpPileup/ex1.txt.gz -example/snpPileupRNA/ex1.generic.txt.gz -example/snpPileupRNA/ex1.txt.gz -demoAncestryCall/ex1.gds -demoKNNSynthetic/ex1.gds +############################################################################### +## example/snpPileup/ex1.vcf.gz +## example/snpPileup/ex1.generic.txt.gz +## example/snpPileup/ex1.txt.gz +## example/snpPileupRNA/ex1.generic.txt.gz +## example/snpPileupRNA/ex1.txt.gz +## demoAncestryCall/ex1.gds +## demoKNNSynthetic/ex1.gds +############################################################################### -The genotype are synthetic data between a profile in 1000 genome randomly selected with an AFR -ancestry and not in the sample used in tests/ex1_good_small_1KG.gd and one exome from Tiriac et al. 2018. -(the exome is restricted access, it is only use to get the total read deep at the SNV position -and an estimate of allelic fraction of the regions). -Only 500 SNVs per chromosome are kept. +This demonstration profile contains genotype from a synthetic profile +generated using a reference profile from 1000 Genome randomly selected +with an AFR ancestry (this profile is not present in the reference GDS file +tests/ex1_good_small_1KG.gds) and one PDAC cancer exome profile +from Tiriac et al 2018 (this exome is restricted access in dbGAP; it was +only use to extract the total read deep at the SNV positions and to estimate +allelic fraction of the regions). Only 500 SNVs per chromosome have been kept. The pipeline to generate the synthetic data are describe in Belleau et al 2023. -The files : -HG00*.csv.bz2 -are the first 10 SNV from chromosome 1 in 1000 genomes describe in -https://wellcomeopenresearch.org/articles/4-50/ -The file : -matFreqSNV_Demo.txt.bz2 -is the csv file with the frequency for the 5 super population of the 10 first SNV from -chromosome 1 in 1000 genomes describe in -https://wellcomeopenresearch.org/articles/4-50/ +############################################################################### +## demoPorfileGenotypes/HG00*.csv.bz2 +############################################################################### + +Each file contains the first 10 SNVs from chromosome 1 of profiles +present in 1000 Genomes as described in: + https://wellcomeopenresearch.org/articles/4-50/ + + +############################################################################### +## matFreqSNV_Demo.txt.bz2 +############################################################################### + +This is a text file with the frequency for the 5 super populations of the +10 first SNVs from chromosome 1 in 1000 Genomes as described in: + https://wellcomeopenresearch.org/articles/4-50/ The file: listSNPIndexes_Demo.rds From eb802e23a4931c56136cae93f7eef7ac1ff9062d Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 15:57:33 -0400 Subject: [PATCH 259/385] Update README --- inst/extdata/README.txt | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/inst/extdata/README.txt b/inst/extdata/README.txt index dd2db1dcd..e399e0ec8 100644 --- a/inst/extdata/README.txt +++ b/inst/extdata/README.txt @@ -67,16 +67,28 @@ This is a text file with the frequency for the 5 super populations of the 10 first SNVs from chromosome 1 in 1000 Genomes as described in: https://wellcomeopenresearch.org/articles/4-50/ -The file: -listSNPIndexes_Demo.rds -mapSNVSelected_Demo.rds -are create from matFreqSNV_Demo.txt.bz2 -listSNPIndexes_Demo.rds: is an index of the variant where the frequency of at -least one 1000 genomes superpopulation is bigger than 1%. -mapSNVSelected_Demo.rds: subset matFreqSNV_Demo.txt.bz2 of the SNV selected -in listSNPIndexes_Demo.rds - -The file: -unrelatedPatientsInfo_Demo.rds -list of unrelated (the file does not represent real relation between) patient from 1000 genome describe in -https://wellcomeopenresearch.org/articles/4-50/ + +############################################################################### +## listSNPIndexes_Demo.rds +## mapSNVSelected_Demo.rds +############################################################################### + +Those 2 files are created using the information from the +matFreqSNV_Demo.txt.bz2 file. The listSNPIndexes_Demo.rds is an index of the +SNVs that have a frequency for at least one of the 1000 Genomes super-population +bigger than 1%. The mapSNVSelected_Demo.rds is a subset of +matFreqSNV_Demo.txt.bz2 containing the selected SNVs present in +listSNPIndexes_Demo.rds. + + +############################################################################### +## unrelatedPatientsInfo_Demo.rds +############################################################################### + +The file contains the list of unrelated profiles from 1000 Genomes. +The values does not represent the real relation between profiles; the +values have been modified for demonstration purpose. +The profiles from 1000 Genomes are described in: + https://wellcomeopenresearch.org/articles/4-50/ + + From 8ab4c74fd0ce5f1ee0125f25ae5f0a5945bd389d Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 29 Sep 2023 16:31:01 -0400 Subject: [PATCH 260/385] Update README example --- inst/extdata/README.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/inst/extdata/README.txt b/inst/extdata/README.txt index e399e0ec8..92f35a024 100644 --- a/inst/extdata/README.txt +++ b/inst/extdata/README.txt @@ -34,6 +34,7 @@ in this version of 1000 Genomes, 6 profiles have been randomly selected ## example/snpPileup/ex1.vcf.gz ## example/snpPileup/ex1.generic.txt.gz ## example/snpPileup/ex1.txt.gz +## example/snpPileupRNA/ex1.vcf.gz ## example/snpPileupRNA/ex1.generic.txt.gz ## example/snpPileupRNA/ex1.txt.gz ## demoAncestryCall/ex1.gds From 4c77f930bf2a39f9f2f447e2070dac695b55cdcf Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 17:01:40 -0400 Subject: [PATCH 261/385] Correct indents in Reference GDS vignette --- vignettes/Create_Reference_GDS_File.Rmd | 43 ++++++++++++------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/vignettes/Create_Reference_GDS_File.Rmd b/vignettes/Create_Reference_GDS_File.Rmd index 875e3f784..7cbb7e826 100644 --- a/vignettes/Create_Reference_GDS_File.Rmd +++ b/vignettes/Create_Reference_GDS_File.Rmd @@ -172,21 +172,20 @@ sampleInformation <- data.frame(sex=c("1", "2", "1", "1", "1", "1", "2", "2", "1", "2"), pop.group=c(rep("GBR", 6), rep("FIN", 4)), superPop=c(rep("EUR", 10)), batch=rep(0, 10), stringsAsFactors=FALSE) add.gdsn(node=gdsRefNew, name="sample.annot", val=sampleInformation, - check=TRUE) + check=TRUE) ## The identifier of each SNV is added in the 'snp.id' entry snvID <- c("s29603", "s29605", "s29633", "s29634", "s29635", "s29637", "s29638", "s29663", "s29664", "s29666", "s29667", "s29686", "s29687", "s29711", "s29741", "s29742", "s29746", "s29750", "s29751", "s29753") -add.gdsn(node=gdsRefNew, name="snp.id", val=snvID, - check=TRUE) +add.gdsn(node=gdsRefNew, name="snp.id", val=snvID, check=TRUE) ## The chromosome of each SNV is added to the 'snp.chromosome' entry ## The order of the SNVs is the same than in the 'snp.id' entry snvChrom <- c(rep(1, 20)) add.gdsn(node=gdsRefNew, name="snp.chromosome", val=snvChrom, storage="uint16", - check=TRUE) + check=TRUE) ## The position on the chromosome of each SNV is added to ## the 'snp.position' entry @@ -194,56 +193,56 @@ add.gdsn(node=gdsRefNew, name="snp.chromosome", val=snvChrom, storage="uint16", snvPos <- c(3467333, 3467428, 3469375, 3469387, 3469502, 3469527, 3469737, 3471497, 3471565, 3471618) add.gdsn(node=gdsRefNew, name="snp.position", val=snvPos, storage="int32", - check=TRUE) + check=TRUE) ## The allele information of each SNV is added to the 'snp.allele' entry ## The order of the SNVs is the same than in the 'snp.allele' entry snvAllele <- c("A/G", "C/G", "C/T", "C/T", "T/G", "C/T", "G/A", "A/G", "G/A", "G/A") add.gdsn(node=gdsRefNew, name="snp.allele", val=snvAllele, storage="string", - check=TRUE) + check=TRUE) ## The allele frequency in the general population (between 0 and 1) of each ## SNV is added to the 'snp.AF' entry ## The order of the SNVs is the same than in the 'snp.id' entry snvAF <- c(0.86, 0.01, 0.00, 0.00, 0.01, 0.00, 0.00, 0.00, 0.00, 0.01) add.gdsn(node=gdsRefNew, name="snp.AF", val=snvAF, storage="packedreal24", - check=TRUE) + check=TRUE) ## The allele frequency in the East Asian population (between 0 and 1) of each ## SNV is added to the 'snp.EAS_AF' entry ## The order of the SNVs is the same than in the 'snp.id' entry snvAF <- c(0.80, 0.00, 0.00, 0.01, 0.00, 0.00, 0.01, 0.00, 0.02, 0.00) add.gdsn(node=gdsRefNew, name="snp.EAS_AF", val=snvAF, storage="packedreal24", - check=TRUE) + check=TRUE) ## The allele frequency in the European population (between 0 and 1) of each ## SNV is added to the 'snp.EUR_AF' entry ## The order of the SNVs is the same than in the 'snp.id' entry snvAF <- c(0.91, 0.00, 0.01, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03) add.gdsn(node=gdsRefNew, name="snp.EUR_AF", val=snvAF, storage="packedreal24", - check=TRUE) + check=TRUE) ## The allele frequency in the African population (between 0 and 1) of each ## SNV is added to the 'snp.AFR_AF' entry ## The order of the SNVs is the same than in the 'snp.id' entry snvAF <- c(0.85, 0.04, 0.00, 0.00, 0.00, 0.01, 0.00, 0.00, 0.00, 0.00) add.gdsn(node=gdsRefNew, name="snp.AFR_AF", val=snvAF, storage="packedreal24", - check=TRUE) + check=TRUE) ## The allele frequency in the American population (between 0 and 1) of each ## SNV is added to the 'snp.AMR_AF' entry ## The order of the SNVs is the same than in the 'snp.id' entry snvAF <- c(0.83, 0.01, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.02) add.gdsn(node=gdsRefNew, name="snp.AMR_AF", val=snvAF, storage="packedreal24", - check=TRUE) + check=TRUE) ## The allele frequency in the South Asian population (between 0 and 1) of each ## SNV is added to the 'snp.SAS_AF' entry ## The order of the SNVs is the same than in the 'snp.id' entry snvAF <- c(0.89, 0.00, 0.00, 0.00, 0.05, 0.00, 0.00, 0.01, 0.00, 0.00) add.gdsn(node=gdsRefNew, name="snp.SAS_AF", val=snvAF, storage="packedreal24", - check=TRUE) + check=TRUE) ## The genotype of each SNV for each sample is added to the 'genotype' entry ## The genotype correspond to the number of A alleles @@ -368,7 +367,7 @@ phase <- matrix(data=c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 1, 1, 0, 1, 1, 1, 1), ncol=10, byrow=TRUE) + 0, 1, 0, 1, 1, 0, 1, 1, 1, 1), ncol=10, byrow=TRUE) add.gdsn(node=gdsRefAnnotNew, name="phase", val=phase, storage="bit2", check=TRUE) @@ -392,15 +391,15 @@ add.gdsn(node=gdsRefAnnotNew, name="block.annot", val=blockAnnot, check=TRUE) ## The block groups (columns) are in the same order as in ## the 'block.annot' entry. block <- matrix(data=c(-1, -1, -1, -1, -1, - -2, -2, 1, -2, -2, - -2, 1, 1, 1, -2, - -2, 1, 1, 1, -2, - -2, -3, -2, -3, -2, - 1, 2, 2, 2, 1, - 1, 2, 2, 2, 1, - -3, -4, -3, -4, -3, - 2, -4, 3, -4, -3, - 2, -4, 3, -4, -3), ncol=5, byrow=TRUE) + -2, -2, 1, -2, -2, + -2, 1, 1, 1, -2, + -2, 1, 1, 1, -2, + -2, -3, -2, -3, -2, + 1, 2, 2, 2, 1, + 1, 2, 2, 2, 1, + -3, -4, -3, -4, -3, + 2, -4, 3, -4, -3, + 2, -4, 3, -4, -3), ncol=5, byrow=TRUE) add.gdsn(node=gdsRefAnnotNew, name="block", val=block, storage="int32", check=TRUE) From 1550d5055313a0b4bcc8d644c839663606503ef1 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 17:21:07 -0400 Subject: [PATCH 262/385] Update text in main vignette --- vignettes/RAIDS.Rmd | 82 +++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index a55d3242c..faa3bfe74 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -152,8 +152,9 @@ The wrapper function, called _runExomeAncestry()_, requires 4 files as input: - The **population reference GDS file** - The **population reference SNV Annotation GDS file** -- The **Profile SNP VCF file** (one per sample present in the study) -- The **Profile PED RDS file** (one file with information for all profiles in the study) +- The **Profile SNP file** (one per sample present in the study) +- The **Profile PED RDS file** (one file with information for all +profiles in the study) In addition, a *data.frame* containing the general information about the study is also required. The *data.frame* must contain those 3 columns: @@ -183,21 +184,22 @@ as **pathReference**. #### **Profile SNP file** -The VCF **Profile SNP file** file follow the VCF standard with at least those genotype -fields: GT, AD, DP. The identifiant of the genotype in the VCF must -be (Name.ID). The variants in the VCF must be germline variants -and should include the genotype of the wild-type homozygous -at the selected positions in the reference. One file per -profile are need and must be gzipped. +The **Profile SNP file** can be either in a VCF format or in a generic format. + +The **Profile SNP VCF file** follows the VCF standard with at least +those genotype fields: _GT_, _AD_ and _DP_. The identifier of the genotype +in the VCF file must correspond to the profile identifier _Name.ID_. +The SNVs must be germline variants and should include the genotype of the +wild-type homozygous at the selected positions in the reference. One file per +profile is need and the VCF file must be gzipped. -Note that the name assigned to the VCF **Profile SNP file** has to -correspond to the profile identifier (Name.ID) in the following analysis. +Note that the name assigned to the **Profile SNP VCF file** has to +correspond to the profile identifier _Name.ID_ in the following analysis. For example, a SNP file called "Sample.01.vcf.gz" would be associated to the "Sample.01" profile. - -The generic **Profile SNP file** format is coma separated and the -mandatory columns are: +A generic SNP file can replace the VCF file. The **Profile SNP Generic file** +format is coma separated and the mandatory columns are: * _Chromosome_: The name of the chromosome * _Position_: The position on the chromosome @@ -208,11 +210,11 @@ mandatory columns are: * _File1A_: The count for the alternative nucleotide Beware that the starting position in the **population reference GDS File** is -zero (like BED files). The **Profile SNP file** should also start +zero (like BED files). The **Profile SNP Generic file** should also start at position zero. -Note that the name assigned to the **Profile SNP file** has to -correspond to the profile identifier (Name.ID) in the following analysis. +Note that the name assigned to the **Profile SNP Generic file** has to +correspond to the profile identifier _Name.ID_ in the following analysis. For example, a SNP file called "Sample.01.generic.txt.gz" would be associated to the "Sample.01" profile. @@ -223,7 +225,7 @@ associated to the "Sample.01" profile. The **Profile PED RDS file** must contain a *data.frame* describing all the profiles to be analyzed. These 5 mandatory columns: -- _Name.ID_: The unique sample identifier. The profile VCF file +- _Name.ID_: The unique sample identifier. The associated **profile SNP file** should be called "Name.ID.txt.gz". - _Case.ID_: The patient identifier associated to the sample. - _Sample.Type_: The information about the profile tissue source @@ -231,7 +233,7 @@ should be called "Name.ID.txt.gz". - _Diagnosis_: The donor's diagnosis. - _Source_: The source of the profile sequence data (example: dbGAP_XYZ). -Important: The row names of the *data.frame* must be the profiles' **Name.ID**. +Important: The row names of the *data.frame* must be the profiles *Name.ID*. This file is referred to as the **Profile PED RDS file** (PED for pedigree). Alternatively, the PED information can be saved in another type of @@ -387,7 +389,8 @@ in the *pathOut* directory. * The ancestry inference CSV file (**".Ancestry.csv"** file) * The inference information RDS file (**".infoCall.rds"** file) -* The parameter information RDS files from the synthetic inference (**"KNN.synt.*.rds"** files in a sub-directory) +* The parameter information RDS files from the synthetic inference +(__"KNN.synt.__*__.rds"__ files in a sub-directory) In addition, a sub-directory (named using the *profile ID*) is also created. @@ -414,7 +417,8 @@ It requires 4 files as input: - The **population reference GDS file** - The **population reference SNV Annotation GDS file** - The **Profile SNP file** (one per sample present in the study) -- The **Profile PED RDS file** (one file with information for all profiles in the study) +- The **Profile PED RDS file** (one file with information for all +profiles in the study) A *data.frame* containing the general information about the study is also required. The *data.frame* must contain those 3 columns: @@ -444,20 +448,22 @@ as **pathReference**. #### **Profile SNP file** -The VCF **Profile SNP file** file follow the VCF standard with at least those genotype -fields: GT, AD, DP. The identifiant of the genotype in the VCF must -be (Name.ID). The variants in the VCF must be germline variants -and should include the genotype of the wild-type homozygous -at the selected positions in the reference. One file per -profile are need and must be gzipped. +The **Profile SNP file** can be either in a VCF format or in a generic format. + +The **Profile SNP VCF file** follows the VCF standard with at least +those genotype fields: _GT_, _AD_ and _DP_. The identifier of the genotype +in the VCF file must correspond to the profile identifier _Name.ID_. +The SNVs must be germline variants and should include the genotype of the +wild-type homozygous at the selected positions in the reference. One file per +profile is need and the VCF file must be gzipped. -Note that the name assigned to the VCF **Profile SNP file** has to -correspond to the profile identifier (Name.ID) in the following analysis. +Note that the name assigned to the **Profile SNP VCF file** has to +correspond to the profile identifier _Name.ID_ in the following analysis. For example, a SNP file called "Sample.01.vcf.gz" would be associated to the "Sample.01" profile. -The generic **Profile SNP file** format is coma separated and the -mandatory columns are: +A generic SNP file can replace the VCF file. The **Profile SNP Generic file** +format is coma separated and the mandatory columns are: * _Chromosome_: The name of the chromosome * _Position_: The position on the chromosome @@ -468,11 +474,11 @@ mandatory columns are: * _File1A_: The count for the alternative nucleotide Beware that the starting position in the **population reference GDS File** is -zero (like BED files). The **Profile SNP file** should also start +zero (like BED files). The **Profile SNP Generic file** should also start at position zero. -Note that the name assigned to the **Profile SNP file** has to -correspond to the profile identifier (Name.ID) in the following analysis. +Note that the name assigned to the **Profile SNP Generic file** has to +correspond to the profile identifier _Name.ID_ in the following analysis. For example, a SNP file called "Sample.01.generic.txt.gz" would be associated to the "Sample.01" profile. @@ -483,7 +489,7 @@ associated to the "Sample.01" profile. The **Profile PED RDS file** must contain a *data.frame* describing all the profiles to be analyzed. These 5 mandatory columns: -- _Name.ID_: The unique sample identifier. The profile VCF file +- _Name.ID_: The unique sample identifier. The associated **profile SNP file** should be called "Name.ID.txt.gz". - _Case.ID_: The patient identifier associated to the sample. - _Sample.Type_: The information about the profile tissue source @@ -491,7 +497,7 @@ should be called "Name.ID.txt.gz". - _Diagnosis_: The donor's diagnosis. - _Source_: The source of the profile sequence data (example: dbGAP_XYZ). -Important: The row names of the *data.frame* must be the profiles' **Name.ID**. +Important: The row names of the *data.frame* must be the profiles _Name.ID_. This file is referred to as the **Profile PED RDS file** (PED for pedigree). Alternatively, the PED information can be saved in another type of @@ -647,7 +653,8 @@ in the *pathOut* directory. * The ancestry inference CSV file (**".Ancestry.csv"** file) * The inference information RDS file (**".infoCall.rds"** file) -* The parameter information RDS files from the synthetic inference (**"KNN.synt.*.rds"** files in a sub-directory) +* The parameter information RDS files from the synthetic inference +(__"KNN.synt.__*__.rds"__ files in a sub-directory) In addition, a sub-directory (named using the *profile ID*) is also created. @@ -684,7 +691,8 @@ the reference dataset, are required: - The population reference SNV Retained VCF file -The format of those files are described the [Population reference dataset GDS files](Create_Reference_GDS_File.html) +The format of those files are described +the [Population reference dataset GDS files](Create_Reference_GDS_File.html) vignette. The reference files associated to From d5490e0a23ca8bf6fefbc82959b113fff4e866ba Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 17:45:47 -0400 Subject: [PATCH 263/385] Update package version to 0.99.12 --- DESCRIPTION | 2 +- inst/NEWS.md | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 281c6e859..b2aa92c08 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.11 +Version: 0.99.12 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index c2b18249d..ca9453e39 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,12 @@ +CHANGES IN VERSION 0.99.12 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o Seven new loadable objects are available in the package. + o The new readSNVVCF() function enable the use of VCF SNP files as input for the runExomeAncestry() and runRNAAncestry() functions. + + CHANGES IN VERSION 0.99.11 ------------------------ From 64de5fe83fe5d5b6a27266cfc5cd9eff35ddc0ed Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 18:52:09 -0400 Subject: [PATCH 264/385] Add values to biocViews in DESCRIPTION --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index b2aa92c08..7df4826d4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -50,6 +50,6 @@ Suggests: testthat, BugReports: https://github.com/KrasnitzLab/RAIDS/issues URL: https://krasnitzlab.github.io/RAIDS/ biocViews: Genetics, Software, Sequencing, WholeGenome, PrincipalComponent, - GeneticVariability, DimensionReduction + GeneticVariability, DimensionReduction, BiocViews Roxygen: list(markdown = TRUE) RoxygenNote: 7.2.3 From e11e68e8e6486d09b1201258bad062fdeb2c3fad Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 18:54:45 -0400 Subject: [PATCH 265/385] Update doc for addGeneBlockGDSRefAnnot() function --- R/process1KG.R | 22 ++++++++++++---------- man/addGeneBlockGDSRefAnnot.Rd | 22 ++++++++++++---------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index 8d3a449b1..a9595cfe6 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -819,22 +819,24 @@ getRef1KGPop <- function(gdsReference, popName="superPop") { #' fileReferenceGDS <- file.path(dataDir, "tests", #' "ex1_good_small_1KG.gds") #' -#' ## Open the reference GDS file (demo version) -#' gds1KG <- snpgdsOpen(fileReferenceGDS) +#' \donttest{ +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileReferenceGDS) #' -#' ## Append information associated to blocks -#' addGeneBlockGDSRefAnnot(gdsReference=gds1KG, +#' ## Append information associated to blocks +#' addGeneBlockGDSRefAnnot(gdsReference=gds1KG, #' gdsRefAnnotFile=fileAnnotGDS, #' ensDb=edb, #' suffixBlockName="EnsDb.Hsapiens.v86") #' -#' gdsAnnot1KG <- openfn.gds(fileAnnotGDS) -#' print(gdsAnnot1KG) -#' print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) +#' gdsAnnot1KG <- openfn.gds(fileAnnotGDS) +#' print(gdsAnnot1KG) +#' print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) #' -#' ## Close GDS files -#' closefn.gds(gds1KG) -#' closefn.gds(gdsAnnot1KG) +#' ## Close GDS files +#' closefn.gds(gds1KG) +#' closefn.gds(gdsAnnot1KG) +#' } #' #' ## Remove temporary file #' unlink(fileAnnotGDS, force=TRUE) diff --git a/man/addGeneBlockGDSRefAnnot.Rd b/man/addGeneBlockGDSRefAnnot.Rd index 0a414473e..c8cd79029 100644 --- a/man/addGeneBlockGDSRefAnnot.Rd +++ b/man/addGeneBlockGDSRefAnnot.Rd @@ -65,22 +65,24 @@ if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { fileReferenceGDS <- file.path(dataDir, "tests", "ex1_good_small_1KG.gds") - ## Open the reference GDS file (demo version) - gds1KG <- snpgdsOpen(fileReferenceGDS) + \donttest{ + ## Open the reference GDS file (demo version) + gds1KG <- snpgdsOpen(fileReferenceGDS) - ## Append information associated to blocks - addGeneBlockGDSRefAnnot(gdsReference=gds1KG, + ## Append information associated to blocks + addGeneBlockGDSRefAnnot(gdsReference=gds1KG, gdsRefAnnotFile=fileAnnotGDS, ensDb=edb, suffixBlockName="EnsDb.Hsapiens.v86") - gdsAnnot1KG <- openfn.gds(fileAnnotGDS) - print(gdsAnnot1KG) - print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) + gdsAnnot1KG <- openfn.gds(fileAnnotGDS) + print(gdsAnnot1KG) + print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) - ## Close GDS files - closefn.gds(gds1KG) - closefn.gds(gdsAnnot1KG) + ## Close GDS files + closefn.gds(gds1KG) + closefn.gds(gdsAnnot1KG) + } ## Remove temporary file unlink(fileAnnotGDS, force=TRUE) From 82f9a002016da069a8068eb62c287ab31188eed2 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 18:57:41 -0400 Subject: [PATCH 266/385] Update doc for generateGeneBloc() function --- R/process1KG_internal.R | 20 +++++++++++++------- man/generateGeneBlock.Rd | 18 ++++++++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index ac467ea65..597cf365b 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -194,13 +194,19 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, #' ## Reference GDS file #' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") #' -#' ## Open the reference GDS file (demo version) -#' gds1KG <- snpgdsOpen(fileReferenceGDS) -#' -#' ## The function returns a data frame containing gene block information -#' matGeneBlock <- RAIDS:::generateGeneBlock(gdsReference=gds1KG, ensDb=edb) -#' print(head(matGeneBlock[grep("ENSG00000157152", matGeneBlock$GName),])) -#' closefn.gds(gds1KG) +#' \donttest{ +#' ## Open the reference GDS file (demo version) +#' gds1KG <- snpgdsOpen(fileReferenceGDS) +#' +#' ## The function returns a data.frame containing +#' ## gene block information +#' matGeneBlock <- RAIDS:::generateGeneBlock(gdsReference=gds1KG, +#' ensDb=edb) +#' print(head(matGeneBlock[grep("ENSG00000157152", +#' matGeneBlock$GName),])) +#' +#' closefn.gds(gds1KG) +#' } #' } #' #' @author Pascal Belleau, Astrid Deschênes and Alex Krasnitz diff --git a/man/generateGeneBlock.Rd b/man/generateGeneBlock.Rd index 5dc672a0a..0c8002910 100644 --- a/man/generateGeneBlock.Rd +++ b/man/generateGeneBlock.Rd @@ -70,13 +70,19 @@ if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { ## Reference GDS file fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") - ## Open the reference GDS file (demo version) - gds1KG <- snpgdsOpen(fileReferenceGDS) + \donttest{ + ## Open the reference GDS file (demo version) + gds1KG <- snpgdsOpen(fileReferenceGDS) - ## The function returns a data frame containing gene block information - matGeneBlock <- RAIDS:::generateGeneBlock(gdsReference=gds1KG, ensDb=edb) - print(head(matGeneBlock[grep("ENSG00000157152", matGeneBlock$GName),])) - closefn.gds(gds1KG) + ## The function returns a data.frame containing + ## gene block information + matGeneBlock <- RAIDS:::generateGeneBlock(gdsReference=gds1KG, + ensDb=edb) + print(head(matGeneBlock[grep("ENSG00000157152", + matGeneBlock$GName),])) + + closefn.gds(gds1KG) + } } } From 3201329ca49597a84ccb279e553e063645ba810b Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 29 Sep 2023 21:45:58 -0400 Subject: [PATCH 267/385] Update version to 0.99.13 --- DESCRIPTION | 2 +- inst/NEWS.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 7df4826d4..81fb2898f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.12 +Version: 0.99.13 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index ca9453e39..a2ced3d52 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,10 @@ +CHANGES IN VERSION 0.99.13 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o Update in Reference GDS vignette. + CHANGES IN VERSION 0.99.12 ------------------------ From 7c6742b0b2dc71028e2fb5bfb7463c3268690c10 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 5 Oct 2023 17:17:27 -0400 Subject: [PATCH 268/385] Adding author --- DESCRIPTION | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DESCRIPTION b/DESCRIPTION index 81fb2898f..ff660c75f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -14,6 +14,9 @@ Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", role=c("aut"), comment = c(ORCID = "0000-0001-7846-6749")), + person(given="David A.", family="Tuveson", + email="dtuveson@cshl.edu", + role=c("aut"), comment=c(ORCID="0000-0002-8017-2712")), person("Alexander", "Krasnitz", email="krasnitz@cshl.edu", role=c("aut"))) License: Apache License (>= 2) From e7e545eb21cf4086131e7de9d6d1b4df7d5a6bd4 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 6 Oct 2023 11:15:05 -0400 Subject: [PATCH 269/385] Update biocViews field to removed unwamted term --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index ff660c75f..2ea6dc008 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -53,6 +53,6 @@ Suggests: testthat, BugReports: https://github.com/KrasnitzLab/RAIDS/issues URL: https://krasnitzlab.github.io/RAIDS/ biocViews: Genetics, Software, Sequencing, WholeGenome, PrincipalComponent, - GeneticVariability, DimensionReduction, BiocViews + GeneticVariability, DimensionReduction Roxygen: list(markdown = TRUE) RoxygenNote: 7.2.3 From b482829aa5fd48cd69e7f1a734b6c1336c41ef70 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 6 Oct 2023 11:48:57 -0400 Subject: [PATCH 270/385] Update package version to 0.99.14 --- DESCRIPTION | 2 +- inst/NEWS.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 2ea6dc008..9d9eb3cee 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.13 +Version: 0.99.14 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index a2ced3d52..fe5130a53 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,11 @@ +CHANGES IN VERSION 0.99.14 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o Adding missing author David Tuveson. + o Updating BiocViews terms. + CHANGES IN VERSION 0.99.13 ------------------------ From 9ddc78e285d47c6dcefa561a710e7aa93e4c94bf Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 12 Oct 2023 12:33:44 -0400 Subject: [PATCH 271/385] Update README --- README.md | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f510c33f4..57e4596b3 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,31 @@ the following: > Pascal Belleau, Astrid Deschênes, Nyasha Chambwe, David A. Tuveson, Alexander Krasnitz; Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. https://doi.org/10.1158/0008-5472.CAN-22-0682 +## Bioconductor Package ## + +[![Bioconductor Time](https://bioconductor.org/shields/years-in-bioc/RAIDS.svg)](https://bioconductor.org/packages/RAIDS) + +The **RAIDS** package is now an official package +of [Bioconductor](http://bioconductor.org/). + +The current Bioconductor release can be directly downloaded from their website: +[Current release](https://bioconductor.org/packages/RAIDS) + + ## Installation ## -To install the latest version accessible, the [devtools](https://cran.r-project.org/web/packages/devtools/index.html) +To install this package +from [Bioconductor](https://bioconductor.org/packages/CNVMetrics), start R +(version "4.3" or later) and enter: + + if (!requireNamespace("BiocManager", quietly = TRUE)) + install.packages("BiocManager") + + BiocManager::install("RAIDS") + + +To install the latest version accessible from Github, +the [devtools](https://cran.r-project.org/web/packages/devtools/index.html) package is required. ## Load required package @@ -56,7 +78,7 @@ package is required. ## License ## -This package and the underlying **_RAIDS_** code are distributed under +This package and the underlying **RAIDS** code are distributed under the Apache-2.0 license. You are free to use and redistribute this software. For more information on Apache-2.0 License see From 498c1f67386f5633835de10506e7c3e1f37dc222 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 12 Oct 2023 13:40:48 -0400 Subject: [PATCH 272/385] Update readme file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57e4596b3..abd516b6d 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ The current Bioconductor release can be directly downloaded from their website: ## Installation ## To install this package -from [Bioconductor](https://bioconductor.org/packages/CNVMetrics), start R +from [Bioconductor](https://bioconductor.org/packages/RAIDS), start R (version "4.3" or later) and enter: if (!requireNamespace("BiocManager", quietly = TRUE)) From 1345a5e1d30aa9f85a774ae7ca4044e70f29e2b3 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 12 Oct 2023 14:49:35 -0400 Subject: [PATCH 273/385] Update installation section in vignette --- vignettes/RAIDS.Rmd | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index faa3bfe74..6af40508d 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -87,16 +87,16 @@ accuracy estimate. # Installation -To install the latest version from the -[RAIDS Github Website](https://github.com/KrasnitzLab/RAIDS "RAIDS Github Site"), -the `r CRANpkg("devtools")` package is required. +To install this package +from [Bioconductor](https://bioconductor.org/packages/RAIDS), start R +(version 4.3 or later) and enter: + ```{r installDemo01, eval=FALSE, warning=FALSE, message=FALSE} -## Load required package -library(devtools) +if (!requireNamespace("BiocManager", quietly = TRUE)) + install.packages("BiocManager") -## Install the latest version of RAIDS -devtools::install_github('KrasnitzLab/RAIDS') +BiocManager::install("RAIDS") ```
From 36ebb6f806a13ee8b8df5561db92336ee63c75e8 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 12 Oct 2023 22:31:53 -0400 Subject: [PATCH 274/385] Update version to 0.99.15 --- DESCRIPTION | 2 +- inst/NEWS.md | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 9d9eb3cee..c6a22ded1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.14 +Version: 0.99.15 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index fe5130a53..5aa1d2ac9 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,10 @@ +CHANGES IN VERSION 0.99.15 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o Updating installation section in vignette. + CHANGES IN VERSION 0.99.14 ------------------------ @@ -5,7 +12,7 @@ SIGNIFICANT USER-VISIBLE CHANGES o Adding missing author David Tuveson. o Updating BiocViews terms. - + CHANGES IN VERSION 0.99.13 ------------------------ From 12ea1e76f214b2a7a1e1693e2bd023c998411c32 Mon Sep 17 00:00:00 2001 From: J Wokaty Date: Tue, 24 Oct 2023 11:51:36 -0400 Subject: [PATCH 275/385] bump x.y.z version to even y prior to creation of RELEASE_3_18 branch --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index c6a22ded1..653d53a3f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.15 +Version: 1.0.0 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", From e58671a083e7c67244373fea6baa7936caa06439 Mon Sep 17 00:00:00 2001 From: J Wokaty Date: Tue, 24 Oct 2023 11:51:36 -0400 Subject: [PATCH 276/385] bump x.y.z version to odd y following creation of RELEASE_3_18 branch --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 653d53a3f..b1ab5fdf1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 1.0.0 +Version: 1.1.0 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", From a9ec943308a25fa981dc4442315f8d7532bb201f Mon Sep 17 00:00:00 2001 From: J Wokaty Date: Tue, 30 Apr 2024 11:51:55 -0400 Subject: [PATCH 277/385] bump x.y.z version to even y prior to creation of RELEASE_3_19 branch --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index b1ab5fdf1..ebcb40d7c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 1.1.0 +Version: 1.2.0 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", From 8c31b43b8656bfbf888c0c9627083eaca70cf7eb Mon Sep 17 00:00:00 2001 From: J Wokaty Date: Tue, 30 Apr 2024 11:51:55 -0400 Subject: [PATCH 278/385] bump x.y.z version to odd y following creation of RELEASE_3_19 branch --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index ebcb40d7c..66ee71128 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 1.2.0 +Version: 1.3.0 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", From d135565ef7a1fa6cb8f5a5e725dd165574b420f3 Mon Sep 17 00:00:00 2001 From: belleau Date: Mon, 5 Aug 2024 09:41:43 -0400 Subject: [PATCH 279/385] We stop to use pedProfile rownames. We changed function addStudyGDSSample. --- R/gdsWrapper_internal.R | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 4b2803d21..d07e3386c 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -645,8 +645,12 @@ addStudyGDSSample <- function(gdsProfile, pedProfile, batch, listSamples, ## Used only the selected samples (all when listSamples == NULL) if(!(is.null(listSamples))) { if(length(listSamples) == length(intersect(listSamples, - rownames(pedProfile)))) { - pedProfile <- pedProfile[listSamples,] + pedProfile$Name.ID))) { + # if we remove the names we should manage the order + # something like + tmp1 <- order(as.character(pedProfile$Name.ID)) + tmp2 <- order(as.character(listSamples)) + pedProfile <- pedProfile[tmp1[which(pedProfile$Name.ID[tmp1] %in% listSamples)][order(tmp2)],] } else { stop("List of samples includes samples not present in ", "the \'pedProfile\' data frame. The sample names must be ", From 4a878216c06e2a18d44d3cb8df686861c85213a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Mon, 5 Aug 2024 17:44:42 -0400 Subject: [PATCH 280/385] Update check-bioc.yaml --- .github/workflows/check-bioc.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index 69b85aa46..9a39ec64b 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -52,9 +52,9 @@ jobs: matrix: config: ## - { os: ubuntu-latest, r: '4.2.2', bioc: '3.16', cont: "bioconductor/bioconductor_docker:RELEASE_3_16", rspm: "https://packagemanager.posit.co" } - - { os: ubuntu-latest, r: '4.3', bioc: '3.17', cont: "bioconductor/bioconductor_docker:RELEASE_3_17", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + - { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } ## - { os: macOS-latest, r: '4.2.2', bioc: '3.16'} - - { os: macOS-latest, r: '4.3', bioc: '3.17'} + - { os: macOS-latest, r: '4.4', bioc: '3.19'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true From 38d46f1e740495cd28422565507b8a11b400df31 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 16 Aug 2024 17:36:40 -0400 Subject: [PATCH 281/385] Add createAccuracyGraph() function; change itemize to describe in doc --- DESCRIPTION | 4 +- NAMESPACE | 16 ++ R/RAIDS.R | 199 ++++++++-------- R/allelicFraction_internal.R | 234 +++++++++---------- R/gdsWrapper.R | 2 +- R/gdsWrapper_internal.R | 4 +- R/process1KG.R | 30 +-- R/process1KG_internal.R | 16 +- R/processStudy.R | 115 +++++---- R/processStudy_internal.R | 63 ++--- R/synthetic.R | 18 +- R/synthetic_internal.R | 6 +- R/tools_internal.R | 28 +-- R/visualization.R | 105 +++++++++ R/visualization_internal.R | 80 +++++++ inst/extdata/TEST_01.infoCall.RDS | Bin 0 -> 8408 bytes man/RAIDS-package.Rd | 22 +- man/appendGDSSampleOnly.Rd | 2 +- man/appendGDSgenotype.Rd | 8 +- man/calcAFMLRNA.Rd | 18 +- man/computeAllelicFractionDNA.Rd | 30 +-- man/computeAllelicFractionRNA.Rd | 36 +-- man/computeAllelicImbDNAChr.Rd | 28 +-- man/computeAncestryFromSyntheticFile.Rd | 21 +- man/computeKNNRefSample.Rd | 16 +- man/computeKNNRefSynthetic.Rd | 20 +- man/computeLOHBlocksDNAChr.Rd | 48 ++-- man/computePCAMultiSynthetic.Rd | 8 +- man/computePCARefRMMulti.Rd | 2 +- man/computePCARefSample.Rd | 8 +- man/computePoolSyntheticAncestryGr.Rd | 10 +- man/computeSyntheticConfMat.Rd | 6 +- man/computeSyntheticROC.Rd | 2 +- man/createAccuracyGraph.Rd | 65 ++++++ man/demoKnownSuperPop1KG.Rd | 6 +- man/demoPCA1KG.Rd | 4 +- man/demoPCASyntheticProfiles.Rd | 12 +- man/demoPedigreeEx1.Rd | 8 +- man/generateGeneBlock.Rd | 16 +- man/generateMapSnvSel.Rd | 18 +- man/getTableSNV.Rd | 24 +- man/matKNNSynthetic.Rd | 24 +- man/pedSynthetic.Rd | 40 ++-- man/prepPed1KG.Rd | 12 +- man/readSNVFileGeneric.Rd | 8 +- man/readSNVPileupFile.Rd | 12 +- man/readSNVVCF.Rd | 8 +- man/runExomeAncestry.Rd | 16 +- man/runIBDKING.Rd | 2 +- man/runProfileAncestry.Rd | 16 +- man/runRNAAncestry.Rd | 16 +- man/runWrapperAncestry.Rd | 16 +- man/selParaPCAUpQuartile.Rd | 16 +- man/select1KGPop.Rd | 8 +- man/snpPositionDemo.Rd | 79 ++++--- man/splitSelectByPop.Rd | 8 +- man/tableBlockAF.Rd | 28 +-- man/testAlleleFractionChange.Rd | 14 +- man/testEmptyBox.Rd | 8 +- man/validateCreateAccuracyGraph.Rd | 50 ++++ man/validateProfileGDSExist.Rd | 2 +- man/validateRunExomeOrRNAAncestry.Rd | 8 +- tests/testthat/fixtures/TEST_01.infoCall.RDS | Bin 0 -> 8408 bytes tests/testthat/test-visualization.R | 104 +++++++++ tests/testthat/test-visualization_internal.R | 23 ++ 65 files changed, 1154 insertions(+), 722 deletions(-) create mode 100644 R/visualization.R create mode 100644 R/visualization_internal.R create mode 100644 inst/extdata/TEST_01.infoCall.RDS create mode 100644 man/createAccuracyGraph.Rd create mode 100644 man/validateCreateAccuracyGraph.Rd create mode 100644 tests/testthat/fixtures/TEST_01.infoCall.RDS create mode 100644 tests/testthat/test-visualization.R create mode 100644 tests/testthat/test-visualization_internal.R diff --git a/DESCRIPTION b/DESCRIPTION index c6a22ded1..86a88d2f1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -42,6 +42,8 @@ Imports: S4Vectors, rlang, VariantAnnotation, MatrixGenerics, + ggplot2, + stringr Suggests: testthat, knitr, rmarkdown, @@ -55,4 +57,4 @@ URL: https://krasnitzlab.github.io/RAIDS/ biocViews: Genetics, Software, Sequencing, WholeGenome, PrincipalComponent, GeneticVariability, DimensionReduction Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.2 diff --git a/NAMESPACE b/NAMESPACE index 9f4e6315c..c137b74fa 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -11,6 +11,7 @@ export(computePCAMultiSynthetic) export(computePCARefSample) export(computePoolSyntheticAncestryGr) export(computeSyntheticROC) +export(createAccuracyGraph) export(createStudy2GDS1KG) export(estimateAllelicFraction) export(generateGDS1KG) @@ -70,9 +71,23 @@ importFrom(gdsfmt,read.gdsn) importFrom(gdsfmt,readmode.gdsn) importFrom(gdsfmt,sync.gds) importFrom(gdsfmt,write.gdsn) +importFrom(ggplot2,aes) +importFrom(ggplot2,element_rect) +importFrom(ggplot2,element_text) +importFrom(ggplot2,facet_grid) +importFrom(ggplot2,geom_line) +importFrom(ggplot2,geom_ribbon) +importFrom(ggplot2,ggplot) +importFrom(ggplot2,ggtitle) +importFrom(ggplot2,scale_colour_manual) +importFrom(ggplot2,theme) +importFrom(ggplot2,theme_classic) +importFrom(ggplot2,ylab) +importFrom(ggplot2,ylim) importFrom(methods,is) importFrom(pROC,multiclass.roc) importFrom(pROC,roc) +importFrom(rlang,.data) importFrom(rlang,arg_match) importFrom(stats,dbinom) importFrom(stats,mad) @@ -81,6 +96,7 @@ importFrom(stats,pbinom) importFrom(stats,qbinom) importFrom(stats,quantile) importFrom(stats,rmultinom) +importFrom(stringr,str_detect) importFrom(utils,read.csv) importFrom(utils,read.csv2) importFrom(utils,read.delim) diff --git a/R/RAIDS.R b/R/RAIDS.R index f263e61ad..4a04dcf18 100644 --- a/R/RAIDS.R +++ b/R/RAIDS.R @@ -25,8 +25,6 @@ #' https://doi.org/10.1158/0008-5472.CAN-22-0682 #' #' -#' @docType package -#' #' @name RAIDS-package #' #' @aliases RAIDS-package RAIDS @@ -38,28 +36,22 @@ #' Pascal Belleau #' #' @seealso -#' \itemize{ -#' \item \code{\link{runExomeAncestry}} {This function runs most steps +#' \describe{ +#' \item{\code{\link{runExomeAncestry}}}{This function runs most steps #' leading to the ancestry inference call on a specific exome profile.} -#' \item \code{\link{runExomeAncestry}} {This function runs most steps +#' \item{\code{\link{runExomeAncestry}}}{This function runs most steps #' leading to the ancestry inference call on a specific RNA profile.} -#' \item \code{\link{estimateAllelicFraction}} { This function estimates -#' the allelic fraction of the pruned SNVs for a specific sample and add -#' the information to the associated GDS Sample file. The allelic fraction -#' estimation method is adapted to the type of study (DNA or RNA). } -#' \item \code{\link{computeSyntheticROC}} { This function calculate the -#' AUROC of the inferences for specific values of D and K using the -#' inferred ancestry results from the synthetic profiles.} -#' \item \code{\link{generateMapSnvSel}} {The function applies a cut-off -#' filter to the SNV information file to retain only the SNV that have a -#' frequency superior or equal to the specified cut-off in at least one -#' super population.} +#' \item{\code{\link{createAccuracyGraph}}}{The function extracts the +#' required information from an output generated by RAIDS to create a +#' graphic representation of the accuracy for different values of +#' PCA dimensions and K-neighbors through all tested ancestries.} #' } #' #' @return RAIDS #' @encoding UTF-8 #' @keywords package -NULL +#' @keywords internal +"_PACKAGE" #' A small \code{data.frame} containing the information related to @@ -82,49 +74,49 @@ NULL #' synthetic profiles. The row names of #' the \code{data.frame} correspond to the profile unique identifiers. #' The \code{data.frame} contains 7 columns: -#' \itemize{ -#' \item \code{data.id} {a \code{character} string representing the unique +#' \describe{ +#' \item{\code{data.id}}{ a \code{character} string representing the unique #' synthetic profile identifier.} -#' \item \code{case.id} {a \code{character} string representing the unique +#' \item{\code{case.id}}{ a \code{character} string representing the unique #' profile identifier that was used to generate the synthetic profile.} -#' \item \code{sample.type} {a \code{character} string representing the type +#' \item{\code{sample.type}}{ a \code{character} string representing the type #' of profile. } -#' \item \code{diagnosis} {a \code{character} string representing the +#' \item{\code{diagnosis}}{ a \code{character} string representing the #' diagnosis of profile that was used to generate the synthetic profile. } -#' \item \code{source} {a \code{character} string representing the +#' \item{\code{source}}{ a \code{character} string representing the #' source of the synthetic profile. } -#' \item \code{study.id} {a \code{character} string representing the +#' \item{\code{study.id}}{ a \code{character} string representing the #' name of the study to which the synthetic profile is associated. } -#' \item \code{superPop} {a \code{character} string representing the +#' \item{\code{superPop}}{ a \code{character} string representing the #' super population of the profile that was used to generate the synthetic #' profile. } #' } #' #' @return The \code{data.frame} containing the information about the -#' synthetic profiles. The row names of +#' synthetic profiles. The row names of #' the \code{data.frame} correspond to the profile unique identifiers. #' The \code{data.frame} contains 7 columns: -#' \itemize{ -#' \item \code{data.id} {a \code{character} string representing the unique +#' \describe{ +#' \item{\code{data.id}}{ a \code{character} string representing the unique #' synthetic profile identifier.} -#' \item \code{case.id} {a \code{character} string representing the unique +#' \item{\code{case.id}}{ a \code{character} string representing the unique #' profile identifier that was used to generate the synthetic profile.} -#' \item \code{sample.type} {a \code{character} string representing the type -#' of profile. } -#' \item \code{diagnosis} {a \code{character} string representing the +#' \item{\code{sample.type}}{ a \code{character} string representing the type +#' of profile.} +#' \item{\code{diagnosis}}{ a \code{character} string representing the #' diagnosis of profile that was used to generate the synthetic profile. } -#' \item \code{source} {a \code{character} string representing the +#' \item{\code{source}}{ a \code{character} string representing the #' source of the synthetic profile. } -#' \item \code{study.id} {a \code{character} string representing the +#' \item{\code{study.id}}{ a \code{character} string representing the #' name of the study to which the synthetic profile is associated. } -#' \item \code{superPop} {a \code{character} string representing the +#' \item{\code{superPop}}{ a \code{character} string representing the #' super population of the profile that was used to generate the synthetic #' profile. } #' } #' #' @seealso -#' \itemize{ -#' \item \code{\link{computeSyntheticROC}} {for calculating the AUROC of +#' \describe{ +#' \item{\code{\link{computeSyntheticROC}}}{ for calculating the AUROC of #' the inferences for specific values of D and K using the inferred #' ancestry results from the synthetic profiles} #' } @@ -177,33 +169,33 @@ NULL #' #' @format The \code{data.frame} containing the information about the #' synthetic profiles. The \code{data.frame} contains 4 columns: -#' \itemize{ -#' \item \code{sample.id} {a \code{character} string representing the unique +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique #' synthetic profile identifier.} -#' \item \code{D} {a \code{numeric} representing the number of dimensions used +#' \item{\code{D}}{ a \code{numeric} representing the number of dimensions used #' to infer the ancestry of the synthetic profile.} -#' \item \code{K} {a \code{numeric} representing the number of neighbors used +#' \item{\code{K}}{ a \code{numeric} representing the number of neighbors used #' to infer the ancestry of the synthetic profile.} -#' \item \code{SuperPop} {a \code{character} string representing the +#' \item{\code{SuperPop}}{ a \code{character} string representing the #' inferred ancestry of the synthetic profile for the specific D and K values.} #' } #' #' @return The \code{data.frame} containing the information about the #' synthetic profiles. The \code{data.frame} contains 4 columns: -#' \itemize{ -#' \item \code{sample.id} {a \code{character} string representing the unique +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique #' synthetic profile identifier.} -#' \item \code{D} {a \code{numeric} representing the number of dimensions used +#' \item{\code{D}}{ a \code{numeric} representing the number of dimensions used #' to infer the ancestry of the synthetic profile.} -#' \item \code{K} {a \code{numeric} representing the number of neighbors used +#' \item{\code{K}}{ a \code{numeric} representing the number of neighbors used #' to infer the ancestry of the synthetic profile.} -#' \item \code{SuperPop} {a \code{character} string representing the +#' \item{\code{SuperPop}}{ a \code{character} string representing the #' inferred ancestry of the synthetic profile for the specific D and K values.} #' } #' #' @seealso -#' \itemize{ -#' \item \code{\link{computeSyntheticROC}} {for calculating the AUROC of +#' \describe{ +#' \item{\code{\link{computeSyntheticROC}}}{ for calculating the AUROC of #' the inferences for specific values of D and K using the inferred #' ancestry results from the synthetic profiles} #' } @@ -257,73 +249,76 @@ NULL #' #' @format The \code{data.frame} containing the information about the #' synthetic profiles. The \code{data.frame} contains 4 columns: -#' \itemize{ -#' \item \code{cnt.tot} {a \code{integer} representing the number of reads at +#' \describe{ +#' \item{\code{cnt.tot}}{ a \code{integer} representing the number of reads at #' the SNV position.} -#' \item \code{cnt.ref} {a \code{integer} representing the number of reads +#' \item{\code{cnt.ref}}{ a \code{integer} representing the number of reads #' corresponding to the reference at the SNV position.} -#' \item \code{cnt.alt} {a \code{integer} representing the number of reads +#' \item{\code{cnt.alt}}{ a \code{integer} representing the number of reads #' different than the reference at the SNV position.} -#' \item \code{snp.pos} {a \code{integer} representing the position of the +#' \item{\code{snp.pos}}{ a \code{integer} representing the position of the #' SNV on the chromosome.} -#' \item \code{snp.chr} {a \code{integer} representing the chromosome on which +#' \item{\code{snp.chr}}{ a \code{integer} representing the chromosome on which #' the SNV is located.} -#' \item \code{normal.geno} {a \code{integer} representing the genotype -#' (0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown).} -#' \item \code{pruned} {a \code{logical} indicated if the SNV is pruned.} -#' \item \code{snp.index} {a \code{integer} representing the index of the +#' \item{\code{normal.geno}}{ a \code{integer} representing the genotype +#' (0=wild-type reference; 1=heterozygote; 2=homozygote alternative; +#' 3=unkown).} +#' \item{\code{pruned}}{ a \code{logical} indicated if the SNV is pruned.} +#' \item{\code{snp.index}}{ a \code{integer} representing the index of the #' SNV in the reference SNV GDS file.} -#' \item \code{keep} {a \code{logical} indicated if the genotype +#' \item{\code{keep}}{ a \code{logical} indicated if the genotype #' exists for the SNV.} -#' \item \code{hetero} {a \code{logical} indicated if the SNV is heterozygote.} -#' \item \code{homo} {a \code{logical} indicated if the SNV is homozygote.} -#' \item \code{block.id} {a \code{integer} representing the block identifier +#' \item{\code{hetero}}{ a \code{logical} indicated if the SNV is +#' heterozygote.} +#' \item{\code{homo}}{ a \code{logical} indicated if the SNV is homozygote.} +#' \item{\code{block.id}}{ a \code{integer} representing the block identifier #' associated to the current SNV.} -#' \item \code{phase} {a \code{integer} representing the block identifier +#' \item{\code{phase}}{ a \code{integer} representing the block identifier #' associated to the current SNV.} -#' \item \code{lap} {a \code{numeric} representing the lower allelic fraction.} -#' \item \code{LOH} {a \code{integer} indicating if the SNV is in an LOH region -#' (0=not LOH, 1=in LOH).} -#' \item \code{imbAR} {a \code{integer} indicating if the SNV is in an +#' \item{\code{lap}}{ a \code{numeric} representing the lower allelic +#' fraction.} +#' \item{\code{LOH}}{ a \code{integer} indicating if the SNV is in an LOH +#' region (0=not LOH, 1=in LOH).} +#' \item{\code{imbAR}}{ a \code{integer} indicating if the SNV is in an #' imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; #' 1=tested positive for imbalance in at least 1 window).} -#' \item \code{freq} {a \code{numeric} representing the frequency of the +#' \item{\code{freq}}{ a \code{numeric} representing the frequency of the #' variant in the the reference.} #' } #' #' @return The \code{data.frame} containing the information about the #' synthetic profiles. The \code{data.frame} contains 4 columns: -#' \itemize{ -#' \item \code{cnt.tot} {a \code{integer} representing the number of reads at +#' \describe{ +#' \item{\code{cnt.tot}}{ a \code{integer} representing the number of reads at #' the SNV position.} -#' \item \code{cnt.ref} {a \code{integer} representing the number of reads +#' \item{\code{cnt.ref}}{ a \code{integer} representing the number of reads #' corresponding to the reference at the SNV position.} -#' \item \code{cnt.alt} {a \code{integer} representing the number of reads +#' \item{\code{cnt.alt}}{ a \code{integer} representing the number of reads #' different than the reference at the SNV position.} -#' \item \code{snp.pos} {a \code{integer} representing the position of the +#' \item{\code{snp.pos}}{ a \code{integer} representing the position of the #' SNV on the chromosome.} -#' \item \code{snp.chr} {a \code{integer} representing the chromosome on which +#' \item{\code{snp.chr}}{ a \code{integer} representing the chromosome on which #' the SNV is located.} -#' \item \code{normal.geno} {a \code{integer} representing the genotype +#' \item{\code{normal.geno}}{ a \code{integer} representing the genotype #' (0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown).} -#' \item \code{pruned} {a \code{logical} indicated if the SNV is pruned.} -#' \item \code{snp.index} {a \code{integer} representing the index of the +#' \item{\code{pruned}}{ a \code{logical} indicated if the SNV is pruned.} +#' \item{\code{snp.index}}{ a \code{integer} representing the index of the #' SNV in the reference SNV GDS file.} -#' \item \code{keep} {a \code{logical} indicated if the genotype +#' \item{\code{keep}}{ a \code{logical} indicated if the genotype #' exists for the SNV.} -#' \item \code{hetero} {a \code{logical} indicated if the SNV is heterozygote.} -#' \item \code{homo} {a \code{logical} indicated if the SNV is homozygote.} -#' \item \code{block.id} {a \code{integer} representing the block identifier +#' \item{\code{hetero}}{ a \code{logical} indicated if the SNV is heterozygote.} +#' \item{\code{homo}}{ a \code{logical} indicated if the SNV is homozygote.} +#' \item{\code{block.id}}{ a \code{integer} representing the block identifier #' associated to the current SNV.} -#' \item \code{phase} {a \code{integer} representing the block identifier +#' \item{\code{phase}}{ a \code{integer} representing the block identifier #' associated to the current SNV.} -#' \item \code{lap} {a \code{numeric} representing the lower allelic fraction.} -#' \item \code{LOH} {a \code{integer} indicating if the SNV is in an LOH region +#' \item{\code{lap}}{ a \code{numeric} representing the lower allelic fraction.} +#' \item{\code{LOH}}{ a \code{integer} indicating if the SNV is in an LOH region #' (0=not LOH, 1=in LOH).} -#' \item \code{imbAR} {a \code{integer} indicating if the SNV is in an +#' \item{\code{imbAR}}{ a \code{integer} indicating if the SNV is in an #' imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; #' 1=tested positive for imbalance in at least 1 window).} -#' \item \code{freq} {a \code{numeric} representing the frequency of the +#' \item{\code{freq}}{ a \code{numeric} representing the frequency of the #' variant in the the reference.} #' } #' @@ -367,7 +362,7 @@ NULL #' #' @format The \code{list} containing the PCA results for a small subset of #' the reference 1KG dataset. The \code{list} contains 2 entries: -#' \itemize{ +#' \describe{ #' \item{pruned}{ a \code{vector} of SNV identifiers specifying selected SNVs #' for the PCA analysis.} #' \item{pca.unrel}{ a \code{snpgdsPCAClass} object containing the eigenvalues @@ -376,7 +371,7 @@ NULL #' #' @return The \code{list} containing the PCA results for a small subset of #' the reference 1KG dataset. The \code{list} contains 2 entries: -#' \itemize{ +#' \describe{ #' \item{pruned}{ a \code{vector} of SNV identifiers specifying selected SNVs #' for the PCA analysis.} #' \item{pca.unrel}{ a \code{snpgdsPCAClass} object containing the eigenvalues @@ -444,10 +439,10 @@ NULL #' @format The \code{list} containing the PCA result of demo synthetic #' profiles projected on the demo subset 1KG reference PCA. #' The \code{list} contains 3 entries: -#' \itemize{ +#' \describe{ #' \item{sample.id}{ a \code{character} string representing the unique #' identifier of the synthetic profiles.} -#' \item{eigenvector.ref} { a \code{matrix} of \code{numeric} containing +#' \item{eigenvector.ref}{ a \code{matrix} of \code{numeric} containing #' the eigenvectors for the reference profiles.} #' \item{eigenvector}{ a \code{matrix} of \code{numeric} containing the #' eigenvectors for the current synthetic profiles projected on the demo @@ -457,10 +452,10 @@ NULL #' @return The \code{list} containing the PCA result of demo synthetic #' profiles projected on the demo subset 1KG reference PCA. #' The \code{list} contains 3 entries: -#' \itemize{ +#' \describe{ #' \item{sample.id}{ a \code{character} string representing the unique #' identifier of the synthetic profiles.} -#' \item{eigenvector.ref} { a \code{matrix} of \code{numeric} containing +#' \item{eigenvector.ref}{ a \code{matrix} of \code{numeric} containing #' the eigenvectors for the reference profiles.} #' \item{eigenvector}{ a \code{matrix} of \code{numeric} containing the #' eigenvectors for the current synthetic profiles projected on the demo @@ -468,8 +463,8 @@ NULL #' } #' #' @seealso -#' \itemize{ -#' \item \code{\link{computeKNNRefSynthetic}} {for running a k-nearest +#' \describe{ +#' \item{\code{\link{computeKNNRefSynthetic}}}{ for running a k-nearest #' neighbors analysis on a subset of the synthetic data set.} #' } #' @@ -535,10 +530,10 @@ NULL #' for the demo 1KG reference profiles. #' #' @seealso -#' \itemize{ -#' \item \code{\link{computeKNNRefSynthetic}} {for running a k-nearest +#' \describe{ +#' \item{\code{\link{computeKNNRefSynthetic}}}{ for running a k-nearest #' neighbors analysis on a subset of the synthetic data set.} -#' \item \code{\link{computePoolSyntheticAncestryGr}} { for running a +#' \item{\code{\link{computePoolSyntheticAncestryGr}}}{ for running a #' PCA analysis using 1 synthetic profile from each sub-continental #' population.} #' } @@ -599,7 +594,7 @@ NULL #' #' @format The \code{data.frame} containing the information about a demo #' profile called 'ex1'. the \code{data.frame} has 5 columns: -#' \itemize{ +#' \describe{ #' \item{Name.ID}{ a \code{character} string representing the unique #' identifier of the profile.} #' \item{Case.ID}{ a \code{character} string representing the unique @@ -615,7 +610,7 @@ NULL #' #' @return The \code{data.frame} containing the information about a demo #' profile called 'ex1'. the \code{data.frame} has 5 columns: -#' \itemize{ +#' \describe{ #' \item{Name.ID}{ a \code{character} string representing the unique #' identifier of the profile.} #' \item{Case.ID}{ a \code{character} string representing the unique @@ -629,8 +624,8 @@ NULL #' } #' #' @seealso -#' \itemize{ -#' \item \code{\link{runExomeAncestry}} {for running runs most +#' \describe{ +#' \item{\code{\link{runExomeAncestry}}}{ for running runs most #' steps leading to the ancestry inference call on a specific exome #' profile.} #' } diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 3b8993fff..2481cde94 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -32,25 +32,25 @@ #' when the function is running. #' #' @return a \code{data.frame} containing: -#' \itemize{ -#' \item{cnt.tot} {a single \code{integer} representing the total coverage for +#' \describe{ +#' \item{cnt.tot}{ a single \code{integer} representing the total coverage for #' the SNV.} -#' \item{cnt.ref} {a single \code{integer} representing the coverage for +#' \item{cnt.ref}{ a single \code{integer} representing the coverage for #' the reference allele.} -#' \item{cnt.alt} {a single \code{integer} representing the coverage for +#' \item{cnt.alt}{ a single \code{integer} representing the coverage for #' the alternative allele.} -#' \item{snpPos} {a single \code{integer} representing the SNV position.} -#' \item{snp.chr} {a single \code{integer} representing the SNV chromosome.} -#' \item{normal.geno} {a single \code{numeric} indicating the genotype of the +#' \item{snpPos}{ a single \code{integer} representing the SNV position.} +#' \item{snp.chr}{ a single \code{integer} representing the SNV chromosome.} +#' \item{normal.geno}{ a single \code{numeric} indicating the genotype of the #' SNV. The possibles are: \code{0} (wild-type homozygote), \code{1} #' (heterozygote), \code{2} (altenative homozygote), \code{3} indicating that #' the normal genotype is unknown.} -#' \item{pruned} { a \code{logical}} -#' \item{snp.index} {a \code{vector} of \code{integer} representing the +#' \item{pruned}{ a \code{logical}} +#' \item{snp.index}{ a \code{vector} of \code{integer} representing the #' position of the SNVs in the Reference GDS file.} -#' \item{keep} {a \code{logical} } -#' \item{hetero} {a \code{logical} } -#' \item{homo} {a \code{logical} } +#' \item{keep}{ a \code{logical} } +#' \item{hetero}{ a \code{logical} } +#' \item{homo}{ a \code{logical} } #' } #' #' @examples @@ -240,26 +240,26 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' @param snpPos a \code{data.frame} containing the SNV information for the #' chromosome specified by the \code{chr} argument. The \code{data.frame} must #' contain: -#' \itemize{ -#' \item{cnt.tot} {a single \code{integer} representing the total coverage for +#' \describe{ +#' \item{cnt.tot}{ a single \code{integer} representing the total coverage for #' the SNV.} -#' \item{cnt.ref} {a single \code{integer} representing the coverage for +#' \item{cnt.ref}{ a single \code{integer} representing the coverage for #' the reference allele.} -#' \item{cnt.alt} {a single \code{integer} representing the coverage for +#' \item{cnt.alt}{ a single \code{integer} representing the coverage for #' the alternative allele.} -#' \item{snp.pos} {a single \code{integer} representing the SNV position.} -#' \item{snp.chr} {a single \code{integer} representing the SNV chromosome.} -#' \item{normal.geno} {a single \code{numeric} indicating the genotype of the +#' \item{snp.pos}{ a single \code{integer} representing the SNV position.} +#' \item{snp.chr}{ a single \code{integer} representing the SNV chromosome.} +#' \item{normal.geno}{ a single \code{numeric} indicating the genotype of the #' SNV. The possibles are: \code{0} (wild-type homozygote), \code{1} #' (heterozygote), \code{2} (altenative homozygote), \code{3} indicating that #' the normal genotype is unknown.} -#' \item{pruned} {a \code{logical} indicating if the SNV is retained after +#' \item{pruned}{ a \code{logical} indicating if the SNV is retained after #' pruning} -#' \item{snp.index} {a \code{integer} representing the index position of the +#' \item{snp.index}{ a \code{integer} representing the index position of the #' SNV in the Reference GDS file that contains all SNVs} -#' \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} -#' \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} -#' \item{homo} {a \code{logical} indicating if the SNV is homozygote} +#' \item{keep}{ a \code{logical} indicating if the genotype exists for the SNV} +#' \item{hetero}{ a \code{logical} indicating if the SNV is heterozygote} +#' \item{homo}{ a \code{logical} indicating if the SNV is homozygote} #' } #' #' @param chr a single positive \code{integer} for the current chromosome. The @@ -271,32 +271,32 @@ getTableSNV <- function(gdsReference, gdsSample, currentProfile, studyID, #' #' @return a \code{data.frame} with the informations about LOH on a specific #' chromosome. The \code{data.frame} contains those columns: -#' \itemize{ -#' \item{chr} {a \code{integer} representing the current chromosome} -#' \item{start} {a \code{integer} representing the starting position on the +#' \describe{ +#' \item{chr}{ a \code{integer} representing the current chromosome} +#' \item{start}{ a \code{integer} representing the starting position on the #' box containing only homozygote SNVs (or not SNV). The first box starts at #' position \code{1}.} -#' \item{end} {a \code{integer} representing the end position on the +#' \item{end}{ a \code{integer} representing the end position on the #' box containing only homozygote SNVs (or not SNV). The last box ends at the #' length of the chromosome.} -#' \item{logLHR} {a \code{numeric} representing the LOH score basde on +#' \item{logLHR}{ a \code{numeric} representing the LOH score basde on #' population frequencies. It is the sum of #' the log10 of the frequencies of the observed gegenotype minus the #' the sum of the log10 of the higher frequent genotype. #' (-100 when normal genotype are present)} -#' \item{LH1} { a \code{numeric} representing the probability to be +#' \item{LH1}{ a \code{numeric} representing the probability to be #' heterozygote based on the coverage of each allele when normal #' genotype is present} -#' \item{LM1} {a \code{numeric} representing the max probability +#' \item{LM1}{ a \code{numeric} representing the max probability #' for the read coverage at the position} -#' \item{homoScore} {a \code{numeric} representing \code{LH1} - \code{LM1}} -#' \item{nbSNV} {a \code{integer} representing th number of SNVs in +#' \item{homoScore}{ a \code{numeric} representing \code{LH1} - \code{LM1}} +#' \item{nbSNV}{ a \code{integer} representing th number of SNVs in #' the box} -#' \item{nbPruned} {a \code{integer} representing the number of pruned SNVs in +#' \item{nbPruned}{ a \code{integer} representing the number of pruned SNVs in #' the box} -#' \item{nbNorm} { a \code{integer} representing of the number of +#' \item{nbNorm}{ a \code{integer} representing of the number of #' heterozygote genotypes for the normal SNVs in the block} -#' \item{LOH} { a \code{integer} representing a flag, if \code{1} it means +#' \item{LOH}{ a \code{integer} representing a flag, if \code{1} it means #' the block is satisfying the criteria to be LOH. The value is not assigned #' in this function; the value \code{0} is assigned} #' } @@ -682,25 +682,25 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { #' @return a \code{data.frame} containing the allelic information for the #' pruned SNV dataset with coverage > \code{minCov}. The \code{data.frame} #' contains those columns: -#' \itemize{ -#' \item{cnt.tot} {a \code{integer} representing the total allele count} -#' \item{cnt.ref} {a \code{integer} representing the reference allele count} -#' \item{cnt.alt} {a \code{integer} representing the alternative allele count} -#' \item{snp.pos} {a \code{integer} representing the position on the chromosome} -#' \item{snp.chr} {a \code{integer} representing the chromosome} -#' \item{normal.geno} {a \code{integer} representing the genotype +#' \describe{ +#' \item{cnt.tot}{ a \code{integer} representing the total allele count} +#' \item{cnt.ref}{ a \code{integer} representing the reference allele count} +#' \item{cnt.alt}{ a \code{integer} representing the alternative allele count} +#' \item{snp.pos}{ a \code{integer} representing the position on the chromosome} +#' \item{snp.chr}{ a \code{integer} representing the chromosome} +#' \item{normal.geno}{ a \code{integer} representing the genotype #' (0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown)} -#' \item{pruned} {a \code{logical} indicating if the SNV is retained after +#' \item{pruned}{ a \code{logical} indicating if the SNV is retained after #' pruning} -#' \item{snp.index} {a \code{integer} representing the index position of the +#' \item{snp.index}{ a \code{integer} representing the index position of the #' SNV in the Reference GDS file that contains all SNVs} -#' \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} -#' \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} -#' \item{homo} {a \code{logical} indicating if the SNV is homozygote} -#' \item{lap} {a \code{numeric} representing the lower allelic fraction} -#' \item{LOH} {a \code{integer} indicating if the SNV is in an LOH region +#' \item{keep}{ a \code{logical} indicating if the genotype exists for the SNV} +#' \item{hetero}{ a \code{logical} indicating if the SNV is heterozygote} +#' \item{homo}{ a \code{logical} indicating if the SNV is homozygote} +#' \item{lap}{ a \code{numeric} representing the lower allelic fraction} +#' \item{LOH}{ a \code{integer} indicating if the SNV is in an LOH region #' (0=not LOH, 1=in LOH)} -#' \item{imbAR} {a \code{integer} indicating if the SNV is in an imbalanced +#' \item{imbAR}{ a \code{integer} indicating if the SNV is in an imbalanced #' region (-1=not classified as imbalanced or LOH, 0=in LOH; 1=tested #' positive for imbalance in at least 1 window)} #' } @@ -891,33 +891,33 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, #' @return a \code{data.frame} containing the allelic information for the #' pruned SNV dataset with coverage > \code{minCov}. The \code{data.frame} #' contains those columns: -#' \itemize{ -#' \item{cnt.tot} {a \code{integer} representing the total allele count} -#' \item{cnt.ref} {a \code{integer} representing the reference allele count} -#' \item{cnt.alt} {a \code{integer} representing the alternative allele count} -#' \item{snp.pos} {a \code{integer} representing the position on the chromosome} -#' \item{snp.chr} {a \code{integer} representing the chromosome} -#' \item{normal.geno} {a \code{integer} representing the genotype +#' \describe{ +#' \item{cnt.tot}{ a \code{integer} representing the total allele count} +#' \item{cnt.ref}{ a \code{integer} representing the reference allele count} +#' \item{cnt.alt}{ a \code{integer} representing the alternative allele count} +#' \item{snp.pos}{ a \code{integer} representing the position on the chromosome} +#' \item{snp.chr}{ a \code{integer} representing the chromosome} +#' \item{normal.geno}{ a \code{integer} representing the genotype #' (0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown)} -#' \item{pruned} {a \code{logical} indicating if the SNV is retained after +#' \item{pruned}{ a \code{logical} indicating if the SNV is retained after #' pruning} -#' \item{snp.index} {a \code{integer} representing the index position of the +#' \item{snp.index}{ a \code{integer} representing the index position of the #' SNV in the Reference GDS file that contains all SNVs} -#' \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} -#' \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} -#' \item{homo} {a \code{logical} indicating if the SNV is homozygote} -#' \item{block.id} { a \code{integer} indicating the unique identifier of the +#' \item{keep}{ a \code{logical} indicating if the genotype exists for the SNV} +#' \item{hetero}{ a \code{logical} indicating if the SNV is heterozygote} +#' \item{homo}{ a \code{logical} indicating if the SNV is homozygote} +#' \item{block.id}{ a \code{integer} indicating the unique identifier of the #' block in the Population Reference Annotation #' GDS file that contains the current SNV} -#' \item{phase} { a \code{integer} indicating the phase of the variant +#' \item{phase}{ a \code{integer} indicating the phase of the variant #' if known, \code{3} if not known} -#' \item{lap} {a \code{numeric} indicating lower allelic fraction} -#' \item{LOH} {a \code{integer} indicating if the SNV is in an LOH region +#' \item{lap}{ a \code{numeric} indicating lower allelic fraction} +#' \item{LOH}{ a \code{integer} indicating if the SNV is in an LOH region #' (0=not LOH, 1=in LOH)} -#' \item{imbAR} {a \code{integer} indicating if the SNV is in an imbalanced +#' \item{imbAR}{ a \code{integer} indicating if the SNV is in an imbalanced #' region (-1=not classified as imbalanced or LOH, 0=in LOH; 1=tested #' positive for imbalance in at least 1 window)} -#' \item{freq} {a \code{numeric} indicating the frequency of the variant +#' \item{freq}{ a \code{numeric} indicating the frequency of the variant #' in the the reference} #' } #' @@ -1056,28 +1056,28 @@ computeAllelicFractionRNA <- function(gdsReference, gdsSample, gdsRefAnnot, #' @param snpPos a \code{data.frame} containing the SNV information for the #' chromosome specified by the \code{chr} argument. The \code{data.frame} must #' contain: -#' \itemize{ -#' \item{cnt.tot} {a single \code{integer} representing the total coverage for +#' \describe{ +#' \item{cnt.tot}{ a single \code{integer} representing the total coverage for #' the SNV.} -#' \item{cnt.ref} {a single \code{integer} representing the coverage for +#' \item{cnt.ref}{ a single \code{integer} representing the coverage for #' the reference allele.} -#' \item{cnt.alt} {a single \code{integer} representing the coverage for +#' \item{cnt.alt}{ a single \code{integer} representing the coverage for #' the alternative allele.} -#' \item{snp.pos} {a single \code{integer} representing the SNV position.} -#' \item{snp.chr} {a single \code{integer} representing the SNV chromosome.} -#' \item{normal.geno} {a single \code{numeric} indicating the genotype of the +#' \item{snp.pos}{ a single \code{integer} representing the SNV position.} +#' \item{snp.chr}{ a single \code{integer} representing the SNV chromosome.} +#' \item{normal.geno}{ a single \code{numeric} indicating the genotype of the #' SNV. The possibles are: \code{0} (wild-type homozygote), \code{1} #' (heterozygote), \code{2} (altenative homozygote), \code{3} indicating that #' the normal genotype is unknown.} -#' \item{pruned} {a \code{logical} indicating if the SNV is retained after +#' \item{pruned}{ a \code{logical} indicating if the SNV is retained after #' pruning} -#' \item{snp.index} {a \code{integer} representing the index position of the +#' \item{snp.index}{ a \code{integer} representing the index position of the #' SNV in the Reference GDS file that contains all SNVs} -#' \item{keep} {a \code{logical} indicating if the genotype exists for the SNV} -#' \item{hetero} {a \code{logical} indicating if the SNV is heterozygote} -#' \item{homo} {a \code{logical} indicating if the SNV is homozygote} -#' \item{lap} {a \code{numeric} indicating lower allelic fraction} -#' \item{LOH} {a \code{integer} indicating if the SNV is in an LOH region +#' \item{keep}{ a \code{logical} indicating if the genotype exists for the SNV} +#' \item{hetero}{ a \code{logical} indicating if the SNV is heterozygote} +#' \item{homo}{ a \code{logical} indicating if the SNV is homozygote} +#' \item{lap}{ a \code{numeric} indicating lower allelic fraction} +#' \item{LOH}{ a \code{integer} indicating if the SNV is in an LOH region #' (0=not LOH, 1=in LOH)} #' } #' @@ -1193,10 +1193,10 @@ computeAllelicImbDNAChr <- function(snpPos, chr, wAR=10, cutOffEmptyBox=-3) { #' #' @param matCov a \code{data.frame} containing only heterozygote SNVs. The #' \code{data.frame} must contain those columns: -#' \itemize{ -#' \item{cnt.ref} {a single \code{integer} representing the coverage for +#' \describe{ +#' \item{cnt.ref}{ a single \code{integer} representing the coverage for #' the reference allele.} -#' \item{cnt.alt} {a single \code{integer} representing the coverage for +#' \item{cnt.alt}{ a single \code{integer} representing the coverage for #' the alternative allele.} #' } #' @@ -1210,16 +1210,16 @@ computeAllelicImbDNAChr <- function(snpPos, chr, wAR=10, cutOffEmptyBox=-3) { #' reference to see if there is a allelic fraction change. #' #' @return a \code{list} containing 4 entries: -#' \itemize{ +#' \describe{ #' \item{pWin}{ a \code{vector} of \code{numeric} representing the #' probability (x2) of obtaining the current #' alternative/(alternative+reference) ratio from a reference distribution #' specified by user.} -#' \item{p}{a \code{integer} indicating if all SNVs tested +#' \item{p}{ a \code{integer} indicating if all SNVs tested #' positive (1=TRUE, 0=FALSE). The cut-off is 0.5. } -#' \item{pCut}{a \code{integer} indicating if all SNVs tested +#' \item{pCut}{ a \code{integer} indicating if all SNVs tested #' positive (1=TRUE, 0-FALSE). } -#' \item{pCut1}{a \code{integer} indicating if the region tested +#' \item{pCut1}{ a \code{integer} indicating if the region tested #' positive (1=TRUE, 0=FALSE) for allelic ratio change.} #' } #' @@ -1289,10 +1289,10 @@ testAlleleFractionChange <- function(matCov, pCutOff=-3, vMean) { #' #' @param matCov a \code{data.frame} containing only heterozygote SNVs. The #' \code{data.frame} must contain those columns: -#' \itemize{ -#' \item{cnt.ref} {a single \code{integer} representing the coverage for +#' \describe{ +#' \item{cnt.ref}{ a single \code{integer} representing the coverage for #' the reference allele.} -#' \item{cnt.alt} {a single \code{integer} representing the coverage for +#' \item{cnt.alt}{ a single \code{integer} representing the coverage for #' the alternative allele.} #' } #' @@ -1301,7 +1301,7 @@ testAlleleFractionChange <- function(matCov, pCutOff=-3, vMean) { #' likelihood not to be imbalanced. Default: \code{-3}. #' #' @return a \code{list} containing 4 entries: -#' \itemize{ +#' \describe{ #' \item{pWin}{ a \code{vector} of \code{numeric} representing the #' probability (x2) of obtaining the current #' alternative/(alternative+reference) ratio from a 0.5 distribution.} @@ -1382,27 +1382,27 @@ testEmptyBox <- function(matCov, pCutOff=-3) { #' @param snpPosHetero a \code{data.frame} #' containing the SNV information for a specific block (gene if RNA-seq). #' The \code{data.frame} must contain those columns: -#' \itemize{ -#' \item{cnt.ref} {a single \code{integer} representing the coverage for +#' \describe{ +#' \item{cnt.ref}{ a single \code{integer} representing the coverage for #' the reference allele.} -#' \item{cnt.alt} {a single \code{integer} representing the coverage for +#' \item{cnt.alt}{ a single \code{integer} representing the coverage for #' the alternative allele.} -#' \item{phase} { a single \code{integer} indicating the phase of the variant +#' \item{phase}{ a single \code{integer} indicating the phase of the variant #' if known, \code{3} if not known} #' } #' #' @return a \code{list} for the block with the information #' relative to the heterozygotes. #' The \code{list} contains: -#' \itemize{ -#' \item{lR} { a single \code{numeric} representing the sum of the log of +#' \describe{ +#' \item{lR}{ a single \code{numeric} representing the sum of the log of #' read depth of the lowest depth divide by the total depth of the position #' minus of likelihood of the allelic fraction of 0.5.} -#' \item{aFraction} { a single \code{numeric} representing the allele +#' \item{aFraction}{ a single \code{numeric} representing the allele #' fraction estimation.} -#' \item{sumAlleleLow} { a \code{integer} representing the +#' \item{sumAlleleLow}{ a \code{integer} representing the #' sum of the allele read depth of the lowest read allele depth} -#' \item{sumAlleleHigh} { a \code{integer} representing the +#' \item{sumAlleleHigh}{ a \code{integer} representing the #' sum of the allele read depth #' of the highest read allele depth} #' } @@ -1491,32 +1491,32 @@ calcAFMLRNA <- function(snpPosHetero) { #' @return a \code{data.frame} containing only heterozygote #' SNV information. The #' \code{data.frame} contain those columns: -#' \itemize{ -#' \item{block} {a single \code{integer} representing the unique identifier +#' \describe{ +#' \item{block}{ a single \code{integer} representing the unique identifier #' of the block.} -#' \item{aRF} {a single \code{numeric} representing the final allelic +#' \item{aRF}{ a single \code{numeric} representing the final allelic #' fraction; not computed yet, \code{-1} value assigned to all entries.} -#' \item{aFraction} {a single \code{integer} representing the possible allelic +#' \item{aFraction}{a single \code{integer} representing the possible allelic #' fraction in absence of loss of heterozygosity (LOH).} -#' \item{lR} {a single \code{integer} representing the coverage for +#' \item{lR}{ a single \code{integer} representing the coverage for #' the alternative allele.} -#' \item{nPhase} {a single \code{integer} representing the number of SNV +#' \item{nPhase}{ a single \code{integer} representing the number of SNV #' phases.} -#' \item{sumAlleleLow} {a single \code{integer} representing the sum of the +#' \item{sumAlleleLow}{ a single \code{integer} representing the sum of the #' alleles with the less coverage.} -#' \item{sumAlleleHigh} {a single \code{integer} representing the sum of +#' \item{sumAlleleHigh}{ a single \code{integer} representing the sum of #' the alleles with more coverage.} -#' \item{lH} {a single \code{numeric} for the homozygotes log10 of the product +#' \item{lH}{ a single \code{numeric} for the homozygotes log10 of the product #' frequencies of the allele not found in the profile (not a probability).} -#' \item{lM} {a single \code{numeric} log10 product frequency allele +#' \item{lM}{ a single \code{numeric} log10 product frequency allele #' in population.} -#' \item{lRhomo} {a single \code{numeric} representing the score +#' \item{lRhomo}{a single \code{numeric} representing the score #' \code{lH} - \code{lM}.} -#' \item{nbHomo} {a single \code{integer} representing the number of +#' \item{nbHomo}{ a single \code{integer} representing the number of #' homozygote SNVs per block.} -#' \item{nbKeep} {a single \code{integer} representing the number of +#' \item{nbKeep}{ a single \code{integer} representing the number of #' SNVs retained per block.} -#' \item{nbHetero} {a single \code{integer} representing the number of +#' \item{nbHetero}{ a single \code{integer} representing the number of #' heterozygote SNVs per block.} #' } #' diff --git a/R/gdsWrapper.R b/R/gdsWrapper.R index 6ad0b053c..16ce32cc1 100644 --- a/R/gdsWrapper.R +++ b/R/gdsWrapper.R @@ -235,7 +235,7 @@ generateGDSgenotype <- function(gds, pathGeno, fileSNPsRDS, listSamples, #' name of the RDS file that contains the indexes of the retained SNPs. The #' file must exist. The file must be a RDS file. #' -#' @param listSamples a \code{character} string representing the path and file +#' @param listSample a \code{character} string representing the path and file #' name of the RDS file that contains the indexes of the retained SNPs. The #' file must exist. The file must be a RDS file. #' diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 4b2803d21..6c94fcc84 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -745,7 +745,7 @@ addStudyGDSSample <- function(gdsProfile, pedProfile, batch, listSamples, #' the process in the \code{\link[SNPRelate]{snpgdsIBDKING}}() function. #' #' @return a \code{list} containing: -#' \itemize{ +#' \describe{ #' \item{sample.id}{a \code{character} string representing the sample #' ids used in the analysis} #' \item{snp.id}{a \code{character} string representing the SNP ids @@ -1279,7 +1279,7 @@ addUpdateSegment <- function(gdsProfile, snpSeg) { #' @param gds an object of class #' \link[gdsfmt]{gds.class} (a GDS file), the opened GDS file. #' -#' @param listSample a \code{vector} of \code{character} string representing +#' @param listSamples a \code{vector} of \code{character} string representing #' the sample identifiers to be added to GDS file. #' #' diff --git a/R/process1KG.R b/R/process1KG.R index a9595cfe6..7d653b43e 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -25,16 +25,16 @@ #' #' @return a \code{data.frame} containing the needed pedigree information #' from Reference. The \code{data.frame} contains those columns: -#' \itemize{ -#' \item{sample.id}{a \code{character} string representing the profile unique +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the profile unique #' ID.} -#' \item{Name.ID}{a \code{character} string representing the profile name.} +#' \item{Name.ID}{ a \code{character} string representing the profile name.} #' \item{sex}{a \code{character} string representing the sex of the profile.} -#' \item{pop.group}{a \code{character} string representing the +#' \item{pop.group}{ a \code{character} string representing the #' sub-continental ancestry of the profile.} -#' \item{superPop }{a \code{character} string representing the continental +#' \item{superPop }{ a \code{character} string representing the continental #' ancestry of the profile.} -#' \item{superPop }{a \code{integer} representing the batch of the profile.} +#' \item{superPop }{ a \code{integer} representing the batch of the profile.} #' } #' #' @examples @@ -138,22 +138,22 @@ prepPed1KG <- function(filePed, pathGeno=file.path("data", "sampleGeno"), #' #' The filtered SNP information RDS file (parameter \code{fileFREQ}), contains #' a \code{data.frame} with those columns: -#' \itemize{ -#' \item{CHROM} {a \code{character} string representing the chromosome where +#' \describe{ +#' \item{CHROM}{ a \code{character} string representing the chromosome where #' the SNV is located.} -#' \item{POS} {a \code{character} string representing the SNV position on the +#' \item{POS}{ a \code{character} string representing the SNV position on the #' chromosome.} -#' \item{REF} {a \code{character} string representing the reference DNA base +#' \item{REF}{ a \code{character} string representing the reference DNA base #' for the SNV.} -#' \item{ALT} {a \code{character} string representing the alternative DNA base +#' \item{ALT}{ a \code{character} string representing the alternative DNA base #' for the SNV.}\ -#' \item{EAS_AF} {a \code{character} string representing the allele frequency +#' \item{EAS_AF}{ a \code{character} string representing the allele frequency #' of the EAS super population.} -#' \item{AFR_AF} {a \code{character} string representing the allele frequency +#' \item{AFR_AF}{ a \code{character} string representing the allele frequency #' of the AFR super population.} -#' \item{AMR_AF} {a \code{character} string representing the allele frequency +#' \item{AMR_AF}{ a \code{character} string representing the allele frequency #' of the AMR super population.} -#' \item{SAS_AF} {a \code{character} string representing the allele frequency +#' \item{SAS_AF}{ a \code{character} string representing the allele frequency #' of the SAS super population.} #' } #' diff --git a/R/process1KG_internal.R b/R/process1KG_internal.R index 597cf365b..95280a027 100644 --- a/R/process1KG_internal.R +++ b/R/process1KG_internal.R @@ -149,18 +149,18 @@ pruning1KGbyChr <- function(gdsReference, method="corr", listSamples=NULL, #' annotation. By default, the \code{EnsDb.Hsapiens.v86} class has been used. #' #' @return a \code{data.frame} with those columns: -#' \itemize{ -#' \item{chr} {a single \code{integer} representing the SNV chromosome.} -#' \item{pos} {a single \code{integer} representing the SNV position.} -#' \item{snp.allele} {a \code{character} string representing the reference allele +#' \describe{ +#' \item{chr}{ a single \code{integer} representing the SNV chromosome.} +#' \item{pos}{ a single \code{integer} representing the SNV position.} +#' \item{snp.allele}{ a \code{character} string representing the reference allele #' and alternative allele for each of the SNV} -#' \item{Exon} {a \code{character} with the ensembl GeneId(s) if the SNV is in +#' \item{Exon}{ a \code{character} with the ensembl GeneId(s) if the SNV is in #' one exon. If more than one GeneId they are separted by ':'} -#' \item{GName} {a \code{character} with the ensembl GeneId(s) if the SNV is in +#' \item{GName}{ a \code{character} with the ensembl GeneId(s) if the SNV is in #' the gene. If more than one GeneId they are separted by ':'} -#' \item{Gene} {A single \code{integer} specific to the SNVs that share +#' \item{Gene}{ a single \code{integer} specific to the SNVs that share #' at least one genes} -#' \item{GeneS} {A single \code{integer} specific to the SNVs that share +#' \item{GeneS}{ a single \code{integer} specific to the SNVs that share #' a unique combination of genes} #' } #' "chr", "pos", "snp.allele", "Exon", "GName", "Gene", "GeneS" diff --git a/R/processStudy.R b/R/processStudy.R index 0d31f9025..ed7fdfb1e 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -767,13 +767,13 @@ addStudy1Kg <- function(gdsReference, fileProfileGDS, verbose=FALSE) { #' to show how the different steps in the function. Default: \code{FALSE}. #' #' @return a \code{list} containing 3 entries: -#' \itemize{ -#' \item{sample.id} { a \code{vector} of \code{character} strings representing +#' \describe{ +#' \item{sample.id}{ a \code{vector} of \code{character} strings representing #' the identifiers of the synthetic profiles that have been projected onto #' the 1KG PCA. } -#' \item{eigenvector.ref} { a \code{matrix} of \code{numeric} with the +#' \item{eigenvector.ref}{ a \code{matrix} of \code{numeric} with the #' eigenvectors of the 1KG reference profiles used to generate the PCA.} -#' \item{eigenvector} { a \code{matrix} of \code{numeric} with the +#' \item{eigenvector}{ a \code{matrix} of \code{numeric} with the #' eigenvectors of the synthetic profiles projected onto the 1KG PCA. } #' } #' @@ -904,12 +904,12 @@ computePCAMultiSynthetic <- function(gdsProfile, listPCA, #' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. #' #' @return a \code{list} containing 3 entries: -#' \itemize{ -#' \item{\code{sample.id}} { a \code{character} string representing the unique +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique #' identifier of the analyzed profile.} -#' \item{\code{eigenvector.ref}} { a \code{matrix} of \code{numeric} +#' \item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} #' representing the eigenvectors of the reference profiles. } -#' \item{\code{eigenvector}} { a \code{matrix} of \code{numeric} representing +#' \item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} representing #' the eigenvectors of the analyzed profile. } #' } #' @@ -1040,28 +1040,28 @@ computePCARefSample <- function(gdsProfile, currentProfile, #' Default: \code{seq(2, 15, 1)}. #' #' @return a \code{list} containing 4 entries: -#' \itemize{ -#' \item{\code{sample.id}} {a \code{vector} of \code{character} strings +#' \describe{ +#' \item{\code{sample.id}}{ a \code{vector} of \code{character} strings #' representing the identifiers of the synthetic profiles analysed.} -#' \item{\code{sample1Kg}} {a \code{vector} of \code{character} strings +#' \item{\code{sample1Kg}}{ a \code{vector} of \code{character} strings #' representing the identifiers of the 1KG reference profiles used to #' generate the synthetic profiles.} -#' \item{\code{sp}} {a \code{vector} of \code{character} strings representing +#' \item{\code{sp}}{ a \code{vector} of \code{character} strings representing #' the known super population ancestry of the 1KG reference profiles used #' to generate the synthetic profiles.} -#' \item{\code{matKNN}} {a \code{data.frame} containing the super population +#' \item{\code{matKNN}}{ a \code{data.frame} containing the super population #' inference for each synthetic profiles for different values of PCA #' dimensions \code{D} and k-neighbors values \code{K}. The fourth column title #' corresponds to the \code{fieldPopInfAnc} parameter. #' The \code{data.frame} contains 4 columns: -#' \itemize{ -#' \item{\code{sample.id}} {a \code{character} string representing +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing #' the identifier of the synthetic profile analysed.} -#' \item{\code{D}} {a \code{numeric} strings representing +#' \item{\code{D}}{ a \code{numeric} strings representing #' the value of the PCA dimension used to infer the super population.} -#' \item{\code{K}} {a \code{numeric} strings representing +#' \item{\code{K}}{ a \code{numeric} strings representing #' the value of the k-neighbors used to infer the super population.} -#' \item{\code{fieldPopInfAnc} value} {a \code{character} string representing +#' \item{\code{fieldPopInfAnc} value}{ a \code{character} string representing #' the inferred ancestry.} #' } #' } @@ -1216,22 +1216,22 @@ computeKNNRefSynthetic <- function(gdsProfile, listEigenvector, #' Default: \code{seq(2, 15, 1)}. #' #' @return a \code{list} containing 4 entries: -#' \itemize{ -#' \item{\code{sample.id}} { a \code{vector} of \code{character} strings +#' \describe{ +#' \item{\code{sample.id}}{ a \code{vector} of \code{character} strings #' representing the identifier of the profile analysed.} -#' \item{\code{matKNN}} { a \code{data.frame} containing the super population +#' \item{\code{matKNN}}{ a \code{data.frame} containing the super population #' inference for the profile for different values of PCA #' dimensions \code{D} and k-neighbors values \code{K}. The fourth column title #' corresponds to the \code{fieldPopInfAnc} parameter. #' The \code{data.frame} contains 4 columns: -#' \itemize{ -#' \item{\code{sample.id}} {a \code{character} string representing +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing #' the identifier of the profile analysed.} -#' \item{\code{D}} { a \code{numeric} strings representing +#' \item{\code{D}}{ a \code{numeric} strings representing #' the value of the PCA dimension used to infer the ancestry.} -#' \item{\code{K}} { a \code{numeric} strings representing +#' \item{\code{K}}{ a \code{numeric} strings representing #' the value of the k-neighbors used to infer the ancestry..} -#' \item{\code{fieldPopInfAnc}} { a \code{character} string representing +#' \item{\code{fieldPopInfAnc}}{ a \code{character} string representing #' the inferred ancestry.} #' } #' } @@ -1395,16 +1395,16 @@ computeKNNRefSample <- function(listEigenvector, #' printed. Default: \code{FALSE}. #' #' @return a \code{list} containing the following entries: -#' \itemize{ -#' \item{sample.id}{a \code{vector} of \code{character} strings representing +#' \describe{ +#' \item{sample.id}{ a \code{vector} of \code{character} strings representing #' the identifiers of the synthetic profiles. } -#' \item{sample1Kg}{a \code{vector} of \code{character} strings representing +#' \item{sample1Kg}{ a \code{vector} of \code{character} strings representing #' the identifiers of the reference 1KG profiles used to generate the #' synthetic profiles. } -#' \item{sp}{a \code{vector} of \code{character} strings representing the +#' \item{sp}{ a \code{vector} of \code{character} strings representing the #' known ancestry for the reference 1KG profiles used to generate the #' synthetic profiles. } -#' \item{matKNN}{a \code{data.frame} containing 4 columns. The first column +#' \item{matKNN}{ a \code{data.frame} containing 4 columns. The first column #' 'sample.id' contains the name of the synthetic profile. The second column #' 'D' represents the dimension D used to infer the ancestry. The third column #' 'K' represents the number of neighbors K used to infer the ancestry. The @@ -1591,10 +1591,10 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, #' to show how the different steps in the function. Default: \code{FALSE}. #' #' @return a \code{list} containing 4 entries: -#' \itemize{ +#' \describe{ #' \item{\code{pcaSample}}{ a \code{list} containing the information related #' to the eigenvectors. The \code{list} contains those 3 entries: -#' \itemize{ +#' \describe{ #' \item{\code{sample.id}}{ a \code{character} string representing the unique #' identifier of the current profile.} #' \item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing @@ -1604,15 +1604,14 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, #' reference profiles.} #' } #' } -#' #' \item{\code{paraSample}}{ a \code{list} containing the results with #' different \code{D} and \code{K} values that lead to optimal parameter #' selection. The \code{list} contains those entries: -#' \itemize{ +#' \describe{ #' \item{\code{dfPCA}}{ a \code{data.frame} containing statistical results #' on all combined synthetic results done with a fixed value of \code{D} (the #' number of dimensions). The \code{data.frame} contains those columns: -#' \itemize{ +#' \describe{ #' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the #' number of dimensions).} #' \item{\code{median}}{ a \code{numeric} representing the median of the @@ -1632,7 +1631,7 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, #' all combined synthetic results done with different values of \code{D} (the #' number of dimensions) and \code{K} (the number of neighbors). #' The \code{data.frame} contains those columns: -#' \itemize{ +#' \describe{ #' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the #' number of dimensions).} #' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the @@ -1651,7 +1650,7 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, #' \item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by #' super-population. The \code{data.frame} contains #' those columns: -#' \itemize{ +#' \describe{ #' \item{\code{pcaD}}{ a \code{numeric} representing the value of \code{D} (the #' number of dimensions).} #' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the @@ -1677,17 +1676,16 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, #' \code{D} is possible.} #' } #' } -#' #' \item{\code{KNNSample}}{ a \code{list} containing the inferred ancestry #' using different \code{D} and \code{K} values. The \code{list} contains #' those entries: -#' \itemize{ +#' \describe{ #' \item{\code{sample.id}}{ a \code{character} string representing the unique #' identifier of the current profile.} #' \item{\code{matKNN}}{ a \code{data.frame} containing the inferred ancestry #' for different values of \code{K} and \code{D}. The \code{data.frame} #' contains those columns: -#' \itemize{ +#' \describe{ #' \item{\code{sample.id}}{ a \code{character} string representing the unique #' identifier of the current profile.} #' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the @@ -1700,11 +1698,10 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, #' } #' } #' } -#' #' \item{\code{Ancestry}}{ a \code{data.frame} containing the inferred #' ancestry for the current profile. The \code{data.frame} contains those #' columns: -#' \itemize{ +#' \describe{ #' \item{\code{sample.id}}{ a \code{character} string representing the unique #' identifier of the current profile.} #' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the @@ -1908,12 +1905,12 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' @param syntheticRefDF a \code{data.frame} containing a subset of #' reference profiles for each sub-population present in the Reference GDS #' file. The \code{data.frame} must have those columns: -#' \itemize{ -#' \item{sample.id} { a \code{character} string representing the sample +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample #' identifier. } -#' \item{pop.group} { a \code{character} string representing the +#' \item{pop.group}{ a \code{character} string representing the #' subcontinental population assigned to the sample. } -#' \item{superPop} { a \code{character} string representing the +#' \item{superPop}{ a \code{character} string representing the #' super-population assigned to the sample. } #' } #' @@ -1941,12 +1938,12 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, #' #' The runExomeAncestry() function generates 3 types of files #' in the OUTPUT directory. -#' \itemize{ -#' \item{Ancestry Inference}{The ancestry inference CSV file +#' \describe{ +#' \item{Ancestry Inference}{ The ancestry inference CSV file #' (".Ancestry.csv" file)} -#' \item{Inference Informaton}{The inference information RDS file +#' \item{Inference Informaton}{ The inference information RDS file #' (".infoCall.rds" file)} -#' \item{Synthetic Information}{The parameter information RDS files +#' \item{Synthetic Information}{ The parameter information RDS files #' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} #' } #' @@ -2121,12 +2118,12 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @param syntheticRefDF a \code{data.frame} containing a subset of #' reference profiles for each sub-population present in the Reference GDS #' file. The \code{data.frame} must have those columns: -#' \itemize{ -#' \item{sample.id} { a \code{character} string representing the sample +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample #' identifier. } -#' \item{pop.group} { a \code{character} string representing the +#' \item{pop.group}{ a \code{character} string representing the #' subcontinental population assigned to the sample. } -#' \item{superPop} { a \code{character} string representing the +#' \item{superPop}{ a \code{character} string representing the #' super-population assigned to the sample. } #' } #' @@ -2158,12 +2155,12 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' #' The runExomeAncestry() function generates 3 types of files #' in the OUTPUT directory. -#' \itemize{ -#' \item{Ancestry Inference}{The ancestry inference CSV file +#' \describe{ +#' \item{Ancestry Inference}{ The ancestry inference CSV file #' (".Ancestry.csv" file)} -#' \item{Inference Informaton}{The inference information RDS file +#' \item{Inference Informaton}{ The inference information RDS file #' (".infoCall.rds" file)} -#' \item{Synthetic Information}{The parameter information RDS files +#' \item{Synthetic Information}{ The parameter information RDS files #' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} #' } #' diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 4b237e7b1..0a28d5c66 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -978,12 +978,12 @@ validateAdd1KG2SampleGDS <- function(gdsReference, gdsProfileFile, #' representing the length of the chromosomes. See 'details' section. #' #' @param syntheticRefDF a \code{data.frame} containing those columns: -#' \itemize{ -#' \item{sample.id} { a \code{character} string representing the sample +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample #' identifier. } -#' \item{pop.group} { a \code{character} string representing the +#' \item{pop.group}{ a \code{character} string representing the #' subcontinental population assigned to the sample. } -#' \item{superPop} { a \code{character} string representing the +#' \item{superPop}{ a \code{character} string representing the #' super-population assigned to the sample. } #' } #' @@ -1292,7 +1292,7 @@ validateAddStudy1Kg <- function(gdsReference, fileProfileGDS, verbose) { #' @param pathProfile a \code{character} string representing the directory #' where the Profile GDS files will be created. The directory must exist. #' -#' @param currentProfile a \code{character} string +#' @param profile a \code{character} string #' corresponding to the profile identifier. A Profile GDS file #' corresponding to the profile identifier must exist and be located in the #' \code{pathProfile} directory. @@ -1666,7 +1666,7 @@ validateComputeKNNRefSample <- function(listEigenvector, listCatPop, spRef, #' printed. #' #' @return a \code{list} containing 2 entries: -#' \itemize{ +#' \describe{ #' \item{pruned}{ a \code{vector} of SNV identifiers specifying selected SNVs #' for the PCA analysis.} #' \item{pca.unrel}{ a \code{snpgdsPCAClass} object containing the eigenvalues @@ -1790,11 +1790,11 @@ computePCARefRMMulti <- function(gdsProfile, refProfileIDs, listRM, np=1L, #' Default: \code{seq(2,15,1)}. #' #' @return a \code{list} containing 5 entries: -#' \itemize{ -#' \item{\code{dfPCA}} { a \code{data.frame} containing statistical results +#' \describe{ +#' \item{\code{dfPCA}}{ a \code{data.frame} containing statistical results #' on all combined synthetic results done with a fixed value of \code{D} (the #' number of dimensions). The \code{data.frame} contains those columns: -#' \itemize{ +#' \describe{ #' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the #' number of dimensions).} #' \item{\code{median}}{ a \code{numeric} representing the median of the @@ -1810,11 +1810,11 @@ computePCARefRMMulti <- function(gdsProfile, refProfileIDs, listRM, np=1L, #' (the number of neighbors) for a fixed \code{D} value. } #' } #' } -#' \item{\code{dfPop}} { a \code{data.frame} containing statistical results on +#' \item{\code{dfPop}}{ a \code{data.frame} containing statistical results on #' all combined synthetic results done with different values of \code{D} (the #' number of dimensions) and \code{K} (the number of neighbors). #' The \code{data.frame} contains those columns: -#' \itemize{ +#' \describe{ #' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the #' number of dimensions).} #' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the @@ -1830,11 +1830,11 @@ computePCARefRMMulti <- function(gdsProfile, refProfileIDs, listRM, np=1L, #' the specified values of \code{D} and \code{K}.} #' } #' } -#' \item{\code{D}} { a \code{numeric} representing the optimal \code{D} value +#' \item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value #' (the number of dimensions) for the specific profile.} -#' \item{\code{K}} { a \code{numeric} representing the optimal \code{K} value +#' \item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value #' (the number of neighbors) for the specific profile.} -#' \item{\code{listD}} { a \code{numeric} representing the optimal \code{D} +#' \item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} #' values (the number of dimensions) for the specific profile. More than one #' \code{D} is possible.} #' } @@ -1966,12 +1966,12 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' @param syntheticRefDF a \code{data.frame} containing a subset of #' reference profiles for each sub-population present in the Reference GDS #' file. The \code{data.frame} must have those columns: -#' \itemize{ -#' \item{sample.id} { a \code{character} string representing the sample +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample #' identifier. } -#' \item{pop.group} { a \code{character} string representing the +#' \item{pop.group}{ a \code{character} string representing the #' subcontinental population assigned to the sample. } -#' \item{superPop} { a \code{character} string representing the +#' \item{superPop}{ a \code{character} string representing the #' super-population assigned to the sample. } #' } #' @@ -2006,12 +2006,12 @@ selParaPCAUpQuartile <- function(matKNN, pedCall, refCall, #' #' The runWrapperAncestry() function generates 3 types of files #' in the \code{pathOut} directory: -#' \itemize{ -#' \item{Ancestry Inference}{The ancestry inference CSV file +#' \describe{ +#' \item{Ancestry Inference}{ The ancestry inference CSV file #' (".Ancestry.csv" file)} -#' \item{Inference Informaton}{The inference information RDS file +#' \item{Inference Informaton}{ The inference information RDS file #' (".infoCall.rds" file)} -#' \item{Synthetic Information}{The parameter information RDS files +#' \item{Synthetic Information}{ The parameter information RDS files #' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} #' } #' @@ -2275,12 +2275,12 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' @param syntheticRefDF a \code{data.frame} containing a subset of #' reference profiles for each sub-population present in the Reference GDS #' file. The \code{data.frame} must have those columns: -#' \itemize{ -#' \item{sample.id} { a \code{character} string representing the sample +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample #' identifier. } -#' \item{pop.group} { a \code{character} string representing the +#' \item{pop.group}{ a \code{character} string representing the #' subcontinental population assigned to the sample. } -#' \item{superPop} { a \code{character} string representing the +#' \item{superPop}{ a \code{character} string representing the #' super-population assigned to the sample. } #' } #' @@ -2316,12 +2316,12 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' #' The runWrapperAncestry() function generates 3 types of files #' in the \code{pathOut} directory. -#' \itemize{ -#' \item{Ancestry Inference}{The ancestry inference CSV file +#' \describe{ +#' \item{Ancestry Inference}{ The ancestry inference CSV file #' (".Ancestry.csv" file)} -#' \item{Inference Informaton}{The inference information RDS file +#' \item{Inference Informaton}{ The inference information RDS file #' (".infoCall.rds" file)} -#' \item{Synthetic Information}{The parameter information RDS files +#' \item{Synthetic Information}{ The parameter information RDS files #' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} #' } #' @@ -2424,7 +2424,8 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' @keywords internal runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, genoSource=c("snp-pileup", "generic", "VCF"), + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic", "VCF"), studyType=c("DNA", "RNA"), np=1L, blockTypeID=NULL, verbose=FALSE) { diff --git a/R/synthetic.R b/R/synthetic.R index 53a942fb8..a3e75062b 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -17,12 +17,12 @@ #' subcontinental population will correspond to the size of this population. #' #' @return a \code{data.frame} containing those columns: -#' \itemize{ -#' \item{sample.id} { a \code{character} string representing the sample +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample #' identifier. } -#' \item{pop.group} { a \code{character} string representing the +#' \item{pop.group}{ a \code{character} string representing the #' subcontinental population assigned to the sample. } -#' \item{superPop} { a \code{character} string representing the +#' \item{superPop}{ a \code{character} string representing the #' super-population assigned to the sample. } #' } #' @@ -103,12 +103,12 @@ select1KGPop <- function(gdsReference, nbProfiles) { #' population. #' #' @param dataRef a \code{data.frame} containing those columns: -#' \itemize{ -#' \item{sample.id} { a \code{character} string representing the sample +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample #' identifier. } -#' \item{pop.group} { a \code{character} string representing the +#' \item{pop.group}{ a \code{character} string representing the #' subcontinental population assigned to the sample. } -#' \item{superPop} { a \code{character} string representing the +#' \item{superPop}{ a \code{character} string representing the #' super-population assigned to the sample. } #' } #' @@ -727,7 +727,7 @@ syntheticGeno <- function(gdsReference, gdsRefAnnot, fileProfileGDS, profileID, #' Default: \code{c("EAS", "EUR", "AFR", "AMR", "SAS")}. #' #' @return \code{list} containing 3 entries: -#' \itemize{ +#' \describe{ #' \item{\code{matAUROC.All}}{ a \code{data.frame} containing the AUROC for all #' the ancestry results. } #' \item{\code{matAUROC.Call}}{ a \code{data.frame} containing the AUROC diff --git a/R/synthetic_internal.R b/R/synthetic_internal.R index 56e7e2aa9..d3ec33232 100644 --- a/R/synthetic_internal.R +++ b/R/synthetic_internal.R @@ -476,9 +476,9 @@ prepPedSynthetic1KG <- function(gdsReference, gdsSample, studyID, popName) { #' the list of possible ancestry assignations. #' #' @return \code{list} containing 2 entries: -#' \itemize{ -#' \item{confMat} { a \code{matrix} representing the confusion matrix } -#' \item{matAccuracy} { a \code{data.frame} containing the statistics +#' \describe{ +#' \item{confMat}{ a \code{matrix} representing the confusion matrix } +#' \item{matAccuracy}{ a \code{data.frame} containing the statistics #' associated to the confusion matrix} #' } #' diff --git a/R/tools_internal.R b/R/tools_internal.R index cad972cc2..b75cdbf45 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -196,7 +196,7 @@ validatePositiveIntegerVector <- function(value, name) { #' is added to the position present in the file. Default: \code{0L}. #' #' @return the a \code{data.frame} containing at least: -#' \itemize{ +#' \describe{ #' \item{Chromosome}{ a \code{numeric} representing the name of #' the chromosome} #' \item{Position}{ a \code{numeric} representing the position on the @@ -204,15 +204,15 @@ validatePositiveIntegerVector <- function(value, name) { #' \item{Ref}{ a \code{character} string representing the reference nucleotide} #' \item{Alt}{ a \code{character} string representing the alternative #' nucleotide} -#' \item{File1R} { a \code{numeric} representing the count for +#' \item{File1R}{ a \code{numeric} representing the count for #' the reference nucleotide} -#' \item{File1A} { a \code{numeric} representing the count for the +#' \item{File1A}{ a \code{numeric} representing the count for the #' alternative nucleotide} -#' \item{File1E} {a \code{numeric} representing the count for the +#' \item{File1E}{a \code{numeric} representing the count for the #' errors} -#' \item{File1D} {a \code{numeric} representing the count for the +#' \item{File1D}{a \code{numeric} representing the count for the #' deletions} -#' \item{count} { a \code{numeric} representing the total count} +#' \item{count}{ a \code{numeric} representing the total count} #' } #' #' @examples @@ -270,7 +270,7 @@ readSNVPileupFile <- function(fileName, offset = 0L) { #' is added to the position present in the file. Default: \code{0L}. #' #' @return a \code{data.frame} containing at least: -#' \itemize{ +#' \describe{ #' \item{Chromosome}{ a \code{numeric} representing the name of #' the chromosome} #' \item{Position}{ a \code{numeric} representing the position on the @@ -278,11 +278,11 @@ readSNVPileupFile <- function(fileName, offset = 0L) { #' \item{Ref}{ a \code{character} string representing the reference nucleotide} #' \item{Alt}{ a \code{character} string representing the alternative #' nucleotide} -#' \item{File1R} { a \code{numeric} representing the count for +#' \item{File1R}{ a \code{numeric} representing the count for #' the reference nucleotide} -#' \item{File1A} { a \code{numeric} representing the count for the +#' \item{File1A}{ a \code{numeric} representing the count for the #' alternative nucleotide} -#' \item{count} { a \code{numeric} representing the total count} +#' \item{count}{ a \code{numeric} representing the total count} #' } #' #' @examples @@ -340,7 +340,7 @@ readSNVFileGeneric <- function(fileName, offset = 0L) { #' is added to the position present in the file. Default: \code{0L}. #' #' @return a \code{data.frame} containing at least: -#' \itemize{ +#' \describe{ #' \item{Chromosome}{ a \code{numeric} representing the name of #' the chromosome} #' \item{Position}{ a \code{numeric} representing the position on the @@ -348,11 +348,11 @@ readSNVFileGeneric <- function(fileName, offset = 0L) { #' \item{Ref}{ a \code{character} string representing the reference nucleotide} #' \item{Alt}{ a \code{character} string representing the alternative #' nucleotide} -#' \item{File1R} { a \code{numeric} representing the count for +#' \item{File1R}{ a \code{numeric} representing the count for #' the reference nucleotide} -#' \item{File1A} { a \code{numeric} representing the count for the +#' \item{File1A}{ a \code{numeric} representing the count for the #' alternative nucleotide} -#' \item{count} { a \code{numeric} representing the total count} +#' \item{count}{ a \code{numeric} representing the total count} #' } #' #' @examples diff --git a/R/visualization.R b/R/visualization.R new file mode 100644 index 000000000..44666197b --- /dev/null +++ b/R/visualization.R @@ -0,0 +1,105 @@ +#' @title Generate accuracy graph +#' +#' @description This function extracts the required information from an +#' output generated by RAIDS to create a graphic representation of the +#' accuracy for different values of PCA dimensions and K-neighbors through +#' all tested ancestries. +#' +#' @param fileRDS a \code{character} string representing the path and file +#' name of the RDS file containing the ancestry information as generated by +#' RAIDS. +#' +#' @param title a \code{character} string representing the title of the graph. +#' Default: \code{""}. +#' +#' @param selectD a \code{array} of \code{integer} representing the selected +#' PCA dimensions to plot. The length of the \code{array} cannot be more than +#' 5 entries. The dimensions must tested by RAIDS (i.e. be present in the +#' RDS file). Default: \code{c(3,7,11)}. +#' +#' @param selectColor a \code{array} of \code{character} strings representing +#' the selected colors for the associated PCA dimensions to plot. The length +#' of the \code{array} must correspond to the length of the \code{selectD} +#' parameter. In addition, the length of the \code{array} cannot be more than +#' 5 entries. +#' Default: \code{c("#5e688a", "#cd5700", "#CC79A7")}. +#' +#' @return a \code{ggplot} object containing the graphic representation of the +#' accuracy for different values of PCA dimensions and K-neighbors through +#' all tested ancestries. +#' +#' @examples +#' +#' ## Required library +#' library(ggplot2) +#' +#' ## Path to RDS file with ancestry information generated by RAIDS (demo file) +#' dataDir <- system.file("extdata", package="RAIDS") +#' fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") +#' +#' ## Create accuracy graph +#' accuracyGraph <- createAccuracyGraph(fileRDS=fileRDS, title="Test 01", +#' selectD=c(3,6,9,12,15), +#' selectColor=c("steelblue", "darkorange", "violet", "pink", "gray80")) +#' +#' accuracyGraph +#' +#' @author Astrid Deschênes and Pascal Belleau +#' @importFrom ggplot2 ggplot geom_ribbon geom_line theme_classic ylim +#' @importFrom ggplot2 ylab facet_grid theme scale_colour_manual ggtitle +#' @importFrom ggplot2 element_text element_rect aes +#' @importFrom rlang .data +#' @encoding UTF-8 +#' @export +createAccuracyGraph <- function(fileRDS, title="", + selectD=c(3,7,11), selectColor=c("#5e688a", "#cd5700", "#CC79A7")) { + + ## Validate parameters + validateCreateAccuracyGraph(fileRDS=fileRDS, title=title, selectD=selectD, + selectColor=selectColor) + + ## Extract required information from RDS file + info <- readRDS(fileRDS) + dfAUROC <- info$paraSample$dfAUROC + + if (!all(selectD %in% unique(dfAUROC$pcaD))) { + stop("Not all values in \'selectD\' are present in the RDS file.") + } + + ## Retained selected dimensions + dfAUROC <- dfAUROC[which(dfAUROC$pcaD %in% selectD), ] + dfAUROC$pcaD <- as.factor(dfAUROC$pcaD) + + colnames(dfAUROC)[colnames(dfAUROC) == "pcaD"] <- "D" + + ## Set y axis minimum value + ymin <- min(c(dfAUROC$L)) - 0.008 + + ## Generate graph + accuracy <- ggplot(dfAUROC, aes(x=.data$K, y=.data$AUC, group=.data$D, + color=.data$D, linetype=.data$D)) + + ylab(label = "AUROC") + + geom_ribbon(aes(ymin=.data$L, ymax=.data$H, group=.data$D), + linetype="dotted", cex=2, alpha=0.1) + + geom_line(cex=2) + facet_grid(. ~ Call) + + ylim(c(ymin, 1)) + ggtitle(title) + + scale_colour_manual(aesthetics = c("colour", "fill"), + breaks=selectD, values=selectColor) + + theme_classic() + + theme(axis.text=element_text(size=1, colour = "white"), + panel.background = element_rect(color="black"), + axis.text.x=element_text(size=30, angle=90, + vjust = 0.5, hjust=1, colour="black"), + plot.title = element_text(size=22, face="bold", + colour="gray20", hjust=0.5), + axis.title.x=element_text(size=30,face="bold.italic"), + axis.title.y=element_text(size=30,face="bold.italic"), + strip.text.x = element_text(size=20, face="bold"), + strip.text.y = element_text(size=20, face="bold"), + strip.background = element_rect(fill="gray90"), + legend.text=element_text(size=19), + legend.title=element_text(size=22, face="bold.italic")) + + ## Successful + return(accuracy) +} \ No newline at end of file diff --git a/R/visualization_internal.R b/R/visualization_internal.R new file mode 100644 index 000000000..598c935f7 --- /dev/null +++ b/R/visualization_internal.R @@ -0,0 +1,80 @@ +#' @title Validate input parameters for createAccuracyGraph +#' function +#' +#' @description This function validates the parameters for the +#' \code{\link{createAccuracyGraph}} function. +#' +#' @param fileRDS a \code{character} string representing the path and file +#' name of the RDS file containing the ancestry information as generated by +#' RAIDS. +#' +#' @param title a \code{character} string representing the title of the graph. +#' +#' @param selectD a \code{array} of \code{integer} representing the selected +#' PCA dimensions to plot. The length of the \code{array} cannot be more than +#' 5 entries. The dimensions must tested by RAIDS (i.e. be present in the +#' RDS file). +#' +#' @param selectColor a \code{array} of \code{character} strings representing +#' the selected colors for the associated PCA dimensions to plot. The length +#' of the \code{array} must correspond to the length of the \code{selectD} +#' parameter. In addition, the length of the \code{array} cannot be more than +#' 5 entries. +#' +#' @return The function returns \code{0L} when successful. +#' +#' @examples +#' +#' ## Path to RDS file with ancestry information generated by RAIDS (demo file) +#' dataDir <- system.file("extdata", package="RAIDS") +#' fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") +#' +#' ## Validate parameters +#' RAIDS:::validateCreateAccuracyGraph(fileRDS=fileRDS, title="Accuracy Graph", +#' selectD=c(5, 10), selectColor=c("blue","darkblue")) +#' +#' @author Astrid Deschênes and Pascal Belleau +#' @importFrom stringr str_detect +#' @encoding UTF-8 +#' @keywords internal +validateCreateAccuracyGraph <- function(fileRDS, title, selectD, selectColor) { + + ## Validate fileRDS is character string + if(!is.character(fileRDS)) { + stop("The \'fileRDS\' parameter must be a character string.") + } + + ## Validate fileRDS exist + if(!file.exists(fileRDS)) { + stop("The \'fileRDS\' file does not exist.") + } + + ## Validate the file extension + if (!str_detect(fileRDS, "\\.(RDS|rds)$")) { + stop("The \'fileRDS\' must have a RDS (or rds) extension.") + } + + ## Validate the title is a string + if (!is.character(title)) { + stop("The \'title\' must be a character string.") + } + + ## Validate the length of the selectD parameter + if (length(selectD) == 0) { + stop("The \'selectD\' parameter cannot be empty.") + } + + ## Validate the length of the selectD parameter + if (length(selectD) > 5) { + stop("The \'selectD\' parameter can contain a maximum of 5 elements.") + } + + ## Validate lengths of selectD and selectcolor identical + if (length(selectColor) != length(selectD)) { + stop("The \'selectColor\' parameter must be the same length than ", + "the \'selectD\' parameter.") + } + + ## Success + return(0L) +} \ No newline at end of file diff --git a/inst/extdata/TEST_01.infoCall.RDS b/inst/extdata/TEST_01.infoCall.RDS new file mode 100644 index 0000000000000000000000000000000000000000..10e2d7170b327c39150bee66925fee412552ae15 GIT binary patch literal 8408 zcmbVxS5Om#Wlp#n)8KZy16g0c1}=@TQDBdN)bP|t`kOTM_x(FB zf%tnj``R}XRyL1aM0#wm$M6U%{MgUr=kyc*LTs*x)DIp5pv67atmMB>K2k`zd|eZ^ z7{A@$|2J3Ur~H3l!dVX}{LbZHa2o&Dg8U;Q#r+*XjD;YyuGPgg9+8Z)ovtP}1h0<* zx3kN8ueL~#U(LV#f?*Gt4_^5O|HP8pjBB(3(`bG52xKxYd}xtj%H|B&NB@Jd@%_sE ze}@017Q6Y+|L}&>-v9sh|ERBZHSE9&UsjfXv=5?nalU5at`~kqc~|Fo`0Zub`yiY5 zNA2Uon~t9p8o8IgyFXLTNgw+^(v#~_?$rugtU#-*%Jr>MbFEepyc<=M;9QqNpxD?$ z0C>CeLb1y!q>91V*72l!DLSa#sB+@+q3uk=ErWn%Mk5=g$kWnBrB!TJu#MH0$-6(r zY+Jz0i3cE~hnYMYNZ(<5CLKCojM_$uhdC-%G)<{zB-etHmUFyhe zXWneIdaCb}>K~jdK)t`c4Q`DP260QmN+ta*UgEoxpL$^xq%*%BaS0I4f zk()x$R+wQ1TEx6_eb8f&hIPoPLG<2lk1O*8=nm$h{6*{zv~BNl^d zR-}hS;3BP0p0Uf2=NI(=QT#jJj@0TYAcov$OhKTYd4K$UI&aS?Zuw=v&W+@6$-nHP z7{=Dh0+!Xq>tyz8Nm4omm_0~GU6K2?9;*|0}tNqXPT zb*STDW#IG5=n?grPx(X!kjhfD9oTA29=7xI5Yo1SQuxir#-IA6d@@4OVR0%vx>`Ft z1oZAu6H8^e9phr<&P`Kr@O%1`(&pWJ^6T6kraUv;4L8Fq;}bC;X824KHN_*_{eB6+ zcPK9{($iH3F}Uh@e(!ugjTX`zT_dCV(v19qy{ZXHd!`9^c+Nvp|HSk&{%w@k>Lf;t zj_7~nK#;iU{_?T?purd5gV(hmWoL;GcD~%BsfRaAPIB&As%i_;pRMabM4tB~%?&IN zLJ%&P%oSd$67Te+;Wdui`^;LGyUksNwNwj$3^x-lgAhXIkI9Ih%%I8obXU_N@JbJ% z@s@O{wuf{&eSMYwhr64uDQ>Ul0Of*GM*d&8+goP^{gnZc6tHT8S48rTTK0nIn7j_? z&_WacO6&SwCG+nNb_Ua8fkon~V0XGW_$#Tdxr%P4xa-=TgIaov&NWf!$nv9O4T~uP z6(OxdYC4_T>)aMMIpbjJHzPZ@h#uJMyGBA%SRra$n2n?)^(4EUrk&P*R`dIMQ|pEl z@7(AA5#fhTV^cv)58^h2te*H6J-^FdafGTcCF9%NPfjuHro?W}zStyoEj(ppyUNE# z>d)Qu9J|f$@uVA8GhGrRfMhCJh%Ul7Wp1R?oSh17@aGK3SZ;Rup-mI|#oiV-U)tRz zJ=RLud8PCcJ#PIm$2)jLeGjCcj~A*T?3-5Nwlf5yWl6)n7X$G%S9}?*&*;~Qr;eU2 za$Hu}B-}hfm9W2l$VBIJ1WXeNM{GHTMz%g9{0MTM`aVe|!3Tjz=h2fiRWSFqFT3ZA zD=hBd&wo8LPm@4!yo%|jn+cpdWb0OW|GfH;ZaO$Hy{Y9sb|NBCu)Fz28|QlRo(Tbn zk8^q1hQR%nYpN+cd-no1Kwd#*wZ>C;3UgRvxD1SONlyg+U=A8|lD;jA-1zJOe7P
ZAHC`dSL)SS-u#juiPS8IKwqEO}ChkssFZk?E>9zX;DWA+6IZp(*)3G!eQ|2T-oj z!2M9f`iQV=Ax6V<75R141NneeOaj_;SsFpmHMn9c^tU1;&E@h)$Q+7G`V z7-`9H(}z1}hZoJWuh@q^8jeTNdK-@qzl43Vho+0Mnnu>(29ALLMj({zWYTfrB>gj{ z=sG1eVK9y*9+m0g#VMFkfPrV5pBst}ZjUIXu`FzN+eWAt;nozLW9<6AjyDXB72S(PXCqBO3EuCk!>n z8G}x=n%d_N#9+v#KWK*BeXZ-!N6mg|^<2V1%Iz+{L)S6JLg{JFO8$v&?Yz6vH)gwE z2er88Kut=@SqKAaH<8$?SN$5J1?Kxix|O5J(vn0um8PMUFKTbCl0k1lLTe!oI9^|db$qpe(4wcEB56bWSF>;M0->*70RA%GUv41S`@iG)6 z))8<{b!6FW`HpMN4fa{FflpgwbRglwms56AGxCa??p@JlZ^3m};r_DA^+MgLZ~7Ge}riM{D1=rix%{b>d(> z>eFt#Ei&Y4|8+@)??~3cy_T{9e=n_(to|CarVEEV(E6o6*7}nz9mwc+_uLI4G)yu~vF6DNh^Lx+W-8 zzlyPHtUbSR&}OK78}s4U{sFr}b~5i9*>OgJ!15K0hy4X#^^4S~37^}-~ zP+xw)F#R|>?bW}@gBg{Y!CHwLqDuJ`r}tW&-m|##?z%*e&}Q*nU3HW9te+woQ@jyF z^Wu+CTt}I+DTUv67qrHA`5KsX0{>1uuO=tDB=IS)8366JRCsJ{UJT2HLUO;P^N>Nm z%`K*QWy`BCr+BQ}WiQ8P-j-d~iZgFwP!8nnrG|ciJJW18e+lHB%(GqHZQ_|?r|`SW zTi?cucNM{R(#}+ryywUe$}35JM;qFT4Xxsa!`Cvh9U1&eDp~(hoMSFMEHS>dYJ$wu zacdM)`EsKkFRdX;Ot81VEvN~=va`1~T)G&WgygsQ^s2q-*XB+?6;B|R45Yn`%TFq? zwA28ZRy$pVP;I6A+p!|Z<(wD<_#n0a*V`*2$_FPzk9evwQ^Mt*^uwSC>)Q(395FizqGS%V}iWmap)Mk6m^k6V)KtT(kb7wSk$-b0NRpPw6O z3*R|2^?vOeZ;V(}>^vNim~@|_*#x!MFEitJQbl>A1|v^mg!F!mxc06o#>Z8i_<+65 zN5Hn^g`Gb=W-{p_z2|*er5rV7YV=Bq?$WAwXNlPgN(Zh$>fkE4@7$hD_`B0v)P&2r z{o6YmD(CZIw>iREDVsS}PTn84x$vi>@v9QaS%-bo=e&>`!M0rYadx*QQS^ zJ$w`9eGRoDMoz!2)@aX6qy{sbSSZt-W_bE?lNKq~XM%zn?xP<>M z`|`q6)M92KTHl}}|8{AEpdK~Nhd*QIH7S^fOEwwrdjI~alN_x;jhBT|xvtNz+e_Vz z>gm-5*2WT%J0FUE|G70Ysy1U&3EeCqQ2}iqbiE@|gl_SP)epWku|40vFF)Ga)RH11 z>&ehwgGp*st}+wh0k(8zp6j(?Uo{T{C!nz!(7I#c4gEFitmKx+uq+d92Y z+(iil)qi-EeP6foo=_*cwM0+Ye$INUL+k39R{EW2{Nh!!kYazNo#y95IcwCDhpP4P zEDO7t8QZyj@^{ZsG}oumaW~9{CiY$UZCDJdD0Ugc)mq?|;@o*Yd76I?^7TDcWAF zbs%8!FxsvN0lHPY?FI1L34K!NOoh*>+a!-&1v=WPKE-68RUpKj#y%L~p5 z#wguNE9r-u^(+pIMU&55Nzr!8-M>Gn{YHU%X1w#cv}GJvCSRkmHw+BJ7fj~Id#)1~ z2mS(d0ztd2?vE=k4V302H|)WlB=6tOfQc-GZ(8u(j=iIQGQPjA7+fVZGct!j-=w{G zN$2#zNzp~9hq*ijYk+!$dLNiWjqc6YbLD$`)cw${f#x!~QXSSty4bfAcT6E9;TOhw zNfqSTGk~W22yhdJC zpdID2-1|=LDp3TyKsM{~nPo1=!T_V+;H!*Gy^z5mUllv91G^3){kH)0$)Bkw62%3Q zlIblTT`#*|TlVu}tS$=$w*{&98&2%8zHOw%phsH0+uccp&$x{q!7a+f+}VgSdm>o@ zS!718uHQKLd)8(YJu~&F(Oo8SnU6?NS$x)!?oDLgry4G&tc%@$!m+>q{-u1(&K5Z7 zk>=cREb-m;3Jf5pU*zEB4B`30Fp}Ajg1Kr99F!WVR_nt>SS$2<>&v*mb*L_tM^kLv zAQ*S${Ud`9y|qR(ezKz|!N;|LfK#lNjf+NLmaAGOgB*XccD;Tj+8Xw6{%5@n(kaZb z)}>hLDpD_w;$lBhPyLTrP>8F;GDr!)zIUPw+Yx9qnm#aU_u6Z@tSUoma8p>&-yv&eP zE;=&Z&QsJ0bPK}Y{pWD|s8OP_;^URvEqsHyO!;YI9zXvYX!F?KTLLZgG40NG*WY`hqZ@8}L9{ct{=ZB4EE~zSZY3&&`Rx%QF#KtCTviC8L26a_mbBkr z)ZHOXt4Q5P#YQ3r>qE6C6~RC@rq+=521$-X#>nHhjs#=_9c*ASL8O9z*K9w%cTh|l zAxHmp@b@yKMi8?X{{miTpskhhqVmG`l%s>X`J%y)Cv3-%TSg=CRluk4P)V9<83QW132KsHWzaLPI+GoRn*QwO0|Lk)x|pW zBgLM~xV(N4q<42hou}GDl!+RUJWD%IDSdq;IHdYAvSzVN7xmcIv20V{y#C$-BF*k% zQ!lLr&o$(VbBg0)x{@|^u?QjP6x$G~PgfFoU(*C;pzc16_tc+><(8zkYtCb5b zANe(nD8G7nBh0H|{KM9bGx~2#Wsw)#({aLpf~alSV2qiD9V&!9>9g#z)n}~m8{bjI zfW-7$=#Ru+5Ct>SebqO}OpC_qBVb)96l-6yW8Yk4fR=7Qe7AZa)cDH-J4{KmhveRI z2Cv|Ih~J(^sxTwjS{O*?N!~PGwjH0wT$M*d4(pub>YB| zhp~eo_E(ax?TopoH8TJDXys=)@D-(3C}k^TOLJ{gYtS{=|MxM|-;rZKeI+m0cgV2@ zD*PqHr+nS8<=7R*57g+WXoqK9t={N~OD;b;5%xRKNg(!#whf!l>6eTBXiavae;?0W z0-LfFK+w#G$r8KuH~hv2$|`M;@}-O9hv{Z{u`3D_?bX!{96h+L-kku6z?{isW7>mgOG3HzZxWie=6Y=hvhk@CG`sv#2j#HGWYy9XD41%9!c zoG31Flb8|fHFi9)5+C={RYjwc*Kz$DVP>mIeSsNFvOlC1^vKb<)bZ4iZTdq&m?F>> zeU%ukxEL>i`;9NX#+)nlRTz)OFr_Ge2tp=y#}F#}l=p)z19bXWrrYhq3YJy-?NzFnCG<70DOqXh6Zb97JI>JzE;x@EID;^2dS zX|vop9YAO-tXW98?$JdSDZM@fTBnSYX+J#Dqsi9XOeYxc-#-vA`^Zj$P_A6akEn$~ z?^1n=ZG%j$+88c_ejP&^%V(sbQ22b^nwNnIHeC&Gk*w-gYSYx=+FDHa1H+)sJ5dm&{iBFV8&v2DnoRAv!bStfhjGxYgtL8-3rSE9_S^QWAv00(7yd-(AoZ zKmOdB$1Th)a_zp*0z4wL7?-~w=b}6RNZpk_a?dxC5aShEWaZYMDcI8!t7h@=4yK?{w34>R z?*-Nz-$3>aNSbD|{r8*4`WANX?lZ?`#g$Y{GR#T}NGsF>FUf2gsA6vStUT$>zDsk} zI*Nz8AmI%YZV6(|-;_w7Z1x3wZdy1v#&rO_gV1 zDdBN|oH}i*pX_lMEF~wDyjT!U%Ibl$^qPTsAh>;F~)blOe3h-bWS3sReD?P#n8_{W2dP9;|+dX2Pl(f+c=)!%1`EgY{yRyRK1} z4ito~FB=82#8`dU)J-Yq=1d9HQR+JZmaZW?qAF)yXS+(VjM(HRILn}S`FPqif}(uq zMS_@)`n}Sl$@hn%6i9IYn0Ib`bb-&8mXFyk>}=^fc7sygYvLw3KW@K?`&6jzCIfKM z3?nE%F$1yU&D19Rnb*RWYz!P8xRcz0`~*|V&wdxf%`^_P0D)LDIaIHBLa8{o~@* zoxc&RLroPRIRAE;@hm^?38Cm@+NCtY1UAS&OI1_e9Cfgx39#?=U^aN}c-*>irmBBc ztU9(fSb4wFYPq-ddCe}htv`y;7jxw6pX}@}$d-ffx97JyE$rx9_7YSA=xF1{!GDTY zCV-5}D_SQa&JgU5m#tpm@XC!jy~;1X%kRXY+p85HdeFcYl$gD%$Ak2s?qIuA+EUWh zi{`l2T)pIx5B{i0Cn+Uv2ukgq z%*h6ye2BmykVCwN?|C5LqiF(yIkd`%u)($$g5LLe@dJ0GUj;$(+B>_>{B5(i<WAhgWo3U?7kl@ESD6LS0ljl}ZJlhBfeSt9y2>uu&%qtrC0&ikTpJ7H zJCirg3dzyUFdGYlD=nU9sQDK6|0IP3c#o!t= zHg0Bx%!>6UOkU$|U3%!P>3Vka;59k9eLinVfilU_$eU{Jit(OX1=(qDRO17i3{{zP zZL`4%=6C{->-=w{M|^fb7n&o8G=1$g3cX;NHMt=A=@8o2@yeF~-Q{S4E$puy5|Cnx zi&wM7d%fX0XVc>2k&lNztW{@pX!eU!`>o27k$s-9u!b{wvzvf=wRBBbgq~@-{#}F$ zoY_$K{>+96u0qlZGK2vhU&h3Khm))Ydf8N8-9Op}8+_5zjTl+6QBMGGE5B+Ywr8wTmvz_!-yoV+6oNPD%OtawP%)z!c}<&ueP0^V3lC9q!W} z$Dy0d^^#{L1sjpah=t0D#aV1UBLcuCD_5tORXcd6Ru|XEow4(Z2KMv7LpiV|`#=Wg z7j)e;-e-$PUFi~oyoaXN zPFjQ)mZ@#Dbyx)v6J7rm)#HoEYuGB)6uq?QF7O;3pY*Q@U$>Qj2LwJ%W4QcrwWE;5 s*Mp)uu~pl+im85Br! \code{minCov}. The \code{data.frame} contains those columns: -\itemize{ -\item{cnt.tot} {a \code{integer} representing the total allele count} -\item{cnt.ref} {a \code{integer} representing the reference allele count} -\item{cnt.alt} {a \code{integer} representing the alternative allele count} -\item{snp.pos} {a \code{integer} representing the position on the chromosome} -\item{snp.chr} {a \code{integer} representing the chromosome} -\item{normal.geno} {a \code{integer} representing the genotype +\describe{ +\item{cnt.tot}{ a \code{integer} representing the total allele count} +\item{cnt.ref}{ a \code{integer} representing the reference allele count} +\item{cnt.alt}{ a \code{integer} representing the alternative allele count} +\item{snp.pos}{ a \code{integer} representing the position on the chromosome} +\item{snp.chr}{ a \code{integer} representing the chromosome} +\item{normal.geno}{ a \code{integer} representing the genotype (0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown)} -\item{pruned} {a \code{logical} indicating if the SNV is retained after +\item{pruned}{ a \code{logical} indicating if the SNV is retained after pruning} -\item{snp.index} {a \code{integer} representing the index position of the +\item{snp.index}{ a \code{integer} representing the index position of the SNV in the Reference GDS file that contains all SNVs} -\item{keep} {a \code{logical} indicating if the genotype exists for the SNV} -\item{hetero} {a \code{logical} indicating if the SNV is heterozygote} -\item{homo} {a \code{logical} indicating if the SNV is homozygote} -\item{lap} {a \code{numeric} representing the lower allelic fraction} -\item{LOH} {a \code{integer} indicating if the SNV is in an LOH region +\item{keep}{ a \code{logical} indicating if the genotype exists for the SNV} +\item{hetero}{ a \code{logical} indicating if the SNV is heterozygote} +\item{homo}{ a \code{logical} indicating if the SNV is homozygote} +\item{lap}{ a \code{numeric} representing the lower allelic fraction} +\item{LOH}{ a \code{integer} indicating if the SNV is in an LOH region (0=not LOH, 1=in LOH)} -\item{imbAR} {a \code{integer} indicating if the SNV is in an imbalanced +\item{imbAR}{ a \code{integer} indicating if the SNV is in an imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; 1=tested positive for imbalance in at least 1 window)} } diff --git a/man/computeAllelicFractionRNA.Rd b/man/computeAllelicFractionRNA.Rd index dbc21c9d7..1b60d3ebb 100644 --- a/man/computeAllelicFractionRNA.Rd +++ b/man/computeAllelicFractionRNA.Rd @@ -70,33 +70,33 @@ message when running.} a \code{data.frame} containing the allelic information for the pruned SNV dataset with coverage > \code{minCov}. The \code{data.frame} contains those columns: -\itemize{ -\item{cnt.tot} {a \code{integer} representing the total allele count} -\item{cnt.ref} {a \code{integer} representing the reference allele count} -\item{cnt.alt} {a \code{integer} representing the alternative allele count} -\item{snp.pos} {a \code{integer} representing the position on the chromosome} -\item{snp.chr} {a \code{integer} representing the chromosome} -\item{normal.geno} {a \code{integer} representing the genotype +\describe{ +\item{cnt.tot}{ a \code{integer} representing the total allele count} +\item{cnt.ref}{ a \code{integer} representing the reference allele count} +\item{cnt.alt}{ a \code{integer} representing the alternative allele count} +\item{snp.pos}{ a \code{integer} representing the position on the chromosome} +\item{snp.chr}{ a \code{integer} representing the chromosome} +\item{normal.geno}{ a \code{integer} representing the genotype (0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown)} -\item{pruned} {a \code{logical} indicating if the SNV is retained after +\item{pruned}{ a \code{logical} indicating if the SNV is retained after pruning} -\item{snp.index} {a \code{integer} representing the index position of the +\item{snp.index}{ a \code{integer} representing the index position of the SNV in the Reference GDS file that contains all SNVs} -\item{keep} {a \code{logical} indicating if the genotype exists for the SNV} -\item{hetero} {a \code{logical} indicating if the SNV is heterozygote} -\item{homo} {a \code{logical} indicating if the SNV is homozygote} -\item{block.id} { a \code{integer} indicating the unique identifier of the +\item{keep}{ a \code{logical} indicating if the genotype exists for the SNV} +\item{hetero}{ a \code{logical} indicating if the SNV is heterozygote} +\item{homo}{ a \code{logical} indicating if the SNV is homozygote} +\item{block.id}{ a \code{integer} indicating the unique identifier of the block in the Population Reference Annotation GDS file that contains the current SNV} -\item{phase} { a \code{integer} indicating the phase of the variant +\item{phase}{ a \code{integer} indicating the phase of the variant if known, \code{3} if not known} -\item{lap} {a \code{numeric} indicating lower allelic fraction} -\item{LOH} {a \code{integer} indicating if the SNV is in an LOH region +\item{lap}{ a \code{numeric} indicating lower allelic fraction} +\item{LOH}{ a \code{integer} indicating if the SNV is in an LOH region (0=not LOH, 1=in LOH)} -\item{imbAR} {a \code{integer} indicating if the SNV is in an imbalanced +\item{imbAR}{ a \code{integer} indicating if the SNV is in an imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; 1=tested positive for imbalance in at least 1 window)} -\item{freq} {a \code{numeric} indicating the frequency of the variant +\item{freq}{ a \code{numeric} indicating the frequency of the variant in the the reference} } } diff --git a/man/computeAllelicImbDNAChr.Rd b/man/computeAllelicImbDNAChr.Rd index bfcf88a9b..7872acdd9 100644 --- a/man/computeAllelicImbDNAChr.Rd +++ b/man/computeAllelicImbDNAChr.Rd @@ -11,28 +11,28 @@ computeAllelicImbDNAChr(snpPos, chr, wAR = 10, cutOffEmptyBox = -3) \item{snpPos}{a \code{data.frame} containing the SNV information for the chromosome specified by the \code{chr} argument. The \code{data.frame} must contain: -\itemize{ -\item{cnt.tot} {a single \code{integer} representing the total coverage for +\describe{ +\item{cnt.tot}{ a single \code{integer} representing the total coverage for the SNV.} -\item{cnt.ref} {a single \code{integer} representing the coverage for +\item{cnt.ref}{ a single \code{integer} representing the coverage for the reference allele.} -\item{cnt.alt} {a single \code{integer} representing the coverage for +\item{cnt.alt}{ a single \code{integer} representing the coverage for the alternative allele.} -\item{snp.pos} {a single \code{integer} representing the SNV position.} -\item{snp.chr} {a single \code{integer} representing the SNV chromosome.} -\item{normal.geno} {a single \code{numeric} indicating the genotype of the +\item{snp.pos}{ a single \code{integer} representing the SNV position.} +\item{snp.chr}{ a single \code{integer} representing the SNV chromosome.} +\item{normal.geno}{ a single \code{numeric} indicating the genotype of the SNV. The possibles are: \code{0} (wild-type homozygote), \code{1} (heterozygote), \code{2} (altenative homozygote), \code{3} indicating that the normal genotype is unknown.} -\item{pruned} {a \code{logical} indicating if the SNV is retained after +\item{pruned}{ a \code{logical} indicating if the SNV is retained after pruning} -\item{snp.index} {a \code{integer} representing the index position of the +\item{snp.index}{ a \code{integer} representing the index position of the SNV in the Reference GDS file that contains all SNVs} -\item{keep} {a \code{logical} indicating if the genotype exists for the SNV} -\item{hetero} {a \code{logical} indicating if the SNV is heterozygote} -\item{homo} {a \code{logical} indicating if the SNV is homozygote} -\item{lap} {a \code{numeric} indicating lower allelic fraction} -\item{LOH} {a \code{integer} indicating if the SNV is in an LOH region +\item{keep}{ a \code{logical} indicating if the genotype exists for the SNV} +\item{hetero}{ a \code{logical} indicating if the SNV is heterozygote} +\item{homo}{ a \code{logical} indicating if the SNV is homozygote} +\item{lap}{ a \code{numeric} indicating lower allelic fraction} +\item{LOH}{ a \code{integer} indicating if the SNV is in an LOH region (0=not LOH, 1=in LOH)} }} diff --git a/man/computeAncestryFromSyntheticFile.Rd b/man/computeAncestryFromSyntheticFile.Rd index d09d6cf6f..337bba3f0 100644 --- a/man/computeAncestryFromSyntheticFile.Rd +++ b/man/computeAncestryFromSyntheticFile.Rd @@ -95,10 +95,10 @@ to show how the different steps in the function. Default: \code{FALSE}.} } \value{ a \code{list} containing 4 entries: -\itemize{ +\describe{ \item{\code{pcaSample}}{ a \code{list} containing the information related to the eigenvectors. The \code{list} contains those 3 entries: -\itemize{ +\describe{ \item{\code{sample.id}}{ a \code{character} string representing the unique identifier of the current profile.} \item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing @@ -108,15 +108,14 @@ eigenvectors for the current profile projected on the PCA from the reference profiles.} } } - \item{\code{paraSample}}{ a \code{list} containing the results with different \code{D} and \code{K} values that lead to optimal parameter selection. The \code{list} contains those entries: -\itemize{ +\describe{ \item{\code{dfPCA}}{ a \code{data.frame} containing statistical results on all combined synthetic results done with a fixed value of \code{D} (the number of dimensions). The \code{data.frame} contains those columns: -\itemize{ +\describe{ \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the number of dimensions).} \item{\code{median}}{ a \code{numeric} representing the median of the @@ -136,7 +135,7 @@ combination of the fixed \code{D} value and all tested \code{K} values. } all combined synthetic results done with different values of \code{D} (the number of dimensions) and \code{K} (the number of neighbors). The \code{data.frame} contains those columns: -\itemize{ +\describe{ \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the number of dimensions).} \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the @@ -155,7 +154,7 @@ the specified values of \code{D} and \code{K}.} \item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by super-population. The \code{data.frame} contains those columns: -\itemize{ +\describe{ \item{\code{pcaD}}{ a \code{numeric} representing the value of \code{D} (the number of dimensions).} \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the @@ -181,17 +180,16 @@ values (the number of dimensions) for the specific profile. More than one \code{D} is possible.} } } - \item{\code{KNNSample}}{ a \code{list} containing the inferred ancestry using different \code{D} and \code{K} values. The \code{list} contains those entries: -\itemize{ +\describe{ \item{\code{sample.id}}{ a \code{character} string representing the unique identifier of the current profile.} \item{\code{matKNN}}{ a \code{data.frame} containing the inferred ancestry for different values of \code{K} and \code{D}. The \code{data.frame} contains those columns: -\itemize{ +\describe{ \item{\code{sample.id}}{ a \code{character} string representing the unique identifier of the current profile.} \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the @@ -204,11 +202,10 @@ ancestry for the specified \code{D} and \code{K} values.} } } } - \item{\code{Ancestry}}{ a \code{data.frame} containing the inferred ancestry for the current profile. The \code{data.frame} contains those columns: -\itemize{ +\describe{ \item{\code{sample.id}}{ a \code{character} string representing the unique identifier of the current profile.} \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the diff --git a/man/computeKNNRefSample.Rd b/man/computeKNNRefSample.Rd index 18b6af45c..92a5b5617 100644 --- a/man/computeKNNRefSample.Rd +++ b/man/computeKNNRefSample.Rd @@ -47,22 +47,22 @@ Default: \code{seq(2, 15, 1)}.} } \value{ a \code{list} containing 4 entries: -\itemize{ -\item{\code{sample.id}} { a \code{vector} of \code{character} strings +\describe{ +\item{\code{sample.id}}{ a \code{vector} of \code{character} strings representing the identifier of the profile analysed.} -\item{\code{matKNN}} { a \code{data.frame} containing the super population +\item{\code{matKNN}}{ a \code{data.frame} containing the super population inference for the profile for different values of PCA dimensions \code{D} and k-neighbors values \code{K}. The fourth column title corresponds to the \code{fieldPopInfAnc} parameter. The \code{data.frame} contains 4 columns: -\itemize{ -\item{\code{sample.id}} {a \code{character} string representing +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the identifier of the profile analysed.} -\item{\code{D}} { a \code{numeric} strings representing +\item{\code{D}}{ a \code{numeric} strings representing the value of the PCA dimension used to infer the ancestry.} -\item{\code{K}} { a \code{numeric} strings representing +\item{\code{K}}{ a \code{numeric} strings representing the value of the k-neighbors used to infer the ancestry..} -\item{\code{fieldPopInfAnc}} { a \code{character} string representing +\item{\code{fieldPopInfAnc}}{ a \code{character} string representing the inferred ancestry.} } } diff --git a/man/computeKNNRefSynthetic.Rd b/man/computeKNNRefSynthetic.Rd index 8c9e9094c..ef47f2bce 100644 --- a/man/computeKNNRefSynthetic.Rd +++ b/man/computeKNNRefSynthetic.Rd @@ -57,28 +57,28 @@ Default: \code{seq(2, 15, 1)}.} } \value{ a \code{list} containing 4 entries: -\itemize{ -\item{\code{sample.id}} {a \code{vector} of \code{character} strings +\describe{ +\item{\code{sample.id}}{ a \code{vector} of \code{character} strings representing the identifiers of the synthetic profiles analysed.} -\item{\code{sample1Kg}} {a \code{vector} of \code{character} strings +\item{\code{sample1Kg}}{ a \code{vector} of \code{character} strings representing the identifiers of the 1KG reference profiles used to generate the synthetic profiles.} -\item{\code{sp}} {a \code{vector} of \code{character} strings representing +\item{\code{sp}}{ a \code{vector} of \code{character} strings representing the known super population ancestry of the 1KG reference profiles used to generate the synthetic profiles.} -\item{\code{matKNN}} {a \code{data.frame} containing the super population +\item{\code{matKNN}}{ a \code{data.frame} containing the super population inference for each synthetic profiles for different values of PCA dimensions \code{D} and k-neighbors values \code{K}. The fourth column title corresponds to the \code{fieldPopInfAnc} parameter. The \code{data.frame} contains 4 columns: -\itemize{ -\item{\code{sample.id}} {a \code{character} string representing +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the identifier of the synthetic profile analysed.} -\item{\code{D}} {a \code{numeric} strings representing +\item{\code{D}}{ a \code{numeric} strings representing the value of the PCA dimension used to infer the super population.} -\item{\code{K}} {a \code{numeric} strings representing +\item{\code{K}}{ a \code{numeric} strings representing the value of the k-neighbors used to infer the super population.} -\item{\code{fieldPopInfAnc} value} {a \code{character} string representing +\item{\code{fieldPopInfAnc} value}{ a \code{character} string representing the inferred ancestry.} } } diff --git a/man/computeLOHBlocksDNAChr.Rd b/man/computeLOHBlocksDNAChr.Rd index 634cd2420..d1bf63705 100644 --- a/man/computeLOHBlocksDNAChr.Rd +++ b/man/computeLOHBlocksDNAChr.Rd @@ -19,26 +19,26 @@ package 'BSgenome.Hsapiens.UCSC.hg38'.} \item{snpPos}{a \code{data.frame} containing the SNV information for the chromosome specified by the \code{chr} argument. The \code{data.frame} must contain: -\itemize{ -\item{cnt.tot} {a single \code{integer} representing the total coverage for +\describe{ +\item{cnt.tot}{ a single \code{integer} representing the total coverage for the SNV.} -\item{cnt.ref} {a single \code{integer} representing the coverage for +\item{cnt.ref}{ a single \code{integer} representing the coverage for the reference allele.} -\item{cnt.alt} {a single \code{integer} representing the coverage for +\item{cnt.alt}{ a single \code{integer} representing the coverage for the alternative allele.} -\item{snp.pos} {a single \code{integer} representing the SNV position.} -\item{snp.chr} {a single \code{integer} representing the SNV chromosome.} -\item{normal.geno} {a single \code{numeric} indicating the genotype of the +\item{snp.pos}{ a single \code{integer} representing the SNV position.} +\item{snp.chr}{ a single \code{integer} representing the SNV chromosome.} +\item{normal.geno}{ a single \code{numeric} indicating the genotype of the SNV. The possibles are: \code{0} (wild-type homozygote), \code{1} (heterozygote), \code{2} (altenative homozygote), \code{3} indicating that the normal genotype is unknown.} -\item{pruned} {a \code{logical} indicating if the SNV is retained after +\item{pruned}{ a \code{logical} indicating if the SNV is retained after pruning} -\item{snp.index} {a \code{integer} representing the index position of the +\item{snp.index}{ a \code{integer} representing the index position of the SNV in the Reference GDS file that contains all SNVs} -\item{keep} {a \code{logical} indicating if the genotype exists for the SNV} -\item{hetero} {a \code{logical} indicating if the SNV is heterozygote} -\item{homo} {a \code{logical} indicating if the SNV is homozygote} +\item{keep}{ a \code{logical} indicating if the genotype exists for the SNV} +\item{hetero}{ a \code{logical} indicating if the SNV is heterozygote} +\item{homo}{ a \code{logical} indicating if the SNV is homozygote} }} \item{chr}{a single positive \code{integer} for the current chromosome. The @@ -51,32 +51,32 @@ probability of sequencing error. Default: \code{0.0001}.} \value{ a \code{data.frame} with the informations about LOH on a specific chromosome. The \code{data.frame} contains those columns: -\itemize{ -\item{chr} {a \code{integer} representing the current chromosome} -\item{start} {a \code{integer} representing the starting position on the +\describe{ +\item{chr}{ a \code{integer} representing the current chromosome} +\item{start}{ a \code{integer} representing the starting position on the box containing only homozygote SNVs (or not SNV). The first box starts at position \code{1}.} -\item{end} {a \code{integer} representing the end position on the +\item{end}{ a \code{integer} representing the end position on the box containing only homozygote SNVs (or not SNV). The last box ends at the length of the chromosome.} -\item{logLHR} {a \code{numeric} representing the LOH score basde on +\item{logLHR}{ a \code{numeric} representing the LOH score basde on population frequencies. It is the sum of the log10 of the frequencies of the observed gegenotype minus the the sum of the log10 of the higher frequent genotype. (-100 when normal genotype are present)} -\item{LH1} { a \code{numeric} representing the probability to be +\item{LH1}{ a \code{numeric} representing the probability to be heterozygote based on the coverage of each allele when normal genotype is present} -\item{LM1} {a \code{numeric} representing the max probability +\item{LM1}{ a \code{numeric} representing the max probability for the read coverage at the position} -\item{homoScore} {a \code{numeric} representing \code{LH1} - \code{LM1}} -\item{nbSNV} {a \code{integer} representing th number of SNVs in +\item{homoScore}{ a \code{numeric} representing \code{LH1} - \code{LM1}} +\item{nbSNV}{ a \code{integer} representing th number of SNVs in the box} -\item{nbPruned} {a \code{integer} representing the number of pruned SNVs in +\item{nbPruned}{ a \code{integer} representing the number of pruned SNVs in the box} -\item{nbNorm} { a \code{integer} representing of the number of +\item{nbNorm}{ a \code{integer} representing of the number of heterozygote genotypes for the normal SNVs in the block} -\item{LOH} { a \code{integer} representing a flag, if \code{1} it means +\item{LOH}{ a \code{integer} representing a flag, if \code{1} it means the block is satisfying the criteria to be LOH. The value is not assigned in this function; the value \code{0} is assigned} } diff --git a/man/computePCAMultiSynthetic.Rd b/man/computePCAMultiSynthetic.Rd index 6b57b62d4..d859c4959 100644 --- a/man/computePCAMultiSynthetic.Rd +++ b/man/computePCAMultiSynthetic.Rd @@ -37,13 +37,13 @@ to show how the different steps in the function. Default: \code{FALSE}.} } \value{ a \code{list} containing 3 entries: -\itemize{ -\item{sample.id} { a \code{vector} of \code{character} strings representing +\describe{ +\item{sample.id}{ a \code{vector} of \code{character} strings representing the identifiers of the synthetic profiles that have been projected onto the 1KG PCA. } -\item{eigenvector.ref} { a \code{matrix} of \code{numeric} with the +\item{eigenvector.ref}{ a \code{matrix} of \code{numeric} with the eigenvectors of the 1KG reference profiles used to generate the PCA.} -\item{eigenvector} { a \code{matrix} of \code{numeric} with the +\item{eigenvector}{ a \code{matrix} of \code{numeric} with the eigenvectors of the synthetic profiles projected onto the 1KG PCA. } } } diff --git a/man/computePCARefRMMulti.Rd b/man/computePCARefRMMulti.Rd index 8b77f3bc7..5f5d84ce3 100644 --- a/man/computePCARefRMMulti.Rd +++ b/man/computePCARefRMMulti.Rd @@ -53,7 +53,7 @@ printed.} } \value{ a \code{list} containing 2 entries: -\itemize{ +\describe{ \item{pruned}{ a \code{vector} of SNV identifiers specifying selected SNVs for the PCA analysis.} \item{pca.unrel}{ a \code{snpgdsPCAClass} object containing the eigenvalues diff --git a/man/computePCARefSample.Rd b/man/computePCARefSample.Rd index babcdfe64..476afc54e 100644 --- a/man/computePCARefSample.Rd +++ b/man/computePCARefSample.Rd @@ -51,12 +51,12 @@ to show how the different steps in the function. Default: \code{FALSE}.} } \value{ a \code{list} containing 3 entries: -\itemize{ -\item{\code{sample.id}} { a \code{character} string representing the unique +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique identifier of the analyzed profile.} -\item{\code{eigenvector.ref}} { a \code{matrix} of \code{numeric} +\item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} representing the eigenvectors of the reference profiles. } -\item{\code{eigenvector}} { a \code{matrix} of \code{numeric} representing +\item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} representing the eigenvectors of the analyzed profile. } } } diff --git a/man/computePoolSyntheticAncestryGr.Rd b/man/computePoolSyntheticAncestryGr.Rd index 117b47a98..906dd9263 100644 --- a/man/computePoolSyntheticAncestryGr.Rd +++ b/man/computePoolSyntheticAncestryGr.Rd @@ -88,16 +88,16 @@ printed. Default: \code{FALSE}.} } \value{ a \code{list} containing the following entries: -\itemize{ -\item{sample.id}{a \code{vector} of \code{character} strings representing +\describe{ +\item{sample.id}{ a \code{vector} of \code{character} strings representing the identifiers of the synthetic profiles. } -\item{sample1Kg}{a \code{vector} of \code{character} strings representing +\item{sample1Kg}{ a \code{vector} of \code{character} strings representing the identifiers of the reference 1KG profiles used to generate the synthetic profiles. } -\item{sp}{a \code{vector} of \code{character} strings representing the +\item{sp}{ a \code{vector} of \code{character} strings representing the known ancestry for the reference 1KG profiles used to generate the synthetic profiles. } -\item{matKNN}{a \code{data.frame} containing 4 columns. The first column +\item{matKNN}{ a \code{data.frame} containing 4 columns. The first column 'sample.id' contains the name of the synthetic profile. The second column 'D' represents the dimension D used to infer the ancestry. The third column 'K' represents the number of neighbors K used to infer the ancestry. The diff --git a/man/computeSyntheticConfMat.Rd b/man/computeSyntheticConfMat.Rd index 8709504b4..ab9604d2c 100644 --- a/man/computeSyntheticConfMat.Rd +++ b/man/computeSyntheticConfMat.Rd @@ -41,9 +41,9 @@ the list of possible ancestry assignations.} } \value{ \code{list} containing 2 entries: -\itemize{ -\item{confMat} { a \code{matrix} representing the confusion matrix } -\item{matAccuracy} { a \code{data.frame} containing the statistics +\describe{ +\item{confMat}{ a \code{matrix} representing the confusion matrix } +\item{matAccuracy}{ a \code{data.frame} containing the statistics associated to the confusion matrix} } } diff --git a/man/computeSyntheticROC.Rd b/man/computeSyntheticROC.Rd index c4e8e4f7a..e14b32ef6 100644 --- a/man/computeSyntheticROC.Rd +++ b/man/computeSyntheticROC.Rd @@ -44,7 +44,7 @@ Default: \code{c("EAS", "EUR", "AFR", "AMR", "SAS")}.} } \value{ \code{list} containing 3 entries: -\itemize{ +\describe{ \item{\code{matAUROC.All}}{ a \code{data.frame} containing the AUROC for all the ancestry results. } \item{\code{matAUROC.Call}}{ a \code{data.frame} containing the AUROC diff --git a/man/createAccuracyGraph.Rd b/man/createAccuracyGraph.Rd new file mode 100644 index 000000000..4ec28fa68 --- /dev/null +++ b/man/createAccuracyGraph.Rd @@ -0,0 +1,65 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/visualization.R +\encoding{UTF-8} +\name{createAccuracyGraph} +\alias{createAccuracyGraph} +\title{Generate accuracy graph} +\usage{ +createAccuracyGraph( + fileRDS, + title = "", + selectD = c(3, 7, 11), + selectColor = c("#5e688a", "#cd5700", "#CC79A7") +) +} +\arguments{ +\item{fileRDS}{a \code{character} string representing the path and file +name of the RDS file containing the ancestry information as generated by +RAIDS.} + +\item{title}{a \code{character} string representing the title of the graph. +Default: \code{""}.} + +\item{selectD}{a \code{array} of \code{integer} representing the selected +PCA dimensions to plot. The length of the \code{array} cannot be more than +5 entries. The dimensions must tested by RAIDS (i.e. be present in the +RDS file). Default: \code{c(3,7,11)}.} + +\item{selectColor}{a \code{array} of \code{character} strings representing +the selected colors for the associated PCA dimensions to plot. The length +of the \code{array} must correspond to the length of the \code{selectD} +parameter. In addition, the length of the \code{array} cannot be more than +5 entries. +Default: \code{c("#5e688a", "#cd5700", "#CC79A7")}.} +} +\value{ +a \code{ggplot} object containing the graphic representation of the +accuracy for different values of PCA dimensions and K-neighbors through +all tested ancestries. +} +\description{ +This function extracts the required information from an +output generated by RAIDS to create a graphic representation of the +accuracy for different values of PCA dimensions and K-neighbors through +all tested ancestries. +} +\examples{ + +## Required library +library(ggplot2) + +## Path to RDS file with ancestry information generated by RAIDS (demo file) +dataDir <- system.file("extdata", package="RAIDS") +fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") + +## Create accuracy graph +accuracyGraph <- createAccuracyGraph(fileRDS=fileRDS, title="Test 01", + selectD=c(3,6,9,12,15), + selectColor=c("steelblue", "darkorange", "violet", "pink", "gray80")) + +accuracyGraph + +} +\author{ +Astrid Deschênes and Pascal Belleau +} diff --git a/man/demoKnownSuperPop1KG.Rd b/man/demoKnownSuperPop1KG.Rd index 392e76cbd..055ac3e5c 100644 --- a/man/demoKnownSuperPop1KG.Rd +++ b/man/demoKnownSuperPop1KG.Rd @@ -59,10 +59,10 @@ closefn.gds(gdsProfile) } \seealso{ -\itemize{ -\item \code{\link{computeKNNRefSynthetic}} {for running a k-nearest +\describe{ +\item{\code{\link{computeKNNRefSynthetic}}}{ for running a k-nearest neighbors analysis on a subset of the synthetic data set.} -\item \code{\link{computePoolSyntheticAncestryGr}} { for running a +\item{\code{\link{computePoolSyntheticAncestryGr}}}{ for running a PCA analysis using 1 synthetic profile from each sub-continental population.} } diff --git a/man/demoPCA1KG.Rd b/man/demoPCA1KG.Rd index dd6ab095d..325b2a276 100644 --- a/man/demoPCA1KG.Rd +++ b/man/demoPCA1KG.Rd @@ -10,7 +10,7 @@ and should not be used to call ancestry inference on a real profile.} \format{ The \code{list} containing the PCA results for a small subset of the reference 1KG dataset. The \code{list} contains 2 entries: -\itemize{ +\describe{ \item{pruned}{ a \code{vector} of SNV identifiers specifying selected SNVs for the PCA analysis.} \item{pca.unrel}{ a \code{snpgdsPCAClass} object containing the eigenvalues @@ -23,7 +23,7 @@ data(demoPCA1KG) \value{ The \code{list} containing the PCA results for a small subset of the reference 1KG dataset. The \code{list} contains 2 entries: -\itemize{ +\describe{ \item{pruned}{ a \code{vector} of SNV identifiers specifying selected SNVs for the PCA analysis.} \item{pca.unrel}{ a \code{snpgdsPCAClass} object containing the eigenvalues diff --git a/man/demoPCASyntheticProfiles.Rd b/man/demoPCASyntheticProfiles.Rd index 54ba7501f..7bcf99a3b 100644 --- a/man/demoPCASyntheticProfiles.Rd +++ b/man/demoPCASyntheticProfiles.Rd @@ -9,10 +9,10 @@ The \code{list} containing the PCA result of demo synthetic profiles projected on the demo subset 1KG reference PCA. The \code{list} contains 3 entries: -\itemize{ +\describe{ \item{sample.id}{ a \code{character} string representing the unique identifier of the synthetic profiles.} -\item{eigenvector.ref} { a \code{matrix} of \code{numeric} containing +\item{eigenvector.ref}{ a \code{matrix} of \code{numeric} containing the eigenvectors for the reference profiles.} \item{eigenvector}{ a \code{matrix} of \code{numeric} containing the eigenvectors for the current synthetic profiles projected on the demo @@ -26,10 +26,10 @@ data(demoPCASyntheticProfiles) The \code{list} containing the PCA result of demo synthetic profiles projected on the demo subset 1KG reference PCA. The \code{list} contains 3 entries: -\itemize{ +\describe{ \item{sample.id}{ a \code{character} string representing the unique identifier of the synthetic profiles.} -\item{eigenvector.ref} { a \code{matrix} of \code{numeric} containing +\item{eigenvector.ref}{ a \code{matrix} of \code{numeric} containing the eigenvectors for the reference profiles.} \item{eigenvector}{ a \code{matrix} of \code{numeric} containing the eigenvectors for the current synthetic profiles projected on the demo @@ -79,8 +79,8 @@ closefn.gds(gdsProfile) } \seealso{ -\itemize{ -\item \code{\link{computeKNNRefSynthetic}} {for running a k-nearest +\describe{ +\item{\code{\link{computeKNNRefSynthetic}}}{ for running a k-nearest neighbors analysis on a subset of the synthetic data set.} } } diff --git a/man/demoPedigreeEx1.Rd b/man/demoPedigreeEx1.Rd index bd85ba63e..0dea25bb8 100644 --- a/man/demoPedigreeEx1.Rd +++ b/man/demoPedigreeEx1.Rd @@ -7,7 +7,7 @@ \format{ The \code{data.frame} containing the information about a demo profile called 'ex1'. the \code{data.frame} has 5 columns: -\itemize{ +\describe{ \item{Name.ID}{ a \code{character} string representing the unique identifier of the profile.} \item{Case.ID}{ a \code{character} string representing the unique @@ -26,7 +26,7 @@ data(demoPedigreeEx1) \value{ The \code{data.frame} containing the information about a demo profile called 'ex1'. the \code{data.frame} has 5 columns: -\itemize{ +\describe{ \item{Name.ID}{ a \code{character} string representing the unique identifier of the profile.} \item{Case.ID}{ a \code{character} string representing the unique @@ -129,8 +129,8 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && } \seealso{ -\itemize{ -\item \code{\link{runExomeAncestry}} {for running runs most +\describe{ +\item{\code{\link{runExomeAncestry}}}{ for running runs most steps leading to the ancestry inference call on a specific exome profile.} } diff --git a/man/generateGeneBlock.Rd b/man/generateGeneBlock.Rd index 0c8002910..f369846eb 100644 --- a/man/generateGeneBlock.Rd +++ b/man/generateGeneBlock.Rd @@ -20,18 +20,18 @@ annotation. By default, the \code{EnsDb.Hsapiens.v86} class has been used.} } \value{ a \code{data.frame} with those columns: -\itemize{ -\item{chr} {a single \code{integer} representing the SNV chromosome.} -\item{pos} {a single \code{integer} representing the SNV position.} -\item{snp.allele} {a \code{character} string representing the reference allele +\describe{ +\item{chr}{ a single \code{integer} representing the SNV chromosome.} +\item{pos}{ a single \code{integer} representing the SNV position.} +\item{snp.allele}{ a \code{character} string representing the reference allele and alternative allele for each of the SNV} -\item{Exon} {a \code{character} with the ensembl GeneId(s) if the SNV is in +\item{Exon}{ a \code{character} with the ensembl GeneId(s) if the SNV is in one exon. If more than one GeneId they are separted by ':'} -\item{GName} {a \code{character} with the ensembl GeneId(s) if the SNV is in +\item{GName}{ a \code{character} with the ensembl GeneId(s) if the SNV is in the gene. If more than one GeneId they are separted by ':'} -\item{Gene} {A single \code{integer} specific to the SNVs that share +\item{Gene}{ a single \code{integer} specific to the SNVs that share at least one genes} -\item{GeneS} {A single \code{integer} specific to the SNVs that share +\item{GeneS}{ a single \code{integer} specific to the SNVs that share a unique combination of genes} } "chr", "pos", "snp.allele", "Exon", "GName", "Gene", "GeneS" diff --git a/man/generateMapSnvSel.Rd b/man/generateMapSnvSel.Rd index f18b05a89..67a161329 100644 --- a/man/generateMapSnvSel.Rd +++ b/man/generateMapSnvSel.Rd @@ -36,22 +36,22 @@ indexes of the retained SNP is also created. \details{ The filtered SNP information RDS file (parameter \code{fileFREQ}), contains a \code{data.frame} with those columns: -\itemize{ -\item{CHROM} {a \code{character} string representing the chromosome where +\describe{ +\item{CHROM}{ a \code{character} string representing the chromosome where the SNV is located.} -\item{POS} {a \code{character} string representing the SNV position on the +\item{POS}{ a \code{character} string representing the SNV position on the chromosome.} -\item{REF} {a \code{character} string representing the reference DNA base +\item{REF}{ a \code{character} string representing the reference DNA base for the SNV.} -\item{ALT} {a \code{character} string representing the alternative DNA base +\item{ALT}{ a \code{character} string representing the alternative DNA base for the SNV.}\ -\item{EAS_AF} {a \code{character} string representing the allele frequency +\item{EAS_AF}{ a \code{character} string representing the allele frequency of the EAS super population.} -\item{AFR_AF} {a \code{character} string representing the allele frequency +\item{AFR_AF}{ a \code{character} string representing the allele frequency of the AFR super population.} -\item{AMR_AF} {a \code{character} string representing the allele frequency +\item{AMR_AF}{ a \code{character} string representing the allele frequency of the AMR super population.} -\item{SAS_AF} {a \code{character} string representing the allele frequency +\item{SAS_AF}{ a \code{character} string representing the allele frequency of the SAS super population.} } } diff --git a/man/getTableSNV.Rd b/man/getTableSNV.Rd index 4fc79fece..7f0ef426c 100644 --- a/man/getTableSNV.Rd +++ b/man/getTableSNV.Rd @@ -45,25 +45,25 @@ when the function is running.} } \value{ a \code{data.frame} containing: -\itemize{ -\item{cnt.tot} {a single \code{integer} representing the total coverage for +\describe{ +\item{cnt.tot}{ a single \code{integer} representing the total coverage for the SNV.} -\item{cnt.ref} {a single \code{integer} representing the coverage for +\item{cnt.ref}{ a single \code{integer} representing the coverage for the reference allele.} -\item{cnt.alt} {a single \code{integer} representing the coverage for +\item{cnt.alt}{ a single \code{integer} representing the coverage for the alternative allele.} -\item{snpPos} {a single \code{integer} representing the SNV position.} -\item{snp.chr} {a single \code{integer} representing the SNV chromosome.} -\item{normal.geno} {a single \code{numeric} indicating the genotype of the +\item{snpPos}{ a single \code{integer} representing the SNV position.} +\item{snp.chr}{ a single \code{integer} representing the SNV chromosome.} +\item{normal.geno}{ a single \code{numeric} indicating the genotype of the SNV. The possibles are: \code{0} (wild-type homozygote), \code{1} (heterozygote), \code{2} (altenative homozygote), \code{3} indicating that the normal genotype is unknown.} -\item{pruned} { a \code{logical}} -\item{snp.index} {a \code{vector} of \code{integer} representing the +\item{pruned}{ a \code{logical}} +\item{snp.index}{ a \code{vector} of \code{integer} representing the position of the SNVs in the Reference GDS file.} -\item{keep} {a \code{logical} } -\item{hetero} {a \code{logical} } -\item{homo} {a \code{logical} } +\item{keep}{ a \code{logical} } +\item{hetero}{ a \code{logical} } +\item{homo}{ a \code{logical} } } } \description{ diff --git a/man/matKNNSynthetic.Rd b/man/matKNNSynthetic.Rd index d58692803..02c9630aa 100644 --- a/man/matKNNSynthetic.Rd +++ b/man/matKNNSynthetic.Rd @@ -8,14 +8,14 @@ inferred ancestry on the synthetic profiles.} \format{ The \code{data.frame} containing the information about the synthetic profiles. The \code{data.frame} contains 4 columns: -\itemize{ -\item \code{sample.id} {a \code{character} string representing the unique +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique synthetic profile identifier.} -\item \code{D} {a \code{numeric} representing the number of dimensions used +\item{\code{D}}{ a \code{numeric} representing the number of dimensions used to infer the ancestry of the synthetic profile.} -\item \code{K} {a \code{numeric} representing the number of neighbors used +\item{\code{K}}{ a \code{numeric} representing the number of neighbors used to infer the ancestry of the synthetic profile.} -\item \code{SuperPop} {a \code{character} string representing the +\item{\code{SuperPop}}{ a \code{character} string representing the inferred ancestry of the synthetic profile for the specific D and K values.} } } @@ -25,14 +25,14 @@ data(matKNNSynthetic) \value{ The \code{data.frame} containing the information about the synthetic profiles. The \code{data.frame} contains 4 columns: -\itemize{ -\item \code{sample.id} {a \code{character} string representing the unique +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique synthetic profile identifier.} -\item \code{D} {a \code{numeric} representing the number of dimensions used +\item{\code{D}}{ a \code{numeric} representing the number of dimensions used to infer the ancestry of the synthetic profile.} -\item \code{K} {a \code{numeric} representing the number of neighbors used +\item{\code{K}}{ a \code{numeric} representing the number of neighbors used to infer the ancestry of the synthetic profile.} -\item \code{SuperPop} {a \code{character} string representing the +\item{\code{SuperPop}}{ a \code{character} string representing the inferred ancestry of the synthetic profile for the specific D and K values.} } } @@ -70,8 +70,8 @@ results$listROC.Call } \seealso{ -\itemize{ -\item \code{\link{computeSyntheticROC}} {for calculating the AUROC of +\describe{ +\item{\code{\link{computeSyntheticROC}}}{ for calculating the AUROC of the inferences for specific values of D and K using the inferred ancestry results from the synthetic profiles} } diff --git a/man/pedSynthetic.Rd b/man/pedSynthetic.Rd index 6139c30c2..4e8fad85e 100644 --- a/man/pedSynthetic.Rd +++ b/man/pedSynthetic.Rd @@ -11,20 +11,20 @@ The \code{data.frame} containing the information about the synthetic profiles. The row names of the \code{data.frame} correspond to the profile unique identifiers. The \code{data.frame} contains 7 columns: -\itemize{ -\item \code{data.id} {a \code{character} string representing the unique +\describe{ +\item{\code{data.id}}{ a \code{character} string representing the unique synthetic profile identifier.} -\item \code{case.id} {a \code{character} string representing the unique +\item{\code{case.id}}{ a \code{character} string representing the unique profile identifier that was used to generate the synthetic profile.} -\item \code{sample.type} {a \code{character} string representing the type +\item{\code{sample.type}}{ a \code{character} string representing the type of profile. } -\item \code{diagnosis} {a \code{character} string representing the +\item{\code{diagnosis}}{ a \code{character} string representing the diagnosis of profile that was used to generate the synthetic profile. } -\item \code{source} {a \code{character} string representing the +\item{\code{source}}{ a \code{character} string representing the source of the synthetic profile. } -\item \code{study.id} {a \code{character} string representing the +\item{\code{study.id}}{ a \code{character} string representing the name of the study to which the synthetic profile is associated. } -\item \code{superPop} {a \code{character} string representing the +\item{\code{superPop}}{ a \code{character} string representing the super population of the profile that was used to generate the synthetic profile. } } @@ -34,23 +34,23 @@ data(pedSynthetic) } \value{ The \code{data.frame} containing the information about the -synthetic profiles. The row names of +synthetic profiles. The row names of the \code{data.frame} correspond to the profile unique identifiers. The \code{data.frame} contains 7 columns: -\itemize{ -\item \code{data.id} {a \code{character} string representing the unique +\describe{ +\item{\code{data.id}}{ a \code{character} string representing the unique synthetic profile identifier.} -\item \code{case.id} {a \code{character} string representing the unique +\item{\code{case.id}}{ a \code{character} string representing the unique profile identifier that was used to generate the synthetic profile.} -\item \code{sample.type} {a \code{character} string representing the type -of profile. } -\item \code{diagnosis} {a \code{character} string representing the +\item{\code{sample.type}}{ a \code{character} string representing the type +of profile.} +\item{\code{diagnosis}}{ a \code{character} string representing the diagnosis of profile that was used to generate the synthetic profile. } -\item \code{source} {a \code{character} string representing the +\item{\code{source}}{ a \code{character} string representing the source of the synthetic profile. } -\item \code{study.id} {a \code{character} string representing the +\item{\code{study.id}}{ a \code{character} string representing the name of the study to which the synthetic profile is associated. } -\item \code{superPop} {a \code{character} string representing the +\item{\code{superPop}}{ a \code{character} string representing the super population of the profile that was used to generate the synthetic profile. } } @@ -90,8 +90,8 @@ results$listROC.Call } \seealso{ -\itemize{ -\item \code{\link{computeSyntheticROC}} {for calculating the AUROC of +\describe{ +\item{\code{\link{computeSyntheticROC}}}{ for calculating the AUROC of the inferences for specific values of D and K using the inferred ancestry results from the synthetic profiles} } diff --git a/man/prepPed1KG.Rd b/man/prepPed1KG.Rd index 6921ff137..c7902315a 100644 --- a/man/prepPed1KG.Rd +++ b/man/prepPed1KG.Rd @@ -28,16 +28,16 @@ Default: \code{0L}.} \value{ a \code{data.frame} containing the needed pedigree information from Reference. The \code{data.frame} contains those columns: -\itemize{ -\item{sample.id}{a \code{character} string representing the profile unique +\describe{ +\item{sample.id}{ a \code{character} string representing the profile unique ID.} -\item{Name.ID}{a \code{character} string representing the profile name.} +\item{Name.ID}{ a \code{character} string representing the profile name.} \item{sex}{a \code{character} string representing the sex of the profile.} -\item{pop.group}{a \code{character} string representing the +\item{pop.group}{ a \code{character} string representing the sub-continental ancestry of the profile.} -\item{superPop }{a \code{character} string representing the continental +\item{superPop }{ a \code{character} string representing the continental ancestry of the profile.} -\item{superPop }{a \code{integer} representing the batch of the profile.} +\item{superPop }{ a \code{integer} representing the batch of the profile.} } } \description{ diff --git a/man/readSNVFileGeneric.Rd b/man/readSNVFileGeneric.Rd index 38319b2f4..64aad2908 100644 --- a/man/readSNVFileGeneric.Rd +++ b/man/readSNVFileGeneric.Rd @@ -20,7 +20,7 @@ is added to the position present in the file. Default: \code{0L}.} } \value{ a \code{data.frame} containing at least: -\itemize{ +\describe{ \item{Chromosome}{ a \code{numeric} representing the name of the chromosome} \item{Position}{ a \code{numeric} representing the position on the @@ -28,11 +28,11 @@ chromosome} \item{Ref}{ a \code{character} string representing the reference nucleotide} \item{Alt}{ a \code{character} string representing the alternative nucleotide} -\item{File1R} { a \code{numeric} representing the count for +\item{File1R}{ a \code{numeric} representing the count for the reference nucleotide} -\item{File1A} { a \code{numeric} representing the count for the +\item{File1A}{ a \code{numeric} representing the count for the alternative nucleotide} -\item{count} { a \code{numeric} representing the total count} +\item{count}{ a \code{numeric} representing the total count} } } \description{ diff --git a/man/readSNVPileupFile.Rd b/man/readSNVPileupFile.Rd index 30ce01657..956ad047f 100644 --- a/man/readSNVPileupFile.Rd +++ b/man/readSNVPileupFile.Rd @@ -20,7 +20,7 @@ is added to the position present in the file. Default: \code{0L}.} } \value{ the a \code{data.frame} containing at least: -\itemize{ +\describe{ \item{Chromosome}{ a \code{numeric} representing the name of the chromosome} \item{Position}{ a \code{numeric} representing the position on the @@ -28,15 +28,15 @@ chromosome} \item{Ref}{ a \code{character} string representing the reference nucleotide} \item{Alt}{ a \code{character} string representing the alternative nucleotide} -\item{File1R} { a \code{numeric} representing the count for +\item{File1R}{ a \code{numeric} representing the count for the reference nucleotide} -\item{File1A} { a \code{numeric} representing the count for the +\item{File1A}{ a \code{numeric} representing the count for the alternative nucleotide} -\item{File1E} {a \code{numeric} representing the count for the +\item{File1E}{a \code{numeric} representing the count for the errors} -\item{File1D} {a \code{numeric} representing the count for the +\item{File1D}{a \code{numeric} representing the count for the deletions} -\item{count} { a \code{numeric} representing the total count} +\item{count}{ a \code{numeric} representing the total count} } } \description{ diff --git a/man/readSNVVCF.Rd b/man/readSNVVCF.Rd index 6aadf71bb..27e3d94c9 100644 --- a/man/readSNVVCF.Rd +++ b/man/readSNVVCF.Rd @@ -20,7 +20,7 @@ is added to the position present in the file. Default: \code{0L}.} } \value{ a \code{data.frame} containing at least: -\itemize{ +\describe{ \item{Chromosome}{ a \code{numeric} representing the name of the chromosome} \item{Position}{ a \code{numeric} representing the position on the @@ -28,11 +28,11 @@ chromosome} \item{Ref}{ a \code{character} string representing the reference nucleotide} \item{Alt}{ a \code{character} string representing the alternative nucleotide} -\item{File1R} { a \code{numeric} representing the count for +\item{File1R}{ a \code{numeric} representing the count for the reference nucleotide} -\item{File1A} { a \code{numeric} representing the count for the +\item{File1A}{ a \code{numeric} representing the count for the alternative nucleotide} -\item{count} { a \code{numeric} representing the total count} +\item{count}{ a \code{numeric} representing the total count} } } \description{ diff --git a/man/runExomeAncestry.Rd b/man/runExomeAncestry.Rd index 3b4e0d76f..b2e9a0141 100644 --- a/man/runExomeAncestry.Rd +++ b/man/runExomeAncestry.Rd @@ -63,12 +63,12 @@ representing the length of the chromosomes. See 'details' section.} \item{syntheticRefDF}{a \code{data.frame} containing a subset of reference profiles for each sub-population present in the Reference GDS file. The \code{data.frame} must have those columns: -\itemize{ -\item{sample.id} { a \code{character} string representing the sample +\describe{ +\item{sample.id}{ a \code{character} string representing the sample identifier. } -\item{pop.group} { a \code{character} string representing the +\item{pop.group}{ a \code{character} string representing the subcontinental population assigned to the sample. } -\item{superPop} { a \code{character} string representing the +\item{superPop}{ a \code{character} string representing the super-population assigned to the sample. } }} @@ -102,12 +102,12 @@ RDS Sample description file and the Population reference GDS file. \details{ The runExomeAncestry() function generates 3 types of files in the OUTPUT directory. -\itemize{ -\item{Ancestry Inference}{The ancestry inference CSV file +\describe{ +\item{Ancestry Inference}{ The ancestry inference CSV file (".Ancestry.csv" file)} -\item{Inference Informaton}{The inference information RDS file +\item{Inference Informaton}{ The inference information RDS file (".infoCall.rds" file)} -\item{Synthetic Information}{The parameter information RDS files +\item{Synthetic Information}{ The parameter information RDS files from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} } diff --git a/man/runIBDKING.Rd b/man/runIBDKING.Rd index bc74b36c8..8665451cb 100644 --- a/man/runIBDKING.Rd +++ b/man/runIBDKING.Rd @@ -29,7 +29,7 @@ the process in the \code{\link[SNPRelate]{snpgdsIBDKING}}() function.} } \value{ a \code{list} containing: -\itemize{ +\describe{ \item{sample.id}{a \code{character} string representing the sample ids used in the analysis} \item{snp.id}{a \code{character} string representing the SNP ids diff --git a/man/runProfileAncestry.Rd b/man/runProfileAncestry.Rd index 3cd052c90..f578560e9 100644 --- a/man/runProfileAncestry.Rd +++ b/man/runProfileAncestry.Rd @@ -52,12 +52,12 @@ representing the length of the chromosomes. See 'details' section.} \item{syntheticRefDF}{a \code{data.frame} containing a subset of reference profiles for each sub-population present in the Reference GDS file. The \code{data.frame} must have those columns: -\itemize{ -\item{sample.id} { a \code{character} string representing the sample +\describe{ +\item{sample.id}{ a \code{character} string representing the sample identifier. } -\item{pop.group} { a \code{character} string representing the +\item{pop.group}{ a \code{character} string representing the subcontinental population assigned to the sample. } -\item{superPop} { a \code{character} string representing the +\item{superPop}{ a \code{character} string representing the super-population assigned to the sample. } }} @@ -98,12 +98,12 @@ description file and the Population reference GDS file. \details{ The runWrapperAncestry() function generates 3 types of files in the \code{pathOut} directory: -\itemize{ -\item{Ancestry Inference}{The ancestry inference CSV file +\describe{ +\item{Ancestry Inference}{ The ancestry inference CSV file (".Ancestry.csv" file)} -\item{Inference Informaton}{The inference information RDS file +\item{Inference Informaton}{ The inference information RDS file (".infoCall.rds" file)} -\item{Synthetic Information}{The parameter information RDS files +\item{Synthetic Information}{ The parameter information RDS files from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} } diff --git a/man/runRNAAncestry.Rd b/man/runRNAAncestry.Rd index 0e07a4394..712409b70 100644 --- a/man/runRNAAncestry.Rd +++ b/man/runRNAAncestry.Rd @@ -64,12 +64,12 @@ representing the length of the chromosomes. See 'details' section.} \item{syntheticRefDF}{a \code{data.frame} containing a subset of reference profiles for each sub-population present in the Reference GDS file. The \code{data.frame} must have those columns: -\itemize{ -\item{sample.id} { a \code{character} string representing the sample +\describe{ +\item{sample.id}{ a \code{character} string representing the sample identifier. } -\item{pop.group} { a \code{character} string representing the +\item{pop.group}{ a \code{character} string representing the subcontinental population assigned to the sample. } -\item{superPop} { a \code{character} string representing the +\item{superPop}{ a \code{character} string representing the super-population assigned to the sample. } }} @@ -107,12 +107,12 @@ RDS Sample description file and the Population Reference GDS file. \details{ The runExomeAncestry() function generates 3 types of files in the OUTPUT directory. -\itemize{ -\item{Ancestry Inference}{The ancestry inference CSV file +\describe{ +\item{Ancestry Inference}{ The ancestry inference CSV file (".Ancestry.csv" file)} -\item{Inference Informaton}{The inference information RDS file +\item{Inference Informaton}{ The inference information RDS file (".infoCall.rds" file)} -\item{Synthetic Information}{The parameter information RDS files +\item{Synthetic Information}{ The parameter information RDS files from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} } diff --git a/man/runWrapperAncestry.Rd b/man/runWrapperAncestry.Rd index f1024f8d3..7f27cc776 100644 --- a/man/runWrapperAncestry.Rd +++ b/man/runWrapperAncestry.Rd @@ -64,12 +64,12 @@ representing the length of the chromosomes. See 'details' section.} \item{syntheticRefDF}{a \code{data.frame} containing a subset of reference profiles for each sub-population present in the Reference GDS file. The \code{data.frame} must have those columns: -\itemize{ -\item{sample.id} { a \code{character} string representing the sample +\describe{ +\item{sample.id}{ a \code{character} string representing the sample identifier. } -\item{pop.group} { a \code{character} string representing the +\item{pop.group}{ a \code{character} string representing the subcontinental population assigned to the sample. } -\item{superPop} { a \code{character} string representing the +\item{superPop}{ a \code{character} string representing the super-population assigned to the sample. } }} @@ -111,12 +111,12 @@ description file and the Population reference GDS file. \details{ The runWrapperAncestry() function generates 3 types of files in the \code{pathOut} directory. -\itemize{ -\item{Ancestry Inference}{The ancestry inference CSV file +\describe{ +\item{Ancestry Inference}{ The ancestry inference CSV file (".Ancestry.csv" file)} -\item{Inference Informaton}{The inference information RDS file +\item{Inference Informaton}{ The inference information RDS file (".infoCall.rds" file)} -\item{Synthetic Information}{The parameter information RDS files +\item{Synthetic Information}{ The parameter information RDS files from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} } diff --git a/man/selParaPCAUpQuartile.Rd b/man/selParaPCAUpQuartile.Rd index 25b94167c..57effa389 100644 --- a/man/selParaPCAUpQuartile.Rd +++ b/man/selParaPCAUpQuartile.Rd @@ -52,11 +52,11 @@ Default: \code{seq(2,15,1)}.} } \value{ a \code{list} containing 5 entries: -\itemize{ -\item{\code{dfPCA}} { a \code{data.frame} containing statistical results +\describe{ +\item{\code{dfPCA}}{ a \code{data.frame} containing statistical results on all combined synthetic results done with a fixed value of \code{D} (the number of dimensions). The \code{data.frame} contains those columns: -\itemize{ +\describe{ \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the number of dimensions).} \item{\code{median}}{ a \code{numeric} representing the median of the @@ -72,11 +72,11 @@ combination of the fixed \code{D} value and all tested \code{K} values. } (the number of neighbors) for a fixed \code{D} value. } } } -\item{\code{dfPop}} { a \code{data.frame} containing statistical results on +\item{\code{dfPop}}{ a \code{data.frame} containing statistical results on all combined synthetic results done with different values of \code{D} (the number of dimensions) and \code{K} (the number of neighbors). The \code{data.frame} contains those columns: -\itemize{ +\describe{ \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the number of dimensions).} \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the @@ -92,11 +92,11 @@ of the confusion matrix obtained by grouping all the synthetic results for the specified values of \code{D} and \code{K}.} } } -\item{\code{D}} { a \code{numeric} representing the optimal \code{D} value +\item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value (the number of dimensions) for the specific profile.} -\item{\code{K}} { a \code{numeric} representing the optimal \code{K} value +\item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value (the number of neighbors) for the specific profile.} -\item{\code{listD}} { a \code{numeric} representing the optimal \code{D} +\item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} values (the number of dimensions) for the specific profile. More than one \code{D} is possible.} } diff --git a/man/select1KGPop.Rd b/man/select1KGPop.Rd index 4bbedab8b..80a60bc1d 100644 --- a/man/select1KGPop.Rd +++ b/man/select1KGPop.Rd @@ -21,12 +21,12 @@ subcontinental population will correspond to the size of this population.} } \value{ a \code{data.frame} containing those columns: -\itemize{ -\item{sample.id} { a \code{character} string representing the sample +\describe{ +\item{sample.id}{ a \code{character} string representing the sample identifier. } -\item{pop.group} { a \code{character} string representing the +\item{pop.group}{ a \code{character} string representing the subcontinental population assigned to the sample. } -\item{superPop} { a \code{character} string representing the +\item{superPop}{ a \code{character} string representing the super-population assigned to the sample. } } } diff --git a/man/snpPositionDemo.Rd b/man/snpPositionDemo.Rd index e0c857c04..a4774fba5 100644 --- a/man/snpPositionDemo.Rd +++ b/man/snpPositionDemo.Rd @@ -8,37 +8,40 @@ SNV information.} \format{ The \code{data.frame} containing the information about the synthetic profiles. The \code{data.frame} contains 4 columns: -\itemize{ -\item \code{cnt.tot} {a \code{integer} representing the number of reads at +\describe{ +\item{\code{cnt.tot}}{ a \code{integer} representing the number of reads at the SNV position.} -\item \code{cnt.ref} {a \code{integer} representing the number of reads +\item{\code{cnt.ref}}{ a \code{integer} representing the number of reads corresponding to the reference at the SNV position.} -\item \code{cnt.alt} {a \code{integer} representing the number of reads +\item{\code{cnt.alt}}{ a \code{integer} representing the number of reads different than the reference at the SNV position.} -\item \code{snp.pos} {a \code{integer} representing the position of the +\item{\code{snp.pos}}{ a \code{integer} representing the position of the SNV on the chromosome.} -\item \code{snp.chr} {a \code{integer} representing the chromosome on which +\item{\code{snp.chr}}{ a \code{integer} representing the chromosome on which the SNV is located.} -\item \code{normal.geno} {a \code{integer} representing the genotype -(0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown).} -\item \code{pruned} {a \code{logical} indicated if the SNV is pruned.} -\item \code{snp.index} {a \code{integer} representing the index of the +\item{\code{normal.geno}}{ a \code{integer} representing the genotype +(0=wild-type reference; 1=heterozygote; 2=homozygote alternative; +3=unkown).} +\item{\code{pruned}}{ a \code{logical} indicated if the SNV is pruned.} +\item{\code{snp.index}}{ a \code{integer} representing the index of the SNV in the reference SNV GDS file.} -\item \code{keep} {a \code{logical} indicated if the genotype +\item{\code{keep}}{ a \code{logical} indicated if the genotype exists for the SNV.} -\item \code{hetero} {a \code{logical} indicated if the SNV is heterozygote.} -\item \code{homo} {a \code{logical} indicated if the SNV is homozygote.} -\item \code{block.id} {a \code{integer} representing the block identifier +\item{\code{hetero}}{ a \code{logical} indicated if the SNV is +heterozygote.} +\item{\code{homo}}{ a \code{logical} indicated if the SNV is homozygote.} +\item{\code{block.id}}{ a \code{integer} representing the block identifier associated to the current SNV.} -\item \code{phase} {a \code{integer} representing the block identifier +\item{\code{phase}}{ a \code{integer} representing the block identifier associated to the current SNV.} -\item \code{lap} {a \code{numeric} representing the lower allelic fraction.} -\item \code{LOH} {a \code{integer} indicating if the SNV is in an LOH region -(0=not LOH, 1=in LOH).} -\item \code{imbAR} {a \code{integer} indicating if the SNV is in an +\item{\code{lap}}{ a \code{numeric} representing the lower allelic +fraction.} +\item{\code{LOH}}{ a \code{integer} indicating if the SNV is in an LOH +region (0=not LOH, 1=in LOH).} +\item{\code{imbAR}}{ a \code{integer} indicating if the SNV is in an imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; 1=tested positive for imbalance in at least 1 window).} -\item \code{freq} {a \code{numeric} representing the frequency of the +\item{\code{freq}}{ a \code{numeric} representing the frequency of the variant in the the reference.} } } @@ -48,37 +51,37 @@ data(snpPositionDemo) \value{ The \code{data.frame} containing the information about the synthetic profiles. The \code{data.frame} contains 4 columns: -\itemize{ -\item \code{cnt.tot} {a \code{integer} representing the number of reads at +\describe{ +\item{\code{cnt.tot}}{ a \code{integer} representing the number of reads at the SNV position.} -\item \code{cnt.ref} {a \code{integer} representing the number of reads +\item{\code{cnt.ref}}{ a \code{integer} representing the number of reads corresponding to the reference at the SNV position.} -\item \code{cnt.alt} {a \code{integer} representing the number of reads +\item{\code{cnt.alt}}{ a \code{integer} representing the number of reads different than the reference at the SNV position.} -\item \code{snp.pos} {a \code{integer} representing the position of the +\item{\code{snp.pos}}{ a \code{integer} representing the position of the SNV on the chromosome.} -\item \code{snp.chr} {a \code{integer} representing the chromosome on which +\item{\code{snp.chr}}{ a \code{integer} representing the chromosome on which the SNV is located.} -\item \code{normal.geno} {a \code{integer} representing the genotype +\item{\code{normal.geno}}{ a \code{integer} representing the genotype (0=wild-type reference; 1=heterozygote; 2=homozygote alternative; 3=unkown).} -\item \code{pruned} {a \code{logical} indicated if the SNV is pruned.} -\item \code{snp.index} {a \code{integer} representing the index of the +\item{\code{pruned}}{ a \code{logical} indicated if the SNV is pruned.} +\item{\code{snp.index}}{ a \code{integer} representing the index of the SNV in the reference SNV GDS file.} -\item \code{keep} {a \code{logical} indicated if the genotype +\item{\code{keep}}{ a \code{logical} indicated if the genotype exists for the SNV.} -\item \code{hetero} {a \code{logical} indicated if the SNV is heterozygote.} -\item \code{homo} {a \code{logical} indicated if the SNV is homozygote.} -\item \code{block.id} {a \code{integer} representing the block identifier +\item{\code{hetero}}{ a \code{logical} indicated if the SNV is heterozygote.} +\item{\code{homo}}{ a \code{logical} indicated if the SNV is homozygote.} +\item{\code{block.id}}{ a \code{integer} representing the block identifier associated to the current SNV.} -\item \code{phase} {a \code{integer} representing the block identifier +\item{\code{phase}}{ a \code{integer} representing the block identifier associated to the current SNV.} -\item \code{lap} {a \code{numeric} representing the lower allelic fraction.} -\item \code{LOH} {a \code{integer} indicating if the SNV is in an LOH region +\item{\code{lap}}{ a \code{numeric} representing the lower allelic fraction.} +\item{\code{LOH}}{ a \code{integer} indicating if the SNV is in an LOH region (0=not LOH, 1=in LOH).} -\item \code{imbAR} {a \code{integer} indicating if the SNV is in an +\item{\code{imbAR}}{ a \code{integer} indicating if the SNV is in an imbalanced region (-1=not classified as imbalanced or LOH, 0=in LOH; 1=tested positive for imbalance in at least 1 window).} -\item \code{freq} {a \code{numeric} representing the frequency of the +\item{\code{freq}}{ a \code{numeric} representing the frequency of the variant in the the reference.} } } diff --git a/man/splitSelectByPop.Rd b/man/splitSelectByPop.Rd index fdeb556d3..586bbd65c 100644 --- a/man/splitSelectByPop.Rd +++ b/man/splitSelectByPop.Rd @@ -9,12 +9,12 @@ splitSelectByPop(dataRef) } \arguments{ \item{dataRef}{a \code{data.frame} containing those columns: -\itemize{ -\item{sample.id} { a \code{character} string representing the sample +\describe{ +\item{sample.id}{ a \code{character} string representing the sample identifier. } -\item{pop.group} { a \code{character} string representing the +\item{pop.group}{ a \code{character} string representing the subcontinental population assigned to the sample. } -\item{superPop} { a \code{character} string representing the +\item{superPop}{ a \code{character} string representing the super-population assigned to the sample. } }} } diff --git a/man/tableBlockAF.Rd b/man/tableBlockAF.Rd index 232ecf86c..9b7e2747d 100644 --- a/man/tableBlockAF.Rd +++ b/man/tableBlockAF.Rd @@ -16,32 +16,32 @@ the SNVs with coverage > \code{minCov}, for a specific chromosome.} a \code{data.frame} containing only heterozygote SNV information. The \code{data.frame} contain those columns: -\itemize{ -\item{block} {a single \code{integer} representing the unique identifier +\describe{ +\item{block}{ a single \code{integer} representing the unique identifier of the block.} -\item{aRF} {a single \code{numeric} representing the final allelic +\item{aRF}{ a single \code{numeric} representing the final allelic fraction; not computed yet, \code{-1} value assigned to all entries.} -\item{aFraction} {a single \code{integer} representing the possible allelic +\item{aFraction}{a single \code{integer} representing the possible allelic fraction in absence of loss of heterozygosity (LOH).} -\item{lR} {a single \code{integer} representing the coverage for +\item{lR}{ a single \code{integer} representing the coverage for the alternative allele.} -\item{nPhase} {a single \code{integer} representing the number of SNV +\item{nPhase}{ a single \code{integer} representing the number of SNV phases.} -\item{sumAlleleLow} {a single \code{integer} representing the sum of the +\item{sumAlleleLow}{ a single \code{integer} representing the sum of the alleles with the less coverage.} -\item{sumAlleleHigh} {a single \code{integer} representing the sum of +\item{sumAlleleHigh}{ a single \code{integer} representing the sum of the alleles with more coverage.} -\item{lH} {a single \code{numeric} for the homozygotes log10 of the product +\item{lH}{ a single \code{numeric} for the homozygotes log10 of the product frequencies of the allele not found in the profile (not a probability).} -\item{lM} {a single \code{numeric} log10 product frequency allele +\item{lM}{ a single \code{numeric} log10 product frequency allele in population.} -\item{lRhomo} {a single \code{numeric} representing the score +\item{lRhomo}{a single \code{numeric} representing the score \code{lH} - \code{lM}.} -\item{nbHomo} {a single \code{integer} representing the number of +\item{nbHomo}{ a single \code{integer} representing the number of homozygote SNVs per block.} -\item{nbKeep} {a single \code{integer} representing the number of +\item{nbKeep}{ a single \code{integer} representing the number of SNVs retained per block.} -\item{nbHetero} {a single \code{integer} representing the number of +\item{nbHetero}{ a single \code{integer} representing the number of heterozygote SNVs per block.} } } diff --git a/man/testAlleleFractionChange.Rd b/man/testAlleleFractionChange.Rd index d200209b3..6d5412e80 100644 --- a/man/testAlleleFractionChange.Rd +++ b/man/testAlleleFractionChange.Rd @@ -11,10 +11,10 @@ testAlleleFractionChange(matCov, pCutOff = -3, vMean) \arguments{ \item{matCov}{a \code{data.frame} containing only heterozygote SNVs. The \code{data.frame} must contain those columns: -\itemize{ -\item{cnt.ref} {a single \code{integer} representing the coverage for +\describe{ +\item{cnt.ref}{ a single \code{integer} representing the coverage for the reference allele.} -\item{cnt.alt} {a single \code{integer} representing the coverage for +\item{cnt.alt}{ a single \code{integer} representing the coverage for the alternative allele.} }} @@ -29,16 +29,16 @@ reference to see if there is a allelic fraction change.} } \value{ a \code{list} containing 4 entries: -\itemize{ +\describe{ \item{pWin}{ a \code{vector} of \code{numeric} representing the probability (x2) of obtaining the current alternative/(alternative+reference) ratio from a reference distribution specified by user.} -\item{p}{a \code{integer} indicating if all SNVs tested +\item{p}{ a \code{integer} indicating if all SNVs tested positive (1=TRUE, 0=FALSE). The cut-off is 0.5. } -\item{pCut}{a \code{integer} indicating if all SNVs tested +\item{pCut}{ a \code{integer} indicating if all SNVs tested positive (1=TRUE, 0-FALSE). } -\item{pCut1}{a \code{integer} indicating if the region tested +\item{pCut1}{ a \code{integer} indicating if the region tested positive (1=TRUE, 0=FALSE) for allelic ratio change.} } } diff --git a/man/testEmptyBox.Rd b/man/testEmptyBox.Rd index d7c838bad..e5520967f 100644 --- a/man/testEmptyBox.Rd +++ b/man/testEmptyBox.Rd @@ -11,10 +11,10 @@ testEmptyBox(matCov, pCutOff = -3) \arguments{ \item{matCov}{a \code{data.frame} containing only heterozygote SNVs. The \code{data.frame} must contain those columns: -\itemize{ -\item{cnt.ref} {a single \code{integer} representing the coverage for +\describe{ +\item{cnt.ref}{ a single \code{integer} representing the coverage for the reference allele.} -\item{cnt.alt} {a single \code{integer} representing the coverage for +\item{cnt.alt}{ a single \code{integer} representing the coverage for the alternative allele.} }} @@ -24,7 +24,7 @@ likelihood not to be imbalanced. Default: \code{-3}.} } \value{ a \code{list} containing 4 entries: -\itemize{ +\describe{ \item{pWin}{ a \code{vector} of \code{numeric} representing the probability (x2) of obtaining the current alternative/(alternative+reference) ratio from a 0.5 distribution.} diff --git a/man/validateCreateAccuracyGraph.Rd b/man/validateCreateAccuracyGraph.Rd new file mode 100644 index 000000000..81ddcf818 --- /dev/null +++ b/man/validateCreateAccuracyGraph.Rd @@ -0,0 +1,50 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/visualization_internal.R +\encoding{UTF-8} +\name{validateCreateAccuracyGraph} +\alias{validateCreateAccuracyGraph} +\title{Validate input parameters for createAccuracyGraph +function} +\usage{ +validateCreateAccuracyGraph(fileRDS, title, selectD, selectColor) +} +\arguments{ +\item{fileRDS}{a \code{character} string representing the path and file +name of the RDS file containing the ancestry information as generated by +RAIDS.} + +\item{title}{a \code{character} string representing the title of the graph.} + +\item{selectD}{a \code{array} of \code{integer} representing the selected +PCA dimensions to plot. The length of the \code{array} cannot be more than +5 entries. The dimensions must tested by RAIDS (i.e. be present in the +RDS file).} + +\item{selectColor}{a \code{array} of \code{character} strings representing +the selected colors for the associated PCA dimensions to plot. The length +of the \code{array} must correspond to the length of the \code{selectD} +parameter. In addition, the length of the \code{array} cannot be more than +5 entries.} +} +\value{ +The function returns \code{0L} when successful. +} +\description{ +This function validates the parameters for the +\code{\link{createAccuracyGraph}} function. +} +\examples{ + +## Path to RDS file with ancestry information generated by RAIDS (demo file) +dataDir <- system.file("extdata", package="RAIDS") +fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") + +## Validate parameters +RAIDS:::validateCreateAccuracyGraph(fileRDS=fileRDS, title="Accuracy Graph", + selectD=c(5, 10), selectColor=c("blue","darkblue")) + +} +\author{ +Astrid Deschênes and Pascal Belleau +} +\keyword{internal} diff --git a/man/validateProfileGDSExist.Rd b/man/validateProfileGDSExist.Rd index 9adcb1d72..e507e518b 100644 --- a/man/validateProfileGDSExist.Rd +++ b/man/validateProfileGDSExist.Rd @@ -11,7 +11,7 @@ validateProfileGDSExist(pathProfile, profile) \item{pathProfile}{a \code{character} string representing the directory where the Profile GDS files will be created. The directory must exist.} -\item{currentProfile}{a \code{character} string +\item{profile}{a \code{character} string corresponding to the profile identifier. A Profile GDS file corresponding to the profile identifier must exist and be located in the \code{pathProfile} directory.} diff --git a/man/validateRunExomeOrRNAAncestry.Rd b/man/validateRunExomeOrRNAAncestry.Rd index 8b13619a4..52029c1bc 100644 --- a/man/validateRunExomeOrRNAAncestry.Rd +++ b/man/validateRunExomeOrRNAAncestry.Rd @@ -57,12 +57,12 @@ The file must exist.} representing the length of the chromosomes. See 'details' section.} \item{syntheticRefDF}{a \code{data.frame} containing those columns: -\itemize{ -\item{sample.id} { a \code{character} string representing the sample +\describe{ +\item{sample.id}{ a \code{character} string representing the sample identifier. } -\item{pop.group} { a \code{character} string representing the +\item{pop.group}{ a \code{character} string representing the subcontinental population assigned to the sample. } -\item{superPop} { a \code{character} string representing the +\item{superPop}{ a \code{character} string representing the super-population assigned to the sample. } }} diff --git a/tests/testthat/fixtures/TEST_01.infoCall.RDS b/tests/testthat/fixtures/TEST_01.infoCall.RDS new file mode 100644 index 0000000000000000000000000000000000000000..10e2d7170b327c39150bee66925fee412552ae15 GIT binary patch literal 8408 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 s*Mp)uu~pl+im85Br! Date: Fri, 16 Aug 2024 17:56:41 -0400 Subject: [PATCH 282/385] Update test to correct error --- tests/testthat/test-visualization.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-visualization.R b/tests/testthat/test-visualization.R index ab69d428a..d32b5f218 100644 --- a/tests/testthat/test-visualization.R +++ b/tests/testthat/test-visualization.R @@ -38,7 +38,7 @@ test_that("createAccuracyGraph() must return error when fileRDS is not RDS", { expect_error(createAccuracyGraph(fileRDS=fileGDS, title="", selectD=c(3,7,11), selectColor=c("#5e688a", "#cd5700", "#CC79A7")), - error_message) + error_message, fixed=TRUE) }) From 23f9fa526b893fcc8d3218dc8e75af43be9211ef Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 16 Aug 2024 18:12:20 -0400 Subject: [PATCH 283/385] Update to r 4.4 and bioc 3.19 --- .github/workflows/check-bioc.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index 69b85aa46..9a39ec64b 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -52,9 +52,9 @@ jobs: matrix: config: ## - { os: ubuntu-latest, r: '4.2.2', bioc: '3.16', cont: "bioconductor/bioconductor_docker:RELEASE_3_16", rspm: "https://packagemanager.posit.co" } - - { os: ubuntu-latest, r: '4.3', bioc: '3.17', cont: "bioconductor/bioconductor_docker:RELEASE_3_17", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + - { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } ## - { os: macOS-latest, r: '4.2.2', bioc: '3.16'} - - { os: macOS-latest, r: '4.3', bioc: '3.17'} + - { os: macOS-latest, r: '4.4', bioc: '3.19'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true From 4a66297dcce901b4dbd1a435e4ede548cfdcf115 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 16 Aug 2024 18:28:14 -0400 Subject: [PATCH 284/385] Update biocViews section --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 86a88d2f1..e6f7afece 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -55,6 +55,6 @@ Suggests: testthat, BugReports: https://github.com/KrasnitzLab/RAIDS/issues URL: https://krasnitzlab.github.io/RAIDS/ biocViews: Genetics, Software, Sequencing, WholeGenome, PrincipalComponent, - GeneticVariability, DimensionReduction + GeneticVariability, DimensionReduction, BiocViews Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 From aa1f9ab6f2d8f50aef1ce9c06fe73828900ebf4c Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 16 Aug 2024 18:49:22 -0400 Subject: [PATCH 285/385] Update action item to v4 --- .github/workflows/check-bioc.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index 9a39ec64b..9d2a94980 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -78,7 +78,7 @@ jobs: ## https://github.com/r-lib/actions/blob/master/examples/check-standard.yaml ## If they update their steps, we will also need to update ours. - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 ## R is already included in the Bioconductor docker images - name: Setup R from r-lib @@ -101,7 +101,7 @@ jobs: - name: Cache R packages if: "!contains(github.event.head_commit.message, '/nocache') && runner.os != 'Linux'" - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ env.R_LIBS_USER }} key: ${{ env.cache-version }}-${{ runner.os }}-biocversion-RELEASE_$${{ matrix.config.bioc }}-$${{ matrix.config.r }}-${{ hashFiles('.github/depends.Rds') }} @@ -109,7 +109,7 @@ jobs: - name: Cache R packages on Linux if: "!contains(github.event.head_commit.message, '/nocache') && runner.os == 'Linux' " - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: /home/runner/work/_temp/Library key: ${{ env.cache-version }}-${{ runner.os }}-biocversion-RELEASE_$${{ matrix.config.bioc }}-r-${{ matrix.config.r }}--${{ hashFiles('.github/depends.Rds') }} From 501ff815556210e3b943028934a0311dfb5afca6 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Fri, 16 Aug 2024 19:09:45 -0400 Subject: [PATCH 286/385] Update package version to 1.3.1 --- DESCRIPTION | 2 +- inst/NEWS.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index e6f7afece..1b8934797 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 0.99.15 +Version: 1.3.1 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index 5aa1d2ac9..0279b5efc 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,10 @@ +CHANGES IN VERSION 1.3.1 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o New function createAccuracyGraph() that creates a graphic representation of the accuracy for different values of PCA dimensions and K-neighbors through all tested ancestries. + CHANGES IN VERSION 0.99.15 ------------------------ From 79712a42e8599ad1ca82b114250700f91c608982 Mon Sep 17 00:00:00 2001 From: belleau Date: Sat, 31 Aug 2024 17:09:43 -0400 Subject: [PATCH 287/385] Updata addStudyGDSSample in gdsWrapper_internal.R --- R/gdsWrapper_internal.R | 10 ++++++---- man/RAIDS-package.Rd | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 54b6a918a..b127d465a 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -646,11 +646,13 @@ addStudyGDSSample <- function(gdsProfile, pedProfile, batch, listSamples, if(!(is.null(listSamples))) { if(length(listSamples) == length(intersect(listSamples, pedProfile$Name.ID))) { - # if we remove the names we should manage the order + # if we remove the names we should manage the listSamples order # something like - tmp1 <- order(as.character(pedProfile$Name.ID)) - tmp2 <- order(as.character(listSamples)) - pedProfile <- pedProfile[tmp1[which(pedProfile$Name.ID[tmp1] %in% listSamples)][order(tmp2)],] + + tmp <- order(as.character(listSamples)) + pedProfile <- pedProfile[which(pedProfile$Name.ID %in% listSamples), ] + pedProfile <- pedProfile[order(pedProfile$Name.ID), ][order(tmp),] + } else { stop("List of samples includes samples not present in ", "the \'pedProfile\' data frame. The sample names must be ", diff --git a/man/RAIDS-package.Rd b/man/RAIDS-package.Rd index d670a1307..31215a20f 100644 --- a/man/RAIDS-package.Rd +++ b/man/RAIDS-package.Rd @@ -4,6 +4,7 @@ \encoding{UTF-8} \name{RAIDS-package} \alias{RAIDS-package} +\alias{_PACKAGE} \alias{RAIDS} \title{RAIDS: Accurate Inference of Genetic Ancestry from Cancer Sequences} \value{ From 930b62d29c292ade2c4910692b1fd2d494b0e943 Mon Sep 17 00:00:00 2001 From: belleau Date: Sat, 31 Aug 2024 19:11:47 -0400 Subject: [PATCH 288/385] In generateMapSnvSel change read.csv2 to read.csv --- R/process1KG.R | 4 +-- inst/extdata/matFreqSNV_Demo.txt.bz2 | Bin 227 -> 215 bytes man/RAIDS-package.Rd | 1 - .../testthat/fixtures/matFreqSNV_Demo.txt.bz2 | Bin 227 -> 215 bytes tests/testthat/test-process1KG.R | 24 +++++++++--------- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index 7d653b43e..7074a8173 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -197,8 +197,8 @@ generateMapSnvSel <- function(cutOff=0.01, fileSNV, fileSNPsRDS, fileFREQ) { } ## Read the bulk SNP information file - mapSNVSel <- read.csv2(fileSNV) - + # mapSNVSel <- read.csv2(fileSNV) + mapSNVSel <- read.csv(fileSNV) ## Identify SNPs that have a frequency equal or superior to the cut-off ## in at least one super population listSNP <- which(rowSums(mapSNVSel[,c("EAS_AF", diff --git a/inst/extdata/matFreqSNV_Demo.txt.bz2 b/inst/extdata/matFreqSNV_Demo.txt.bz2 index c30dd4f8c0ec8d7e71a3d0c97cb0ba989b4f7ef6..11ed7d00281305be8d0f042aea44bda4c1c802bb 100644 GIT binary patch literal 215 zcmV;|04V=LT4*^jL0KkKSqP|GE5_ach(HhkFaXBTX)-XB^z^2h zGH3y)#+1`Rpa20PLNyv_&@nSazg7*Soiv~!o>sx}+3b@ERL;8G-t|YKnzTg|rLhXn zbaDd?ND@XBTB6mNKOC*ZPC*bYh>Kv5nmjQbSW(I;E>L=a%J{1!uD!~zHwjWG7^qW1 zKwOArkP?Ut6dAig(HaO=NRKlDDm7<@I1S>1 RgdCv$F64@Ep&$`aDGpljTcQ8} literal 227 zcmV<903829T4*^jL0KkKS-7`UIRF4uUw{A*5CMPaE5_ach(HhkFaYMwh9akp6G@XG zFo2XaN_w7<1|R@QB4_|;&;TGsyHHaYWsguuEC|nPOjjLiC(5tU^V3T-Tcg68PL-;B zC3?=0XS~!5iv%0a&mnRKWF1f?5Wq-MNk~Xch%k$oBF}Um@(i32q1CXO+Z|p9hHV`* z!Ai8L1)URcyM;*QV$#X1lhj@z>e!hxH-H4jNtQOkVzCT2#&;3Z(-Xq>9T3EKZPd7s d-=CXApd-q{_ynAR^oPhl7ji{7P>{H{R5=eZU@8Cr diff --git a/man/RAIDS-package.Rd b/man/RAIDS-package.Rd index 31215a20f..d670a1307 100644 --- a/man/RAIDS-package.Rd +++ b/man/RAIDS-package.Rd @@ -4,7 +4,6 @@ \encoding{UTF-8} \name{RAIDS-package} \alias{RAIDS-package} -\alias{_PACKAGE} \alias{RAIDS} \title{RAIDS: Accurate Inference of Genetic Ancestry from Cancer Sequences} \value{ diff --git a/tests/testthat/fixtures/matFreqSNV_Demo.txt.bz2 b/tests/testthat/fixtures/matFreqSNV_Demo.txt.bz2 index c30dd4f8c0ec8d7e71a3d0c97cb0ba989b4f7ef6..11ed7d00281305be8d0f042aea44bda4c1c802bb 100644 GIT binary patch literal 215 zcmV;|04V=LT4*^jL0KkKSqP|GE5_ach(HhkFaXBTX)-XB^z^2h zGH3y)#+1`Rpa20PLNyv_&@nSazg7*Soiv~!o>sx}+3b@ERL;8G-t|YKnzTg|rLhXn zbaDd?ND@XBTB6mNKOC*ZPC*bYh>Kv5nmjQbSW(I;E>L=a%J{1!uD!~zHwjWG7^qW1 zKwOArkP?Ut6dAig(HaO=NRKlDDm7<@I1S>1 RgdCv$F64@Ep&$`aDGpljTcQ8} literal 227 zcmV<903829T4*^jL0KkKS-7`UIRF4uUw{A*5CMPaE5_ach(HhkFaYMwh9akp6G@XG zFo2XaN_w7<1|R@QB4_|;&;TGsyHHaYWsguuEC|nPOjjLiC(5tU^V3T-Tcg68PL-;B zC3?=0XS~!5iv%0a&mnRKWF1f?5Wq-MNk~Xch%k$oBF}Um@(i32q1CXO+Z|p9hHV`* z!Ai8L1)URcyM;*QV$#X1lhj@z>e!hxH-H4jNtQOkVzCT2#&;3Z(-Xq>9T3EKZPd7s d-=CXApd-q{_ynAR^oPhl7ji{7P>{H{R5=eZU@8Cr diff --git a/tests/testthat/test-process1KG.R b/tests/testthat/test-process1KG.R index 62a2b9179..4479bf389 100644 --- a/tests/testthat/test-process1KG.R +++ b/tests/testthat/test-process1KG.R @@ -173,18 +173,18 @@ test_that("generateMapSnvSel() must generate expected output", { 54489, 54707, 54715), REF=c("T", "T", "C", "G", "G", "G", "C"), ALT=c("G", "A", "A", "A", "A", "C", "T"), - AF=as.character(c(0.02, 0.11, 0.08, 0.07, - 0.1, 0.23, 0.21)), - EAS_AF=c("0.0", "0.0", "0.05", "0.01", - "0.0", "0.08", "0.07"), - EUR_AF=c("0.04", "0.2", "0.12", "0.14", - "0.18", "0.38", "0.34"), - AFR_AF=c("0.03", "0.02", "0.05", "0.06", - "0.02", "0.18", "0.16"), - AMR_AF=c("0.03", "0.12", "0.06", "0.07", - "0.1", "0.25", "0.24"), - SAS_AF=c("0.02", "0.22", "0.1", "0.09", - "0.21", "0.28", "0.27"), + AF=c(0.02, 0.11, 0.08, 0.07, + 0.1, 0.23, 0.21), + EAS_AF=c(0.0, 0.0, 0.05, 0.01, + 0.0, 0.08, 0.07), + EUR_AF=c(0.04, 0.2, 0.12, 0.14, + 0.18, 0.38, 0.34), + AFR_AF=c(0.03, 0.02, 0.05, 0.06, + 0.02, 0.18, 0.16), + AMR_AF=c(0.03, 0.12, 0.06, 0.07, + 0.1, 0.25, 0.24), + SAS_AF=c(0.02, 0.22, 0.1, 0.09, + 0.21, 0.28, 0.27), stringsAsFactors = FALSE) expect_equivalent(readRDS(filterSNVFile), snpFilteredExpected) From 645f796c0bdcbebc4560545418b7cbab49195c40 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 5 Sep 2024 18:38:05 -0400 Subject: [PATCH 289/385] Update createAccuracyGraph() to show y lab values --- R/visualization.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/visualization.R b/R/visualization.R index 44666197b..5e64056fe 100644 --- a/R/visualization.R +++ b/R/visualization.R @@ -86,9 +86,9 @@ createAccuracyGraph <- function(fileRDS, title="", scale_colour_manual(aesthetics = c("colour", "fill"), breaks=selectD, values=selectColor) + theme_classic() + - theme(axis.text=element_text(size=1, colour = "white"), + theme(axis.text=element_text(size=20, colour = "black"), panel.background = element_rect(color="black"), - axis.text.x=element_text(size=30, angle=90, + axis.text.x=element_text(size=20, angle=90, vjust = 0.5, hjust=1, colour="black"), plot.title = element_text(size=22, face="bold", colour="gray20", hjust=0.5), From 72f70d9f0858b39a448cf9b0bdce1a9d834e5ca9 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 5 Sep 2024 18:49:35 -0400 Subject: [PATCH 290/385] Update action test-coverage --- .github/workflows/test-coverage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 5f31712af..cecf6b749 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -15,7 +15,7 @@ jobs: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-r@v2 with: From 6069e9c868980a8854e6bcde3060f64784e13f84 Mon Sep 17 00:00:00 2001 From: belleau Date: Mon, 9 Sep 2024 09:45:38 -0400 Subject: [PATCH 291/385] add function select1KGPopForSynthetic in synthetic.R --- NAMESPACE | 1 + R/synthetic.R | 76 +++++++++++++++++++++++++++++++++ man/select1KGPopForSynthetic.Rd | 64 +++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 man/select1KGPopForSynthetic.Rd diff --git a/NAMESPACE b/NAMESPACE index c137b74fa..73e8030aa 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -26,6 +26,7 @@ export(pruningSample) export(runExomeAncestry) export(runRNAAncestry) export(select1KGPop) +export(select1KGPopForSynthetic) export(snvListVCF) export(splitSelectByPop) export(syntheticGeno) diff --git a/R/synthetic.R b/R/synthetic.R index a3e75062b..aa9ca4004 100644 --- a/R/synthetic.R +++ b/R/synthetic.R @@ -1,3 +1,79 @@ +#' @title Random selection of a specific number of reference profiles in each +#' subcontinental population present in the 1KG GDS file ( same as select1KGPop +#' but the function doesn't need gds object as parameters but the file name +#' of the referenceGDS ) +#' +#' @description The function randomly selects a fixed number of reference +#' for each subcontinental population present in the 1KG GDS file. When a +#' subcontinental population has less samples than the fixed number, all +#' samples from the subcontinental population are selected. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Reference GDS file. The file must exist. +#' +#' @param nbProfiles a single positive \code{integer} representing the number +#' of samples that will be selected for each subcontinental population present +#' in the 1KG GDS file. If the number of samples in a specific subcontinental +#' population is smaller than the \code{nbProfiles}, the number of samples +#' selected in this +#' subcontinental population will correspond to the size of this population. +#' +#' @return a \code{data.frame} containing those columns: +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample +#' identifier. } +#' \item{pop.group}{ a \code{character} string representing the +#' subcontinental population assigned to the sample. } +#' \item{superPop}{ a \code{character} string representing the +#' super-population assigned to the sample. } +#' } +#' +#' @examples +#' +#' ## Required library +#' library(gdsfmt) +#' +#' ## The number of samples needed by subcontinental population +#' ## The number is small for demonstration purpose +#' nbProfiles <- 5L +#' +#' ## 1KG GDS Demo file +#' ## This file only one superpopulation (for demonstration purpose) +#' dataDir <- system.file("extdata", package="RAIDS") +#' fileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") +#' +#' ## Extract a selected number of random samples +#' ## for each subcontinental population +#' ## In the 1KG GDS Demo file, there is one subcontinental population +#' dataR <- select1KGPopForSynthetic(fileReferenceGDS=fileGDS, nbProfiles=nbProfiles) +#' +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt index.gdsn read.gdsn +#' @importFrom S4Vectors isSingleNumber +#' @importFrom SNPRelate snpgdsOpen +#' @encoding UTF-8 +#' @export +select1KGPopForSynthetic <- function(fileReferenceGDS, nbProfiles) { + + ## The fileReferenceGDS must be a character string and the file must exists + if (!(is.character(fileReferenceGDS) && (file.exists(fileReferenceGDS)))) { + stop("The \'fileReferenceGDS\' must be a character string ", + "representing the Reference GDS file. The file must exist.") + } + ## Validate that nbProfiles parameter is a single positive numeric + if(! (isSingleNumber(nbProfiles) && nbProfiles > 0)) { + stop("The \'nbProfiles\' parameter must be a single positive integer.") + } + + gdsReference <- snpgdsOpen(filename=fileReferenceGDS) + df <- select1KGPop(gdsReference, nbProfiles) + closefn.gds(gdsReference) + + return(df) +} + + #' @title Random selection of a specific number of reference profiles in each #' subcontinental population present in the 1KG GDS file #' diff --git a/man/select1KGPopForSynthetic.Rd b/man/select1KGPopForSynthetic.Rd new file mode 100644 index 000000000..d6c519c98 --- /dev/null +++ b/man/select1KGPopForSynthetic.Rd @@ -0,0 +1,64 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/synthetic.R +\encoding{UTF-8} +\name{select1KGPopForSynthetic} +\alias{select1KGPopForSynthetic} +\title{Random selection of a specific number of reference profiles in each +subcontinental population present in the 1KG GDS file ( same as select1KGPop +but the function doesn't need gds object as parameters but the file name +of the referenceGDS )} +\usage{ +select1KGPopForSynthetic(fileReferenceGDS, nbProfiles) +} +\arguments{ +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Reference GDS file. The file must exist.} + +\item{nbProfiles}{a single positive \code{integer} representing the number +of samples that will be selected for each subcontinental population present +in the 1KG GDS file. If the number of samples in a specific subcontinental +population is smaller than the \code{nbProfiles}, the number of samples +selected in this +subcontinental population will correspond to the size of this population.} +} +\value{ +a \code{data.frame} containing those columns: +\describe{ +\item{sample.id}{ a \code{character} string representing the sample +identifier. } +\item{pop.group}{ a \code{character} string representing the +subcontinental population assigned to the sample. } +\item{superPop}{ a \code{character} string representing the +super-population assigned to the sample. } +} +} +\description{ +The function randomly selects a fixed number of reference +for each subcontinental population present in the 1KG GDS file. When a +subcontinental population has less samples than the fixed number, all +samples from the subcontinental population are selected. +} +\examples{ + +## Required library +library(gdsfmt) + +## The number of samples needed by subcontinental population +## The number is small for demonstration purpose +nbProfiles <- 5L + +## 1KG GDS Demo file +## This file only one superpopulation (for demonstration purpose) +dataDir <- system.file("extdata", package="RAIDS") +fileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") + +## Extract a selected number of random samples +## for each subcontinental population +## In the 1KG GDS Demo file, there is one subcontinental population +dataR <- select1KGPopForSynthetic(fileReferenceGDS=fileGDS, nbProfiles=nbProfiles) + + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} From dd5daa9d89283702a6a4430e1a8ac1028d7d578c Mon Sep 17 00:00:00 2001 From: belleau Date: Mon, 9 Sep 2024 20:04:06 -0400 Subject: [PATCH 292/385] Add functions runDNAAncestryProfile and runRNAAncestryProfile --- NAMESPACE | 2 + R/processStudy.R | 419 +++++++++++++++++++++++++++++++++++ man/runDNAAncestryProfile.Rd | 176 +++++++++++++++ man/runRNAAncestryProfile.Rd | 182 +++++++++++++++ 4 files changed, 779 insertions(+) create mode 100644 man/runDNAAncestryProfile.Rd create mode 100644 man/runRNAAncestryProfile.Rd diff --git a/NAMESPACE b/NAMESPACE index 73e8030aa..e057bacbf 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -23,8 +23,10 @@ export(identifyRelative) export(prepPed1KG) export(prepSynthetic) export(pruningSample) +export(runDNAAncestryProfile) export(runExomeAncestry) export(runRNAAncestry) +export(runRNAAncestryProfile) export(select1KGPop) export(select1KGPopForSynthetic) export(snvListVCF) diff --git a/R/processStudy.R b/R/processStudy.R index ed7fdfb1e..6ede57398 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2069,6 +2069,214 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, return(r) } +#' @title Run most steps leading to the ancestry inference call on a specific +#' DNA profile +#' +#' @description This function runs most steps leading to the ancestry inference +#' call on a specific RNA profile. First, the function creates the +#' Profile GDS file for the specific profile using the information from a +#' RDS Sample description file and the Population Reference GDS file. +#' +#' @param profileFile a \code{character} string representing the path and the +#' file name of the genotype file or the bam if genoSource is snp-pileup the +#' fine extension must be .txt.gz, if VCF the extension must be .vcf.gz +#' +#' @param pathProfileGDS a \code{character} string representing the path to +#' the directory where the GDS Profile files will be created. +#' Default: \code{NULL}. +#' +#' @param pathOut a \code{character} string representing the path to +#' the directory where the output files are created. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Population Reference GDS file. The file must exist. +#' +#' @param fileReferenceAnnotGDS a \code{character} string representing the +#' file name of the Population Reference GDS Annotation file. The file +#' must exist. +#' +#' @param chrInfo a \code{vector} of positive \code{integer} values +#' representing the length of the chromosomes. See 'details' section. +#' +#' @param syntheticRefDF a \code{data.frame} containing a subset of +#' reference profiles for each sub-population present in the Reference GDS +#' file. The \code{data.frame} must have those columns: +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample +#' identifier. } +#' \item{pop.group}{ a \code{character} string representing the +#' subcontinental population assigned to the sample. } +#' \item{superPop}{ a \code{character} string representing the +#' super-population assigned to the sample. } +#' } +#' +#' @param genoSource a \code{character} string with two possible values: +#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +#' are generated by snp-pileup (Facets) or are a generic format CSV file +#' with at least those columns: +#' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +#' The 'Count' is the depth at the specified position; +#' 'FileR' is the depth of the reference allele and +#' 'File1A' is the depth of the specific alternative allele. +#' Finally the file can be a VCF file with at least those genotype +#' fields: GT, AD, DP. +#' +#' @param np a single positive \code{integer} specifying the number of +#' threads to be used. Default: \code{1L}. +#' +#' @param verbose a \code{logical} indicating if messages should be printed +#' to show how the different steps in the function. Default: \code{FALSE}. +#' +#' @return The integer \code{0L} when successful. See details section for +#' more information about the generated output files. +#' +#' @details +#' +#' The runExomeAncestry() function generates 3 types of files +#' in the OUTPUT directory. +#' \describe{ +#' \item{Ancestry Inference}{ The ancestry inference CSV file +#' (".Ancestry.csv" file)} +#' \item{Inference Informaton}{ The inference information RDS file +#' (".infoCall.rds" file)} +#' \item{Synthetic Information}{ The parameter information RDS files +#' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +#' } +#' +#' In addition, a sub-directory (named using the profile ID) is +#' also created. +#' +#' @references +#' +#' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +#' Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +#' of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +#' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +#' +#' @examples +#' +#' ## Required library for GDS +#' library(SNPRelate) +#' +#' ## Path to the demo 1KG GDS file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' +#' ################################################################# +#' ## The 1KG GDS file and the 1KG SNV Annotation GDS file +#' ## need to be located in the same directory +#' ## Note that the 1KG GDS file used for this example is a +#' ## simplified version and CANNOT be used for any real analysis +#' ################################################################# +#' path1KG <- file.path(dataDir, "tests") +#' +#' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +#' fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") +#' +#' ################################################################# +#' ## The Sample SNP pileup files (one per sample) need +#' ## to be located in the same directory. +#' ################################################################# +#' demoProfileEx1 <- file.path(dataDir, "example", "snpPileup", "ex1.txt.gz") +#' +#' ################################################################# +#' ## The path where the Profile GDS Files (one per sample) +#' ## will be created need to be specified. +#' ################################################################# +#' pathProfileGDS <- file.path(tempdir(), "out.tmp") +#' +#' pathOut <- file.path(tempdir(), "res.out") +#' +#' +#' #################################################################### +#' ## Fix seed to ensure reproducible results +#' #################################################################### +#' set.seed(3043) +#' +#' gds1KG <- snpgdsOpen(fileReferenceGDS) +#' dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +#' closefn.gds(gds1KG) +#' +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' \donttest{ +#' +#' runDNAAncestryProfile(profileFile=demoProfileEx1, +#' pathProfileGDS=pathProfileGDS, +#' pathOut=pathOut, +#' fileReferenceGDS=fileReferenceGDS, +#' fileReferenceAnnotGDS=fileAnnotGDS, +#' chrInfo=chrInfo, +#' syntheticRefDF=dataRef, +#' genoSource="snp-pileup") +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' +#' } +#' } +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom utils write.csv +#' @importFrom rlang arg_match +#' @encoding UTF-8 +#' @export + +runDNAAncestryProfile <- function(profileFile, pathProfileGDS, + pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, + verbose=FALSE) { + + profileBaseName <- basename(profileFile) + pathGeno <- dirname(profileFile) + + genoSource <- arg_match(genoSource) + + + profileName <- gsub("\\.gz$", "", profileBaseName, ignore.case = TRUE) + for(extCur in c( "\\.vcf$", "\\.txt$", "\\.bam", "\\.tsv", "\\.csv")){ + profileName <- gsub(extCur, "", profileName, ignore.case = TRUE) + } + #profileName <- "profile" + studyDF <- data.frame(study.id="NotDef", + study.desc="NotDef", + study.platform="NotDef", + stringsAsFactors=FALSE) + pedStudy <- data.frame(Name.ID = c(profileName), + Case.ID = c(profileName), + Sample.Type = c("DNA"), + Diagnosis = "NotDef", + Source = c("ENotDef"), + stringsAsFactors = FALSE) + row.names(pedStudy) <- pedStudy$Name.ID + + ## Validate parameters + validateRunExomeOrRNAAncestry(pedStudy=pedStudy, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, + syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) + + + if(genoSource %in% c("snp-pileup", "generic", "VCF")){ + + r <- runWrapperAncestry(pedStudy, studyDF, pathProfileGDS, + pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, genoSource, studyType="DNA", np=np, + verbose) + } + ## Successful + return(r) +} + + #' @title Run most steps leading to the ancestry inference call on a specific #' RNA profile #' @@ -2288,3 +2496,214 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, return(r) } +#' @title Run most steps leading to the ancestry inference call on a specific +#' RNA profile +#' +#' @description This function runs most steps leading to the ancestry inference +#' call on a specific RNA profile. First, the function creates the +#' Profile GDS file for the specific profile using the information from a +#' RDS Sample description file and the Population Reference GDS file. +#' +#' @param profileFile a \code{character} string representing the path and the +#' file name of the genotype file or the bam if genoSource is snp-pileup the +#' fine extension must be .txt.gz, if VCF the extension must be .vcf.gz +#' +#' @param pathProfileGDS a \code{character} string representing the path to +#' the directory where the GDS Profile files will be created. +#' Default: \code{NULL}. +#' +#' @param pathOut a \code{character} string representing the path to +#' the directory where the output files are created. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Population Reference GDS file. The file must exist. +#' +#' @param fileReferenceAnnotGDS a \code{character} string representing the +#' file name of the Population Reference GDS Annotation file. The file +#' must exist. +#' +#' @param chrInfo a \code{vector} of positive \code{integer} values +#' representing the length of the chromosomes. See 'details' section. +#' +#' @param syntheticRefDF a \code{data.frame} containing a subset of +#' reference profiles for each sub-population present in the Reference GDS +#' file. The \code{data.frame} must have those columns: +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample +#' identifier. } +#' \item{pop.group}{ a \code{character} string representing the +#' subcontinental population assigned to the sample. } +#' \item{superPop}{ a \code{character} string representing the +#' super-population assigned to the sample. } +#' } +#' +#' @param genoSource a \code{character} string with two possible values: +#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +#' are generated by snp-pileup (Facets) or are a generic format CSV file +#' with at least those columns: +#' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +#' The 'Count' is the depth at the specified position; +#' 'FileR' is the depth of the reference allele and +#' 'File1A' is the depth of the specific alternative allele. +#' Finally the file can be a VCF file with at least those genotype +#' fields: GT, AD, DP. +#' +#' @param np a single positive \code{integer} specifying the number of +#' threads to be used. Default: \code{1L}. +#' +#' @param blockTypeID a \code{character} string corresponding to the block +#' type used to extract the block identifiers. The block type must be +#' present in the GDS Reference Annotation file. +#' +#' @param verbose a \code{logical} indicating if messages should be printed +#' to show how the different steps in the function. Default: \code{FALSE}. +#' +#' @return The integer \code{0L} when successful. See details section for +#' more information about the generated output files. +#' +#' @details +#' +#' The runExomeAncestry() function generates 3 types of files +#' in the OUTPUT directory. +#' \describe{ +#' \item{Ancestry Inference}{ The ancestry inference CSV file +#' (".Ancestry.csv" file)} +#' \item{Inference Informaton}{ The inference information RDS file +#' (".infoCall.rds" file)} +#' \item{Synthetic Information}{ The parameter information RDS files +#' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +#' } +#' +#' In addition, a sub-directory (named using the profile ID) is +#' also created. +#' +#' @references +#' +#' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +#' Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +#' of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +#' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +#' +#' @examples +#' +#' ## Required library for GDS +#' library(SNPRelate) +#' +#' ## Path to the demo 1KG GDS file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' +#' ################################################################# +#' ## The 1KG GDS file and the 1KG SNV Annotation GDS file +#' ## need to be located in the same directory +#' ## Note that the 1KG GDS file used for this example is a +#' ## simplified version and CANNOT be used for any real analysis +#' ################################################################# +#' path1KG <- file.path(dataDir, "tests") +#' +#' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +#' fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") +#' +#' ################################################################# +#' ## The Sample SNP pileup files (one per sample) need +#' ## to be located in the same directory. +#' ################################################################# +#' demoProfileEx1 <- file.path(dataDir, "example", "snpPileup", "ex1.txt.gz") +#' +#' ################################################################# +#' ## The path where the Profile GDS Files (one per sample) +#' ## will be created need to be specified. +#' ################################################################# +#' pathProfileGDS <- file.path(tempdir(), "out.tmp") +#' +#' pathOut <- file.path(tempdir(), "res.out") +#' +#' +#' #################################################################### +#' ## Fix seed to ensure reproducible results +#' #################################################################### +#' set.seed(3043) +#' +#' gds1KG <- snpgdsOpen(fileReferenceGDS) +#' dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +#' closefn.gds(gds1KG) +#' +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' \donttest{ +#' +#' runRNAAncestryProfile(profileFile=demoProfileEx1, +#' pathProfileGDS=pathProfileGDS, +#' pathOut=pathOut, +#' fileReferenceGDS=fileReferenceGDS, +#' fileReferenceAnnotGDS=fileAnnotGDS, +#' chrInfo=chrInfo, +#' syntheticRefDF=dataRef, +#' blockTypeID="GeneS.Ensembl.Hsapiens.v86", +#' genoSource="snp-pileup") +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' unlink(pathOut, recursive=TRUE, force=TRUE) +#' +#' } +#' } +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom utils write.csv +#' @importFrom rlang arg_match +#' @encoding UTF-8 +#' @export +runRNAAncestryProfile <- function(profileFile, pathProfileGDS, + pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, + blockTypeID, verbose=FALSE) { + + profileBaseName <- basename(profileFile) + pathGeno <- dirname(profileFile) + + genoSource <- arg_match(genoSource) + + + profileName <- gsub("\\.gz$", "", profileBaseName, ignore.case = TRUE) + for(extCur in c( "\\.vcf$", "\\.txt$", "\\.bam", "\\.tsv", "\\.csv")){ + profileName <- gsub(extCur, "", profileName, ignore.case = TRUE) + } + #profileName <- "profile" + studyDF <- data.frame(study.id="NotDef", + study.desc="NotDef", + study.platform="NotDef", + stringsAsFactors=FALSE) + pedStudy <- data.frame(Name.ID = c(profileName), + Case.ID = c(profileName), + Sample.Type = c("RNA"), + Diagnosis = "NotDef", + Source = c("NotDef"), + stringsAsFactors = FALSE) + row.names(pedStudy) <- pedStudy$Name.ID + + ## Validate parameters + validateRunExomeOrRNAAncestry(pedStudy=pedStudy, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, + syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) + + + if(genoSource %in% c("snp-pileup", "generic", "VCF")){ + + r <- runWrapperAncestry(pedStudy, studyDF, pathProfileGDS, + pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, genoSource, studyType="RNA", np=np, + blockTypeID=blockTypeID, verbose) + } + ## Successful + return(r) +} + diff --git a/man/runDNAAncestryProfile.Rd b/man/runDNAAncestryProfile.Rd new file mode 100644 index 000000000..9323d7833 --- /dev/null +++ b/man/runDNAAncestryProfile.Rd @@ -0,0 +1,176 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/processStudy.R +\encoding{UTF-8} +\name{runDNAAncestryProfile} +\alias{runDNAAncestryProfile} +\title{Run most steps leading to the ancestry inference call on a specific +DNA profile} +\usage{ +runDNAAncestryProfile( + profileFile, + pathProfileGDS, + pathOut, + fileReferenceGDS, + fileReferenceAnnotGDS, + chrInfo, + syntheticRefDF, + genoSource = c("snp-pileup", "generic", "VCF", "bam"), + np = 1L, + verbose = FALSE +) +} +\arguments{ +\item{profileFile}{a \code{character} string representing the path and the +file name of the genotype file or the bam if genoSource is snp-pileup the +fine extension must be .txt.gz, if VCF the extension must be .vcf.gz} + +\item{pathProfileGDS}{a \code{character} string representing the path to +the directory where the GDS Profile files will be created. +Default: \code{NULL}.} + +\item{pathOut}{a \code{character} string representing the path to +the directory where the output files are created.} + +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Population Reference GDS file. The file must exist.} + +\item{fileReferenceAnnotGDS}{a \code{character} string representing the +file name of the Population Reference GDS Annotation file. The file +must exist.} + +\item{chrInfo}{a \code{vector} of positive \code{integer} values +representing the length of the chromosomes. See 'details' section.} + +\item{syntheticRefDF}{a \code{data.frame} containing a subset of +reference profiles for each sub-population present in the Reference GDS +file. The \code{data.frame} must have those columns: +\describe{ +\item{sample.id}{ a \code{character} string representing the sample +identifier. } +\item{pop.group}{ a \code{character} string representing the +subcontinental population assigned to the sample. } +\item{superPop}{ a \code{character} string representing the +super-population assigned to the sample. } +}} + +\item{genoSource}{a \code{character} string with two possible values: +'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +are generated by snp-pileup (Facets) or are a generic format CSV file +with at least those columns: +'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +The 'Count' is the depth at the specified position; +'FileR' is the depth of the reference allele and +'File1A' is the depth of the specific alternative allele. +Finally the file can be a VCF file with at least those genotype +fields: GT, AD, DP.} + +\item{np}{a single positive \code{integer} specifying the number of +threads to be used. Default: \code{1L}.} + +\item{verbose}{a \code{logical} indicating if messages should be printed +to show how the different steps in the function. Default: \code{FALSE}.} +} +\value{ +The integer \code{0L} when successful. See details section for +more information about the generated output files. +} +\description{ +This function runs most steps leading to the ancestry inference +call on a specific RNA profile. First, the function creates the +Profile GDS file for the specific profile using the information from a +RDS Sample description file and the Population Reference GDS file. +} +\details{ +The runExomeAncestry() function generates 3 types of files +in the OUTPUT directory. +\describe{ +\item{Ancestry Inference}{ The ancestry inference CSV file +(".Ancestry.csv" file)} +\item{Inference Informaton}{ The inference information RDS file +(".infoCall.rds" file)} +\item{Synthetic Information}{ The parameter information RDS files +from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +} + +In addition, a sub-directory (named using the profile ID) is +also created. +} +\examples{ + +## Required library for GDS +library(SNPRelate) + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + + +################################################################# +## The 1KG GDS file and the 1KG SNV Annotation GDS file +## need to be located in the same directory +## Note that the 1KG GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +################################################################# +path1KG <- file.path(dataDir, "tests") + +fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") + +################################################################# +## The Sample SNP pileup files (one per sample) need +## to be located in the same directory. +################################################################# +demoProfileEx1 <- file.path(dataDir, "example", "snpPileup", "ex1.txt.gz") + +################################################################# +## The path where the Profile GDS Files (one per sample) +## will be created need to be specified. +################################################################# +pathProfileGDS <- file.path(tempdir(), "out.tmp") + +pathOut <- file.path(tempdir(), "res.out") + + +#################################################################### +## Fix seed to ensure reproducible results +#################################################################### +set.seed(3043) + +gds1KG <- snpgdsOpen(fileReferenceGDS) +dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +closefn.gds(gds1KG) + +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + \donttest{ + + runDNAAncestryProfile(profileFile=demoProfileEx1, + pathProfileGDS=pathProfileGDS, + pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + genoSource="snp-pileup") + + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + + } +} + +} +\references{ +Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} diff --git a/man/runRNAAncestryProfile.Rd b/man/runRNAAncestryProfile.Rd new file mode 100644 index 000000000..971a3a678 --- /dev/null +++ b/man/runRNAAncestryProfile.Rd @@ -0,0 +1,182 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/processStudy.R +\encoding{UTF-8} +\name{runRNAAncestryProfile} +\alias{runRNAAncestryProfile} +\title{Run most steps leading to the ancestry inference call on a specific +RNA profile} +\usage{ +runRNAAncestryProfile( + profileFile, + pathProfileGDS, + pathOut, + fileReferenceGDS, + fileReferenceAnnotGDS, + chrInfo, + syntheticRefDF, + genoSource = c("snp-pileup", "generic", "VCF", "bam"), + np = 1L, + blockTypeID, + verbose = FALSE +) +} +\arguments{ +\item{profileFile}{a \code{character} string representing the path and the +file name of the genotype file or the bam if genoSource is snp-pileup the +fine extension must be .txt.gz, if VCF the extension must be .vcf.gz} + +\item{pathProfileGDS}{a \code{character} string representing the path to +the directory where the GDS Profile files will be created. +Default: \code{NULL}.} + +\item{pathOut}{a \code{character} string representing the path to +the directory where the output files are created.} + +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Population Reference GDS file. The file must exist.} + +\item{fileReferenceAnnotGDS}{a \code{character} string representing the +file name of the Population Reference GDS Annotation file. The file +must exist.} + +\item{chrInfo}{a \code{vector} of positive \code{integer} values +representing the length of the chromosomes. See 'details' section.} + +\item{syntheticRefDF}{a \code{data.frame} containing a subset of +reference profiles for each sub-population present in the Reference GDS +file. The \code{data.frame} must have those columns: +\describe{ +\item{sample.id}{ a \code{character} string representing the sample +identifier. } +\item{pop.group}{ a \code{character} string representing the +subcontinental population assigned to the sample. } +\item{superPop}{ a \code{character} string representing the +super-population assigned to the sample. } +}} + +\item{genoSource}{a \code{character} string with two possible values: +'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +are generated by snp-pileup (Facets) or are a generic format CSV file +with at least those columns: +'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +The 'Count' is the depth at the specified position; +'FileR' is the depth of the reference allele and +'File1A' is the depth of the specific alternative allele. +Finally the file can be a VCF file with at least those genotype +fields: GT, AD, DP.} + +\item{np}{a single positive \code{integer} specifying the number of +threads to be used. Default: \code{1L}.} + +\item{blockTypeID}{a \code{character} string corresponding to the block +type used to extract the block identifiers. The block type must be +present in the GDS Reference Annotation file.} + +\item{verbose}{a \code{logical} indicating if messages should be printed +to show how the different steps in the function. Default: \code{FALSE}.} +} +\value{ +The integer \code{0L} when successful. See details section for +more information about the generated output files. +} +\description{ +This function runs most steps leading to the ancestry inference +call on a specific RNA profile. First, the function creates the +Profile GDS file for the specific profile using the information from a +RDS Sample description file and the Population Reference GDS file. +} +\details{ +The runExomeAncestry() function generates 3 types of files +in the OUTPUT directory. +\describe{ +\item{Ancestry Inference}{ The ancestry inference CSV file +(".Ancestry.csv" file)} +\item{Inference Informaton}{ The inference information RDS file +(".infoCall.rds" file)} +\item{Synthetic Information}{ The parameter information RDS files +from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +} + +In addition, a sub-directory (named using the profile ID) is +also created. +} +\examples{ + +## Required library for GDS +library(SNPRelate) + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + + +################################################################# +## The 1KG GDS file and the 1KG SNV Annotation GDS file +## need to be located in the same directory +## Note that the 1KG GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +################################################################# +path1KG <- file.path(dataDir, "tests") + +fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") + +################################################################# +## The Sample SNP pileup files (one per sample) need +## to be located in the same directory. +################################################################# +demoProfileEx1 <- file.path(dataDir, "example", "snpPileup", "ex1.txt.gz") + +################################################################# +## The path where the Profile GDS Files (one per sample) +## will be created need to be specified. +################################################################# +pathProfileGDS <- file.path(tempdir(), "out.tmp") + +pathOut <- file.path(tempdir(), "res.out") + + +#################################################################### +## Fix seed to ensure reproducible results +#################################################################### +set.seed(3043) + +gds1KG <- snpgdsOpen(fileReferenceGDS) +dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +closefn.gds(gds1KG) + +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + \donttest{ + + runRNAAncestryProfile(profileFile=demoProfileEx1, + pathProfileGDS=pathProfileGDS, + pathOut=pathOut, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + blockTypeID="GeneS.Ensembl.Hsapiens.v86", + genoSource="snp-pileup") + + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + + } +} + +} +\references{ +Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} From f4787cc5aa1ccf0e3273f037f2ff2ee7da4d28dd Mon Sep 17 00:00:00 2001 From: belleau Date: Tue, 10 Sep 2024 19:21:09 -0400 Subject: [PATCH 293/385] Rename functions runDNAAncestryProfile to inferAncestry.Rd and runRNAAncestryProfile to inferAncestryGeneAware --- NAMESPACE | 4 ++-- R/processStudy.R | 8 ++++---- man/{runDNAAncestryProfile.Rd => inferAncestry.Rd} | 8 ++++---- ...runRNAAncestryProfile.Rd => inferAncestryGeneAware.Rd} | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) rename man/{runDNAAncestryProfile.Rd => inferAncestry.Rd} (97%) rename man/{runRNAAncestryProfile.Rd => inferAncestryGeneAware.Rd} (97%) diff --git a/NAMESPACE b/NAMESPACE index e057bacbf..edf05be69 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -20,13 +20,13 @@ export(generatePhase1KG2GDS) export(getRef1KGPop) export(groupChr1KGSNV) export(identifyRelative) +export(inferAncestry) +export(inferAncestryGeneAware) export(prepPed1KG) export(prepSynthetic) export(pruningSample) -export(runDNAAncestryProfile) export(runExomeAncestry) export(runRNAAncestry) -export(runRNAAncestryProfile) export(select1KGPop) export(select1KGPopForSynthetic) export(snvListVCF) diff --git a/R/processStudy.R b/R/processStudy.R index 6ede57398..34e9e0587 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2207,7 +2207,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' #' \donttest{ #' -#' runDNAAncestryProfile(profileFile=demoProfileEx1, +#' inferAncestry(profileFile=demoProfileEx1, #' pathProfileGDS=pathProfileGDS, #' pathOut=pathOut, #' fileReferenceGDS=fileReferenceGDS, @@ -2228,7 +2228,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @encoding UTF-8 #' @export -runDNAAncestryProfile <- function(profileFile, pathProfileGDS, +inferAncestry <- function(profileFile, pathProfileGDS, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, @@ -2638,7 +2638,7 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' #' \donttest{ #' -#' runRNAAncestryProfile(profileFile=demoProfileEx1, +#' inferAncestryGeneAware(profileFile=demoProfileEx1, #' pathProfileGDS=pathProfileGDS, #' pathOut=pathOut, #' fileReferenceGDS=fileReferenceGDS, @@ -2659,7 +2659,7 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @importFrom rlang arg_match #' @encoding UTF-8 #' @export -runRNAAncestryProfile <- function(profileFile, pathProfileGDS, +inferAncestryGeneAware <- function(profileFile, pathProfileGDS, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, diff --git a/man/runDNAAncestryProfile.Rd b/man/inferAncestry.Rd similarity index 97% rename from man/runDNAAncestryProfile.Rd rename to man/inferAncestry.Rd index 9323d7833..dde228625 100644 --- a/man/runDNAAncestryProfile.Rd +++ b/man/inferAncestry.Rd @@ -1,12 +1,12 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/processStudy.R \encoding{UTF-8} -\name{runDNAAncestryProfile} -\alias{runDNAAncestryProfile} +\name{inferAncestry} +\alias{inferAncestry} \title{Run most steps leading to the ancestry inference call on a specific DNA profile} \usage{ -runDNAAncestryProfile( +inferAncestry( profileFile, pathProfileGDS, pathOut, @@ -149,7 +149,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && \donttest{ - runDNAAncestryProfile(profileFile=demoProfileEx1, + inferAncestry(profileFile=demoProfileEx1, pathProfileGDS=pathProfileGDS, pathOut=pathOut, fileReferenceGDS=fileReferenceGDS, diff --git a/man/runRNAAncestryProfile.Rd b/man/inferAncestryGeneAware.Rd similarity index 97% rename from man/runRNAAncestryProfile.Rd rename to man/inferAncestryGeneAware.Rd index 971a3a678..8e7dced34 100644 --- a/man/runRNAAncestryProfile.Rd +++ b/man/inferAncestryGeneAware.Rd @@ -1,12 +1,12 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/processStudy.R \encoding{UTF-8} -\name{runRNAAncestryProfile} -\alias{runRNAAncestryProfile} +\name{inferAncestryGeneAware} +\alias{inferAncestryGeneAware} \title{Run most steps leading to the ancestry inference call on a specific RNA profile} \usage{ -runRNAAncestryProfile( +inferAncestryGeneAware( profileFile, pathProfileGDS, pathOut, @@ -154,7 +154,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && \donttest{ - runRNAAncestryProfile(profileFile=demoProfileEx1, + inferAncestryGeneAware(profileFile=demoProfileEx1, pathProfileGDS=pathProfileGDS, pathOut=pathOut, fileReferenceGDS=fileReferenceGDS, From dd43808389edb863c13991e40d31646b5595c97c Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 11 Sep 2024 08:03:18 -0400 Subject: [PATCH 294/385] Add computeAncestryFromSynthetic --- NAMESPACE | 1 + R/processStudy_internal.R | 340 +++++++++++++++++++++++++++- man/computeAncestryFromSynthetic.Rd | 295 ++++++++++++++++++++++++ 3 files changed, 635 insertions(+), 1 deletion(-) create mode 100644 man/computeAncestryFromSynthetic.Rd diff --git a/NAMESPACE b/NAMESPACE index edf05be69..4ea29a569 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,6 +4,7 @@ export(add1KG2SampleGDS) export(addGeneBlockGDSRefAnnot) export(addRef2GDS1KG) export(addStudy1Kg) +export(computeAncestryFromSynthetic) export(computeAncestryFromSyntheticFile) export(computeKNNRefSample) export(computeKNNRefSynthetic) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 0a28d5c66..90aff17ee 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2226,6 +2226,344 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, return(0L) } +#' @title Select the optimal K and D parameters using the synthetic data and +#' infer the ancestry of a specific profile +#' +#' @description The function select the optimal K and D parameters for a +#' specific profile. The results on the synthetic data are used for the +#' parameter selection. Once the optimal parameters are selected, the +#' ancestry is inferred for the specific profile. +#' +#' @param gdsReference an object of class \link[gdsfmt]{gds.class} (a GDS +#' file), the opened 1KG GDS file. +#' +#' @param gdsProfile an object of class \code{\link[gdsfmt]{gds.class}} +#' (a GDS file), the opened Profile GDS file. +#' +#' @param syntheticKNN a \code{vector} of \code{character} strings representing +#' the name of files that contain the results of ancestry inference done on +#' the synthetic profiles for multiple values of _D_ and _K_. The files must +#' exist. +#' +#' @param pedSyn a \code{data.frame} containing the columns extracted from the +#' GDS Sample 'study.annot' node with a extra column named as the 'popName' +#' parameter that has been extracted from the 1KG GDS 'sample.annot' node. +#' +#' @param currentProfile a \code{character} string representing the profile +#' identifier of the current profile on which ancestry will be inferred. +#' +#' @param spRef a \code{vector} of \code{character} strings representing the +#' known super population ancestry for the 1KG profiles. The 1KG profile +#' identifiers are used as names for the \code{vector}. +#' +#' @param studyIDSyn a \code{character} string corresponding to the study +#' identifier. The study identifier must be present in the GDS Sample file. +#' +#' @param np a single positive \code{integer} representing the number of +#' threads. Default: \code{1L}. +#' +#' @param listCatPop a \code{vector} of \code{character} string +#' representing the list of possible ancestry assignations. Default: +#' \code{("EAS", "EUR", "AFR", "AMR", "SAS")}. +#' +#' @param fieldPopIn1KG a \code{character} string representing the name of the +#' column that contains the known ancestry for the reference profiles in +#' the Reference GDS file. +#' +#' @param fieldPopInfAnc a \code{character} string representing the name of +#' the column that will contain the inferred ancestry for the specified +#' profiles. Default: \code{"SuperPop"}. +#' +#' @param kList a \code{vector} of \code{integer} representing the list of +#' values tested for the _K_ parameter. The _K_ parameter represents the +#' number of neighbors used in the K-nearest neighbor analysis. If \code{NULL}, +#' the value \code{seq(2,15,1)} is assigned. +#' Default: \code{seq(2,15,1)}. +#' +#' @param pcaList a \code{vector} of \code{integer} representing the list of +#' values tested for the _D_ parameter. The _D_ parameter represents the +#' number of dimensions used in the PCA analysis. If \code{NULL}, +#' the value \code{seq(2,15,1)} is assigned. +#' Default: \code{seq(2,15,1)}. +#' +#' @param algorithm a \code{character} string representing the algorithm used +#' to calculate the PCA. The 2 choices are "exact" (traditional exact +#' calculation) and "randomized" (fast PCA with randomized algorithm +#' introduced in Galinsky et al. 2016). Default: \code{"exact"}. +#' +#' @param eigenCount a single \code{integer} indicating the number of +#' eigenvectors that will be in the output of the \link[SNPRelate]{snpgdsPCA} +#' function; if 'eigenCount' <= 0, then all eigenvectors are returned. +#' Default: \code{32L}. +#' +#' @param missingRate a \code{numeric} value representing the threshold +#' missing rate at with the SNVs are discarded; the SNVs are retained in the +#' \link[SNPRelate]{snpgdsPCA} +#' with "<= missingRate" only; if \code{NaN}, no missing threshold. +#' Default: \code{NaN}. +#' +#' @param verbose a \code{logical} indicating if messages should be printed +#' to show how the different steps in the function. Default: \code{FALSE}. +#' +#' @return a \code{list} containing 4 entries: +#' \describe{ +#' \item{\code{pcaSample}}{ a \code{list} containing the information related +#' to the eigenvectors. The \code{list} contains those 3 entries: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +#' the eigenvectors for the reference profiles.} +#' \item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +#' eigenvectors for the current profile projected on the PCA from the +#' reference profiles.} +#' } +#' } +#' \item{\code{paraSample}}{ a \code{list} containing the results with +#' different \code{D} and \code{K} values that lead to optimal parameter +#' selection. The \code{list} contains those entries: +#' \describe{ +#' \item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +#' on all combined synthetic results done with a fixed value of \code{D} (the +#' number of dimensions). The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{median}}{ a \code{numeric} representing the median of the +#' minimum AUROC obtained (within super populations) for all combination of +#' the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +#' AUROC obtained (within super populations) for all combination of the fixed +#' \code{D} value and all tested \code{K} values. } +#' \item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +#' of the minimum AUROC obtained (within super populations) for all +#' combination of the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for a fixed \code{D} value. } +#' } +#' } +#' \item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +#' all combined synthetic results done with different values of \code{D} (the +#' number of dimensions) and \code{K} (the number of neighbors). +#' The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +#' obtained by grouping all the synthetic results by super-populations, for +#' the specified values of \code{D} and \code{K}.} +#' \item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +#' by grouping all the synthetic results for the specified values of \code{D} +#' and \code{K}.} +#' \item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +#' of the confusion matrix obtained by grouping all the synthetic results for +#' the specified values of \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +#' super-population. The \code{data.frame} contains +#' those columns: +#' \describe{ +#' \item{\code{pcaD}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{Call}}{ a \code{character} string representing the +#' super-population.} +#' \item{\code{L}}{ a \code{numeric} representing the lower value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' \item{\code{AUR}}{ a \code{numeric} representing the AUROC obtained for the +#' fixed values of super-population, \code{D} and \code{K}.} +#' \item{\code{H}}{ a \code{numeric} representing the higher value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +#' (the number of dimensions) for the specific profile.} +#' \item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for the specific profile.} +#' \item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +#' values (the number of dimensions) for the specific profile. More than one +#' \code{D} is possible.} +#' } +#' } +#' \item{\code{KNNSample}}{ a \code{list} containing the inferred ancestry +#' using different \code{D} and \code{K} values. The \code{list} contains +#' those entries: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{matKNN}}{ a \code{data.frame} containing the inferred ancestry +#' for different values of \code{K} and \code{D}. The \code{data.frame} +#' contains those columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry. } +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry. } +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry for the specified \code{D} and \code{K} values.} +#' } +#' } +#' } +#' } +#' \item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +#' ancestry for the current profile. The \code{data.frame} contains those +#' columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry.} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry.} +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry.} +#' } +#' } +#' } +#' +#' +#' @references +#' +#' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +#' Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +#' of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +#' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +#' +#' @examples +#' +#' +#' ## Required library +#' library(gdsfmt) +#' +#' ## Load the known ancestry for the demo 1KG reference profiles +#' data(demoKnownSuperPop1KG) +#' +#' ## The Reference GDS file +#' path1KG <- system.file("extdata/tests", package="RAIDS") +#' +#' ## Open the Reference GDS file +#' gdsRef <- snpgdsOpen(file.path(path1KG, "ex1_good_small_1KG.gds")) +#' +#' ## Path to the demo synthetic results files +#' ## List of the KNN result files from PCA run on synthetic data +#' dataDirRes <- system.file("extdata/demoAncestryCall/ex1", package="RAIDS") +#' listFilesName <- dir(file.path(dataDirRes), ".rds") +#' listFiles <- file.path(file.path(dataDirRes) , listFilesName) +#' syntheticKNN <- lapply(listFiles, FUN=function(x){return(readRDS(x))}) +#' syntheticKNN <- do.call(rbind, syntheticKNN) +#' +#' # The name of the synthetic study +#' studyID <- "MYDATA.Synthetic" +#' +#' ## Path to the demo Profile GDS file is located in this package +#' dataDir <- system.file("extdata/demoAncestryCall", package="RAIDS") +#' +#' ## Open the Profile GDS file +#' gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) +#' \dontrun{ +#' pedSyn <- RAIDS:::prepPedSynthetic1KG(gdsReference=gdsRef, +#' gdsSample=gdsProfile, studyID=studyID, popName="superPop") +#' +#' ## Run the ancestry inference on one profile called 'ex1' +#' ## The values of K and D used for the inference are selected using the +#' ## synthetic results listFiles=listFiles, +#' resCall <- RAIDS:::computeAncestryFromSynthetic(gdsReference=gdsRef, +#' gdsProfile=gdsProfile, +#' syntheticKNN = syntheticKNN, +#' pedSyn = pedSyn, +#' currentProfile=c("ex1"), +#' spRef=demoKnownSuperPop1KG, +#' studyIDSyn=studyID, np=1L) +#' +#' ## The ancestry called with the optimal D and K values +#' resCall$Ancestry +#' } +#' ## Close the GDS files (important) +#' closefn.gds(gdsProfile) +#' closefn.gds(gdsRef) +#' +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom rlang arg_match +#' @encoding UTF-8 +#' @export +computeAncestryFromSynthetic <- function(gdsReference, gdsProfile, + syntheticKNN, + pedSyn, + currentProfile, + spRef, + studyIDSyn, + np=1L, + listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), + fieldPopIn1KG="superPop", + fieldPopInfAnc="SuperPop", + kList=seq(2, 15, 1), + pcaList=seq(2, 15, 1), + algorithm=c("exact", "randomized"), + eigenCount=32L, + missingRate=NaN, verbose=FALSE) { + + if(is.null(pcaList)) { + pcaList <- seq(2, 15, 1) + } + + if (is.null(kList)) { + kList <- seq(2, 15, 1) + } + + ## Validate input parameters + # validateComputeAncestryFromSynthetic(gdsReference=gdsReference, + # gdsProfile=gdsProfile, syntheticKNN=syntheticKNN, + # pedSyn=pedSyn, + # currentProfile=currentProfile, spRef=spRef, studyIDSyn=studyIDSyn, + # np=np, listCatPop=listCatPop, fieldPopIn1KG=fieldPopIn1KG, + # fieldPopInfAnc=fieldPopInfAnc, kList=kList, pcaList=pcaList, + # algorithm=algorithm, eigenCount=eigenCount, missingRate=missingRate, + # verbose=verbose) + + ## Matches a character method against a table of candidate values + algorithm <- arg_match(algorithm) + + + + ## Compile all the inferred ancestry results for different values of + ## D and K to select the optimal parameters + listParaSample <- selParaPCAUpQuartile(matKNN=syntheticKNN, + pedCall=pedSyn, refCall=fieldPopIn1KG, predCall=fieldPopInfAnc, + listCall=listCatPop) + + ## Project profile on the PCA created with the reference profiles + listPCAProfile <- computePCARefSample(gdsProfile=gdsProfile, + currentProfile=currentProfile, studyIDRef="Ref.1KG", np=np, + algorithm=algorithm, eigenCount=eigenCount, missingRate=missingRate, + verbose=verbose) + + ## Run a k-nearest neighbors analysis on one specific profile + listKNNSample <- computeKNNRefSample(listEigenvector=listPCAProfile, + listCatPop=listCatPop, spRef=spRef, fieldPopInfAnc=fieldPopInfAnc, + kList=kList, pcaList=pcaList) + + ## The ancestry call for the current profile + resCall <- listKNNSample$matKNN[ + which(listKNNSample$matKNN$D == listParaSample$D & + listKNNSample$matKNN$K == listParaSample$K ),] + colnames(listParaSample$dfAUROC) <- c("D", "K", "Call", "L", "AUROC", "H") + res <- list(pcaSample=listPCAProfile, # PCA of the profile + 1KG + paraSample=listParaSample, # Result of the parameter selection + KNNSample=listKNNSample, # KNN for the profile + Ancestry=resCall) # the ancestry call fo the profile + + return(res) +} + #' @title Run most steps leading to the ancestry inference call #' on a specific profile (RNA or DNA) @@ -2424,7 +2762,7 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' @keywords internal runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, + chrInfo, syntheticRefDF, genoSource=c("snp-pileup", "generic", "VCF"), studyType=c("DNA", "RNA"), np=1L, blockTypeID=NULL, verbose=FALSE) { diff --git a/man/computeAncestryFromSynthetic.Rd b/man/computeAncestryFromSynthetic.Rd new file mode 100644 index 000000000..56452ea15 --- /dev/null +++ b/man/computeAncestryFromSynthetic.Rd @@ -0,0 +1,295 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/processStudy_internal.R +\encoding{UTF-8} +\name{computeAncestryFromSynthetic} +\alias{computeAncestryFromSynthetic} +\title{Select the optimal K and D parameters using the synthetic data and +infer the ancestry of a specific profile} +\usage{ +computeAncestryFromSynthetic( + gdsReference, + gdsProfile, + syntheticKNN, + pedSyn, + currentProfile, + spRef, + studyIDSyn, + np = 1L, + listCatPop = c("EAS", "EUR", "AFR", "AMR", "SAS"), + fieldPopIn1KG = "superPop", + fieldPopInfAnc = "SuperPop", + kList = seq(2, 15, 1), + pcaList = seq(2, 15, 1), + algorithm = c("exact", "randomized"), + eigenCount = 32L, + missingRate = NaN, + verbose = FALSE +) +} +\arguments{ +\item{gdsReference}{an object of class \link[gdsfmt]{gds.class} (a GDS +file), the opened 1KG GDS file.} + +\item{gdsProfile}{an object of class \code{\link[gdsfmt]{gds.class}} +(a GDS file), the opened Profile GDS file.} + +\item{syntheticKNN}{a \code{vector} of \code{character} strings representing +the name of files that contain the results of ancestry inference done on +the synthetic profiles for multiple values of \emph{D} and \emph{K}. The files must +exist.} + +\item{pedSyn}{a \code{data.frame} containing the columns extracted from the +GDS Sample 'study.annot' node with a extra column named as the 'popName' +parameter that has been extracted from the 1KG GDS 'sample.annot' node.} + +\item{currentProfile}{a \code{character} string representing the profile +identifier of the current profile on which ancestry will be inferred.} + +\item{spRef}{a \code{vector} of \code{character} strings representing the +known super population ancestry for the 1KG profiles. The 1KG profile +identifiers are used as names for the \code{vector}.} + +\item{studyIDSyn}{a \code{character} string corresponding to the study +identifier. The study identifier must be present in the GDS Sample file.} + +\item{np}{a single positive \code{integer} representing the number of +threads. Default: \code{1L}.} + +\item{listCatPop}{a \code{vector} of \code{character} string +representing the list of possible ancestry assignations. Default: +\code{("EAS", "EUR", "AFR", "AMR", "SAS")}.} + +\item{fieldPopIn1KG}{a \code{character} string representing the name of the +column that contains the known ancestry for the reference profiles in +the Reference GDS file.} + +\item{fieldPopInfAnc}{a \code{character} string representing the name of +the column that will contain the inferred ancestry for the specified +profiles. Default: \code{"SuperPop"}.} + +\item{kList}{a \code{vector} of \code{integer} representing the list of +values tested for the \emph{K} parameter. The \emph{K} parameter represents the +number of neighbors used in the K-nearest neighbor analysis. If \code{NULL}, +the value \code{seq(2,15,1)} is assigned. +Default: \code{seq(2,15,1)}.} + +\item{pcaList}{a \code{vector} of \code{integer} representing the list of +values tested for the \emph{D} parameter. The \emph{D} parameter represents the +number of dimensions used in the PCA analysis. If \code{NULL}, +the value \code{seq(2,15,1)} is assigned. +Default: \code{seq(2,15,1)}.} + +\item{algorithm}{a \code{character} string representing the algorithm used +to calculate the PCA. The 2 choices are "exact" (traditional exact +calculation) and "randomized" (fast PCA with randomized algorithm +introduced in Galinsky et al. 2016). Default: \code{"exact"}.} + +\item{eigenCount}{a single \code{integer} indicating the number of +eigenvectors that will be in the output of the \link[SNPRelate]{snpgdsPCA} +function; if 'eigenCount' <= 0, then all eigenvectors are returned. +Default: \code{32L}.} + +\item{missingRate}{a \code{numeric} value representing the threshold +missing rate at with the SNVs are discarded; the SNVs are retained in the +\link[SNPRelate]{snpgdsPCA} +with "<= missingRate" only; if \code{NaN}, no missing threshold. +Default: \code{NaN}.} + +\item{verbose}{a \code{logical} indicating if messages should be printed +to show how the different steps in the function. Default: \code{FALSE}.} +} +\value{ +a \code{list} containing 4 entries: +\describe{ +\item{\code{pcaSample}}{ a \code{list} containing the information related +to the eigenvectors. The \code{list} contains those 3 entries: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +the eigenvectors for the reference profiles.} +\item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +eigenvectors for the current profile projected on the PCA from the +reference profiles.} +} +} +\item{\code{paraSample}}{ a \code{list} containing the results with +different \code{D} and \code{K} values that lead to optimal parameter +selection. The \code{list} contains those entries: +\describe{ +\item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +on all combined synthetic results done with a fixed value of \code{D} (the +number of dimensions). The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{median}}{ a \code{numeric} representing the median of the +minimum AUROC obtained (within super populations) for all combination of +the fixed \code{D} value and all tested \code{K} values. } +\item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +AUROC obtained (within super populations) for all combination of the fixed +\code{D} value and all tested \code{K} values. } +\item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +of the minimum AUROC obtained (within super populations) for all +combination of the fixed \code{D} value and all tested \code{K} values. } +\item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for a fixed \code{D} value. } +} +} +\item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +all combined synthetic results done with different values of \code{D} (the +number of dimensions) and \code{K} (the number of neighbors). +The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +obtained by grouping all the synthetic results by super-populations, for +the specified values of \code{D} and \code{K}.} +\item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +by grouping all the synthetic results for the specified values of \code{D} +and \code{K}.} +\item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +of the confusion matrix obtained by grouping all the synthetic results for +the specified values of \code{D} and \code{K}.} +} +} +\item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +super-population. The \code{data.frame} contains +those columns: +\describe{ +\item{\code{pcaD}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{Call}}{ a \code{character} string representing the +super-population.} +\item{\code{L}}{ a \code{numeric} representing the lower value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +\item{\code{AUR}}{ a \code{numeric} representing the AUROC obtained for the +fixed values of super-population, \code{D} and \code{K}.} +\item{\code{H}}{ a \code{numeric} representing the higher value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +} +} +\item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +(the number of dimensions) for the specific profile.} +\item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for the specific profile.} +\item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +values (the number of dimensions) for the specific profile. More than one +\code{D} is possible.} +} +} +\item{\code{KNNSample}}{ a \code{list} containing the inferred ancestry +using different \code{D} and \code{K} values. The \code{list} contains +those entries: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{matKNN}}{ a \code{data.frame} containing the inferred ancestry +for different values of \code{K} and \code{D}. The \code{data.frame} +contains those columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry. } +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry. } +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry for the specified \code{D} and \code{K} values.} +} +} +} +} +\item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +ancestry for the current profile. The \code{data.frame} contains those +columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry.} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry.} +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry.} +} +} +} +} +\description{ +The function select the optimal K and D parameters for a +specific profile. The results on the synthetic data are used for the +parameter selection. Once the optimal parameters are selected, the +ancestry is inferred for the specific profile. +} +\examples{ + + +## Required library +library(gdsfmt) + +## Load the known ancestry for the demo 1KG reference profiles +data(demoKnownSuperPop1KG) + +## The Reference GDS file +path1KG <- system.file("extdata/tests", package="RAIDS") + +## Open the Reference GDS file +gdsRef <- snpgdsOpen(file.path(path1KG, "ex1_good_small_1KG.gds")) + +## Path to the demo synthetic results files +## List of the KNN result files from PCA run on synthetic data +dataDirRes <- system.file("extdata/demoAncestryCall/ex1", package="RAIDS") +listFilesName <- dir(file.path(dataDirRes), ".rds") +listFiles <- file.path(file.path(dataDirRes) , listFilesName) +syntheticKNN <- lapply(listFiles, FUN=function(x){return(readRDS(x))}) +syntheticKNN <- do.call(rbind, syntheticKNN) + +# The name of the synthetic study +studyID <- "MYDATA.Synthetic" + +## Path to the demo Profile GDS file is located in this package +dataDir <- system.file("extdata/demoAncestryCall", package="RAIDS") + +## Open the Profile GDS file +gdsProfile <- snpgdsOpen(file.path(dataDir, "ex1.gds")) +\dontrun{ + pedSyn <- RAIDS:::prepPedSynthetic1KG(gdsReference=gdsRef, + gdsSample=gdsProfile, studyID=studyID, popName="superPop") + + ## Run the ancestry inference on one profile called 'ex1' + ## The values of K and D used for the inference are selected using the + ## synthetic results listFiles=listFiles, + resCall <- RAIDS:::computeAncestryFromSynthetic(gdsReference=gdsRef, + gdsProfile=gdsProfile, + syntheticKNN = syntheticKNN, + pedSyn = pedSyn, + currentProfile=c("ex1"), + spRef=demoKnownSuperPop1KG, + studyIDSyn=studyID, np=1L) + + ## The ancestry called with the optimal D and K values + resCall$Ancestry +} +## Close the GDS files (important) +closefn.gds(gdsProfile) +closefn.gds(gdsRef) + + +} +\references{ +Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} From d24b7cdbcec599973220879c2e2cd5f3135b3c2a Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 11 Sep 2024 10:12:49 -0400 Subject: [PATCH 295/385] Add function profileAncestry --- R/processStudy_internal.R | 442 +++++++++++++++++++++++++++- man/computeAncestryFromSynthetic.Rd | 4 +- man/profileAncestry.Rd | 345 ++++++++++++++++++++++ 3 files changed, 787 insertions(+), 4 deletions(-) create mode 100644 man/profileAncestry.Rd diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 90aff17ee..bddc5092c 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2226,6 +2226,444 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, return(0L) } +#' @title Run most steps leading to the ancestry inference call on a +#' specific profile (LD or geneAware) +#' +#' @description This function runs most steps leading to the ancestry inference +#' call on a specific profile. First, the function creates the Profile GDS file +#' for the specific profile using the information from a RDS Sample +#' description file and the Population reference GDS file. +#' +#' @param gdsReference an object of class \code{\link[gdsfmt]{gds.class}} +#' (a GDS file), the opened Population Reference GDS file. +#' +#' @param gdsRefAnnot an object of class \code{\link[gdsfmt]{gds.class}} +#' (a GDS file), the opened Population Reference SNV Annotation GDS file. +#' This parameter is RNA specific. +#' +#' @param studyDF a \code{data.frame} containing the information about the +#' study associated to the analysed sample(s). The \code{data.frame} must have +#' those 3 columns: "study.id", "study.desc", "study.platform". All columns +#' must be in \code{character} strings (no factor). +#' +#' @param currentProfile a \code{character} string representing the profile +#' identifier. +#' +#' @param pathProfileGDS a \code{character} string representing the path to +#' the directory where the GDS Profile files will be created. +#' Default: \code{NULL}. +#' +#' @param chrInfo a \code{vector} of positive \code{integer} values +#' representing the length of the chromosomes. See 'details' section. +#' +#' @param syntheticRefDF a \code{data.frame} containing a subset of +#' reference profiles for each sub-population present in the Reference GDS +#' file. The \code{data.frame} must have those columns: +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample +#' identifier. } +#' \item{pop.group}{ a \code{character} string representing the +#' subcontinental population assigned to the sample. } +#' \item{superPop}{ a \code{character} string representing the +#' super-population assigned to the sample. } +#' } +#' +#' @param studyDFSyn a \code{data.frame} containing the information about the +#' synthetic data to the analysed sample(s). The \code{data.frame} must have +#' those 3 columns: "study.id", "study.desc", "study.platform". All columns +#' must be in \code{character} strings (no factor). +#' +#' @param listProfileRef a \code{vector} of \code{character} string +#' representing the +#' identifiers of the selected 1KG profiles that will be used as reference to +#' generate the synthetic profiles. +#' +#' @param studyType a \code{character} string representing the type of study. +#' The possible choices are: "LD" and "GeneAware". The type of study affects the +#' way the estimation of the allelic fraction is done. Default: \code{"LD"}. +#' +#' @param np a single positive \code{integer} specifying the number of +#' threads to be used. Default: \code{1L}. +#' +#' @param blockTypeID a \code{character} string corresponding to the block +#' type used to extract the block identifiers. The block type must be +#' present in the GDS Reference Annotation file. +#' +#' @param verbose a \code{logical} indicating if messages should be printed +#' to show how the different steps in the function. Default: \code{FALSE}. +#' +#' @return a \code{list} containing 4 entries: +#' \describe{ +#' \item{\code{pcaSample}}{ a \code{list} containing the information related +#' to the eigenvectors. The \code{list} contains those 3 entries: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +#' the eigenvectors for the reference profiles.} +#' \item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +#' eigenvectors for the current profile projected on the PCA from the +#' reference profiles.} +#' } +#' } +#' \item{\code{paraSample}}{ a \code{list} containing the results with +#' different \code{D} and \code{K} values that lead to optimal parameter +#' selection. The \code{list} contains those entries: +#' \describe{ +#' \item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +#' on all combined synthetic results done with a fixed value of \code{D} (the +#' number of dimensions). The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{median}}{ a \code{numeric} representing the median of the +#' minimum AUROC obtained (within super populations) for all combination of +#' the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +#' AUROC obtained (within super populations) for all combination of the fixed +#' \code{D} value and all tested \code{K} values. } +#' \item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +#' of the minimum AUROC obtained (within super populations) for all +#' combination of the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for a fixed \code{D} value. } +#' } +#' } +#' \item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +#' all combined synthetic results done with different values of \code{D} (the +#' number of dimensions) and \code{K} (the number of neighbors). +#' The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +#' obtained by grouping all the synthetic results by super-populations, for +#' the specified values of \code{D} and \code{K}.} +#' \item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +#' by grouping all the synthetic results for the specified values of \code{D} +#' and \code{K}.} +#' \item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +#' of the confusion matrix obtained by grouping all the synthetic results for +#' the specified values of \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +#' super-population. The \code{data.frame} contains +#' those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{Call}}{ a \code{character} string representing the +#' super-population.} +#' \item{\code{L}}{ a \code{numeric} representing the lower value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' \item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for the +#' fixed values of super-population, \code{D} and \code{K}.} +#' \item{\code{H}}{ a \code{numeric} representing the higher value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +#' (the number of dimensions) for the specific profile.} +#' \item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for the specific profile.} +#' \item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +#' values (the number of dimensions) for the specific profile. More than one +#' \code{D} is possible.} +#' } +#' } +#' \item{\code{KNNSample}}{ a \code{data.frame} containing the inferred ancestry +#' for different values of \code{K} and \code{D}. The \code{data.frame} +#' contains those columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry. } +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry. } +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry for the specified \code{D} and \code{K} values.} +#' } +#' } +#' \item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred ancestry +#' for each synthetic data for different values of \code{K} and \code{D}. +#' The \code{data.frame} +#' contains those columns: "sample.id", "D", "K", "infer.superPop", "ref.superPop" +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current synthetic data.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry. } +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry. } +#' \item{\code{infer.superPop}}{ a \code{character} string representing the inferred +#' ancestry for the specified \code{D} and \code{K} values.} +#' \item{\code{ref.superPop}}{ a \code{character} string representing the known +#' ancestry from the reference} +#' } +#' } +#' \item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +#' ancestry for the current profile. The \code{data.frame} contains those +#' columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry.} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry.} +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry.} +#' } +#' } +#' } +#' +#' @details +#' +#' The runWrapperAncestry() function generates 3 types of files +#' in the \code{pathOut} directory: +#' \describe{ +#' \item{Ancestry Inference}{ The ancestry inference CSV file +#' (".Ancestry.csv" file)} +#' \item{Inference Informaton}{ The inference information RDS file +#' (".infoCall.rds" file)} +#' \item{Synthetic Information}{ The parameter information RDS files +#' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +#' } +#' +#' In addition, a sub-directory (named using the profile ID) is +#' also created. +#' +#' @references +#' +#' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +#' Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +#' of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +#' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +#' +#' @examples +#' +#' ## Required library for GDS +#' library(SNPRelate) +#' +#' ## Path to the demo 1KG GDS file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ################################################################# +#' ## Load the information about the profile +#' ################################################################# +#' data(demoPedigreeEx1) +#' head(demoPedigreeEx1) +#' +#' ################################################################# +#' ## The 1KG GDS file and the 1KG SNV Annotation GDS file +#' ## need to be located in the same directory +#' ## Note that the 1KG GDS file used for this example is a +#' ## simplified version and CANNOT be used for any real analysis +#' ################################################################# +#' path1KG <- file.path(dataDir, "tests") +#' +#' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +#' fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") +#' +#' ################################################################# +#' ## The Sample SNP pileup files (one per sample) need +#' ## to be located in the same directory. +#' ################################################################# +#' pathGeno <- file.path(dataDir, "example", "snpPileup") +#' +#' ################################################################# +#' ## The path where the Profile GDS Files (one per sample) +#' ## will be created need to be specified. +#' ################################################################# +#' +#' pathProfileGDS <- file.path(tempdir(), "outTest.tmp") +#' +#' +#' ################################################################# +#' ## A data frame containing general information about the study +#' ## is also required. The data frame must have +#' ## those 3 columns: "studyID", "study.desc", "study.platform" +#' ################################################################# +#' studyDF <- data.frame(study.id="MYDATA", +#' study.desc="Description", +#' study.platform="PLATFORM", +#' stringsAsFactors=FALSE) +#' +#' #################################################################### +#' ## Fix seed to ensure reproducible results +#' #################################################################### +#' set.seed(3043) +#' +#' dataRef <- select1KGPopForSynthetic(fileReferenceGDS, nbProfiles=2L) +#' +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), +#' study.desc=paste0(studyDF$study.id, " synthetic data"), +#' study.platform=studyDF$study.platform, stringsAsFactors=FALSE) +#' +#' listProfileRef <- dataRef$sample.id +#' profileFile <- file.path(pathProfileGDS, "ex1.gds") +#' +#' \dontrun{ +#' +#' dir.create(pathProfileGDS) +#' file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) +#' +#' gdsReference <- snpgdsOpen(fileReferenceGDS) +#' gdsRefAnnot <- openfn.gds(fileAnnotGDS) +#' +#' res <- RAIDS:::profileAncestry(gdsReference=gdsReference, +#' gdsRefAnnot=gdsRefAnnot, +#' studyDF=studyDF, currentProfile=demoPedigreeEx1[1,"Name.ID"], +#' pathProfileGDS=pathProfileGDS, +#' chrInfo=chrInfo, +#' syntheticRefDF=dataRef, +#' studyDFSyn=studyDFSyn, +#' listProfileRef=listProfileRef, +#' studyType="LD") +#' +#' closefn.gds(gdsReference) +#' closefn.gds(gdsRefAnnot) +#' +#' +#' } +#' } +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom utils write.csv +#' @importFrom rlang arg_match +#' @encoding UTF-8 +#' @keywords internal + +profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, + currentProfile, pathProfileGDS, chrInfo, syntheticRefDF, + studyDFSyn, listProfileRef, studyType=c("LD", "GeneAware"), + np=1L, blockTypeID=NULL, verbose=FALSE) { + # This part can be share with runProfileAncestry + studyType <- arg_match(studyType) + + pruningSample(gdsReference=gdsReference, currentProfile=currentProfile, + studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS, np=np) + + fileGDSProfile <- file.path(pathProfileGDS, + paste0(currentProfile, ".gds")) + + add1KG2SampleGDS(gdsReference=gdsReference, fileProfileGDS=fileGDSProfile, + currentProfile=currentProfile, studyID=studyDF$study.id) + + addStudy1Kg(gdsReference, fileGDSProfile) + + gdsProfile <- openfn.gds(fileGDSProfile, readonly=FALSE) + # Change for the old studyType + studyTypeLeg <- ifelse(studyType=="LD", "DNA", "RNA") + estimateAllelicFraction(gdsReference=gdsReference, gdsProfile=gdsProfile, + currentProfile=currentProfile, studyID=studyDF$study.id, + chrInfo=chrInfo, studyType=studyTypeLeg, gdsRefAnnot=gdsRefAnnot, + blockID=blockTypeID, verbose=verbose) + closefn.gds(gdsProfile) + + ## Add information related to the synthetic profiles in Profile GDS file + prepSynthetic(fileProfileGDS=fileGDSProfile, + listSampleRef=listProfileRef, profileID=currentProfile, + studyDF=studyDFSyn, prefix="1", verbose=verbose) + + resG <- syntheticGeno(gdsReference=gdsReference, gdsRefAnnot=gdsRefAnnot, + fileProfileGDS=fileGDSProfile, profileID=currentProfile, + listSampleRef=listProfileRef, prefix="1") + + # if(! file.exists(pathOut)) { + # dir.create(pathOut) + # } + # + spRef <- getRef1KGPop(gdsReference, "superPop") + sampleRM <- splitSelectByPop(syntheticRefDF) + # + # pathOutProfile <- file.path(pathOut, currentProfile) + # if(! file.exists(pathOutProfile)) { + # dir.create(pathOutProfile) + # } + + ##### End share with runProfileAncestry + + ## Open the Profile GDS file + gdsProfile <- snpgdsOpen(fileGDSProfile) + + + ## This variable will contain the results from the PCA analyses + ## For each row of the sampleRM matrix + resSyn <- lapply(seq_len(nrow(sampleRM)), FUN=function(x, sampleRM, + gdsProfile, studyDFSyn, spRef, + pathOutProfile, currentProfile) { + synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, + sampleRM=sampleRM[x,], + studyIDSyn=studyDFSyn$study.id, + np=np, spRef=spRef, eigenCount=15L, + verbose=verbose) + + ## Results are saved + # saveRDS(synthKNN$matKNN, file.path(pathOutProfile, + # paste0("KNN.synt.", currentProfile, ".", x, ".rds"))) + return(synthKNN$matKNN) + }, sampleRM=sampleRM, gdsProfile=gdsProfile, + studyDFSyn=studyDFSyn, spRef=spRef, pathOutProfile=pathOutProfile, + currentProfile=currentProfile) + resSyn <- do.call(rbind, resSyn) + ## Extract the super-population information from the 1KG GDS file + ## for profiles associated to the synthetic study + pedSyn <- prepPedSynthetic1KG(gdsReference=gdsReference, + gdsSample=gdsProfile, studyID=studyDFSyn$study.id, popName="superPop") + + + # idCur <- matrix(unlist(strsplit(resSyn$sample.id, "\\.")), nr=4) + # resKNN$superPopObs <- df[idCur[3,], 3] + # ## Directory where the KNN results have been saved + # pathKNN <- file.path(pathOut, currentProfile) + # listFilesName <- dir(file.path(pathKNN), ".rds") + # ## List of the KNN result files from PCA on synthetic data + # listFiles <- file.path(file.path(pathKNN) , listFilesName) + + resCall <- computeAncestryFromSynthetic(gdsReference=gdsReference, + gdsProfile=gdsProfile, syntheticKNN=resSyn, + pedSyn=pedSyn, + currentProfile=currentProfile, spRef=spRef, + studyIDSyn=studyDFSyn$study.id, np=np) + + # saveRDS(resCall, file.path(pathOut, + # paste0(currentProfile, ".infoCall", ".rds"))) + # + # write.csv(x=resCall$Ancestry, file=file.path(pathOut, + # paste0(currentProfile, ".Ancestry",".csv")), quote=FALSE, + # row.names=FALSE) + + ## Close Profile GDS file (important) + closefn.gds(gdsProfile) + resSyn[[paste0("ref.superPop")]] <- pedSyn[resSyn$sample.id, "superPop"] + + colnames(resSyn) <- c("sample.id", "D", "K", "infer.superPop", "ref.superPop") + res <- list(pcaSample=resCall$pcaSample, # PCA of the profile + 1KG + paraSample=resCall$paraSample, # Result of the parameter selection + KNNSample=resCall$KNNSample$matKNN, # KNN for the profile + KNNSynthetic=resSyn, # KNN results for synthetic data + Ancestry=resCall) # the ancestry call fo the profile + + return(res) +} + #' @title Select the optimal K and D parameters using the synthetic data and #' infer the ancestry of a specific profile #' @@ -2366,7 +2804,7 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' super-population. The \code{data.frame} contains #' those columns: #' \describe{ -#' \item{\code{pcaD}}{ a \code{numeric} representing the value of \code{D} (the +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the #' number of dimensions).} #' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the #' number of neighbors).} @@ -2375,7 +2813,7 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' \item{\code{L}}{ a \code{numeric} representing the lower value of the 95% #' confidence interval for the AUROC obtained for the fixed values of #' super-population, \code{D} and \code{K}.} -#' \item{\code{AUR}}{ a \code{numeric} representing the AUROC obtained for the +#' \item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for the #' fixed values of super-population, \code{D} and \code{K}.} #' \item{\code{H}}{ a \code{numeric} representing the higher value of the 95% #' confidence interval for the AUROC obtained for the fixed values of diff --git a/man/computeAncestryFromSynthetic.Rd b/man/computeAncestryFromSynthetic.Rd index 56452ea15..148d6d685 100644 --- a/man/computeAncestryFromSynthetic.Rd +++ b/man/computeAncestryFromSynthetic.Rd @@ -160,7 +160,7 @@ the specified values of \code{D} and \code{K}.} super-population. The \code{data.frame} contains those columns: \describe{ -\item{\code{pcaD}}{ a \code{numeric} representing the value of \code{D} (the +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the number of dimensions).} \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the number of neighbors).} @@ -169,7 +169,7 @@ super-population.} \item{\code{L}}{ a \code{numeric} representing the lower value of the 95\% confidence interval for the AUROC obtained for the fixed values of super-population, \code{D} and \code{K}.} -\item{\code{AUR}}{ a \code{numeric} representing the AUROC obtained for the +\item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for the fixed values of super-population, \code{D} and \code{K}.} \item{\code{H}}{ a \code{numeric} representing the higher value of the 95\% confidence interval for the AUROC obtained for the fixed values of diff --git a/man/profileAncestry.Rd b/man/profileAncestry.Rd new file mode 100644 index 000000000..b7f0fabce --- /dev/null +++ b/man/profileAncestry.Rd @@ -0,0 +1,345 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/processStudy_internal.R +\encoding{UTF-8} +\name{profileAncestry} +\alias{profileAncestry} +\title{Run most steps leading to the ancestry inference call on a +specific profile (LD or geneAware)} +\usage{ +profileAncestry( + gdsReference, + gdsRefAnnot, + studyDF, + currentProfile, + pathProfileGDS, + chrInfo, + syntheticRefDF, + studyDFSyn, + listProfileRef, + studyType = c("LD", "GeneAware"), + np = 1L, + blockTypeID = NULL, + verbose = FALSE +) +} +\arguments{ +\item{gdsReference}{an object of class \code{\link[gdsfmt]{gds.class}} +(a GDS file), the opened Population Reference GDS file.} + +\item{gdsRefAnnot}{an object of class \code{\link[gdsfmt]{gds.class}} +(a GDS file), the opened Population Reference SNV Annotation GDS file. +This parameter is RNA specific.} + +\item{studyDF}{a \code{data.frame} containing the information about the +study associated to the analysed sample(s). The \code{data.frame} must have +those 3 columns: "study.id", "study.desc", "study.platform". All columns +must be in \code{character} strings (no factor).} + +\item{currentProfile}{a \code{character} string representing the profile +identifier.} + +\item{pathProfileGDS}{a \code{character} string representing the path to +the directory where the GDS Profile files will be created. +Default: \code{NULL}.} + +\item{chrInfo}{a \code{vector} of positive \code{integer} values +representing the length of the chromosomes. See 'details' section.} + +\item{syntheticRefDF}{a \code{data.frame} containing a subset of +reference profiles for each sub-population present in the Reference GDS +file. The \code{data.frame} must have those columns: +\describe{ +\item{sample.id}{ a \code{character} string representing the sample +identifier. } +\item{pop.group}{ a \code{character} string representing the +subcontinental population assigned to the sample. } +\item{superPop}{ a \code{character} string representing the +super-population assigned to the sample. } +}} + +\item{studyDFSyn}{a \code{data.frame} containing the information about the +synthetic data to the analysed sample(s). The \code{data.frame} must have +those 3 columns: "study.id", "study.desc", "study.platform". All columns +must be in \code{character} strings (no factor).} + +\item{listProfileRef}{a \code{vector} of \code{character} string +representing the +identifiers of the selected 1KG profiles that will be used as reference to +generate the synthetic profiles.} + +\item{studyType}{a \code{character} string representing the type of study. +The possible choices are: "LD" and "GeneAware". The type of study affects the +way the estimation of the allelic fraction is done. Default: \code{"LD"}.} + +\item{np}{a single positive \code{integer} specifying the number of +threads to be used. Default: \code{1L}.} + +\item{blockTypeID}{a \code{character} string corresponding to the block +type used to extract the block identifiers. The block type must be +present in the GDS Reference Annotation file.} + +\item{verbose}{a \code{logical} indicating if messages should be printed +to show how the different steps in the function. Default: \code{FALSE}.} +} +\value{ +a \code{list} containing 4 entries: +\describe{ +\item{\code{pcaSample}}{ a \code{list} containing the information related +to the eigenvectors. The \code{list} contains those 3 entries: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +the eigenvectors for the reference profiles.} +\item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +eigenvectors for the current profile projected on the PCA from the +reference profiles.} +} +} +\item{\code{paraSample}}{ a \code{list} containing the results with +different \code{D} and \code{K} values that lead to optimal parameter +selection. The \code{list} contains those entries: +\describe{ +\item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +on all combined synthetic results done with a fixed value of \code{D} (the +number of dimensions). The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{median}}{ a \code{numeric} representing the median of the +minimum AUROC obtained (within super populations) for all combination of +the fixed \code{D} value and all tested \code{K} values. } +\item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +AUROC obtained (within super populations) for all combination of the fixed +\code{D} value and all tested \code{K} values. } +\item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +of the minimum AUROC obtained (within super populations) for all +combination of the fixed \code{D} value and all tested \code{K} values. } +\item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for a fixed \code{D} value. } +} +} +\item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +all combined synthetic results done with different values of \code{D} (the +number of dimensions) and \code{K} (the number of neighbors). +The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +obtained by grouping all the synthetic results by super-populations, for +the specified values of \code{D} and \code{K}.} +\item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +by grouping all the synthetic results for the specified values of \code{D} +and \code{K}.} +\item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +of the confusion matrix obtained by grouping all the synthetic results for +the specified values of \code{D} and \code{K}.} +} +} +\item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +super-population. The \code{data.frame} contains +those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{Call}}{ a \code{character} string representing the +super-population.} +\item{\code{L}}{ a \code{numeric} representing the lower value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +\item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for the +fixed values of super-population, \code{D} and \code{K}.} +\item{\code{H}}{ a \code{numeric} representing the higher value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +} +} +\item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +(the number of dimensions) for the specific profile.} +\item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for the specific profile.} +\item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +values (the number of dimensions) for the specific profile. More than one +\code{D} is possible.} +} +} +\item{\code{KNNSample}}{ a \code{data.frame} containing the inferred ancestry +for different values of \code{K} and \code{D}. The \code{data.frame} +contains those columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry. } +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry. } +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry for the specified \code{D} and \code{K} values.} +} +} +\item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred ancestry +for each synthetic data for different values of \code{K} and \code{D}. +The \code{data.frame} +contains those columns: "sample.id", "D", "K", "infer.superPop", "ref.superPop" +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current synthetic data.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry. } +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry. } +\item{\code{infer.superPop}}{ a \code{character} string representing the inferred +ancestry for the specified \code{D} and \code{K} values.} +\item{\code{ref.superPop}}{ a \code{character} string representing the known +ancestry from the reference} +} +} +\item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +ancestry for the current profile. The \code{data.frame} contains those +columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry.} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry.} +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry.} +} +} +} +} +\description{ +This function runs most steps leading to the ancestry inference +call on a specific profile. First, the function creates the Profile GDS file +for the specific profile using the information from a RDS Sample +description file and the Population reference GDS file. +} +\details{ +The runWrapperAncestry() function generates 3 types of files +in the \code{pathOut} directory: +\describe{ +\item{Ancestry Inference}{ The ancestry inference CSV file +(".Ancestry.csv" file)} +\item{Inference Informaton}{ The inference information RDS file +(".infoCall.rds" file)} +\item{Synthetic Information}{ The parameter information RDS files +from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +} + +In addition, a sub-directory (named using the profile ID) is +also created. +} +\examples{ + +## Required library for GDS +library(SNPRelate) + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +################################################################# +## Load the information about the profile +################################################################# +data(demoPedigreeEx1) +head(demoPedigreeEx1) + +################################################################# +## The 1KG GDS file and the 1KG SNV Annotation GDS file +## need to be located in the same directory +## Note that the 1KG GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +################################################################# +path1KG <- file.path(dataDir, "tests") + +fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") + +################################################################# +## The Sample SNP pileup files (one per sample) need +## to be located in the same directory. +################################################################# +pathGeno <- file.path(dataDir, "example", "snpPileup") + +################################################################# +## The path where the Profile GDS Files (one per sample) +## will be created need to be specified. +################################################################# + +pathProfileGDS <- file.path(tempdir(), "outTest.tmp") + + +################################################################# +## A data frame containing general information about the study +## is also required. The data frame must have +## those 3 columns: "studyID", "study.desc", "study.platform" +################################################################# +studyDF <- data.frame(study.id="MYDATA", + study.desc="Description", + study.platform="PLATFORM", + stringsAsFactors=FALSE) + +#################################################################### +## Fix seed to ensure reproducible results +#################################################################### +set.seed(3043) + +dataRef <- select1KGPopForSynthetic(fileReferenceGDS, nbProfiles=2L) + +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), + study.desc=paste0(studyDF$study.id, " synthetic data"), + study.platform=studyDF$study.platform, stringsAsFactors=FALSE) + + listProfileRef <- dataRef$sample.id + profileFile <- file.path(pathProfileGDS, "ex1.gds") + + \dontrun{ + + dir.create(pathProfileGDS) + file.copy(file.path(dataDir, "tests", "ex1_demo.gds"), profileFile) + + gdsReference <- snpgdsOpen(fileReferenceGDS) + gdsRefAnnot <- openfn.gds(fileAnnotGDS) + + res <- RAIDS:::profileAncestry(gdsReference=gdsReference, + gdsRefAnnot=gdsRefAnnot, + studyDF=studyDF, currentProfile=demoPedigreeEx1[1,"Name.ID"], + pathProfileGDS=pathProfileGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + studyDFSyn=studyDFSyn, + listProfileRef=listProfileRef, + studyType="LD") + + closefn.gds(gdsReference) + closefn.gds(gdsRefAnnot) + + + } +} + +} +\references{ +Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} From 3938d28750a8421adad96dda3fed0811eac56853 Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 11 Sep 2024 10:35:48 -0400 Subject: [PATCH 296/385] Changed the man of profileAncestry --- R/processStudy_internal.R | 19 ++++--------------- man/profileAncestry.Rd | 15 ++------------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index bddc5092c..912963ea0 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2427,19 +2427,8 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' #' @details #' -#' The runWrapperAncestry() function generates 3 types of files -#' in the \code{pathOut} directory: -#' \describe{ -#' \item{Ancestry Inference}{ The ancestry inference CSV file -#' (".Ancestry.csv" file)} -#' \item{Inference Informaton}{ The inference information RDS file -#' (".infoCall.rds" file)} -#' \item{Synthetic Information}{ The parameter information RDS files -#' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} -#' } -#' -#' In addition, a sub-directory (named using the profile ID) is -#' also created. +#' The profileAncestry() generates list \code{list} +#' TODO update the description #' #' @references #' @@ -2608,7 +2597,7 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, ## For each row of the sampleRM matrix resSyn <- lapply(seq_len(nrow(sampleRM)), FUN=function(x, sampleRM, gdsProfile, studyDFSyn, spRef, - pathOutProfile, currentProfile) { + currentProfile) { synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, sampleRM=sampleRM[x,], studyIDSyn=studyDFSyn$study.id, @@ -2620,7 +2609,7 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, # paste0("KNN.synt.", currentProfile, ".", x, ".rds"))) return(synthKNN$matKNN) }, sampleRM=sampleRM, gdsProfile=gdsProfile, - studyDFSyn=studyDFSyn, spRef=spRef, pathOutProfile=pathOutProfile, + studyDFSyn=studyDFSyn, spRef=spRef, currentProfile=currentProfile) resSyn <- do.call(rbind, resSyn) ## Extract the super-population information from the 1KG GDS file diff --git a/man/profileAncestry.Rd b/man/profileAncestry.Rd index b7f0fabce..71d179689 100644 --- a/man/profileAncestry.Rd +++ b/man/profileAncestry.Rd @@ -222,19 +222,8 @@ for the specific profile using the information from a RDS Sample description file and the Population reference GDS file. } \details{ -The runWrapperAncestry() function generates 3 types of files -in the \code{pathOut} directory: -\describe{ -\item{Ancestry Inference}{ The ancestry inference CSV file -(".Ancestry.csv" file)} -\item{Inference Informaton}{ The inference information RDS file -(".infoCall.rds" file)} -\item{Synthetic Information}{ The parameter information RDS files -from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} -} - -In addition, a sub-directory (named using the profile ID) is -also created. +The profileAncestry() generates list \code{list} +TODO update the description } \examples{ From 33ac4f216f79b3cdb31b5a07db1306a6e10991f3 Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 11 Sep 2024 11:08:41 -0400 Subject: [PATCH 297/385] Add function wrapperAncestry --- R/processStudy_internal.R | 350 ++++++++++++++++++++++++++++++++++++++ man/wrapperAncestry.Rd | 331 +++++++++++++++++++++++++++++++++++ 2 files changed, 681 insertions(+) create mode 100644 man/wrapperAncestry.Rd diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 912963ea0..c06a96ecb 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -3235,3 +3235,353 @@ runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, ## Successful return(0L) } + +#' @title Run most steps leading to the ancestry inference call +#' on a specific profile (RNA or DNA) +#' +#' @description This function runs most steps leading to the ancestry inference +#' call on a specific profile. First, the function creates the Profile GDS file +#' for the specific profile using the information from a RDS Sample +#' description file and the Population reference GDS file. +#' +#' @param pedStudy a \code{data.frame} with those mandatory columns: "Name.ID", +#' "Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +#' \code{character} strings (no factor). The \code{data.frame} +#' must contain the information for all the samples passed in the +#' \code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +#' can be defined. +#' +#' @param studyDF a \code{data.frame} containing the information about the +#' study associated to the analysed sample(s). The \code{data.frame} must have +#' those 3 columns: "study.id", "study.desc", "study.platform". All columns +#' must be in \code{character} strings (no factor). +#' +#' @param pathProfileGDS a \code{character} string representing the path to +#' the directory where the GDS Profile files will be created. +#' Default: \code{NULL}. +#' +#' @param pathGeno a \code{character} string representing the path to the +#' directory containing the VCF output of SNP-pileup for each sample. The +#' SNP-pileup files must be compressed (gz files) and have the name identifiers +#' of the samples. A sample with "Name.ID" identifier would have an +#' associated file called +#' if genoSource is "VCF", then "Name.ID.vcf.gz", +#' if genoSource is "generic", then "Name.ID.generic.txt.gz" +#' if genoSource is "snp-pileup", then "Name.ID.txt.gz". +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Reference GDS file. The file must exist. +#' +#' @param fileReferenceAnnotGDS a \code{character} string representing the +#' file name of the Reference GDS Annotation file. The file must exist. +#' +#' @param chrInfo a \code{vector} of positive \code{integer} values +#' representing the length of the chromosomes. See 'details' section. +#' +#' @param syntheticRefDF a \code{data.frame} containing a subset of +#' reference profiles for each sub-population present in the Reference GDS +#' file. The \code{data.frame} must have those columns: +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample +#' identifier. } +#' \item{pop.group}{ a \code{character} string representing the +#' subcontinental population assigned to the sample. } +#' \item{superPop}{ a \code{character} string representing the +#' super-population assigned to the sample. } +#' } +#' +#' @param studyType a \code{character} string representing the type of study. +#' The possible choices are: "DNA" and "RNA". The type of study affects the +#' way the estimation of the allelic fraction is done. Default: \code{"DNA"}. +#' +#' @param genoSource a \code{character} string with two possible values: +#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +#' are generated by snp-pileup (Facets) or are a generic format CSV file +#' with at least those columns: +#' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +#' The 'Count' is the depth at the specified position; +#' 'FileR' is the depth of the reference allele and +#' 'File1A' is the depth of the specific alternative allele. +#' Finally the file can be a VCF file with at least those genotype +#' fields: GT, AD, DP. +#' +#' @param np a single positive \code{integer} specifying the number of +#' threads to be used. Default: \code{1L}. +#' +#' @param blockTypeID a \code{character} string corresponding to the block +#' type used to extract the block identifiers. The block type must be +#' present in the GDS Reference Annotation file. +#' +#' @param verbose a \code{logical} indicating if messages should be printed +#' to show how the different steps in the function. Default: \code{FALSE}. +#' +#' @return a \code{list} containing 4 entries: +#' \describe{ +#' \item{\code{pcaSample}}{ a \code{list} containing the information related +#' to the eigenvectors. The \code{list} contains those 3 entries: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +#' the eigenvectors for the reference profiles.} +#' \item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +#' eigenvectors for the current profile projected on the PCA from the +#' reference profiles.} +#' } +#' } +#' \item{\code{paraSample}}{ a \code{list} containing the results with +#' different \code{D} and \code{K} values that lead to optimal parameter +#' selection. The \code{list} contains those entries: +#' \describe{ +#' \item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +#' on all combined synthetic results done with a fixed value of \code{D} (the +#' number of dimensions). The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{median}}{ a \code{numeric} representing the median of the +#' minimum AUROC obtained (within super populations) for all combination of +#' the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +#' AUROC obtained (within super populations) for all combination of the fixed +#' \code{D} value and all tested \code{K} values. } +#' \item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +#' of the minimum AUROC obtained (within super populations) for all +#' combination of the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for a fixed \code{D} value. } +#' } +#' } +#' \item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +#' all combined synthetic results done with different values of \code{D} (the +#' number of dimensions) and \code{K} (the number of neighbors). +#' The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +#' obtained by grouping all the synthetic results by super-populations, for +#' the specified values of \code{D} and \code{K}.} +#' \item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +#' by grouping all the synthetic results for the specified values of \code{D} +#' and \code{K}.} +#' \item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +#' of the confusion matrix obtained by grouping all the synthetic results for +#' the specified values of \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +#' super-population. The \code{data.frame} contains +#' those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{Call}}{ a \code{character} string representing the +#' super-population.} +#' \item{\code{L}}{ a \code{numeric} representing the lower value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' \item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for the +#' fixed values of super-population, \code{D} and \code{K}.} +#' \item{\code{H}}{ a \code{numeric} representing the higher value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +#' (the number of dimensions) for the specific profile.} +#' \item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for the specific profile.} +#' \item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +#' values (the number of dimensions) for the specific profile. More than one +#' \code{D} is possible.} +#' } +#' } +#' \item{\code{KNNSample}}{ a \code{data.frame} containing the inferred ancestry +#' for different values of \code{K} and \code{D}. The \code{data.frame} +#' contains those columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry. } +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry. } +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry for the specified \code{D} and \code{K} values.} +#' } +#' } +#' \item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred ancestry +#' for each synthetic data for different values of \code{K} and \code{D}. +#' The \code{data.frame} +#' contains those columns: "sample.id", "D", "K", "infer.superPop", "ref.superPop" +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current synthetic data.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry. } +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry. } +#' \item{\code{infer.superPop}}{ a \code{character} string representing the inferred +#' ancestry for the specified \code{D} and \code{K} values.} +#' \item{\code{ref.superPop}}{ a \code{character} string representing the known +#' ancestry from the reference} +#' } +#' } +#' \item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +#' ancestry for the current profile. The \code{data.frame} contains those +#' columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry.} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry.} +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry.} +#' } +#' } +#' } +#' +#' @details +#' +#' The runWrapperAncestry() generates list \code{list} +#' TODO update the description +#' +#' +#' @references +#' +#' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +#' Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +#' of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +#' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +#' +#' @examples +#' +#' ## Required library for GDS +#' library(SNPRelate) +#' +#' ## Path to the demo 1KG GDS file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ################################################################# +#' ## Load the information about the profile +#' ################################################################# +#' data(demoPedigreeEx1) +#' head(demoPedigreeEx1) +#' +#' ################################################################# +#' ## The 1KG GDS file and the 1KG SNV Annotation GDS file +#' ## need to be located in the same directory +#' ## Note that the 1KG GDS file used for this example is a +#' ## simplified version and CANNOT be used for any real analysis +#' ################################################################# +#' path1KG <- file.path(dataDir, "tests") +#' +#' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +#' fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") +#' +#' ################################################################# +#' ## The Sample SNP pileup files (one per sample) need +#' ## to be located in the same directory. +#' ################################################################# +#' pathGeno <- file.path(dataDir, "example", "snpPileup") +#' +#' ################################################################# +#' ## The path where the Profile GDS Files (one per sample) +#' ## will be created need to be specified. +#' ################################################################# +#' pathProfileGDS <- file.path(tempdir(), "out.tmp") +#' +#' +#' ################################################################# +#' ## A data frame containing general information about the study +#' ## is also required. The data frame must have +#' ## those 3 columns: "studyID", "study.desc", "study.platform" +#' ################################################################# +#' studyDF <- data.frame(study.id="MYDATA", +#' study.desc="Description", +#' study.platform="PLATFORM", +#' stringsAsFactors=FALSE) +#' +#' #################################################################### +#' ## Fix seed to ensure reproducible results +#' #################################################################### +#' set.seed(3043) +#' +#' gds1KG <- snpgdsOpen(fileReferenceGDS) +#' dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +#' closefn.gds(gds1KG) +#' +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' \dontrun{ +#' +#' res <- RAIDS:::wrapperAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, +#' pathProfileGDS=pathProfileGDS, +#' pathGeno=pathGeno, +#' fileReferenceGDS=fileReferenceGDS, +#' fileReferenceAnnotGDS=fileAnnotGDS, +#' chrInfo=chrInfo, syntheticRefDF=dataRef, +#' studyType="LD", genoSource="snp-pileup") +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' +#' } +#' } +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom utils write.csv +#' @importFrom rlang arg_match +#' @encoding UTF-8 +#' @keywords internal +wrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, + pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic", "VCF"), + studyType=c("LD", "GeneAware"), np=1L, blockTypeID=NULL, + verbose=FALSE) { + + genoSource <- arg_match(genoSource) + + listProfiles <- pedStudy[, "Name.ID"] + + createStudy2GDS1KG(pathGeno=pathGeno, pedStudy=pedStudy, + fileNameGDS=fileReferenceGDS, listProfiles=listProfiles, + studyDF=studyDF, pathProfileGDS=pathProfileGDS, genoSource=genoSource, + verbose=verbose) + + ## Open the 1KG GDS file (demo version) + gdsReference <- snpgdsOpen(fileReferenceGDS) + ## Open the 1KG GDS file and 1KG SNV Annotation file + gdsRefAnnot <- openfn.gds(fileReferenceAnnotGDS) + + listProfileRef <- syntheticRefDF$sample.id + studyDFSyn <- data.frame(study.id=paste0(studyDF$study.id, ".Synthetic"), + study.desc=paste0(studyDF$study.id, " synthetic data"), + study.platform=studyDF$study.platform, stringsAsFactors=FALSE) + + res <- profileAncestry(gdsReference, gdsRefAnnot, studyDF, + currentProfile=pedStudy[1,"Name.ID"], pathProfileGDS, chrInfo, + syntheticRefDF, studyDFSyn, listProfileRef, + studyType, np=np, blockTypeID=blockTypeID, verbose=verbose) + + + ## Close all GDS files + closefn.gds(gdsReference) + closefn.gds(gdsRefAnnot) + + ## Successful + return(res) +} diff --git a/man/wrapperAncestry.Rd b/man/wrapperAncestry.Rd new file mode 100644 index 000000000..2025fbcda --- /dev/null +++ b/man/wrapperAncestry.Rd @@ -0,0 +1,331 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/processStudy_internal.R +\encoding{UTF-8} +\name{wrapperAncestry} +\alias{wrapperAncestry} +\title{Run most steps leading to the ancestry inference call +on a specific profile (RNA or DNA)} +\usage{ +wrapperAncestry( + pedStudy, + studyDF, + pathProfileGDS, + pathGeno, + fileReferenceGDS, + fileReferenceAnnotGDS, + chrInfo, + syntheticRefDF, + genoSource = c("snp-pileup", "generic", "VCF"), + studyType = c("LD", "GeneAware"), + np = 1L, + blockTypeID = NULL, + verbose = FALSE +) +} +\arguments{ +\item{pedStudy}{a \code{data.frame} with those mandatory columns: "Name.ID", +"Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +\code{character} strings (no factor). The \code{data.frame} +must contain the information for all the samples passed in the +\code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +can be defined.} + +\item{studyDF}{a \code{data.frame} containing the information about the +study associated to the analysed sample(s). The \code{data.frame} must have +those 3 columns: "study.id", "study.desc", "study.platform". All columns +must be in \code{character} strings (no factor).} + +\item{pathProfileGDS}{a \code{character} string representing the path to +the directory where the GDS Profile files will be created. +Default: \code{NULL}.} + +\item{pathGeno}{a \code{character} string representing the path to the +directory containing the VCF output of SNP-pileup for each sample. The +SNP-pileup files must be compressed (gz files) and have the name identifiers +of the samples. A sample with "Name.ID" identifier would have an +associated file called +if genoSource is "VCF", then "Name.ID.vcf.gz", +if genoSource is "generic", then "Name.ID.generic.txt.gz" +if genoSource is "snp-pileup", then "Name.ID.txt.gz".} + +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Reference GDS file. The file must exist.} + +\item{fileReferenceAnnotGDS}{a \code{character} string representing the +file name of the Reference GDS Annotation file. The file must exist.} + +\item{chrInfo}{a \code{vector} of positive \code{integer} values +representing the length of the chromosomes. See 'details' section.} + +\item{syntheticRefDF}{a \code{data.frame} containing a subset of +reference profiles for each sub-population present in the Reference GDS +file. The \code{data.frame} must have those columns: +\describe{ +\item{sample.id}{ a \code{character} string representing the sample +identifier. } +\item{pop.group}{ a \code{character} string representing the +subcontinental population assigned to the sample. } +\item{superPop}{ a \code{character} string representing the +super-population assigned to the sample. } +}} + +\item{genoSource}{a \code{character} string with two possible values: +'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +are generated by snp-pileup (Facets) or are a generic format CSV file +with at least those columns: +'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +The 'Count' is the depth at the specified position; +'FileR' is the depth of the reference allele and +'File1A' is the depth of the specific alternative allele. +Finally the file can be a VCF file with at least those genotype +fields: GT, AD, DP.} + +\item{studyType}{a \code{character} string representing the type of study. +The possible choices are: "DNA" and "RNA". The type of study affects the +way the estimation of the allelic fraction is done. Default: \code{"DNA"}.} + +\item{np}{a single positive \code{integer} specifying the number of +threads to be used. Default: \code{1L}.} + +\item{blockTypeID}{a \code{character} string corresponding to the block +type used to extract the block identifiers. The block type must be +present in the GDS Reference Annotation file.} + +\item{verbose}{a \code{logical} indicating if messages should be printed +to show how the different steps in the function. Default: \code{FALSE}.} +} +\value{ +a \code{list} containing 4 entries: +\describe{ +\item{\code{pcaSample}}{ a \code{list} containing the information related +to the eigenvectors. The \code{list} contains those 3 entries: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +the eigenvectors for the reference profiles.} +\item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +eigenvectors for the current profile projected on the PCA from the +reference profiles.} +} +} +\item{\code{paraSample}}{ a \code{list} containing the results with +different \code{D} and \code{K} values that lead to optimal parameter +selection. The \code{list} contains those entries: +\describe{ +\item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +on all combined synthetic results done with a fixed value of \code{D} (the +number of dimensions). The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{median}}{ a \code{numeric} representing the median of the +minimum AUROC obtained (within super populations) for all combination of +the fixed \code{D} value and all tested \code{K} values. } +\item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +AUROC obtained (within super populations) for all combination of the fixed +\code{D} value and all tested \code{K} values. } +\item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +of the minimum AUROC obtained (within super populations) for all +combination of the fixed \code{D} value and all tested \code{K} values. } +\item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for a fixed \code{D} value. } +} +} +\item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +all combined synthetic results done with different values of \code{D} (the +number of dimensions) and \code{K} (the number of neighbors). +The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +obtained by grouping all the synthetic results by super-populations, for +the specified values of \code{D} and \code{K}.} +\item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +by grouping all the synthetic results for the specified values of \code{D} +and \code{K}.} +\item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +of the confusion matrix obtained by grouping all the synthetic results for +the specified values of \code{D} and \code{K}.} +} +} +\item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +super-population. The \code{data.frame} contains +those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{Call}}{ a \code{character} string representing the +super-population.} +\item{\code{L}}{ a \code{numeric} representing the lower value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +\item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for the +fixed values of super-population, \code{D} and \code{K}.} +\item{\code{H}}{ a \code{numeric} representing the higher value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +} +} +\item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +(the number of dimensions) for the specific profile.} +\item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for the specific profile.} +\item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +values (the number of dimensions) for the specific profile. More than one +\code{D} is possible.} +} +} +\item{\code{KNNSample}}{ a \code{data.frame} containing the inferred ancestry +for different values of \code{K} and \code{D}. The \code{data.frame} +contains those columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry. } +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry. } +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry for the specified \code{D} and \code{K} values.} +} +} +\item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred ancestry +for each synthetic data for different values of \code{K} and \code{D}. +The \code{data.frame} +contains those columns: "sample.id", "D", "K", "infer.superPop", "ref.superPop" +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current synthetic data.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry. } +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry. } +\item{\code{infer.superPop}}{ a \code{character} string representing the inferred +ancestry for the specified \code{D} and \code{K} values.} +\item{\code{ref.superPop}}{ a \code{character} string representing the known +ancestry from the reference} +} +} +\item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +ancestry for the current profile. The \code{data.frame} contains those +columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry.} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry.} +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry.} +} +} +} +} +\description{ +This function runs most steps leading to the ancestry inference +call on a specific profile. First, the function creates the Profile GDS file +for the specific profile using the information from a RDS Sample +description file and the Population reference GDS file. +} +\details{ +The runWrapperAncestry() generates list \code{list} +TODO update the description +} +\examples{ + +## Required library for GDS +library(SNPRelate) + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +################################################################# +## Load the information about the profile +################################################################# +data(demoPedigreeEx1) +head(demoPedigreeEx1) + +################################################################# +## The 1KG GDS file and the 1KG SNV Annotation GDS file +## need to be located in the same directory +## Note that the 1KG GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +################################################################# +path1KG <- file.path(dataDir, "tests") + +fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") + +################################################################# +## The Sample SNP pileup files (one per sample) need +## to be located in the same directory. +################################################################# +pathGeno <- file.path(dataDir, "example", "snpPileup") + +################################################################# +## The path where the Profile GDS Files (one per sample) +## will be created need to be specified. +################################################################# +pathProfileGDS <- file.path(tempdir(), "out.tmp") + + +################################################################# +## A data frame containing general information about the study +## is also required. The data frame must have +## those 3 columns: "studyID", "study.desc", "study.platform" +################################################################# +studyDF <- data.frame(study.id="MYDATA", + study.desc="Description", + study.platform="PLATFORM", + stringsAsFactors=FALSE) + +#################################################################### +## Fix seed to ensure reproducible results +#################################################################### +set.seed(3043) + +gds1KG <- snpgdsOpen(fileReferenceGDS) +dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +closefn.gds(gds1KG) + +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + \dontrun{ + + res <- RAIDS:::wrapperAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, + pathGeno=pathGeno, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, syntheticRefDF=dataRef, + studyType="LD", genoSource="snp-pileup") + + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + + } +} + +} +\references{ +Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} From 98cc871e4553f2bbbe65d6b02186d2958113e054 Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 11 Sep 2024 12:00:19 -0400 Subject: [PATCH 298/385] Update function inferAncestry and inferAncestryGeneAware --- R/processStudy.R | 225 +++++++++++++++++++++++++--------- man/inferAncestry.Rd | 159 ++++++++++++++++++++---- man/inferAncestryGeneAware.Rd | 11 +- 3 files changed, 301 insertions(+), 94 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 34e9e0587..f98b9c1b9 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2085,9 +2085,6 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' the directory where the GDS Profile files will be created. #' Default: \code{NULL}. #' -#' @param pathOut a \code{character} string representing the path to -#' the directory where the output files are created. -#' #' @param fileReferenceGDS a \code{character} string representing the file #' name of the Population Reference GDS file. The file must exist. #' @@ -2127,24 +2124,143 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @param verbose a \code{logical} indicating if messages should be printed #' to show how the different steps in the function. Default: \code{FALSE}. #' -#' @return The integer \code{0L} when successful. See details section for -#' more information about the generated output files. -#' -#' @details -#' -#' The runExomeAncestry() function generates 3 types of files -#' in the OUTPUT directory. +#' @return a \code{list} containing 4 entries: #' \describe{ -#' \item{Ancestry Inference}{ The ancestry inference CSV file -#' (".Ancestry.csv" file)} -#' \item{Inference Informaton}{ The inference information RDS file -#' (".infoCall.rds" file)} -#' \item{Synthetic Information}{ The parameter information RDS files -#' from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} +#' \item{\code{pcaSample}}{ a \code{list} containing the information related +#' to the eigenvectors. The \code{list} contains those 3 entries: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +#' the eigenvectors for the reference profiles.} +#' \item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +#' eigenvectors for the current profile projected on the PCA from the +#' reference profiles.} +#' } +#' } +#' \item{\code{paraSample}}{ a \code{list} containing the results with +#' different \code{D} and \code{K} values that lead to optimal parameter +#' selection. The \code{list} contains those entries: +#' \describe{ +#' \item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +#' on all combined synthetic results done with a fixed value of \code{D} (the +#' number of dimensions). The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{median}}{ a \code{numeric} representing the median of the +#' minimum AUROC obtained (within super populations) for all combination of +#' the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +#' AUROC obtained (within super populations) for all combination of the fixed +#' \code{D} value and all tested \code{K} values. } +#' \item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +#' of the minimum AUROC obtained (within super populations) for all +#' combination of the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for a fixed \code{D} value. } +#' } +#' } +#' \item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +#' all combined synthetic results done with different values of \code{D} (the +#' number of dimensions) and \code{K} (the number of neighbors). +#' The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +#' obtained by grouping all the synthetic results by super-populations, for +#' the specified values of \code{D} and \code{K}.} +#' \item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +#' by grouping all the synthetic results for the specified values of \code{D} +#' and \code{K}.} +#' \item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +#' of the confusion matrix obtained by grouping all the synthetic results for +#' the specified values of \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +#' super-population. The \code{data.frame} contains +#' those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{Call}}{ a \code{character} string representing the +#' super-population.} +#' \item{\code{L}}{ a \code{numeric} representing the lower value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' \item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for the +#' fixed values of super-population, \code{D} and \code{K}.} +#' \item{\code{H}}{ a \code{numeric} representing the higher value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +#' (the number of dimensions) for the specific profile.} +#' \item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for the specific profile.} +#' \item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +#' values (the number of dimensions) for the specific profile. More than one +#' \code{D} is possible.} +#' } +#' } +#' \item{\code{KNNSample}}{ a \code{data.frame} containing the inferred ancestry +#' for different values of \code{K} and \code{D}. The \code{data.frame} +#' contains those columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry. } +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry. } +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry for the specified \code{D} and \code{K} values.} +#' } +#' } +#' \item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred ancestry +#' for each synthetic data for different values of \code{K} and \code{D}. +#' The \code{data.frame} +#' contains those columns: "sample.id", "D", "K", "infer.superPop", "ref.superPop" +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current synthetic data.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry. } +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry. } +#' \item{\code{infer.superPop}}{ a \code{character} string representing the inferred +#' ancestry for the specified \code{D} and \code{K} values.} +#' \item{\code{ref.superPop}}{ a \code{character} string representing the known +#' ancestry from the reference} +#' } +#' } +#' \item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +#' ancestry for the current profile. The \code{data.frame} contains those +#' columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry.} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry.} +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry.} +#' } +#' } #' } #' -#' In addition, a sub-directory (named using the profile ID) is -#' also created. +#' @details +#' +#' The profileAncestry() generates list \code{list} +#' TODO update the description #' #' @references #' @@ -2185,8 +2301,6 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ################################################################# #' pathProfileGDS <- file.path(tempdir(), "out.tmp") #' -#' pathOut <- file.path(tempdir(), "res.out") -#' #' #' #################################################################### #' ## Fix seed to ensure reproducible results @@ -2207,9 +2321,8 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' #' \donttest{ #' -#' inferAncestry(profileFile=demoProfileEx1, +#' res <- inferAncestry(profileFile=demoProfileEx1, #' pathProfileGDS=pathProfileGDS, -#' pathOut=pathOut, #' fileReferenceGDS=fileReferenceGDS, #' fileReferenceAnnotGDS=fileAnnotGDS, #' chrInfo=chrInfo, @@ -2217,7 +2330,6 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' genoSource="snp-pileup") #' #' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) #' #' } #' } @@ -2229,10 +2341,10 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @export inferAncestry <- function(profileFile, pathProfileGDS, - pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, - verbose=FALSE) { + fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, + verbose=FALSE) { profileBaseName <- basename(profileFile) pathGeno <- dirname(profileFile) @@ -2250,16 +2362,16 @@ inferAncestry <- function(profileFile, pathProfileGDS, study.platform="NotDef", stringsAsFactors=FALSE) pedStudy <- data.frame(Name.ID = c(profileName), - Case.ID = c(profileName), - Sample.Type = c("DNA"), - Diagnosis = "NotDef", - Source = c("ENotDef"), - stringsAsFactors = FALSE) + Case.ID = c(profileName), + Sample.Type = c("DNA"), + Diagnosis = "NotDef", + Source = c("ENotDef"), + stringsAsFactors = FALSE) row.names(pedStudy) <- pedStudy$Name.ID ## Validate parameters validateRunExomeOrRNAAncestry(pedStudy=pedStudy, studyDF=studyDF, - pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, + pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut="./", fileReferenceGDS=fileReferenceGDS, fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) @@ -2267,16 +2379,17 @@ inferAncestry <- function(profileFile, pathProfileGDS, if(genoSource %in% c("snp-pileup", "generic", "VCF")){ - r <- runWrapperAncestry(pedStudy, studyDF, pathProfileGDS, - pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, genoSource, studyType="DNA", np=np, - verbose) + r <- wrapperAncestry(pedStudy, studyDF, pathProfileGDS, + pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, genoSource, studyType="LD", np=np, + verbose) } ## Successful return(r) } + #' @title Run most steps leading to the ancestry inference call on a specific #' RNA profile #' @@ -2512,9 +2625,6 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' the directory where the GDS Profile files will be created. #' Default: \code{NULL}. #' -#' @param pathOut a \code{character} string representing the path to -#' the directory where the output files are created. -#' #' @param fileReferenceGDS a \code{character} string representing the file #' name of the Population Reference GDS file. The file must exist. #' @@ -2616,9 +2726,6 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ################################################################# #' pathProfileGDS <- file.path(tempdir(), "out.tmp") #' -#' pathOut <- file.path(tempdir(), "res.out") -#' -#' #' #################################################################### #' ## Fix seed to ensure reproducible results #' #################################################################### @@ -2638,9 +2745,8 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' #' \donttest{ #' -#' inferAncestryGeneAware(profileFile=demoProfileEx1, +#' res <- inferAncestryGeneAware(profileFile=demoProfileEx1, #' pathProfileGDS=pathProfileGDS, -#' pathOut=pathOut, #' fileReferenceGDS=fileReferenceGDS, #' fileReferenceAnnotGDS=fileAnnotGDS, #' chrInfo=chrInfo, @@ -2649,7 +2755,6 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' genoSource="snp-pileup") #' #' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) -#' unlink(pathOut, recursive=TRUE, force=TRUE) #' #' } #' } @@ -2660,10 +2765,10 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @encoding UTF-8 #' @export inferAncestryGeneAware <- function(profileFile, pathProfileGDS, - pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, - blockTypeID, verbose=FALSE) { + fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, + blockTypeID, verbose=FALSE) { profileBaseName <- basename(profileFile) pathGeno <- dirname(profileFile) @@ -2681,16 +2786,16 @@ inferAncestryGeneAware <- function(profileFile, pathProfileGDS, study.platform="NotDef", stringsAsFactors=FALSE) pedStudy <- data.frame(Name.ID = c(profileName), - Case.ID = c(profileName), - Sample.Type = c("RNA"), - Diagnosis = "NotDef", - Source = c("NotDef"), - stringsAsFactors = FALSE) + Case.ID = c(profileName), + Sample.Type = c("RNA"), + Diagnosis = "NotDef", + Source = c("NotDef"), + stringsAsFactors = FALSE) row.names(pedStudy) <- pedStudy$Name.ID ## Validate parameters validateRunExomeOrRNAAncestry(pedStudy=pedStudy, studyDF=studyDF, - pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut=pathOut, + pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut="./", fileReferenceGDS=fileReferenceGDS, fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) @@ -2698,10 +2803,10 @@ inferAncestryGeneAware <- function(profileFile, pathProfileGDS, if(genoSource %in% c("snp-pileup", "generic", "VCF")){ - r <- runWrapperAncestry(pedStudy, studyDF, pathProfileGDS, - pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, genoSource, studyType="RNA", np=np, - blockTypeID=blockTypeID, verbose) + r <- wrapperAncestry(pedStudy, studyDF, pathProfileGDS, + pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, genoSource, studyType="GeneAware", np=np, + blockTypeID=blockTypeID, verbose) } ## Successful return(r) diff --git a/man/inferAncestry.Rd b/man/inferAncestry.Rd index dde228625..48243f796 100644 --- a/man/inferAncestry.Rd +++ b/man/inferAncestry.Rd @@ -9,7 +9,6 @@ DNA profile} inferAncestry( profileFile, pathProfileGDS, - pathOut, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, @@ -28,9 +27,6 @@ fine extension must be .txt.gz, if VCF the extension must be .vcf.gz} the directory where the GDS Profile files will be created. Default: \code{NULL}.} -\item{pathOut}{a \code{character} string representing the path to -the directory where the output files are created.} - \item{fileReferenceGDS}{a \code{character} string representing the file name of the Population Reference GDS file. The file must exist.} @@ -71,8 +67,138 @@ threads to be used. Default: \code{1L}.} to show how the different steps in the function. Default: \code{FALSE}.} } \value{ -The integer \code{0L} when successful. See details section for -more information about the generated output files. +a \code{list} containing 4 entries: +\describe{ +\item{\code{pcaSample}}{ a \code{list} containing the information related +to the eigenvectors. The \code{list} contains those 3 entries: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +the eigenvectors for the reference profiles.} +\item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +eigenvectors for the current profile projected on the PCA from the +reference profiles.} +} +} +\item{\code{paraSample}}{ a \code{list} containing the results with +different \code{D} and \code{K} values that lead to optimal parameter +selection. The \code{list} contains those entries: +\describe{ +\item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +on all combined synthetic results done with a fixed value of \code{D} (the +number of dimensions). The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{median}}{ a \code{numeric} representing the median of the +minimum AUROC obtained (within super populations) for all combination of +the fixed \code{D} value and all tested \code{K} values. } +\item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +AUROC obtained (within super populations) for all combination of the fixed +\code{D} value and all tested \code{K} values. } +\item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +of the minimum AUROC obtained (within super populations) for all +combination of the fixed \code{D} value and all tested \code{K} values. } +\item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for a fixed \code{D} value. } +} +} +\item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +all combined synthetic results done with different values of \code{D} (the +number of dimensions) and \code{K} (the number of neighbors). +The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +obtained by grouping all the synthetic results by super-populations, for +the specified values of \code{D} and \code{K}.} +\item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +by grouping all the synthetic results for the specified values of \code{D} +and \code{K}.} +\item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +of the confusion matrix obtained by grouping all the synthetic results for +the specified values of \code{D} and \code{K}.} +} +} +\item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +super-population. The \code{data.frame} contains +those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{Call}}{ a \code{character} string representing the +super-population.} +\item{\code{L}}{ a \code{numeric} representing the lower value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +\item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for the +fixed values of super-population, \code{D} and \code{K}.} +\item{\code{H}}{ a \code{numeric} representing the higher value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +} +} +\item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +(the number of dimensions) for the specific profile.} +\item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for the specific profile.} +\item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +values (the number of dimensions) for the specific profile. More than one +\code{D} is possible.} +} +} +\item{\code{KNNSample}}{ a \code{data.frame} containing the inferred ancestry +for different values of \code{K} and \code{D}. The \code{data.frame} +contains those columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry. } +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry. } +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry for the specified \code{D} and \code{K} values.} +} +} +\item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred ancestry +for each synthetic data for different values of \code{K} and \code{D}. +The \code{data.frame} +contains those columns: "sample.id", "D", "K", "infer.superPop", "ref.superPop" +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current synthetic data.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry. } +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry. } +\item{\code{infer.superPop}}{ a \code{character} string representing the inferred +ancestry for the specified \code{D} and \code{K} values.} +\item{\code{ref.superPop}}{ a \code{character} string representing the known +ancestry from the reference} +} +} +\item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +ancestry for the current profile. The \code{data.frame} contains those +columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry.} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry.} +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry.} +} +} +} } \description{ This function runs most steps leading to the ancestry inference @@ -81,19 +207,8 @@ Profile GDS file for the specific profile using the information from a RDS Sample description file and the Population Reference GDS file. } \details{ -The runExomeAncestry() function generates 3 types of files -in the OUTPUT directory. -\describe{ -\item{Ancestry Inference}{ The ancestry inference CSV file -(".Ancestry.csv" file)} -\item{Inference Informaton}{ The inference information RDS file -(".infoCall.rds" file)} -\item{Synthetic Information}{ The parameter information RDS files -from the synthetic inference ("KNN.synt.*.rds" files in a sub-directory)} -} - -In addition, a sub-directory (named using the profile ID) is -also created. +The profileAncestry() generates list \code{list} +TODO update the description } \examples{ @@ -127,8 +242,6 @@ demoProfileEx1 <- file.path(dataDir, "example", "snpPileup", "ex1.txt.gz") ################################################################# pathProfileGDS <- file.path(tempdir(), "out.tmp") -pathOut <- file.path(tempdir(), "res.out") - #################################################################### ## Fix seed to ensure reproducible results @@ -149,9 +262,8 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && \donttest{ - inferAncestry(profileFile=demoProfileEx1, + res <- inferAncestry(profileFile=demoProfileEx1, pathProfileGDS=pathProfileGDS, - pathOut=pathOut, fileReferenceGDS=fileReferenceGDS, fileReferenceAnnotGDS=fileAnnotGDS, chrInfo=chrInfo, @@ -159,7 +271,6 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && genoSource="snp-pileup") unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) } } diff --git a/man/inferAncestryGeneAware.Rd b/man/inferAncestryGeneAware.Rd index 8e7dced34..4902b7b5e 100644 --- a/man/inferAncestryGeneAware.Rd +++ b/man/inferAncestryGeneAware.Rd @@ -9,7 +9,6 @@ RNA profile} inferAncestryGeneAware( profileFile, pathProfileGDS, - pathOut, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, @@ -29,9 +28,6 @@ fine extension must be .txt.gz, if VCF the extension must be .vcf.gz} the directory where the GDS Profile files will be created. Default: \code{NULL}.} -\item{pathOut}{a \code{character} string representing the path to -the directory where the output files are created.} - \item{fileReferenceGDS}{a \code{character} string representing the file name of the Population Reference GDS file. The file must exist.} @@ -132,9 +128,6 @@ demoProfileEx1 <- file.path(dataDir, "example", "snpPileup", "ex1.txt.gz") ################################################################# pathProfileGDS <- file.path(tempdir(), "out.tmp") -pathOut <- file.path(tempdir(), "res.out") - - #################################################################### ## Fix seed to ensure reproducible results #################################################################### @@ -154,9 +147,8 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && \donttest{ - inferAncestryGeneAware(profileFile=demoProfileEx1, + res <- inferAncestryGeneAware(profileFile=demoProfileEx1, pathProfileGDS=pathProfileGDS, - pathOut=pathOut, fileReferenceGDS=fileReferenceGDS, fileReferenceAnnotGDS=fileAnnotGDS, chrInfo=chrInfo, @@ -165,7 +157,6 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && genoSource="snp-pileup") unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) } } From 8f57ec6e2f670e22b2c088766075836004b27384 Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 11 Sep 2024 12:31:47 -0400 Subject: [PATCH 299/385] Add function createAUROCGraph --- NAMESPACE | 1 + R/processStudy.R | 4 + R/visualization.R | 182 +++++++++++++++++++++++++++++-------- man/createAUROCGraph.Rd | 66 ++++++++++++++ man/createAccuracyGraph.Rd | 6 +- 5 files changed, 219 insertions(+), 40 deletions(-) create mode 100644 man/createAUROCGraph.Rd diff --git a/NAMESPACE b/NAMESPACE index 4ea29a569..7370161d9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -12,6 +12,7 @@ export(computePCAMultiSynthetic) export(computePCARefSample) export(computePoolSyntheticAncestryGr) export(computeSyntheticROC) +export(createAUROCGraph) export(createAccuracyGraph) export(createStudy2GDS1KG) export(estimateAllelicFraction) diff --git a/R/processStudy.R b/R/processStudy.R index f98b9c1b9..4a92a1048 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2383,6 +2383,8 @@ inferAncestry <- function(profileFile, pathProfileGDS, pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, genoSource, studyType="LD", np=np, verbose) + }else{ + stop(paste0("The format ", genoSource," is not implemented yet\n")) } ## Successful return(r) @@ -2807,6 +2809,8 @@ inferAncestryGeneAware <- function(profileFile, pathProfileGDS, pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, genoSource, studyType="GeneAware", np=np, blockTypeID=blockTypeID, verbose) + }else{ + stop(paste0("The format ", genoSource," is not implemented yet\n")) } ## Successful return(r) diff --git a/R/visualization.R b/R/visualization.R index 5e64056fe..ab7499d9a 100644 --- a/R/visualization.R +++ b/R/visualization.R @@ -1,31 +1,31 @@ #' @title Generate accuracy graph #' -#' @description This function extracts the required information from an -#' output generated by RAIDS to create a graphic representation of the -#' accuracy for different values of PCA dimensions and K-neighbors through +#' @description This function extracts the required information from an +#' output generated by RAIDS to create a graphic representation of the +#' accuracy for different values of PCA dimensions and K-neighbors through #' all tested ancestries. #' #' @param fileRDS a \code{character} string representing the path and file -#' name of the RDS file containing the ancestry information as generated by +#' name of the RDS file containing the ancestry information as generated by #' RAIDS. #' #' @param title a \code{character} string representing the title of the graph. #' Default: \code{""}. -#' -#' @param selectD a \code{array} of \code{integer} representing the selected -#' PCA dimensions to plot. The length of the \code{array} cannot be more than -#' 5 entries. The dimensions must tested by RAIDS (i.e. be present in the +#' +#' @param selectD a \code{array} of \code{integer} representing the selected +#' PCA dimensions to plot. The length of the \code{array} cannot be more than +#' 5 entries. The dimensions must tested by RAIDS (i.e. be present in the #' RDS file). Default: \code{c(3,7,11)}. -#' -#' @param selectColor a \code{array} of \code{character} strings representing -#' the selected colors for the associated PCA dimensions to plot. The length -#' of the \code{array} must correspond to the length of the \code{selectD} -#' parameter. In addition, the length of the \code{array} cannot be more than -#' 5 entries. +#' +#' @param selectColor a \code{array} of \code{character} strings representing +#' the selected colors for the associated PCA dimensions to plot. The length +#' of the \code{array} must correspond to the length of the \code{selectD} +#' parameter. In addition, the length of the \code{array} cannot be more than +#' 5 entries. #' Default: \code{c("#5e688a", "#cd5700", "#CC79A7")}. -#' -#' @return a \code{ggplot} object containing the graphic representation of the -#' accuracy for different values of PCA dimensions and K-neighbors through +#' +#' @return a \code{ggplot} object containing the graphic representation of the +#' accuracy for different values of PCA dimensions and K-neighbors through #' all tested ancestries. #' #' @examples @@ -38,12 +38,12 @@ #' fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") #' #' ## Create accuracy graph -#' accuracyGraph <- createAccuracyGraph(fileRDS=fileRDS, title="Test 01", -#' selectD=c(3,6,9,12,15), +#' accuracyGraph <- createAccuracyGraph(fileRDS=fileRDS, title="Test 01", +#' selectD=c(3,6,9,12,15), #' selectColor=c("steelblue", "darkorange", "violet", "pink", "gray80")) -#' +#' #' accuracyGraph -#' +#' #' @author Astrid Deschênes and Pascal Belleau #' @importFrom ggplot2 ggplot geom_ribbon geom_line theme_classic ylim #' @importFrom ggplot2 ylab facet_grid theme scale_colour_manual ggtitle @@ -51,46 +51,46 @@ #' @importFrom rlang .data #' @encoding UTF-8 #' @export -createAccuracyGraph <- function(fileRDS, title="", +createAccuracyGraph <- function(fileRDS, title="", selectD=c(3,7,11), selectColor=c("#5e688a", "#cd5700", "#CC79A7")) { - + ## Validate parameters - validateCreateAccuracyGraph(fileRDS=fileRDS, title=title, selectD=selectD, + validateCreateAccuracyGraph(fileRDS=fileRDS, title=title, selectD=selectD, selectColor=selectColor) - + ## Extract required information from RDS file info <- readRDS(fileRDS) dfAUROC <- info$paraSample$dfAUROC - + if (!all(selectD %in% unique(dfAUROC$pcaD))) { stop("Not all values in \'selectD\' are present in the RDS file.") } - + ## Retained selected dimensions dfAUROC <- dfAUROC[which(dfAUROC$pcaD %in% selectD), ] dfAUROC$pcaD <- as.factor(dfAUROC$pcaD) - + colnames(dfAUROC)[colnames(dfAUROC) == "pcaD"] <- "D" - + ## Set y axis minimum value ymin <- min(c(dfAUROC$L)) - 0.008 - + ## Generate graph - accuracy <- ggplot(dfAUROC, aes(x=.data$K, y=.data$AUC, group=.data$D, + accuracy <- ggplot(dfAUROC, aes(x=.data$K, y=.data$AUC, group=.data$D, color=.data$D, linetype=.data$D)) + - ylab(label = "AUROC") + + ylab(label = "AUROC") + geom_ribbon(aes(ymin=.data$L, ymax=.data$H, group=.data$D), linetype="dotted", cex=2, alpha=0.1) + geom_line(cex=2) + facet_grid(. ~ Call) + ylim(c(ymin, 1)) + ggtitle(title) + - scale_colour_manual(aesthetics = c("colour", "fill"), + scale_colour_manual(aesthetics = c("colour", "fill"), breaks=selectD, values=selectColor) + theme_classic() + theme(axis.text=element_text(size=20, colour = "black"), panel.background = element_rect(color="black"), - axis.text.x=element_text(size=20, angle=90, + axis.text.x=element_text(size=20, angle=90, vjust = 0.5, hjust=1, colour="black"), - plot.title = element_text(size=22, face="bold", + plot.title = element_text(size=22, face="bold", colour="gray20", hjust=0.5), axis.title.x=element_text(size=30,face="bold.italic"), axis.title.y=element_text(size=30,face="bold.italic"), @@ -99,7 +99,115 @@ createAccuracyGraph <- function(fileRDS, title="", strip.background = element_rect(fill="gray90"), legend.text=element_text(size=19), legend.title=element_text(size=22, face="bold.italic")) - + + ## Successful + return(accuracy) +} + +#' @title Generate accuracy graph +#' +#' @description This function extracts the required information from an +#' output generated by RAIDS to create a graphic representation of the +#' accuracy for different values of PCA dimensions and K-neighbors through +#' all tested ancestries. +#' +#' @param dfAUROC a \code{data.frame} corresponding to res$paraSample$dfAUROC +#' where res is the result of inferAncestry or inferAncestryGeneAware. +#' +#' @param title a \code{character} string representing the title of the graph. +#' Default: \code{""}. +#' +#' @param selectD a \code{array} of \code{integer} representing the selected +#' PCA dimensions to plot. The length of the \code{array} cannot be more than +#' 5 entries. The dimensions must tested by RAIDS (i.e. be present in the +#' RDS file). Default: \code{c(3,7,11)}. +#' +#' @param selectColor a \code{array} of \code{character} strings representing +#' the selected colors for the associated PCA dimensions to plot. The length +#' of the \code{array} must correspond to the length of the \code{selectD} +#' parameter. In addition, the length of the \code{array} cannot be more than +#' 5 entries. +#' Default: \code{c("#5e688a", "#cd5700", "#CC79A7")}. +#' +#' @return a \code{ggplot} object containing the graphic representation of the +#' accuracy for different values of PCA dimensions and K-neighbors through +#' all tested ancestries. +#' +#' @examples +#' +#' ## Required library +#' library(ggplot2) +#' +#' ## Path to RDS file with ancestry information generated by RAIDS (demo file) +#' dataDir <- system.file("extdata", package="RAIDS") +#' fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") +#' info <- readRDS(fileRDS) +#' dfAUROC <- info$paraSample$dfAUROC +#' colnames(dfAUROC) <- c("D", "K", "Call", "L", "AUROC", "H") +#' ## Create accuracy graph +#' accuracyGraph <- createAUROCGraph(dfAUROC=dfAUROC, title="Test 01", +#' selectD=c(3,6,9,12,15), +#' selectColor=c("steelblue", "darkorange", "violet", "pink", "gray80")) +#' +#' accuracyGraph +#' +#' @author Astrid Deschênes and Pascal Belleau +#' @importFrom ggplot2 ggplot geom_ribbon geom_line theme_classic ylim +#' @importFrom ggplot2 ylab facet_grid theme scale_colour_manual ggtitle +#' @importFrom ggplot2 element_text element_rect aes +#' @importFrom rlang .data +#' @encoding UTF-8 +#' @export +createAUROCGraph <- function(dfAUROC, title="", + selectD=c(3,7,11), selectColor=c("#5e688a", "#cd5700", "#CC79A7")) { + + ## Validate parameters + # validateCreateAccuracyGraph(fileRDS=fileRDS, title=title, selectD=selectD, + # selectColor=selectColor) + # + ## Extract required information from RDS file + # info <- readRDS(fileRDS) + # dfAUROC <- info$paraSample$dfAUROC + + if (!all(selectD %in% unique(dfAUROC$D))) { + stop("Not all values in \'selectD\' are present in the RDS file.") + } + + ## Retained selected dimensions + dfAUROC <- dfAUROC[which(dfAUROC$D %in% selectD), ] + dfAUROC$D <- as.factor(dfAUROC$D) + + colnames(dfAUROC)[colnames(dfAUROC) == "D"] <- "D" + + ## Set y axis minimum value + ymin <- min(c(dfAUROC$L)) - 0.008 + + ## Generate graph + accuracy <- ggplot(dfAUROC, aes(x=.data$K, y=.data$AUROC, group=.data$D, + color=.data$D, linetype=.data$D)) + + ylab(label = "AUROC") + + geom_ribbon(aes(ymin=.data$L, ymax=.data$H, group=.data$D), + linetype="dotted", cex=2, alpha=0.1) + + geom_line(cex=2) + facet_grid(. ~ Call) + + ylim(c(ymin, 1)) + ggtitle(title) + + scale_colour_manual(aesthetics = c("colour", "fill"), + breaks=selectD, values=selectColor) + + theme_classic() + + theme(axis.text=element_text(size=20, colour = "black"), + panel.background = element_rect(color="black"), + axis.text.x=element_text(size=20, angle=90, + vjust = 0.5, hjust=1, colour="black"), + plot.title = element_text(size=22, face="bold", + colour="gray20", hjust=0.5), + axis.title.x=element_text(size=30,face="bold.italic"), + axis.title.y=element_text(size=30,face="bold.italic"), + strip.text.x = element_text(size=20, face="bold"), + strip.text.y = element_text(size=20, face="bold"), + strip.background = element_rect(fill="gray90"), + legend.text=element_text(size=19), + legend.title=element_text(size=22, face="bold.italic")) + ## Successful return(accuracy) -} \ No newline at end of file +} + diff --git a/man/createAUROCGraph.Rd b/man/createAUROCGraph.Rd new file mode 100644 index 000000000..857de7080 --- /dev/null +++ b/man/createAUROCGraph.Rd @@ -0,0 +1,66 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/visualization.R +\encoding{UTF-8} +\name{createAUROCGraph} +\alias{createAUROCGraph} +\title{Generate accuracy graph} +\usage{ +createAUROCGraph( + dfAUROC, + title = "", + selectD = c(3, 7, 11), + selectColor = c("#5e688a", "#cd5700", "#CC79A7") +) +} +\arguments{ +\item{dfAUROC}{a \code{data.frame} corresponding to res$paraSample$dfAUROC +where res is the result of inferAncestry or inferAncestryGeneAware.} + +\item{title}{a \code{character} string representing the title of the graph. +Default: \code{""}.} + +\item{selectD}{a \code{array} of \code{integer} representing the selected +PCA dimensions to plot. The length of the \code{array} cannot be more than +5 entries. The dimensions must tested by RAIDS (i.e. be present in the +RDS file). Default: \code{c(3,7,11)}.} + +\item{selectColor}{a \code{array} of \code{character} strings representing +the selected colors for the associated PCA dimensions to plot. The length +of the \code{array} must correspond to the length of the \code{selectD} +parameter. In addition, the length of the \code{array} cannot be more than +5 entries. +Default: \code{c("#5e688a", "#cd5700", "#CC79A7")}.} +} +\value{ +a \code{ggplot} object containing the graphic representation of the +accuracy for different values of PCA dimensions and K-neighbors through +all tested ancestries. +} +\description{ +This function extracts the required information from an +output generated by RAIDS to create a graphic representation of the +accuracy for different values of PCA dimensions and K-neighbors through +all tested ancestries. +} +\examples{ + +## Required library +library(ggplot2) + +## Path to RDS file with ancestry information generated by RAIDS (demo file) +dataDir <- system.file("extdata", package="RAIDS") +fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") +info <- readRDS(fileRDS) +dfAUROC <- info$paraSample$dfAUROC +colnames(dfAUROC) <- c("D", "K", "Call", "L", "AUROC", "H") +## Create accuracy graph +accuracyGraph <- createAUROCGraph(dfAUROC=dfAUROC, title="Test 01", + selectD=c(3,6,9,12,15), + selectColor=c("steelblue", "darkorange", "violet", "pink", "gray80")) + +accuracyGraph + +} +\author{ +Astrid Deschênes and Pascal Belleau +} diff --git a/man/createAccuracyGraph.Rd b/man/createAccuracyGraph.Rd index 4ec28fa68..491d67509 100644 --- a/man/createAccuracyGraph.Rd +++ b/man/createAccuracyGraph.Rd @@ -53,10 +53,10 @@ dataDir <- system.file("extdata", package="RAIDS") fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") ## Create accuracy graph -accuracyGraph <- createAccuracyGraph(fileRDS=fileRDS, title="Test 01", - selectD=c(3,6,9,12,15), +accuracyGraph <- createAccuracyGraph(fileRDS=fileRDS, title="Test 01", + selectD=c(3,6,9,12,15), selectColor=c("steelblue", "darkorange", "violet", "pink", "gray80")) - + accuracyGraph } From 5831d42fe6754e8f376a83fcc666fe38ffa0e1b1 Mon Sep 17 00:00:00 2001 From: belleau Date: Thu, 10 Oct 2024 17:37:31 -0400 Subject: [PATCH 300/385] Solve a variable problem in profileAncestry and add some comments --- R/processStudy.R | 5 ++--- R/processStudy_internal.R | 2 +- man/inferAncestry.Rd | 2 +- man/inferAncestryGeneAware.Rd | 3 +-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 4a92a1048..6a46b0587 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2124,7 +2124,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @param verbose a \code{logical} indicating if messages should be printed #' to show how the different steps in the function. Default: \code{FALSE}. #' -#' @return a \code{list} containing 4 entries: +#' @return TODO a \code{list} containing 4 entries: #' \describe{ #' \item{\code{pcaSample}}{ a \code{list} containing the information related #' to the eigenvectors. The \code{list} contains those 3 entries: @@ -2670,8 +2670,7 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @param verbose a \code{logical} indicating if messages should be printed #' to show how the different steps in the function. Default: \code{FALSE}. #' -#' @return The integer \code{0L} when successful. See details section for -#' more information about the generated output files. +#' @return The integer \code{list} TODO see inferAncestry. #' #' @details #' diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index c06a96ecb..73bdf0125 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2648,7 +2648,7 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, paraSample=resCall$paraSample, # Result of the parameter selection KNNSample=resCall$KNNSample$matKNN, # KNN for the profile KNNSynthetic=resSyn, # KNN results for synthetic data - Ancestry=resCall) # the ancestry call fo the profile + Ancestry=resCall$Ancestry) # the ancestry call fo the profile return(res) } diff --git a/man/inferAncestry.Rd b/man/inferAncestry.Rd index 48243f796..09616962f 100644 --- a/man/inferAncestry.Rd +++ b/man/inferAncestry.Rd @@ -67,7 +67,7 @@ threads to be used. Default: \code{1L}.} to show how the different steps in the function. Default: \code{FALSE}.} } \value{ -a \code{list} containing 4 entries: +TODO a \code{list} containing 4 entries: \describe{ \item{\code{pcaSample}}{ a \code{list} containing the information related to the eigenvectors. The \code{list} contains those 3 entries: diff --git a/man/inferAncestryGeneAware.Rd b/man/inferAncestryGeneAware.Rd index 4902b7b5e..1c7569287 100644 --- a/man/inferAncestryGeneAware.Rd +++ b/man/inferAncestryGeneAware.Rd @@ -72,8 +72,7 @@ present in the GDS Reference Annotation file.} to show how the different steps in the function. Default: \code{FALSE}.} } \value{ -The integer \code{0L} when successful. See details section for -more information about the generated output files. +The integer \code{list} TODO see inferAncestry. } \description{ This function runs most steps leading to the ancestry inference From e5154266325087b15e911e5b02de1110361b4dbf Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 11 Oct 2024 13:14:39 -0400 Subject: [PATCH 301/385] Don't allow createStudy2GDS1KG when the gds exists. --- R/processStudy_internal.R | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 73bdf0125..901a66b5d 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -571,17 +571,24 @@ validateCreateStudy2GDS1KG <- function(pathGeno, pedStudy, fileNameGDS, batch, validateStudyDataFrameParameter(studyDF=studyDF) ## The listProfiles must be a vector of character string - if (!(is.character(listProfiles) || is.null(listProfiles))) { + if (!(is.character(listProfiles) || is.null(listProfiles))) { # stop("The \'listProfiles\' must be a vector ", "of character strings (1 entry or more) or NULL.") } + ## The pathProfileGDS must be a character string if (!is.character(pathProfileGDS)) { stop("The \'pathProfileGDS\' must be a character string representing", " the path where the Profile GDS files will be generated.") } - + if(is.character(listProfiles)){ + for(profileCur in listProfiles){ + if(file.exists(file.path(pathProfileGDS, paste0(profileCur, ".gds")))){ + stop(paste0("The gds file for ", profileCur, " already exist.")) + } + } + } ## The genoSource must be a character string if(!(is.character(genoSource))) { stop("The \'genoSource\' parameter must be a character string.") From 5e45004923a0b760971dd7667264198445ce7c52 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 11 Oct 2024 17:43:19 -0400 Subject: [PATCH 302/385] Add a test for createStudy2GDS1KG. --- tests/testthat/test-processStudy.R | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/testthat/test-processStudy.R b/tests/testthat/test-processStudy.R index 645fbd31f..5a32e1cbd 100644 --- a/tests/testthat/test-processStudy.R +++ b/tests/testthat/test-processStudy.R @@ -1101,6 +1101,29 @@ test_that("createStudy2GDS1KG() must return error when verbose is numeric", { genoSource="snp-pileup", verbose=22), error_message, fixed=TRUE) }) +test_that("createStudy2GDS1KG() must return error when the gdsProfile already exists", { + + dataDir <- test_path("fixtures") + fileGDS <- test_path("fixtures", "1KG_Test.gds") + + pedDF <- data.frame(Name.ID=c("Sample_01", "Sample_02", "Sample_03"), + Case.ID=c("Patient_h11", "Patient_h12", "Patient_h18"), + Diagnosis=rep("Cancer", 3), + Sample.Type=rep("Primary Tumor", 3), + Source=rep("Databank B", 3), stringsAsFactors=FALSE) + + studyDF <- data.frame(study.id="MYDATA", study.desc="Description", + study.platform="PLATFORM", stringsAsFactors=FALSE) + + error_message <- paste0("The gds file for ", "GDS_Sample_with_study_demo", " already exist.") + + expect_error(createStudy2GDS1KG(pathGeno=dataDir, + filePedRDS=NULL, pedStudy=pedDF, fileNameGDS=fileGDS, + batch=1, studyDF=studyDF, listProfiles=c("GDS_Sample_with_study_demo"), + pathProfileGDS=dataDir, + genoSource="snp-pileup", verbose=FALSE), error_message, fixed=TRUE) +}) + test_that("createStudy2GDS1KG() must return error when pathProfileGDS is numeric", { From d33eb477af08d27f1247ee021d5973547fecf042 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 11 Oct 2024 19:16:50 -0400 Subject: [PATCH 303/385] Add the function getRefSuperPop --- NAMESPACE | 1 + R/process1KG.R | 52 +++++++++++++++++++++++++++++++++++++++++++ man/getRefSuperPop.Rd | 44 ++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 man/getRefSuperPop.Rd diff --git a/NAMESPACE b/NAMESPACE index 7370161d9..d0cd63a67 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -20,6 +20,7 @@ export(generateGDS1KG) export(generateMapSnvSel) export(generatePhase1KG2GDS) export(getRef1KGPop) +export(getRefSuperPop) export(groupChr1KGSNV) export(identifyRelative) export(inferAncestry) diff --git a/R/process1KG.R b/R/process1KG.R index 7074a8173..36fcdd72d 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -766,6 +766,58 @@ getRef1KGPop <- function(gdsReference, popName="superPop") { return(dataRef) } +#' @title Extract the from the 1KG GDS 'sample.ref' node +#' for the reference profiles (real ancestry assignation) +#' +#' @description The function extract the specified column for the 'sample.ref' +#' node present in the Reference GDS file. The column must be present in the +#' \code{data.frame} saved in the 'sample.ref' node. Only the information for +#' the reference profiles is returned. The values +#' represent the known ancestry assignation. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Reference GDS file. The file must exist. +#' +#' +#' @return \code{vector} of \code{character} strings representing the content +#' of the extracted column for the 1KG GDS 'sample.ref' node. The values +#' represent the known ancestry assignation. The profile +#' identifiers are used as names for the \code{vector}. +#' +#' @examples +#' +#' +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## Open existing demo 1K GDS file with "sample.ref" node +#' nameFileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") +#' +#' ## Extract super population information for the 1KG profiles +#' getRefSuperPop(fileReferenceGDS=nameFileGDS) +#' +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt index.gdsn read.gdsn +#' @importFrom stats rmultinom +#' @importFrom SNPRelate snpgdsOpen +#' @encoding UTF-8 +#' @export +getRefSuperPop <- function(fileReferenceGDS) { + + ## The fileReferenceGDS must be a character string and the file must exists + if (!(is.character(fileReferenceGDS) && (file.exists(fileReferenceGDS)))) { + stop("The \'fileReferenceGDS\' must be a character string ", + "representing the Reference GDS file. The file must exist.") + } + + gdsReference <- snpgdsOpen(filename=fileReferenceGDS) + df <- getRef1KGPop(gdsReference) + closefn.gds(gdsReference) + + return(df) +} + #' @title Append information associated to blocks, as indexes, into the #' Population Reference SNV Annotation GDS file diff --git a/man/getRefSuperPop.Rd b/man/getRefSuperPop.Rd new file mode 100644 index 000000000..b61c7511a --- /dev/null +++ b/man/getRefSuperPop.Rd @@ -0,0 +1,44 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/process1KG.R +\encoding{UTF-8} +\name{getRefSuperPop} +\alias{getRefSuperPop} +\title{Extract the from the 1KG GDS 'sample.ref' node +for the reference profiles (real ancestry assignation)} +\usage{ +getRefSuperPop(fileReferenceGDS) +} +\arguments{ +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Reference GDS file. The file must exist.} +} +\value{ +\code{vector} of \code{character} strings representing the content +of the extracted column for the 1KG GDS 'sample.ref' node. The values +represent the known ancestry assignation. The profile +identifiers are used as names for the \code{vector}. +} +\description{ +The function extract the specified column for the 'sample.ref' +node present in the Reference GDS file. The column must be present in the +\code{data.frame} saved in the 'sample.ref' node. Only the information for +the reference profiles is returned. The values +represent the known ancestry assignation. +} +\examples{ + + +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +## Open existing demo 1K GDS file with "sample.ref" node +nameFileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") + +## Extract super population information for the 1KG profiles +getRefSuperPop(fileReferenceGDS=nameFileGDS) + + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} From 2856a66f7f6f8609a9bb5897faab5512ba67c1fd Mon Sep 17 00:00:00 2001 From: belleau Date: Tue, 15 Oct 2024 08:24:09 -0400 Subject: [PATCH 304/385] Add the function identifyRelativeRef wrapper of identifyRelative --- NAMESPACE | 1 + R/process1KG.R | 99 ++++++++++++++++++++++++++++++++++++++ man/identifyRelativeRef.Rd | 96 ++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 man/identifyRelativeRef.Rd diff --git a/NAMESPACE b/NAMESPACE index d0cd63a67..eb471ca6b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -23,6 +23,7 @@ export(getRef1KGPop) export(getRefSuperPop) export(groupChr1KGSNV) export(identifyRelative) +export(identifyRelativeRef) export(inferAncestry) export(inferAncestryGeneAware) export(prepPed1KG) diff --git a/R/process1KG.R b/R/process1KG.R index 36fcdd72d..ec48c2f41 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -595,6 +595,105 @@ identifyRelative <- function(gds, maf=0.05, thresh=2^(-11/2), saveRDS(part, filePart) } +#' @title Identify genetically unrelated patients in GDS Reference file +#' +#' @description The function identify patients that are genetically related in +#' the Reference file. It generates a first RDS file with the list of unrelated +#' patient. It also generates a second RDS file with the kinship coefficient +#' between the patients. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Reference GDS file. The file must exist. +#' +#' @param maf a single \code{numeric} representing the threshold for the minor +#' allele frequency. Only the SNPs with ">= maf" will be used. +#' Default: \code{0.05}. +#' +#' @param thresh a single \code{numeric} representing the threshold value used +#' to decide if a pair of individuals is ancestrally divergent. +#' Default: \code{2^(-11/2)}. +#' +#' @param fileIBD a \code{character} string representing the path and file +#' name of the RDS file that will be created. The RDS file will contain the +#' kinship coefficient between the patients. +#' The extension of the file must be '.rds'. +#' +#' @param filePart a \code{character} string representing the path and file +#' name of the RDS file that will be created. The RDS file will contain the +#' information about the Reference patients that are unrelated. The file will +#' contains two lists: the \code{list} of related samples, called \code{rels} +#' and the list of unrelated samples, called \code{unrels}. +#' The extension of the file must be '.rds'. +#' +#' @return \code{NULL} invisibly. +#' +#' @examples +#' +#' +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## Open existing demo Reference GDS file +#' fileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") +#' +#' +#' ## Temporary output files +#' ## The first RDS file will contain the list of unrelated patients +#' ## The second RDS file will contain the kinship information between patients +#' patientTmpFile <- "unrelatedPatients_TEMP.rds" +#' ibdTmpFile <- "ibd_TEMP.rds" +#' +#' ## Different code depending of the withr package availability +#' if (requireNamespace("withr", quietly=TRUE)) { +#' +#' ## Temporary output files +#' ## The first RDS file will contain the list of unrelated patients +#' ## The second RDS file will contain the kinship information +#' ## between patients +#' patientTmpFileLocal <- withr::local_file(patientTmpFile) +#' ibdTmpFileLocal <- withr::local_file(ibdTmpFile) +#' +#' ## Identify unrelated patients in demo Reference GDS file +#' identifyRelativeRef(fileReferenceGDS=fileGDS, maf=0.05, thresh=2^(-11/2), +#' fileIBD=ibdTmpFileLocal, filePart=patientTmpFileLocal) +#' +#' ## Remove temporary files +#' withr::deferred_run() +#' +#' } else { +#' +#' ## Identify unrelated patients in demo Reference GDS file +#' identifyRelativeRef(fileReferenceGDS=fileGDS, maf=0.05, thresh=2^(-11/2), +#' fileIBD=ibdTmpFile, filePart=patientTmpFile) +#' +#' ## Remove temporary files +#' unlink(patientTmpFile, force=TRUE) +#' unlink(ibdTmpFile, force=TRUE) +#' } +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' +#' @importFrom GENESIS pcairPartition +#' @importFrom S4Vectors isSingleNumber +#' @importFrom methods is +#' @encoding UTF-8 +#' @export +identifyRelativeRef <- function(fileReferenceGDS, maf=0.05, thresh=2^(-11/2), + fileIBD, filePart) { + + if (!(is.character(fileReferenceGDS) && (file.exists(fileReferenceGDS)))) { + stop("The \'fileReferenceGDS\' must be a character string ", + "representing the Reference GDS file. The file must exist.") + } + + gdsReference <- snpgdsOpen(filename=fileReferenceGDS) + + + identifyRelative(gdsReference, maf=maf, thresh=thresh, + fileIBD, filePart) + closefn.gds(gdsReference) + +} #' @title Add the information about the unrelated patients to the Reference #' GDS file diff --git a/man/identifyRelativeRef.Rd b/man/identifyRelativeRef.Rd new file mode 100644 index 000000000..fc04f768e --- /dev/null +++ b/man/identifyRelativeRef.Rd @@ -0,0 +1,96 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/process1KG.R +\encoding{UTF-8} +\name{identifyRelativeRef} +\alias{identifyRelativeRef} +\title{Identify genetically unrelated patients in GDS Reference file} +\usage{ +identifyRelativeRef( + fileReferenceGDS, + maf = 0.05, + thresh = 2^(-11/2), + fileIBD, + filePart +) +} +\arguments{ +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Reference GDS file. The file must exist.} + +\item{maf}{a single \code{numeric} representing the threshold for the minor +allele frequency. Only the SNPs with ">= maf" will be used. +Default: \code{0.05}.} + +\item{thresh}{a single \code{numeric} representing the threshold value used +to decide if a pair of individuals is ancestrally divergent. +Default: \code{2^(-11/2)}.} + +\item{fileIBD}{a \code{character} string representing the path and file +name of the RDS file that will be created. The RDS file will contain the +kinship coefficient between the patients. +The extension of the file must be '.rds'.} + +\item{filePart}{a \code{character} string representing the path and file +name of the RDS file that will be created. The RDS file will contain the +information about the Reference patients that are unrelated. The file will +contains two lists: the \code{list} of related samples, called \code{rels} +and the list of unrelated samples, called \code{unrels}. +The extension of the file must be '.rds'.} +} +\value{ +\code{NULL} invisibly. +} +\description{ +The function identify patients that are genetically related in +the Reference file. It generates a first RDS file with the list of unrelated +patient. It also generates a second RDS file with the kinship coefficient +between the patients. +} +\examples{ + + +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +## Open existing demo Reference GDS file +fileGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") + + +## Temporary output files +## The first RDS file will contain the list of unrelated patients +## The second RDS file will contain the kinship information between patients +patientTmpFile <- "unrelatedPatients_TEMP.rds" +ibdTmpFile <- "ibd_TEMP.rds" + +## Different code depending of the withr package availability +if (requireNamespace("withr", quietly=TRUE)) { + + ## Temporary output files + ## The first RDS file will contain the list of unrelated patients + ## The second RDS file will contain the kinship information + ## between patients + patientTmpFileLocal <- withr::local_file(patientTmpFile) + ibdTmpFileLocal <- withr::local_file(ibdTmpFile) + + ## Identify unrelated patients in demo Reference GDS file + identifyRelativeRef(fileReferenceGDS=fileGDS, maf=0.05, thresh=2^(-11/2), + fileIBD=ibdTmpFileLocal, filePart=patientTmpFileLocal) + + ## Remove temporary files + withr::deferred_run() + +} else { + + ## Identify unrelated patients in demo Reference GDS file + identifyRelativeRef(fileReferenceGDS=fileGDS, maf=0.05, thresh=2^(-11/2), + fileIBD=ibdTmpFile, filePart=patientTmpFile) + + ## Remove temporary files + unlink(patientTmpFile, force=TRUE) + unlink(ibdTmpFile, force=TRUE) +} + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} From cf062dd85bd3df1ca73bf54951c2d9f78cc87d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Tue, 15 Oct 2024 11:13:58 -0400 Subject: [PATCH 305/385] Update check-bioc.yaml --- .github/workflows/check-bioc.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index 9d2a94980..af733f2ef 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -51,10 +51,10 @@ jobs: fail-fast: false matrix: config: - ## - { os: ubuntu-latest, r: '4.2.2', bioc: '3.16', cont: "bioconductor/bioconductor_docker:RELEASE_3_16", rspm: "https://packagemanager.posit.co" } - - { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - ## - { os: macOS-latest, r: '4.2.2', bioc: '3.16'} - - { os: macOS-latest, r: '4.4', bioc: '3.19'} + ## - { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + - { os: ubuntu-latest, r: '4.4.1', bioc: '3.20', cont: "bioconductor/bioconductor_docker:RELEASE_3_20", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} + - { os: macOS-latest, r: '4.4.1', bioc: '3.20'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true From 0a49b99ab6a01e25796a0d911552a9f02e74ff35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Tue, 15 Oct 2024 11:54:01 -0400 Subject: [PATCH 306/385] Update check-bioc.yaml --- .github/workflows/check-bioc.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index af733f2ef..c2632e143 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -51,11 +51,12 @@ jobs: fail-fast: false matrix: config: - ## - { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - - { os: ubuntu-latest, r: '4.4.1', bioc: '3.20', cont: "bioconductor/bioconductor_docker:RELEASE_3_20", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + - { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + ## - { os: ubuntu-latest, r: '4.4.1', bioc: '3.20', cont: "bioconductor/bioconductor_docker:RELEASE_3_20", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} - - { os: macOS-latest, r: '4.4.1', bioc: '3.20'} + - { os: macOS-latest, r: '4.4.1', bioc: '3.20'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} + ## - { os: windows-latest, r: '4.4.1', bioc: '3.20'} env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true RSPM: ${{ matrix.config.rspm }} From d0178e67e96d7e4602c464e900082382d62f37e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Tue, 15 Oct 2024 16:08:59 -0400 Subject: [PATCH 307/385] Update check-bioc.yaml --- .github/workflows/check-bioc.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index c2632e143..b14113fcf 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -56,7 +56,8 @@ jobs: ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} - { os: macOS-latest, r: '4.4.1', bioc: '3.20'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} - ## - { os: windows-latest, r: '4.4.1', bioc: '3.20'} + - { os: windows-latest, r: '4.4.1', bioc: '3.20'} + env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true RSPM: ${{ matrix.config.rspm }} From 7a0f03c4a53c63fd64afd3391a1d57055a20ffc5 Mon Sep 17 00:00:00 2001 From: belleau Date: Tue, 15 Oct 2024 16:25:51 -0400 Subject: [PATCH 308/385] Update generatePhase1KG2GDS and add wrapper generatePhaseRef --- NAMESPACE | 1 + R/process1KG.R | 108 +++++++++++++++++++++++++++++-- man/generatePhase1KG2GDS.Rd | 6 +- man/generatePhaseRef.Rd | 91 ++++++++++++++++++++++++++ tests/testthat/test-process1KG.R | 2 +- 5 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 man/generatePhaseRef.Rd diff --git a/NAMESPACE b/NAMESPACE index eb471ca6b..704763c3d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -19,6 +19,7 @@ export(estimateAllelicFraction) export(generateGDS1KG) export(generateMapSnvSel) export(generatePhase1KG2GDS) +export(generatePhaseRef) export(getRef1KGPop) export(getRefSuperPop) export(groupChr1KGSNV) diff --git a/R/process1KG.R b/R/process1KG.R index ec48c2f41..12069fd2c 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -362,7 +362,7 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' the individual identification (Individual.ID) in the pedigree file. #' Default: \code{"./data/sampleGeno"}. #' -#' @param fileSNPsRDS a \code{character} string representing the path and file +#' @param fileSNVIndex a \code{character} string representing the path and file #' name of the RDS file that contains the indexes of the retained SNPs. The #' file must exist. The file must be a RDS file. #' @@ -412,7 +412,7 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' if (FALSE) { #' generatePhase1KG2GDS(gdsReference=gdsRef, #' gdsReferencePhase=gdsPhase, -#' pathGeno=pathGeno, fileSNPsRDS=filterSNVFile, +#' pathGeno=pathGeno, fileSNVIndex=snpIndexFile, #' verbose=FALSE) #' } #' @@ -431,13 +431,13 @@ generateGDS1KG <- function(pathGeno=file.path("data", "sampleGeno"), #' @encoding UTF-8 #' @export generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, - pathGeno, fileSNPsRDS, verbose=FALSE) { + pathGeno, fileSNVIndex, verbose=FALSE) { ## The verbose parameter must be a logical validateLogical(logical=verbose, "verbose") sample.id <- read.gdsn(index.gdsn(gdsReference, "sample.id")) - listSNP <- readRDS(fileSNPsRDS) + listSNP <- readRDS(fileSNVIndex) var.phase <- NULL for(i in seq_len(length(sample.id))){ @@ -447,6 +447,7 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, file1KG <- file.path(pathGeno, paste0(sample.id[i],".csv.bz2")) matSample <- read.csv2( file1KG, row.names = NULL)[listSNP,, drop=FALSE] + matSample <- matrix(as.numeric(unlist(strsplit(matSample[, 1], "\\|"))), nrow=2)[1,] @@ -471,6 +472,105 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, return(0L) } +#' @title Adding the phase information into the Reference GDS file +#' +#' @description The function is adding the phase information into the +#' Reference Phase GDS file. The phase information is extracted from a Reference +#' GDS file and is added into a Reference Phase GDS file. An entry called +#' 'phase' is added to the Reference Phase GDS file. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Reference GDS file. The file must exist. +#' +#' @param fileReferenceAnnotGDS a \code{character} string representing the +#' file name of the Population Reference GDS Annotation file. The file +#' must exist. +#' +#' @param pathGeno a \code{character} string representing the path where +#' the 1K genotyping files for each sample are located. The name of the +#' genotyping files must correspond to +#' the individual identification (Individual.ID) in the pedigree file. +#' Default: \code{"./data/sampleGeno"}. +#' +#' @param fileSNVIndex a \code{character} string representing the path and file +#' name of the RDS file that contains the indexes of the retained SNPs. The +#' file must exist. The file must be a RDS file. +#' +#' @param verbose a \code{logicial} indicating if the function should +#' print messages when running. Default: \code{FALSE}. +#' +#' @return The function returns \code{0L} when successful. +#' +#' @examples +#' +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## Path where the demo genotype CSV files are located +#' pathGeno <- file.path(dataDir, "demoProfileGenotypes") +#' +#' ## The RDS file containing the pedigree information +#' pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") +#' +#' ## The RDS file containing the indexes of the retained SNPs +#' snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") +#' +#' ## The RDS file containing the filtered SNP information +#' filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") +#' +#' ## Temporary Reference GDS file containing reference information +#' fileReferenceGDS <- file.path(tempdir(), "1KG_TEMP_02.gds") +#' +#' ## Create a temporary Reference GDS file containing information from 1KG +#' generateGDS1KG(pathGeno=pathGeno, filePedRDS=pedigreeFile, +#' fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, +#' fileNameGDS=fileReferenceGDS, listSamples=NULL) +#' +#' ## Temporary Phase GDS file that will contain the 1KG Phase information +#' fileRefPhaseGDS <- file.path(tempdir(), "1KG_TEMP_Phase_02.gds") +#' +#' +#' ## Fill temporary Reference Phase GDS file +#' if (FALSE) { +#' generatePhaseRef(fileReferenceGDS=fileReferenceGDS, +#' fileReferenceAnnotGDS=fileRefPhaseGDS, +#' pathGeno=pathGeno, fileSNVIndex=snpIndexFile, +#' verbose=FALSE) +#' } +#' +#' +#' ## Remove temporary files +#' unlink(fileReferenceGDS, force=TRUE) +#' unlink(fileRefPhaseGDS, force=TRUE) +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt index.gdsn read.gdsn readmode.gdsn +#' @encoding UTF-8 +#' @export +generatePhaseRef <- function(fileReferenceGDS, fileReferenceAnnotGDS, + pathGeno, fileSNVIndex, verbose=FALSE) { + + if (!(is.character(fileReferenceGDS) && (file.exists(fileReferenceGDS)))) { + stop("The \'fileReferenceGDS\' must be a character string ", + "representing the Reference GDS file. The file must exist.") + } + if (!(is.character(fileReferenceAnnotGDS) && (! file.exists(fileReferenceAnnotGDS)))) { + stop("The \'fileReferenceAnnotGDS\' must be a character string ", + "representing the Reference annotation GDS file. The file must not exist.") + } + + gdsReference <- snpgdsOpen(filename=fileReferenceGDS) + gdsReferencePhase <- createfn.gds(fileReferenceAnnotGDS) + + res <- generatePhase1KG2GDS(gdsReference, gdsReferencePhase, + pathGeno, fileSNVIndex, verbose=FALSE) + closefn.gds(gdsReference) + closefn.gds(gdsReferencePhase) + + + return(res) +} + #' @title Identify genetically unrelated patients in GDS Reference file #' #' @description The function identify patients that are genetically related in diff --git a/man/generatePhase1KG2GDS.Rd b/man/generatePhase1KG2GDS.Rd index 18f090804..d35d53f9f 100644 --- a/man/generatePhase1KG2GDS.Rd +++ b/man/generatePhase1KG2GDS.Rd @@ -9,7 +9,7 @@ generatePhase1KG2GDS( gdsReference, gdsReferencePhase, pathGeno, - fileSNPsRDS, + fileSNVIndex, verbose = FALSE ) } @@ -26,7 +26,7 @@ genotyping files must correspond to the individual identification (Individual.ID) in the pedigree file. Default: \code{"./data/sampleGeno"}.} -\item{fileSNPsRDS}{a \code{character} string representing the path and file +\item{fileSNVIndex}{a \code{character} string representing the path and file name of the RDS file that contains the indexes of the retained SNPs. The file must exist. The file must be a RDS file.} @@ -83,7 +83,7 @@ gdsRef <- openfn.gds(fileReferenceGDS) if (FALSE) { generatePhase1KG2GDS(gdsReference=gdsRef, gdsReferencePhase=gdsPhase, - pathGeno=pathGeno, fileSNPsRDS=filterSNVFile, + pathGeno=pathGeno, fileSNVIndex=snpIndexFile, verbose=FALSE) } diff --git a/man/generatePhaseRef.Rd b/man/generatePhaseRef.Rd new file mode 100644 index 000000000..7397aea8c --- /dev/null +++ b/man/generatePhaseRef.Rd @@ -0,0 +1,91 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/process1KG.R +\encoding{UTF-8} +\name{generatePhaseRef} +\alias{generatePhaseRef} +\title{Adding the phase information into the Reference GDS file} +\usage{ +generatePhaseRef( + fileReferenceGDS, + fileReferenceAnnotGDS, + pathGeno, + fileSNVIndex, + verbose = FALSE +) +} +\arguments{ +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Reference GDS file. The file must exist.} + +\item{fileReferenceAnnotGDS}{a \code{character} string representing the +file name of the Population Reference GDS Annotation file. The file +must exist.} + +\item{pathGeno}{a \code{character} string representing the path where +the 1K genotyping files for each sample are located. The name of the +genotyping files must correspond to +the individual identification (Individual.ID) in the pedigree file. +Default: \code{"./data/sampleGeno"}.} + +\item{fileSNVIndex}{a \code{character} string representing the path and file +name of the RDS file that contains the indexes of the retained SNPs. The +file must exist. The file must be a RDS file.} + +\item{verbose}{a \code{logicial} indicating if the function should +print messages when running. Default: \code{FALSE}.} +} +\value{ +The function returns \code{0L} when successful. +} +\description{ +The function is adding the phase information into the +Reference Phase GDS file. The phase information is extracted from a Reference +GDS file and is added into a Reference Phase GDS file. An entry called +'phase' is added to the Reference Phase GDS file. +} +\examples{ + +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +## Path where the demo genotype CSV files are located +pathGeno <- file.path(dataDir, "demoProfileGenotypes") + +## The RDS file containing the pedigree information +pedigreeFile <- file.path(dataDir, "PedigreeReferenceDemo.rds") + +## The RDS file containing the indexes of the retained SNPs +snpIndexFile <- file.path(dataDir, "listSNPIndexes_Demo.rds") + +## The RDS file containing the filtered SNP information +filterSNVFile <- file.path(dataDir, "mapSNVSelected_Demo.rds") + +## Temporary Reference GDS file containing reference information +fileReferenceGDS <- file.path(tempdir(), "1KG_TEMP_02.gds") + +## Create a temporary Reference GDS file containing information from 1KG +generateGDS1KG(pathGeno=pathGeno, filePedRDS=pedigreeFile, + fileSNVIndex=snpIndexFile, fileSNVSelected=filterSNVFile, + fileNameGDS=fileReferenceGDS, listSamples=NULL) + +## Temporary Phase GDS file that will contain the 1KG Phase information +fileRefPhaseGDS <- file.path(tempdir(), "1KG_TEMP_Phase_02.gds") + + +## Fill temporary Reference Phase GDS file +if (FALSE) { + generatePhaseRef(fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileRefPhaseGDS, + pathGeno=pathGeno, fileSNVIndex=snpIndexFile, + verbose=FALSE) +} + + +## Remove temporary files +unlink(fileReferenceGDS, force=TRUE) +unlink(fileRefPhaseGDS, force=TRUE) + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} diff --git a/tests/testthat/test-process1KG.R b/tests/testthat/test-process1KG.R index 4479bf389..5764e9894 100644 --- a/tests/testthat/test-process1KG.R +++ b/tests/testthat/test-process1KG.R @@ -616,7 +616,7 @@ test_that("generatePhase1KG2GDS() must return error when verbose is a numeric", " (TRUE or FALSE).") expect_error(generatePhase1KG2GDS(gdsReference=gds1KG, - gdsReferencePhase=gds1KG, pathGeno=dataDir, fileSNPsRDS="test", + gdsReferencePhase=gds1KG, pathGeno=dataDir, fileSNVIndex="test", verbose="SAVE"), error_message, fixed=TRUE) }) From a5d072f124fb2c00c1a5ccc9684068b7033d96d2 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 15 Oct 2024 18:02:14 -0400 Subject: [PATCH 309/385] Update main steps figure --- vignettes/MainSteps_v05.png | Bin 0 -> 79818 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 vignettes/MainSteps_v05.png diff --git a/vignettes/MainSteps_v05.png b/vignettes/MainSteps_v05.png new file mode 100644 index 0000000000000000000000000000000000000000..ee9fa070c905c1849fc0a7ad1c5d3a851391a274 GIT binary patch literal 79818 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

!Z`{tSdAZc5d-yeKWHCDDie4&9{CP`z7QX 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 NAX;XJ-$ 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 R;4Np)s48h8-zwhs|3Aw)ibntd literal 0 HcmV?d00001 From b0e3eab2b78418c57aa3e851b4a351bc0af6a631 Mon Sep 17 00:00:00 2001 From: belleau Date: Tue, 15 Oct 2024 18:02:56 -0400 Subject: [PATCH 310/385] Add function processBlockChr and correct some importFrom --- R/process1KG.R | 7 +- R/tools_internal.R | 108 +++++++++++++++++++ inst/extdata/block.sp.EUR.Ex.chr1.blocks.det | 10 ++ man/processBlockChr.Rd | 55 ++++++++++ 4 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 inst/extdata/block.sp.EUR.Ex.chr1.blocks.det create mode 100644 man/processBlockChr.Rd diff --git a/R/process1KG.R b/R/process1KG.R index 12069fd2c..21e6178f8 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -544,7 +544,8 @@ generatePhase1KG2GDS <- function(gdsReference, gdsReferencePhase, #' unlink(fileRefPhaseGDS, force=TRUE) #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt index.gdsn read.gdsn readmode.gdsn +#' @importFrom gdsfmt createfn.gds closefn.gds index.gdsn read.gdsn readmode.gdsn +#' @importFrom SNPRelate snpgdsOpen #' @encoding UTF-8 #' @export generatePhaseRef <- function(fileReferenceGDS, fileReferenceAnnotGDS, @@ -774,6 +775,8 @@ identifyRelative <- function(gds, maf=0.05, thresh=2^(-11/2), #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' #' @importFrom GENESIS pcairPartition +#' @importFrom gdsfmt closefn.gds +#' @importFrom SNPRelate snpgdsOpen #' @importFrom S4Vectors isSingleNumber #' @importFrom methods is #' @encoding UTF-8 @@ -997,7 +1000,7 @@ getRef1KGPop <- function(gdsReference, popName="superPop") { #' #' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz -#' @importFrom gdsfmt index.gdsn read.gdsn +#' @importFrom gdsfmt index.gdsn read.gdsn closefn.gds #' @importFrom stats rmultinom #' @importFrom SNPRelate snpgdsOpen #' @encoding UTF-8 diff --git a/R/tools_internal.R b/R/tools_internal.R index b75cdbf45..1fe1d80c9 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -438,3 +438,111 @@ readSNVVCF <- function(fileName, return(matSample) } + +#' @title The function create a vector of integer representing the linkage +#' disequilibrium block for each SNV in the in the same order +#' than the variant in Population reference dataset. +#' +#' @description The function create a vector of integer representing the linkage +#' disequilibrium block for each SNV in the in the same order +#' than the variant in Population reference dataset. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Reference GDS file. The file must exist. +#' +#' @param fileBlock a \code{character} string representing the file +#' name of output file det from the plink block command for a chromosome. +#' +#' @return a \code{list} containing 2 entries: +#' \describe{ +#' \item{\code{chr}}{ a \code{integer} representing a the chromosome from +#' fileBlock. +#' } +#' \item{\code{block.snp}}{ the a \code{array} of integer +#' representing the linkage disequilibrium block for +#' each SNV in the in the same order than the variant +#' in Population reference dataset. +#' } +#' } +#' +#' +#' @examples +#' +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## Demo of Reference GDS file containing reference information +#' fileReferenceGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") +#' +#' ## Demo of of output file det from the plink block +#' ## command for chromosome 1 +#' fileLdBlock <- file.path(dataDir, "block.sp.EUR.Ex.chr1.blocks.det") +#' +#' listLdBlock <- RAIDS:::processBlockChr(fileReferenceGDS, fileLdBlock) +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt read.gdsn index.gdsn closefn.gds +#' @importFrom SNPRelate snpgdsOpen +#' @encoding UTF-8 +#' @keywords internal +processBlockChr <- function(fileReferenceGDS, fileBlock) { + + if (!(is.character(fileReferenceGDS) && (file.exists(fileReferenceGDS)))) { + stop("The \'fileReferenceGDS\' must be a character string ", + "representing the Reference GDS file. The file must exist.") + } + if (!(is.character(fileBlock) && (file.exists(fileBlock)))) { + stop("The \'fileBlock\' must be a character string ", + "representing the file .det from plink block result. The file must exist.") + } + + gdsReference <- snpgdsOpen(filename=fileReferenceGDS) + blockChr <- read.delim(fileBlock, sep="") + + listChr <- unique(blockChr$CHR) + if(length(listChr) != 1){ + stop(paste0("There is not just one CHR in ", fileBlock, "\n")) + } + listChr <- as.integer(gsub("chr", "", listChr)) + listSNVChr <- read.gdsn(index.gdsn(gdsReference, "snp.chromosome")) + listSNVChr <- which(listSNVChr == listChr) + snp.keep <- read.gdsn(index.gdsn(gdsReference, "snp.position"))[listSNVChr] + closefn.gds(gdsReference) + z <- cbind(c(blockChr$BP1, snp.keep, blockChr$BP2+1), + c(seq_len(nrow(blockChr)), + rep(0, length(snp.keep)), -1*seq_len(nrow(blockChr)))) + + z <- z[order(z[,1]),] + block.snp <- cumsum(z[,2])[z[,2] == 0] + + curStart <- 0 + activeBlock <- 0 + blockState <- 0 + block.inter <- rep(0, length(which(block.snp == 0))) + k <- 1 + for(i in seq_len(length(block.snp))){ + if(block.snp[i] == 0){ + if(activeBlock == 1){ + if(snp.keep[i] - curStart >= 10000) { + blockState <- blockState - 1 + + curStart <- snp.keep[i] + } + } else{ + blockState <- blockState - 1 + curStart <- snp.keep[i] + curStart <- snp.keep[i] + activeBlock <- 1 + } + block.inter[k] <- blockState + k <- k + 1 + }else{ + activeBlock <- 0 + } + } + block.snp[block.snp == 0] <- block.inter + res <- list(chr=listChr, + block.snp=block.snp) + return(res) +} + diff --git a/inst/extdata/block.sp.EUR.Ex.chr1.blocks.det b/inst/extdata/block.sp.EUR.Ex.chr1.blocks.det new file mode 100644 index 000000000..3578e69ca --- /dev/null +++ b/inst/extdata/block.sp.EUR.Ex.chr1.blocks.det @@ -0,0 +1,10 @@ + CHR BP1 BP2 KB NSNPS SNPS + 1 51897 51927 0.031 2 s3|s4 + 1 54707 54715 0.009 2 s6|s7 + 1 55544 59039 3.496 2 s14|s15 + 1 61986 66506 4.521 3 s17|s18|s31 + 1 76837 77873 1.037 3 s39|s42|s43 + 1 79771 80140 0.37 2 s48|s49 + 1 82675 86330 3.656 12 s55|s58|s61|s62|s66|s67|s68|s71|s72|s75|s78|s79 + 1 87189 88337 1.149 3 s81|s89|s96 + 1 631489 633328 1.84 3 s150|s159|s160 diff --git a/man/processBlockChr.Rd b/man/processBlockChr.Rd new file mode 100644 index 000000000..acc83d827 --- /dev/null +++ b/man/processBlockChr.Rd @@ -0,0 +1,55 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tools_internal.R +\encoding{UTF-8} +\name{processBlockChr} +\alias{processBlockChr} +\title{The function create a vector of integer representing the linkage +disequilibrium block for each SNV in the in the same order +than the variant in Population reference dataset.} +\usage{ +processBlockChr(fileReferenceGDS, fileBlock) +} +\arguments{ +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Reference GDS file. The file must exist.} + +\item{fileBlock}{a \code{character} string representing the file +name of output file det from the plink block command for a chromosome.} +} +\value{ +a \code{list} containing 2 entries: +\describe{ +\item{\code{chr}}{ a \code{integer} representing a the chromosome from +fileBlock. +} +\item{\code{block.snp}}{ the a \code{array} of integer +representing the linkage disequilibrium block for +each SNV in the in the same order than the variant +in Population reference dataset. +} +} +} +\description{ +The function create a vector of integer representing the linkage +disequilibrium block for each SNV in the in the same order +than the variant in Population reference dataset. +} +\examples{ + +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +## Demo of Reference GDS file containing reference information +fileReferenceGDS <- file.path(dataDir, "PopulationReferenceDemo.gds") + +## Demo of of output file det from the plink block +## command for chromosome 1 +fileLdBlock <- file.path(dataDir, "block.sp.EUR.Ex.chr1.blocks.det") + +listLdBlock <- RAIDS:::processBlockChr(fileReferenceGDS, fileLdBlock) + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} From 79692f8446fe15cb25e8c4552414fe936a507a17 Mon Sep 17 00:00:00 2001 From: belleau Date: Tue, 15 Oct 2024 19:00:22 -0400 Subject: [PATCH 311/385] Add function addGeneBlockRefAnnot wrapper of addGeneBlockGDSRefAnnot --- NAMESPACE | 1 + R/process1KG.R | 92 +++++++++++++++++++++++++++++++++++++ man/addGeneBlockRefAnnot.Rd | 89 +++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 man/addGeneBlockRefAnnot.Rd diff --git a/NAMESPACE b/NAMESPACE index 704763c3d..4f535fe61 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,6 +2,7 @@ export(add1KG2SampleGDS) export(addGeneBlockGDSRefAnnot) +export(addGeneBlockRefAnnot) export(addRef2GDS1KG) export(addStudy1Kg) export(computeAncestryFromSynthetic) diff --git a/R/process1KG.R b/R/process1KG.R index 21e6178f8..76073383b 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -1143,3 +1143,95 @@ addGeneBlockGDSRefAnnot <- function(gdsReference, gdsRefAnnotFile, return(0L) } +#' @title Append information associated to blocks, as indexes, into the +#' Population Reference SNV Annotation GDS file +#' +#' @description The function appends the information about the blocks into +#' the Population Reference SNV Annotation GDS file. The information is +#' extracted from the Population Reference GDS file. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Reference GDS file. The file must exist. +#' +#' @param gdsRefAnnotFile a \code{character} string representing the +#' file name corresponding the Reference SNV +#' Annotation GDS file. The function will +#' open it in write mode and close it after. The file must exist. +#' +#' @param winSize a single positive \code{integer} representing the +#' size of the window to use to group the SNVs when the SNVs are in a +#' non-coding region. Default: \code{10000L}. +#' +#' @param ensDb An object with the ensembl genome annotation +#' Default: \code{EnsDb.Hsapiens.v86}. +#' +#' @param suffixBlockName a \code{character} string that identify the source +#' of the block and that will be added to the block description into +#' the Reference SNV Annotation GDS file, as example: Ensembl.Hsapiens.v86. +#' +#' @return The integer \code{OL} when the function is successful. +#' +#' @examples +#' +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +# ## Temporary file +#' fileAnnotGDS <- file.path(tempdir(), "ex1_good_small_1KG_Ann_GDS.gds") +#' +#' ## Required library +#' if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { +#' +#' file.copy(file.path(dataDir, "tests", +#' "ex1_NoBlockGene.1KG_Annot_GDS.gds"), fileAnnotGDS) +#' +#' ## Making a "short cut" on the ensDb object +#' edb <- EnsDb.Hsapiens.v86::EnsDb.Hsapiens.v86 +#' +#' ## GDS Reference file +#' fileReferenceGDS <- file.path(dataDir, "tests", +#' "ex1_good_small_1KG.gds") +#' +#' \donttest{ +#' +#' +#' ## Append information associated to blocks +#' addGeneBlockRefAnnot(fileReferenceGDS=fileReferenceGDS, +#' gdsRefAnnotFile=fileAnnotGDS, +#' ensDb=edb, +#' suffixBlockName="EnsDb.Hsapiens.v86") +#' +#' gdsAnnot1KG <- openfn.gds(fileAnnotGDS) +#' print(gdsAnnot1KG) +#' print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) +#' +#' closefn.gds(gdsAnnot1KG) +#' } +#' +#' ## Remove temporary file +#' unlink(fileAnnotGDS, force=TRUE) +#' +#' } +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt openfn.gds closefn.gds +#' @importFrom SNPRelate snpgdsOpen +#' @importFrom S4Vectors isSingleNumber +#' @encoding UTF-8 +#' @export +addGeneBlockRefAnnot <- function(fileReferenceGDS, gdsRefAnnotFile, + winSize=10000, ensDb, suffixBlockName) { + + + if (!(is.character(fileReferenceGDS) && (file.exists(fileReferenceGDS)))) { + stop("The \'fileReferenceGDS\' must be a character string ", + "representing the Reference GDS file. The file must exist.") + } + + gdsReference <- snpgdsOpen(filename=fileReferenceGDS) + res <- addGeneBlockGDSRefAnnot(gdsReference, gdsRefAnnotFile, + winSize=10000, ensDb, suffixBlockName) + closefn.gds(gdsReference) + ## Success + return(res) +} diff --git a/man/addGeneBlockRefAnnot.Rd b/man/addGeneBlockRefAnnot.Rd new file mode 100644 index 000000000..b12d09f49 --- /dev/null +++ b/man/addGeneBlockRefAnnot.Rd @@ -0,0 +1,89 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/process1KG.R +\encoding{UTF-8} +\name{addGeneBlockRefAnnot} +\alias{addGeneBlockRefAnnot} +\title{Append information associated to blocks, as indexes, into the +Population Reference SNV Annotation GDS file} +\usage{ +addGeneBlockRefAnnot( + fileReferenceGDS, + gdsRefAnnotFile, + winSize = 10000, + ensDb, + suffixBlockName +) +} +\arguments{ +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Reference GDS file. The file must exist.} + +\item{gdsRefAnnotFile}{a \code{character} string representing the +file name corresponding the Reference SNV +Annotation GDS file. The function will +open it in write mode and close it after. The file must exist.} + +\item{winSize}{a single positive \code{integer} representing the +size of the window to use to group the SNVs when the SNVs are in a +non-coding region. Default: \code{10000L}.} + +\item{ensDb}{An object with the ensembl genome annotation +Default: \code{EnsDb.Hsapiens.v86}.} + +\item{suffixBlockName}{a \code{character} string that identify the source +of the block and that will be added to the block description into +the Reference SNV Annotation GDS file, as example: Ensembl.Hsapiens.v86.} +} +\value{ +The integer \code{OL} when the function is successful. +} +\description{ +The function appends the information about the blocks into +the Population Reference SNV Annotation GDS file. The information is +extracted from the Population Reference GDS file. +} +\examples{ + +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +fileAnnotGDS <- file.path(tempdir(), "ex1_good_small_1KG_Ann_GDS.gds") + +## Required library +if (requireNamespace("EnsDb.Hsapiens.v86", quietly=TRUE)) { + + file.copy(file.path(dataDir, "tests", + "ex1_NoBlockGene.1KG_Annot_GDS.gds"), fileAnnotGDS) + + ## Making a "short cut" on the ensDb object + edb <- EnsDb.Hsapiens.v86::EnsDb.Hsapiens.v86 + + ## GDS Reference file + fileReferenceGDS <- file.path(dataDir, "tests", + "ex1_good_small_1KG.gds") + + \donttest{ + + + ## Append information associated to blocks + addGeneBlockRefAnnot(fileReferenceGDS=fileReferenceGDS, + gdsRefAnnotFile=fileAnnotGDS, + ensDb=edb, + suffixBlockName="EnsDb.Hsapiens.v86") + + gdsAnnot1KG <- openfn.gds(fileAnnotGDS) + print(gdsAnnot1KG) + print(read.gdsn(index.gdsn(gdsAnnot1KG, "block.annot"))) + + closefn.gds(gdsAnnot1KG) + } + + ## Remove temporary file + unlink(fileAnnotGDS, force=TRUE) + +} + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} From b6c173d111179073552a06a0640313a412d7f3a7 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 15 Oct 2024 19:11:12 -0400 Subject: [PATCH 312/385] Adding wrapper vignette --- vignettes/Wrappers.Rmd | 684 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 684 insertions(+) create mode 100644 vignettes/Wrappers.Rmd diff --git a/vignettes/Wrappers.Rmd b/vignettes/Wrappers.Rmd new file mode 100644 index 000000000..ea2d02f55 --- /dev/null +++ b/vignettes/Wrappers.Rmd @@ -0,0 +1,684 @@ +--- +title: "Using wrappper functions" +author: Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +output: + BiocStyle::html_document: + number_sections: yes + toc: true + pkgdown: + number_sections: yes + as_is: true +urlcolor: darkred +linkcolor: darkred +bibliography: aicsBiblio.bibtex +vignette: > + %\VignetteIndexEntry{Using wrappper functionss} + %\VignettePackage{RAIDS} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r style, echo=FALSE, results='hide', warning=FALSE, message=FALSE} +BiocStyle::markdown() + +suppressPackageStartupMessages({ + library(knitr) + library(RAIDS) + library(gdsfmt) +}) + +set.seed(121444) +``` + +
+**Package**: `r Rpackage("RAIDS")`
+**Authors**: `r packageDescription("RAIDS")[["Author"]]`
+**Version**: `r packageDescription("RAIDS")$Version`
+**Compiled date**: `r Sys.Date()`
+**License**: `r packageDescription("RAIDS")[["License"]]`
+ + +
+
+ + + + +This vignette explains, in further details, the used of the wrapper functions +that were developed for a previous release of RAIDS. + +While those functions are still working, we recommend using the new +functions as described in the main vignette. + +
+
+ +# Main Steps + + +This is an overview of genetic ancestry inference from cancer-derived +molecular data: + +```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference process.", out.width='130%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_v04.png") +``` + +The main steps are: + +**Step 1.** Format reference data from the population reference dataset (optional) + +**Step 2.1** Optimize ancestry inference parameters + +**Step 2.2** Infer ancestry for the subjects of the external study + +These steps are described in detail in the following. Steps 2.1 and 2.2 can be +run together using one wrapper function. + +
+
+ + +## Main Step - Ancestry Inference + +A wrapper function encapsulates multiple steps of the workflow. + +```{r graphWrapper, echo=FALSE, fig.align="center", fig.cap="Final step - The wrapper function encapsulates multiple steps of the workflow.", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_Wrapper_v04.png") +``` + +In summary, the wrapper function generates the synthetic dataset and uses +it to selected the optimal parameters before calling the genetic ancestry +on the current profiles. + +According to the type of input data (RNA or DNA), a specific wrapper function +is available. + +
+ +### DNA Data - Wrapper function to run ancestry inference on DNA data + +The wrapper function, called _runExomeAncestry()_, requires 4 files as input: + +- The **population reference GDS file** +- The **population reference SNV Annotation GDS file** +- The **Profile SNP file** (one per sample present in the study) +- The **Profile PED RDS file** (one file with information for all +profiles in the study) + +In addition, a *data.frame* containing the general information about the +study is also required. The *data.frame* must contain those 3 columns: + +- _study.id_: The study identifier (example: TCGA-BRCA). +- _study.desc_: The description of the study. +- _study.platform_: The type of sequencing (example: RNA-seq). + +
+ +#### **Population reference files** + +For demonstration purpose, a small +**population reference GDS file** (called _ex1_good_small_1KG.gds_) and a small +**population reference SNV Annotation GDS file** (called +_ex1_good_small_1KG_Annot.gds_) are +included in this package. Beware that those two files should not be used to +run a real ancestry inference.The results obtained with those files won't be +reliable. + +The required **population reference GDS file** and +**population reference SNV Annotation GDS file** should be stored in the same +directory. In the example below, this directory is referred to +as **pathReference**. + +
+ +#### **Profile SNP file** + +The **Profile SNP file** can be either in a VCF format or in a generic format. + +The **Profile SNP VCF file** follows the VCF standard with at least +those genotype fields: _GT_, _AD_ and _DP_. The identifier of the genotype +in the VCF file must correspond to the profile identifier _Name.ID_. +The SNVs must be germline variants and should include the genotype of the +wild-type homozygous at the selected positions in the reference. One file per +profile is need and the VCF file must be gzipped. + +Note that the name assigned to the **Profile SNP VCF file** has to +correspond to the profile identifier _Name.ID_ in the following analysis. +For example, a SNP file called "Sample.01.vcf.gz" would be +associated to the "Sample.01" profile. + +A generic SNP file can replace the VCF file. The **Profile SNP Generic file** +format is coma separated and the mandatory columns are: + +* _Chromosome_: The name of the chromosome +* _Position_: The position on the chromosome +* _Ref_: The reference nucleotide +* _Alt_: The aternative nucleotide +* _Count_: The total count +* _File1R_: The count for the reference nucleotide +* _File1A_: The count for the alternative nucleotide + +Beware that the starting position in the **population reference GDS File** is +zero (like BED files). The **Profile SNP Generic file** should also start +at position zero. + +Note that the name assigned to the **Profile SNP Generic file** has to +correspond to the profile identifier _Name.ID_ in the following analysis. +For example, a SNP file called "Sample.01.generic.txt.gz" would be +associated to the "Sample.01" profile. + +
+ +#### **Profile PED RDS file** + +The **Profile PED RDS file** must contain a *data.frame* describing all +the profiles to be analyzed. These 5 mandatory columns: + +- _Name.ID_: The unique sample identifier. The associated **profile SNP file** +should be called "Name.ID.txt.gz". +- _Case.ID_: The patient identifier associated to the sample. +- _Sample.Type_: The information about the profile tissue source +(primary tumor, metastatic tumor, normal, etc..). +- _Diagnosis_: The donor's diagnosis. +- _Source_: The source of the profile sequence data (example: dbGAP_XYZ). + +Important: The row names of the *data.frame* must be the profiles *Name.ID*. + +This file is referred to as the **Profile PED RDS file** (PED for pedigree). +Alternatively, the PED information can be saved in another type of +file (CVS, etc..) as long as the *data.frame* information can be regenerated +in R (with _read.csv()_ or else). + +
+ +#### **Example** + +This example run an ancestry inference on an exome sample. Both population +reference files are demonstration files and should not be +used for a real ancestry inference. Beware that running an ancestry inference +on real data will take longer to run. + +```{r runExomeAncestry, echo=TRUE, eval=TRUE, collapse=FALSE, warning=FALSE, message=FALSE} +############################################################################# +## Load required packages +############################################################################# +library(RAIDS) +library(gdsfmt) + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +############################################################################# +## Load the information about the profile +############################################################################# +data(demoPedigreeEx1) +head(demoPedigreeEx1) + +############################################################################# +## The population reference GDS file and SNV Annotation GDS file +## need to be located in the same directory. +## Note that the population reference GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +############################################################################# +pathReference <- file.path(dataDir, "tests") + +fileGDS <- file.path(pathReference, "ex1_good_small_1KG.gds") +fileAnnotGDS <- file.path(pathReference, "ex1_good_small_1KG_Annot.gds") + +############################################################################# +## A data frame containing general information about the study +## is also required. The data frame must have +## those 3 columns: "study.id", "study.desc", "study.platform" +############################################################################# +studyDF <- data.frame(study.id="MYDATA", + study.desc="Description", + study.platform="PLATFORM", + stringsAsFactors=FALSE) + +############################################################################# +## The Sample SNP VCF files (one per sample) need +## to be all located in the same directory. +############################################################################# +pathGeno <- file.path(dataDir, "example", "snpPileup") + +############################################################################# +## Fix RNG seed to ensure reproducible results +############################################################################# +set.seed(3043) + +############################################################################# +## Select the profiles from the population reference GDS file for +## the synthetic data. +## Here we select 2 profiles from the simplified 1KG GDS for each +## subcontinental-level. +## Normally, we use 30 profile for each +## subcontinental-level but it is too big for the example. +## The 1KG files in this example only have 6 profiles for each +## subcontinental-level (for demo purpose only). +############################################################################# +gds1KG <- snpgdsOpen(fileGDS) +dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +closefn.gds(gds1KG) + +## GenomeInfoDb and BSgenome are required libraries to run this example +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + ########################################################################### + ## The path where the Sample GDS files (one per sample) + ## will be created needs to be specified. + ########################################################################### + pathProfileGDS <- file.path(tempdir(), "exampleDNA", "out.tmp") + + ########################################################################### + ## The path where the result files will be created needs to + ## be specified + ########################################################################### + pathOut <- file.path(tempdir(), "exampleDNA", "res.out") + + ## Example can only be run if the current directory is in writing mode + if (!dir.exists(file.path(tempdir(), "exampleDNA"))) { + + dir.create(file.path(tempdir(), "exampleDNA")) + dir.create(pathProfileGDS) + dir.create(pathOut) + + ######################################################################### + ## The wrapper function generates the synthetic dataset and uses it + ## to selected the optimal parameters before calling the genetic + ## ancestry on the current profiles. + ## All important information, for each step, are saved in + ## multiple output files. + ## The 'genoSource' parameter has 2 options depending on how the + ## SNP files have been generated: + ## SNP VCF files have been generated: + ## "VCF" or "generic" (other software) + ## + ######################################################################### + runExomeAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, + pathGeno=pathGeno, + pathOut=pathOut, + fileReferenceGDS=fileGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + genoSource="VCF") + list.files(pathOut) + list.files(file.path(pathOut, demoPedigreeEx1$Name.ID[1])) + + ####################################################################### + ## The file containing the ancestry inference (SuperPop column) and + ## optimal number of PCA component (D column) + ## optimal number of neighbours (K column) + ####################################################################### + resAncestry <- read.csv(file.path(pathOut, + paste0(demoPedigreeEx1$Name.ID[1], ".Ancestry.csv"))) + print(resAncestry) + + ## Remove temporary files created for this demo + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + unlink(file.path(tempdir(), "exampleDNA"), recursive=TRUE, force=TRUE) + } +} + + +``` + +
+
+ +The *runExomeAncestry()* function generates 3 types of files +in the *pathOut* directory. + +* The ancestry inference CSV file (**".Ancestry.csv"** file) +* The inference information RDS file (**".infoCall.rds"** file) +* The parameter information RDS files from the synthetic inference +(__"KNN.synt.__*__.rds"__ files in a sub-directory) + +In addition, a sub-directory (named using the *profile ID*) is +also created. + +The inferred ancestry is stored in the ancestry inference CSV +file (**".Ancestry.csv"** file) which also contains those columns: + +* _sample.id_: The unique identifier of the sample +* _D_: The optimal PCA dimension value used to infer the ancestry +* _k_: The optimal number of neighbors value used to infer the ancestry +* _SuperPop_: The inferred ancestry + +
+
+ + + +### RNA data - Wrapper function to run ancestry inference on RNA data + +The process is the same as for the DNA but use the wrapper function +called _runRNAAncestry()_. Internally the data is process differently. +It requires 4 files as input: + +- The **population reference GDS file** +- The **population reference SNV Annotation GDS file** +- The **Profile SNP file** (one per sample present in the study) +- The **Profile PED RDS file** (one file with information for all +profiles in the study) + +A *data.frame* containing the general information about the study is +also required. The *data.frame* must contain those 3 columns: + +- _study.id_: The study identifier (example: TCGA-BRCA). +- _study.desc_: The description of the study. +- _study.platform_: The type of sequencing (example: RNA-seq). + +
+ +#### **Population reference files** + +For demonstration purpose, a small +**population reference GDS file** (called _ex1_good_small_1KG.gds_) and a small +**population reference SNV Annotation GDS file** (called +_ex1_good_small_1KG_Annot.gds_) are +included in this package. Beware that those two files should not be used to +run a real ancestry inference.The results obtained with those files won't be +reliable. + +The required **population reference GDS file** and +**population reference SNV Annotation GDS file** should be stored in the same +directory. In the example below, this directory is referred to +as **pathReference**. + +
+ +#### **Profile SNP file** + +The **Profile SNP file** can be either in a VCF format or in a generic format. + +The **Profile SNP VCF file** follows the VCF standard with at least +those genotype fields: _GT_, _AD_ and _DP_. The identifier of the genotype +in the VCF file must correspond to the profile identifier _Name.ID_. +The SNVs must be germline variants and should include the genotype of the +wild-type homozygous at the selected positions in the reference. One file per +profile is need and the VCF file must be gzipped. + +Note that the name assigned to the **Profile SNP VCF file** has to +correspond to the profile identifier _Name.ID_ in the following analysis. +For example, a SNP file called "Sample.01.vcf.gz" would be +associated to the "Sample.01" profile. + +A generic SNP file can replace the VCF file. The **Profile SNP Generic file** +format is coma separated and the mandatory columns are: + +* _Chromosome_: The name of the chromosome +* _Position_: The position on the chromosome +* _Ref_: The reference nucleotide +* _Alt_: The aternative nucleotide +* _Count_: The total count +* _File1R_: The count for the reference nucleotide +* _File1A_: The count for the alternative nucleotide + +Beware that the starting position in the **population reference GDS File** is +zero (like BED files). The **Profile SNP Generic file** should also start +at position zero. + +Note that the name assigned to the **Profile SNP Generic file** has to +correspond to the profile identifier _Name.ID_ in the following analysis. +For example, a SNP file called "Sample.01.generic.txt.gz" would be +associated to the "Sample.01" profile. + +
+ +#### **Profile PED RDS file** + +The **Profile PED RDS file** must contain a *data.frame* describing all +the profiles to be analyzed. These 5 mandatory columns: + +- _Name.ID_: The unique sample identifier. The associated **profile SNP file** +should be called "Name.ID.txt.gz". +- _Case.ID_: The patient identifier associated to the sample. +- _Sample.Type_: The information about the profile tissue source +(primary tumor, metastatic tumor, normal, etc..). +- _Diagnosis_: The donor's diagnosis. +- _Source_: The source of the profile sequence data (example: dbGAP_XYZ). + +Important: The row names of the *data.frame* must be the profiles _Name.ID_. + +This file is referred to as the **Profile PED RDS file** (PED for pedigree). +Alternatively, the PED information can be saved in another type of +file (CVS, etc..) as long as the *data.frame* information can be regenerated +in R (with _read.csv()_ or else). + +
+ +#### **Example** + +This example run an ancestry inference on an RNA sample. Both population +reference files are demonstration files and should not be +used for a real ancestry inference. Beware that running an ancestry inference +on real data will take longer to run. + +```{r runRNAAncestry, echo=TRUE, eval=TRUE, collapse=FALSE, warning=FALSE, message=FALSE} +############################################################################# +## Load required packages +############################################################################# +library(RAIDS) +library(gdsfmt) + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +############################################################################# +## Load the information about the profile +############################################################################# +data(demoPedigreeEx1) +head(demoPedigreeEx1) + +############################################################################# +## The population reference GDS file and SNV Annotation GDS file +## need to be located in the same directory. +## Note that the population reference GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +############################################################################# +pathReference <- file.path(dataDir, "tests") + +fileGDS <- file.path(pathReference, "ex1_good_small_1KG.gds") +fileAnnotGDS <- file.path(pathReference, "ex1_good_small_1KG_Annot.gds") + +############################################################################# +## A data frame containing general information about the study +## is also required. The data frame must have +## those 3 columns: "study.id", "study.desc", "study.platform" +############################################################################# +studyDF <- data.frame(study.id="MYDATA", + study.desc="Description", + study.platform="PLATFORM", + stringsAsFactors=FALSE) + +############################################################################# +## The Sample SNP VCF files (one per sample) need +## to be all located in the same directory. +############################################################################# +pathGeno <- file.path(dataDir, "example", "snpPileupRNA") + +############################################################################# +## Fix RNG seed to ensure reproducible results +############################################################################# +set.seed(3043) + +############################################################################# +## Select the profiles from the population reference GDS file for +## the synthetic data. +## Here we select 2 profiles from the simplified 1KG GDS for each +## subcontinental-level. +## Normally, we use 30 profile for each +## subcontinental-level but it is too big for the example. +## The 1KG files in this example only have 6 profiles for each +## subcontinental-level (for demo purpose only). +############################################################################# +gds1KG <- snpgdsOpen(fileGDS) +dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +closefn.gds(gds1KG) + +## GenomeInfoDb and BSgenome are required libraries to run this example +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + ############################################################################# + ## The path where the Sample GDS files (one per sample) + ## will be created needs to be specified. + ############################################################################# + pathProfileGDS <- file.path(tempdir(), "exampleRNA", "outRNA.tmp") + + ############################################################################# + ## The path where the result files will be created needs to + ## be specified + ############################################################################# + pathOut <- file.path(tempdir(), "exampleRNA", "resRNA.out") + + ## Example can only be run if the current directory is in writing mode + if (!dir.exists(file.path(tempdir(), "exampleRNA"))) { + + dir.create(file.path(tempdir(), "exampleRNA")) + dir.create(pathProfileGDS) + dir.create(pathOut) + + ######################################################################### + ## The wrapper function generates the synthetic dataset and uses it + ## to selected the optimal parameters before calling the genetic + ## ancestry on the current profiles. + ## All important information, for each step, are saved in + ## multiple output files. + ## The 'genoSource' parameter has 2 options depending on how the + ## SNP files have been generated: + ## SNP VCF files have been generated: + ## "VCF" or "generic" (other software) + ######################################################################### + runRNAAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, + pathProfileGDS=pathProfileGDS, + pathGeno=pathGeno, + pathOut=pathOut, + fileReferenceGDS=fileGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + blockTypeID="GeneS.Ensembl.Hsapiens.v86", + genoSource="VCF") + + list.files(pathOut) + list.files(file.path(pathOut, demoPedigreeEx1$Name.ID[1])) + + ######################################################################### + ## The file containing the ancestry inference (SuperPop column) and + ## optimal number of PCA component (D column) + ## optimal number of neighbours (K column) + ######################################################################### + resAncestry <- read.csv(file.path(pathOut, + paste0(demoPedigreeEx1$Name.ID[1], ".Ancestry.csv"))) + print(resAncestry) + + ## Remove temporary files created for this demo + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + unlink(pathOut, recursive=TRUE, force=TRUE) + unlink(file.path(tempdir(), "example"), recursive=TRUE, force=TRUE) + } +} + +``` + +
+
+ +The *runRNAAncestry()* function generates 3 types of files +in the *pathOut* directory. + +* The ancestry inference CSV file (**".Ancestry.csv"** file) +* The inference information RDS file (**".infoCall.rds"** file) +* The parameter information RDS files from the synthetic inference +(__"KNN.synt.__*__.rds"__ files in a sub-directory) + +In addition, a sub-directory (named using the *profile ID*) is +also created. + +The inferred ancestry is stored in the ancestry inference CSV +file (**".Ancestry.csv"** file) which also contains those columns: + +* _sample.id_: The unique identifier of the sample +* _D_: The optimal PCA dimension value used to infer the ancestry +* _k_: The optimal number of neighbors value used to infer the ancestry +* _SuperPop_: The inferred ancestry + + +
+
+ + +## Format population reference dataset (optional) + + +```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from the population reference dataset (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("MainSteps_Step1_v04.png") +``` + + +A population reference dataset with known ancestry is required to infer +ancestry. + +Three important reference files, containing formatted information about +the reference dataset, are required: + +- The population reference GDS File +- The population reference SNV Annotation GDS file +- The population reference SNV Retained VCF file + + +The format of those files are described +the [Population reference dataset GDS files](Create_Reference_GDS_File.html) +vignette. + +The reference files associated to +the Cancer Research associated paper are available. Note that these +pre-processed files are for 1000 Genomes (1KG), in hg38. The files are +available here: + + +[https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper](https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper) + + +The size of the 1KG GDS file +is 15GB. + +The 1KG GDS file is mapped on +hg38 [@Lowy-Gallego2019a]. + +This section can be skipped if +you choose to use the pre-processed files. + +
+
+ + + +# Session info + +Here is the output of `sessionInfo()` in the environment in which this +document was compiled: + +```{r sessionInfo, echo=FALSE} +sessionInfo() +``` + +
+
+ + +# References + From b82f880c661368365618c680570dcce8ab65ed0d Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 15 Oct 2024 23:07:19 -0400 Subject: [PATCH 313/385] Warning in red about new functions available --- vignettes/Wrappers.Rmd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vignettes/Wrappers.Rmd b/vignettes/Wrappers.Rmd index ea2d02f55..664b92656 100644 --- a/vignettes/Wrappers.Rmd +++ b/vignettes/Wrappers.Rmd @@ -47,8 +47,9 @@ set.seed(121444) This vignette explains, in further details, the used of the wrapper functions that were developed for a previous release of RAIDS. -While those functions are still working, we recommend using the new -functions as described in the main vignette. +While those functions are still +working, we recommend using the new functions as described in the main +vignette.

From 31cae4f58f2e3279425092a42976f9f8b64b7ff9 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Tue, 15 Oct 2024 23:54:20 -0400 Subject: [PATCH 314/385] Remove old image for main steps section --- vignettes/MainSteps_v03.png | Bin 52211 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 vignettes/MainSteps_v03.png diff --git a/vignettes/MainSteps_v03.png b/vignettes/MainSteps_v03.png deleted file mode 100644 index 83464367ccc3b60fe8aac84f168bf81fb1961509..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52211 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 Date: Wed, 16 Oct 2024 00:42:24 -0400 Subject: [PATCH 315/385] Update main vignette --- vignettes/RAIDS.Rmd | 656 ++++++++---------------- vignettes/Step1_population_file_v01.png | Bin 0 -> 81473 bytes 2 files changed, 209 insertions(+), 447 deletions(-) create mode 100644 vignettes/Step1_population_file_v01.png diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 6af40508d..cffa57fd3 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -24,7 +24,6 @@ BiocStyle::markdown() suppressPackageStartupMessages({ library(knitr) library(RAIDS) - library(gdsfmt) }) set.seed(121444) @@ -106,194 +105,178 @@ BiocManager::install("RAIDS") # Main Steps - -This is an overview of genetic ancestry inference from cancer-derived +This is an overview of the genetic ancestry inference from cancer-derived molecular data: ```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference process.", out.width='130%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_v04.png") +knitr::include_graphics("MainSteps_v05.png") ``` The main steps are: -**Step 1.** Format reference data from the population reference dataset (optional) - -**Step 2.1** Optimize ancestry inference parameters - -**Step 2.2** Infer ancestry for the subjects of the external study - -These steps are described in detail in the following. Steps 2.1 and 2.2 can be -run together using one wrapper function. - -
-
- +**Step 1.** Set-up and provide population reference files -## Main Step - Ancestry Inference +**Step 2** Sample the reference data for donor genotypes, to be used for synthesis and optimize ancestry inference parameters -A wrapper function encapsulates multiple steps of the workflow. - -```{r graphWrapper, echo=FALSE, fig.align="center", fig.cap="Final step - The wrapper function encapsulates multiple steps of the workflow.", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Wrapper_v04.png") -``` +**Step 3** Infer ancestry for the subjects of the external study -In summary, the wrapper function generates the synthetic dataset and uses -it to selected the optimal parameters before calling the genetic ancestry -on the current profiles. +**Step 4** Present and interpret the results -According to the type of input data (RNA or DNA), a specific wrapper function -is available. +These steps are described in detail in the following.
+
-### DNA Data - Wrapper function to run ancestry inference on DNA data -The wrapper function, called _runExomeAncestry()_, requires 4 files as input: +## Step 1. Set-up and provide population reference files -- The **population reference GDS file** -- The **population reference SNV Annotation GDS file** -- The **Profile SNP file** (one per sample present in the study) -- The **Profile PED RDS file** (one file with information for all -profiles in the study) -In addition, a *data.frame* containing the general information about the -study is also required. The *data.frame* must contain those 3 columns: +### 1.1 Create a directory structure -- _study.id_: The study identifier (example: TCGA-BRCA). -- _study.desc_: The description of the study. -- _study.platform_: The type of sequencing (example: RNA-seq). +First, a specific directory structure must be created. The structure must +correspond to this: -
- -#### **Population reference files** +``` -For demonstration purpose, a small -**population reference GDS file** (called _ex1_good_small_1KG.gds_) and a small -**population reference SNV Annotation GDS file** (called -_ex1_good_small_1KG_Annot.gds_) are -included in this package. Beware that those two files should not be used to -run a real ancestry inference.The results obtained with those files won't be -reliable. +############################################################################# +## Working directory structure +############################################################################# +workingDirectory/ + data/ + refGDS + profileGDS -The required **population reference GDS file** and -**population reference SNV Annotation GDS file** should be stored in the same -directory. In the example below, this directory is referred to -as **pathReference**. +```
-#### **Profile SNP file** +This following running example creates a temporary working directory structure +when the demo samples will be run. Some sub-directories in +*workingDirectory/data* will be created in subsequent steps. -The **Profile SNP file** can be either in a VCF format or in a generic format. -The **Profile SNP VCF file** follows the VCF standard with at least -those genotype fields: _GT_, _AD_ and _DP_. The identifier of the genotype -in the VCF file must correspond to the profile identifier _Name.ID_. -The SNVs must be germline variants and should include the genotype of the -wild-type homozygous at the selected positions in the reference. One file per -profile is need and the VCF file must be gzipped. +```{r createDir, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -Note that the name assigned to the **Profile SNP VCF file** has to -correspond to the profile identifier _Name.ID_ in the following analysis. -For example, a SNP file called "Sample.01.vcf.gz" would be -associated to the "Sample.01" profile. +############################################################################# +## Create a temporary working directory structure +############################################################################# +pathWorkingDirectory <- file.path(tempdir(), "workingDirectory") +pathWorkingDirectoryData <- file.path(pathWorkingDirectory, "data") -A generic SNP file can replace the VCF file. The **Profile SNP Generic file** -format is coma separated and the mandatory columns are: +if (!dir.exists(pathWorkingDirectory)) { + dir.create(pathWorkingDirectory) + dir.create(pathWorkingDirectoryData) + dir.create(file.path(pathWorkingDirectoryData, "refGDS")) +} -* _Chromosome_: The name of the chromosome -* _Position_: The position on the chromosome -* _Ref_: The reference nucleotide -* _Alt_: The aternative nucleotide -* _Count_: The total count -* _File1R_: The count for the reference nucleotide -* _File1A_: The count for the alternative nucleotide +``` -Beware that the starting position in the **population reference GDS File** is -zero (like BED files). The **Profile SNP Generic file** should also start -at position zero. +
-Note that the name assigned to the **Profile SNP Generic file** has to -correspond to the profile identifier _Name.ID_ in the following analysis. -For example, a SNP file called "Sample.01.generic.txt.gz" would be -associated to the "Sample.01" profile. +### 1.2 Download the population reference files -
-#### **Profile PED RDS file** +The population reference files should be downloaded in the *data/refGDS* +sub-directory. This following code downloads the complete pre-processed files +for 1000 Genomes (1KG), in hg38. The size of the 1KG GDS file is 15GB. -The **Profile PED RDS file** must contain a *data.frame* describing all -the profiles to be analyzed. These 5 mandatory columns: +``` -- _Name.ID_: The unique sample identifier. The associated **profile SNP file** -should be called "Name.ID.txt.gz". -- _Case.ID_: The patient identifier associated to the sample. -- _Sample.Type_: The information about the profile tissue source -(primary tumor, metastatic tumor, normal, etc..). -- _Diagnosis_: The donor's diagnosis. -- _Source_: The source of the profile sequence data (example: dbGAP_XYZ). +############################################################################# +## How to download the pre-processed files for 1000 Genomes (1KG) (15 GB) +############################################################################# +cd workingDirectory +cd data/refGDS -Important: The row names of the *data.frame* must be the profiles *Name.ID*. +wget https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper/matGeno1000g.gds +wget https://labshare.cshl.edu/shares/krasnitzlab/aicsPaper/matAnnot1000g.gds +cd - -This file is referred to as the **Profile PED RDS file** (PED for pedigree). -Alternatively, the PED information can be saved in another type of -file (CVS, etc..) as long as the *data.frame* information can be regenerated -in R (with _read.csv()_ or else). +```
-#### **Example** - -This example run an ancestry inference on an exome sample. Both population -reference files are demonstration files and should not be -used for a real ancestry inference. Beware that running an ancestry inference -on real data will take longer to run. +For demonstration purpose, a small +**population reference GDS file** (called _ex1_good_small_1KG.gds_) and a small +**population reference SNV Annotation GDS file** (called +_ex1_good_small_1KG_Annot.gds_) are +included in this package. Beware that those two files should not be used to +run a real ancestry inference. The results obtained with those files won't be +reliable. -```{r runExomeAncestry, echo=TRUE, eval=TRUE, collapse=FALSE, warning=FALSE, message=FALSE} -############################################################################# -## Load required packages -############################################################################# -library(RAIDS) -library(gdsfmt) +In this running example, the demonstration files are copied in the required +*data/refGDS* directory. -## Path to the demo 1KG GDS file is located in this package -dataDir <- system.file("extdata", package="RAIDS") +```{r copyRefFile, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# -## Load the information about the profile +## Load RAIDS package ############################################################################# -data(demoPedigreeEx1) -head(demoPedigreeEx1) +library(RAIDS) ############################################################################# ## The population reference GDS file and SNV Annotation GDS file -## need to be located in the same directory. +## need to be located in the same sub-directory. ## Note that the population reference GDS file used for this example is a ## simplified version and CANNOT be used for any real analysis ############################################################################# +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") pathReference <- file.path(dataDir, "tests") fileGDS <- file.path(pathReference, "ex1_good_small_1KG.gds") fileAnnotGDS <- file.path(pathReference, "ex1_good_small_1KG_Annot.gds") +file.copy(fileGDS, file.path(pathWorkingDirectoryData, "refGDS")) +file.copy(fileAnnotGDS, file.path(pathWorkingDirectoryData, "refGDS")) + +``` +
+
+ +## Step 2 Ancestry inference with RAIDS + +### 2.1 Set-up required directories + +```{r installRaids, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} + ############################################################################# -## A data frame containing general information about the study -## is also required. The data frame must have -## those 3 columns: "study.id", "study.desc", "study.platform" +## The file path to the population reference GDS file +## is required (refGenotype will be used as input later) +## The file path to the population reference SNV Annotation GDS file +## is also required (refAnnotation will be used as input later) ############################################################################# -studyDF <- data.frame(study.id="MYDATA", - study.desc="Description", - study.platform="PLATFORM", - stringsAsFactors=FALSE) +pathReference <- file.path(pathWorkingDirectoryData, "refGDS") + +refGenotype <- file.path(pathReference, "ex1_good_small_1KG.gds") +refAnnotation <- file.path(pathReference, "ex1_good_small_1KG_Annot.gds") ############################################################################# -## The Sample SNP VCF files (one per sample) need -## to be all located in the same directory. +## The output directories inside workingDirectory/data must be created +## (pathProfileGDS will be used as input later) ############################################################################# -pathGeno <- file.path(dataDir, "example", "snpPileup") +pathProfileGDS <- file.path(pathWorkingDirectoryData, "profileGDS") + +if (!dir.exists(pathProfileGDS)) { + dir.create(pathProfileGDS) +} + +``` + + +
+ +### 2.2 Sample reference donor profiles from the reference data + +With the 1KG reference, we recommend sampling 30 donor profiles per population. +For reproducibility, be sure to use the same random-number generator seed. + +In the following code, only 2 profiles per population are sampled: + +```{r sampling, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# -## Fix RNG seed to ensure reproducible results +## Fix seed to ensure reproducible results ############################################################################# set.seed(3043) @@ -302,393 +285,173 @@ set.seed(3043) ## the synthetic data. ## Here we select 2 profiles from the simplified 1KG GDS for each ## subcontinental-level. -## Normally, we use 30 profile for each -## subcontinental-level but it is too big for the example. +## Normally, we would use 30 profiles for each subcontinental-level. ## The 1KG files in this example only have 6 profiles for each ## subcontinental-level (for demo purpose only). ############################################################################# -gds1KG <- snpgdsOpen(fileGDS) -dataRef <- select1KGPop(gds1KG, nbProfiles=2L) -closefn.gds(gds1KG) - -## GenomeInfoDb and BSgenome are required libraries to run this example -if (requireNamespace("GenomeInfoDb", quietly=TRUE) && - requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { - - ## Chromosome length information - ## chr23 is chrX, chr24 is chrY and chrM is 25 - chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] - - ########################################################################### - ## The path where the Sample GDS files (one per sample) - ## will be created needs to be specified. - ########################################################################### - pathProfileGDS <- file.path(tempdir(), "exampleDNA", "out.tmp") - - ########################################################################### - ## The path where the result files will be created needs to - ## be specified - ########################################################################### - pathOut <- file.path(tempdir(), "exampleDNA", "res.out") - - ## Example can only be run if the current directory is in writing mode - if (!dir.exists(file.path(tempdir(), "exampleDNA"))) { - - dir.create(file.path(tempdir(), "exampleDNA")) - dir.create(pathProfileGDS) - dir.create(pathOut) - - ######################################################################### - ## The wrapper function generates the synthetic dataset and uses it - ## to selected the optimal parameters before calling the genetic - ## ancestry on the current profiles. - ## All important information, for each step, are saved in - ## multiple output files. - ## The 'genoSource' parameter has 2 options depending on how the - ## SNP files have been generated: - ## SNP VCF files have been generated: - ## "VCF" or "generic" (other software) - ## - ######################################################################### - runExomeAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, - pathProfileGDS=pathProfileGDS, - pathGeno=pathGeno, - pathOut=pathOut, - fileReferenceGDS=fileGDS, - fileReferenceAnnotGDS=fileAnnotGDS, - chrInfo=chrInfo, - syntheticRefDF=dataRef, - genoSource="VCF") - list.files(pathOut) - list.files(file.path(pathOut, demoPedigreeEx1$Name.ID[1])) - - ####################################################################### - ## The file containing the ancestry inference (SuperPop column) and - ## optimal number of PCA component (D column) - ## optimal number of neighbours (K column) - ####################################################################### - resAncestry <- read.csv(file.path(pathOut, - paste0(demoPedigreeEx1$Name.ID[1], ".Ancestry.csv"))) - print(resAncestry) - - ## Remove temporary files created for this demo - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) - unlink(file.path(tempdir(), "exampleDNA"), recursive=TRUE, force=TRUE) - } -} - +dataRef <- select1KGPopForSynthetic(fileReferenceGDS=refGenotype, + nbProfiles=2L) ``` -
+The output object is going to be used later at the ancestry inference step. +
-The *runExomeAncestry()* function generates 3 types of files -in the *pathOut* directory. +### 2.3 Perform the ancestry inference -* The ancestry inference CSV file (**".Ancestry.csv"** file) -* The inference information RDS file (**".infoCall.rds"** file) -* The parameter information RDS files from the synthetic inference -(__"KNN.synt.__*__.rds"__ files in a sub-directory) +Within a single function call, data synthesis is performed, the synthetic +data are used to optimize the inference parameters and, with these, the +ancestry of the input profile donor is inferred. -In addition, a sub-directory (named using the *profile ID*) is -also created. +According to the type of input data (RNA or DNA), a specific function +is available. -The inferred ancestry is stored in the ancestry inference CSV -file (**".Ancestry.csv"** file) which also contains those columns: +The *inferAncestry()* function is used for DNA profiles while +the *inferAncestryGeneAware()* function is RNA specific. -* _sample.id_: The unique identifier of the sample -* _D_: The optimal PCA dimension value used to infer the ancestry -* _k_: The optimal number of neighbors value used to infer the ancestry -* _SuperPop_: The inferred ancestry +In this example, the profile is from DNA source and requires the use of the +*inferAncestry()* function. -
-
+```{r infere, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +########################################################################### +## GenomeInfoDb and BSgenome are required libraries to run this example +########################################################################### +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + ####################################################################### + ## Chromosome length information is required + ## chr23 is chrX, chr24 is chrY and chrM is 25 + ####################################################################### + genome <- BSgenome.Hsapiens.UCSC.hg38::Hsapiens + chrInfo <- GenomeInfoDb::seqlengths(genome)[1:25] + + ####################################################################### + ## The SNP VCF file of the DNA profile donor + ####################################################################### + fileDonorVCF <- file.path(dataDir, "example", "snpPileup", "ex1.vcf.gz") + + ####################################################################### + ## The ancestry inference call + ####################################################################### + resOut <- inferAncestry(profileFile=fileDonorVCF, + pathProfileGDS=pathProfileGDS, + fileReferenceGDS=refGenotype, + fileReferenceAnnotGDS=refAnnotation, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + genoSource=c("VCF")) +} -### RNA data - Wrapper function to run ancestry inference on RNA data +``` -The process is the same as for the DNA but use the wrapper function -called _runRNAAncestry()_. Internally the data is process differently. -It requires 4 files as input: +A profile GDS file is created in the *pathProfileGDS* directory while all the +ancestry and optimal parameters information are integrated in the output +object. -- The **population reference GDS file** -- The **population reference SNV Annotation GDS file** -- The **Profile SNP file** (one per sample present in the study) -- The **Profile PED RDS file** (one file with information for all -profiles in the study) +At last, all temporary files created in this example should be deleted. -A *data.frame* containing the general information about the study is -also required. The *data.frame* must contain those 3 columns: +```{r removeTmp, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -- _study.id_: The study identifier (example: TCGA-BRCA). -- _study.desc_: The description of the study. -- _study.platform_: The type of sequencing (example: RNA-seq). +####################################################################### +## Remove temporary files created for this demo +####################################################################### +unlink(pathWorkingDirectory, recursive=TRUE, force=TRUE) + +```
- -#### **Population reference files** - -For demonstration purpose, a small -**population reference GDS file** (called _ex1_good_small_1KG.gds_) and a small -**population reference SNV Annotation GDS file** (called -_ex1_good_small_1KG_Annot.gds_) are -included in this package. Beware that those two files should not be used to -run a real ancestry inference.The results obtained with those files won't be -reliable. - -The required **population reference GDS file** and -**population reference SNV Annotation GDS file** should be stored in the same -directory. In the example below, this directory is referred to -as **pathReference**. -
-#### **Profile SNP file** - -The **Profile SNP file** can be either in a VCF format or in a generic format. - -The **Profile SNP VCF file** follows the VCF standard with at least -those genotype fields: _GT_, _AD_ and _DP_. The identifier of the genotype -in the VCF file must correspond to the profile identifier _Name.ID_. -The SNVs must be germline variants and should include the genotype of the -wild-type homozygous at the selected positions in the reference. One file per -profile is need and the VCF file must be gzipped. - -Note that the name assigned to the **Profile SNP VCF file** has to -correspond to the profile identifier _Name.ID_ in the following analysis. -For example, a SNP file called "Sample.01.vcf.gz" would be -associated to the "Sample.01" profile. - -A generic SNP file can replace the VCF file. The **Profile SNP Generic file** -format is coma separated and the mandatory columns are: -* _Chromosome_: The name of the chromosome -* _Position_: The position on the chromosome -* _Ref_: The reference nucleotide -* _Alt_: The aternative nucleotide -* _Count_: The total count -* _File1R_: The count for the reference nucleotide -* _File1A_: The count for the alternative nucleotide +## Step 3. Examine the value of the inference call -Beware that the starting position in the **population reference GDS File** is -zero (like BED files). The **Profile SNP Generic file** should also start -at position zero. +The inferred ancestry and the optimal parameters are present in the *list* +object generated by the *inferAncestry()* and *inferAncestryGeneAware()* +functions. -Note that the name assigned to the **Profile SNP Generic file** has to -correspond to the profile identifier _Name.ID_ in the following analysis. -For example, a SNP file called "Sample.01.generic.txt.gz" would be -associated to the "Sample.01" profile. -
- -#### **Profile PED RDS file** - -The **Profile PED RDS file** must contain a *data.frame* describing all -the profiles to be analyzed. These 5 mandatory columns: +```{r printRes, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -- _Name.ID_: The unique sample identifier. The associated **profile SNP file** -should be called "Name.ID.txt.gz". -- _Case.ID_: The patient identifier associated to the sample. -- _Sample.Type_: The information about the profile tissue source -(primary tumor, metastatic tumor, normal, etc..). -- _Diagnosis_: The donor's diagnosis. -- _Source_: The source of the profile sequence data (example: dbGAP_XYZ). +########################################################################### +## The output is a list object with multiple entries +########################################################################### +class(resOut) +names(resOut) -Important: The row names of the *data.frame* must be the profiles _Name.ID_. +``` -This file is referred to as the **Profile PED RDS file** (PED for pedigree). -Alternatively, the PED information can be saved in another type of -file (CVS, etc..) as long as the *data.frame* information can be regenerated -in R (with _read.csv()_ or else).
-#### **Example** - -This example run an ancestry inference on an RNA sample. Both population -reference files are demonstration files and should not be -used for a real ancestry inference. Beware that running an ancestry inference -on real data will take longer to run. +### 3.1 Inspect the inference and the optimal parameters -```{r runRNAAncestry, echo=TRUE, eval=TRUE, collapse=FALSE, warning=FALSE, message=FALSE} -############################################################################# -## Load required packages -############################################################################# -library(RAIDS) -library(gdsfmt) -## Path to the demo 1KG GDS file is located in this package -dataDir <- system.file("extdata", package="RAIDS") +For the global ancestry inference using PCA followed by nearest neighbor +classification these parameters are *D* (the number of the top principal +directions retained) and *k* (the number of nearest neighbors). -############################################################################# -## Load the information about the profile -############################################################################# -data(demoPedigreeEx1) -head(demoPedigreeEx1) +The information is stored in the *Ancestry* entry as a *data.frame* object. +It is a contains those columns: -############################################################################# -## The population reference GDS file and SNV Annotation GDS file -## need to be located in the same directory. -## Note that the population reference GDS file used for this example is a -## simplified version and CANNOT be used for any real analysis -############################################################################# -pathReference <- file.path(dataDir, "tests") - -fileGDS <- file.path(pathReference, "ex1_good_small_1KG.gds") -fileAnnotGDS <- file.path(pathReference, "ex1_good_small_1KG_Annot.gds") +* _sample.id_: The unique identifier of the sample +* _D_: The optimal PCA dimension value used to infer the ancestry +* _k_: The optimal number of neighbors value used to infer the ancestry +* _SuperPop_: The inferred ancestry -############################################################################# -## A data frame containing general information about the study -## is also required. The data frame must have -## those 3 columns: "study.id", "study.desc", "study.platform" -############################################################################# -studyDF <- data.frame(study.id="MYDATA", - study.desc="Description", - study.platform="PLATFORM", - stringsAsFactors=FALSE) -############################################################################# -## The Sample SNP VCF files (one per sample) need -## to be all located in the same directory. -############################################################################# -pathGeno <- file.path(dataDir, "example", "snpPileupRNA") +```{r print, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} -############################################################################# -## Fix RNG seed to ensure reproducible results -############################################################################# -set.seed(3043) +########################################################################### +## The ancestry information is stored in the 'Ancestry' entry +########################################################################### +print(resOut$Ancestry) -############################################################################# -## Select the profiles from the population reference GDS file for -## the synthetic data. -## Here we select 2 profiles from the simplified 1KG GDS for each -## subcontinental-level. -## Normally, we use 30 profile for each -## subcontinental-level but it is too big for the example. -## The 1KG files in this example only have 6 profiles for each -## subcontinental-level (for demo purpose only). -############################################################################# -gds1KG <- snpgdsOpen(fileGDS) -dataRef <- select1KGPop(gds1KG, nbProfiles=2L) -closefn.gds(gds1KG) - -## GenomeInfoDb and BSgenome are required libraries to run this example -if (requireNamespace("GenomeInfoDb", quietly=TRUE) && - requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { - - ## Chromosome length information - ## chr23 is chrX, chr24 is chrY and chrM is 25 - chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] - - ############################################################################# - ## The path where the Sample GDS files (one per sample) - ## will be created needs to be specified. - ############################################################################# - pathProfileGDS <- file.path(tempdir(), "exampleRNA", "outRNA.tmp") - - ############################################################################# - ## The path where the result files will be created needs to - ## be specified - ############################################################################# - pathOut <- file.path(tempdir(), "exampleRNA", "resRNA.out") - - ## Example can only be run if the current directory is in writing mode - if (!dir.exists(file.path(tempdir(), "exampleRNA"))) { - - dir.create(file.path(tempdir(), "exampleRNA")) - dir.create(pathProfileGDS) - dir.create(pathOut) - - ######################################################################### - ## The wrapper function generates the synthetic dataset and uses it - ## to selected the optimal parameters before calling the genetic - ## ancestry on the current profiles. - ## All important information, for each step, are saved in - ## multiple output files. - ## The 'genoSource' parameter has 2 options depending on how the - ## SNP files have been generated: - ## SNP VCF files have been generated: - ## "VCF" or "generic" (other software) - ######################################################################### - runRNAAncestry(pedStudy=demoPedigreeEx1, studyDF=studyDF, - pathProfileGDS=pathProfileGDS, - pathGeno=pathGeno, - pathOut=pathOut, - fileReferenceGDS=fileGDS, - fileReferenceAnnotGDS=fileAnnotGDS, - chrInfo=chrInfo, - syntheticRefDF=dataRef, - blockTypeID="GeneS.Ensembl.Hsapiens.v86", - genoSource="VCF") - - list.files(pathOut) - list.files(file.path(pathOut, demoPedigreeEx1$Name.ID[1])) - - ######################################################################### - ## The file containing the ancestry inference (SuperPop column) and - ## optimal number of PCA component (D column) - ## optimal number of neighbours (K column) - ######################################################################### - resAncestry <- read.csv(file.path(pathOut, - paste0(demoPedigreeEx1$Name.ID[1], ".Ancestry.csv"))) - print(resAncestry) - - ## Remove temporary files created for this demo - unlink(pathProfileGDS, recursive=TRUE, force=TRUE) - unlink(pathOut, recursive=TRUE, force=TRUE) - unlink(file.path(tempdir(), "example"), recursive=TRUE, force=TRUE) - } -} - ``` -

-The *runRNAAncestry()* function generates 3 types of files -in the *pathOut* directory. +### 3.2 Visualize the RAIDS performance for the synthetic data -* The ancestry inference CSV file (**".Ancestry.csv"** file) -* The inference information RDS file (**".infoCall.rds"** file) -* The parameter information RDS files from the synthetic inference -(__"KNN.synt.__*__.rds"__ files in a sub-directory) -In addition, a sub-directory (named using the *profile ID*) is -also created. +The *createAUROCGraph()* function enable the visualization of RAIDS +performance for the synthetic data, as a function of *D* and *k*. -The inferred ancestry is stored in the ancestry inference CSV -file (**".Ancestry.csv"** file) which also contains those columns: +```{r visualize, echo=TRUE, eval=TRUE, fig.align="center", fig.cap="RAIDS performance for the synthtic data.", results='asis', collapse=FALSE, warning=FALSE, message=FALSE} -* _sample.id_: The unique identifier of the sample -* _D_: The optimal PCA dimension value used to infer the ancestry -* _k_: The optimal number of neighbors value used to infer the ancestry -* _SuperPop_: The inferred ancestry +########################################################################### +## Create a graph showing the perfomance for the synthetic data +## The output is a ggplot object +########################################################################### +createAUROCGraph(dfAUROC=resOut$paraSample$dfAUROC, title="Example ex1") +``` + +In this specific demonstration, the performances are lower than expected +with a real profile and a complete reference population file.

+# Format population reference dataset (optional) -## Format population reference dataset (optional) - -```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from the population reference dataset (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step1_v04.png") +```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Provide population reference data", out.width='120%', results='asis', warning=FALSE, message=FALSE} +knitr::include_graphics("Step1_population_file_v01.png") ``` A population reference dataset with known ancestry is required to infer -ancestry. The population must be large enough to ensure ??? +ancestry. Three important reference files, containing formatted information about the reference dataset, are required: - The population reference GDS File - The population reference SNV Annotation GDS file -- The population reference SNV Retained VCF file +- The population reference SNV Retained VCF file (optional) The format of those files are described @@ -717,7 +480,6 @@ you choose to use the pre-processed files.
- # Session info Here is the output of `sessionInfo()` in the environment in which this diff --git a/vignettes/Step1_population_file_v01.png b/vignettes/Step1_population_file_v01.png new file mode 100644 index 0000000000000000000000000000000000000000..926954f477b08a26254eff9ce2d73b2e5c6d224c GIT binary patch literal 81473 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 IviF|;AJ!hlKmY&$ literal 0 HcmV?d00001 From bc8ec34d5c56fa4bbb805f11a050e0290b0d0057 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 16 Oct 2024 10:14:56 -0400 Subject: [PATCH 316/385] Update main vignette --- vignettes/RAIDS.Rmd | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index cffa57fd3..913f3b098 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -133,7 +133,7 @@ These steps are described in detail in the following. ### 1.1 Create a directory structure -First, a specific directory structure must be created. The structure must +First, a specific directory structure should be created. The structure must correspond to this: ``` @@ -151,8 +151,7 @@ workingDirectory/
This following running example creates a temporary working directory structure -when the demo samples will be run. Some sub-directories in -*workingDirectory/data* will be created in subsequent steps. +when the example will be run. ```{r createDir, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} @@ -167,6 +166,7 @@ if (!dir.exists(pathWorkingDirectory)) { dir.create(pathWorkingDirectory) dir.create(pathWorkingDirectoryData) dir.create(file.path(pathWorkingDirectoryData, "refGDS")) + dir.create(file.path(pathWorkingDirectoryData, "profileGDS")) } ``` @@ -252,8 +252,8 @@ refGenotype <- file.path(pathReference, "ex1_good_small_1KG.gds") refAnnotation <- file.path(pathReference, "ex1_good_small_1KG_Annot.gds") ############################################################################# -## The output directories inside workingDirectory/data must be created -## (pathProfileGDS will be used as input later) +## The output profileGDS directory, inside workingDirectory/data, must be +## created (pathProfileGDS will be used as input later) ############################################################################# pathProfileGDS <- file.path(pathWorkingDirectoryData, "profileGDS") @@ -271,7 +271,8 @@ if (!dir.exists(pathProfileGDS)) { With the 1KG reference, we recommend sampling 30 donor profiles per population. For reproducibility, be sure to use the same random-number generator seed. -In the following code, only 2 profiles per population are sampled: +In the following code, only 2 profiles per population are sampled from the +demo population GDS file: ```{r sampling, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} @@ -429,7 +430,7 @@ createAUROCGraph(dfAUROC=resOut$paraSample$dfAUROC, title="Example ex1") ``` -In this specific demonstration, the performances are lower than expected +In this specific example, the performances are lower than expected with a real profile and a complete reference population file.
From 18056f22fcb6ee35d4824ded097611acc82a6284 Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 16 Oct 2024 10:47:30 -0400 Subject: [PATCH 317/385] Update to parse the plink output for LD blocks. --- DESCRIPTION | 2 +- NAMESPACE | 1 + R/gdsWrapper_internal.R | 103 +++++++++++++++++++++ R/process1KG.R | 177 +++++++++++++++++++++++++++++++++++++ R/processStudy.R | 7 +- R/tools_internal.R | 33 +++---- inst/NEWS.md | 7 ++ man/addBlockFromDetFile.Rd | 105 ++++++++++++++++++++++ man/addGDS1KGLDBlock.Rd | 75 ++++++++++++++++ man/processBlockChr.Rd | 2 +- 10 files changed, 494 insertions(+), 18 deletions(-) create mode 100644 man/addBlockFromDetFile.Rd create mode 100644 man/addGDS1KGLDBlock.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 1b8934797..26f6ba1aa 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 1.3.1 +Version: 1.3.2 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/NAMESPACE b/NAMESPACE index 4f535fe61..406f6e41f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand export(add1KG2SampleGDS) +export(addBlockFromDetFile) export(addGeneBlockGDSRefAnnot) export(addGeneBlockRefAnnot) export(addRef2GDS1KG) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index b127d465a..11bd98eb0 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -1335,3 +1335,106 @@ appendGDSSampleOnly <- function(gds, listSamples) { return(0L) } + +#' @title Append information associated to ld blocks, as indexes, into the +#' Population Reference SNV Annotation GDS file +#' +#' @description The function appends the information about the ld blocks into +#' the Population Reference SNV Annotation GDS file. The information is +#' extracted from the parameter listBlock. +#' +#' @param gds an object of class \link[gdsfmt]{gds.class} +#' (GDS file), an opened Reference Annotation GDS file. +#' +#' @param listBlock a \code{array} of integer +#' representing the linkage disequilibrium block for +#' each SNV in the in the same order than the variant +#' in Population reference dataset. +#' +#' @param blockName a \code{character} string representing the id of the block. +#' The blockName should not exist in \'gdsRefAnnotFile\'. +#' +#' @param blockDesc a \code{character} string representing the description of +#' the block. +#' +#' @return The integer \code{0L} when successful. +#' +#' @examples +#' +#' ## Required library for GDS +#' library(gdsfmt) +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +# ## Temporary file +#' fileAnnotGDS <- file.path(tempdir(), "ex1_good_small_1KG_Ann_GDS.gds") +#' +#' +#' file.copy(file.path(dataDir, "tests", +#' "ex1_NoBlockGene.1KG_Annot_GDS.gds"), fileAnnotGDS) +#' +#' +#' fileReferenceGDS <- file.path(dataDir, "tests", +#' "ex1_good_small_1KG.gds") +#' \donttest{ +#' gdsRef <- openfn.gds(fileReferenceGDS) +#' listBlock <- read.gdsn(index.gdsn(gdsRef, "snp.position")) +#' listBlock <- rep(-1, length(listBlock)) +#' closefn.gds(gdsRef) +#' gdsAnnot1KG <- openfn.gds(fileAnnotGDS, readonly=FALSE) +#' ## Append information associated to blocks +#' RAIDS:::addGDS1KGLDBlock(gds=gdsAnnot1KG, +#' listBlock=listBlock, +#' blockName="blockEmpty", +#' blockDesc="Example") +#' +#' gdsAnnot1KG <- openfn.gds(fileAnnotGDS) +#' print(gdsAnnot1KG) +#' +#' closefn.gds(gdsAnnot1KG) +#' } +#' +#' ## Remove temporary file +#' unlink(fileAnnotGDS, force=TRUE) +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt add.gdsn index.gdsn ls.gdsn compression.gdsn +#' @importFrom gdsfmt append.gdsn sync.gds +#' @encoding UTF-8 +#' @keywords internal +addGDS1KGLDBlock <- function(gds, listBlock, blockName, blockDesc) { + + blockAnnot <- data.frame(block.id=blockName, + block.desc=blockDesc, + stringsAsFactors=FALSE) + + if(! ("block.annot" %in% ls.gdsn(gds))) { + varBlockAnnot <- add.gdsn(gds, "block.annot", blockAnnot) + }else { + curAnnot <- index.gdsn(gds, "block.annot/block.id") + append.gdsn(curAnnot,blockAnnot$block.id) + curAnnot <- index.gdsn(gds, "block.annot/block.desc") + append.gdsn(curAnnot, blockAnnot$block.desc) + } + + varBlock <- NULL + if(! ("block" %in% ls.gdsn(gds))){ + varBlock <- add.gdsn(gds, "block", + valdim=c(length(listBlock), 1), + listBlock, storage="int32", + compress = "LZ4_RA") + readmode.gdsn(varBlock) + + }else { + if(is.null(varBlock)) { + varBlock <- index.gdsn(gds, "block") + varBlock <- compression.gdsn(varBlock, "") + } + append.gdsn(varBlock, listBlock) + varBlock <- compression.gdsn(varBlock, "LZ4_RA") + } + + sync.gds(gds) + + return(0L) +} diff --git a/R/process1KG.R b/R/process1KG.R index 76073383b..ffd9c5bb8 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -1020,6 +1020,183 @@ getRefSuperPop <- function(fileReferenceGDS) { return(df) } +#' @title Append information associated to ld blocks, as indexes, into the +#' Population Reference SNV Annotation GDS file +#' +#' @description The function appends the information about the ld blocks into +#' the Population Reference SNV Annotation GDS file. The information is +#' extracted from the Population Reference GDS file and files \'.det\'. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Reference GDS file. The file must exist. +#' +#' @param gdsRefAnnotFile a \code{character} string representing the +#' file name corresponding the Reference SNV +#' Annotation GDS file. The function will +#' open it in write mode and close it after. The file must exist. +#' +#' @param pathBlock a \code{character} string representing the directory +#' where all the output file det from the plink block command are located. +#' The directory must not include other file with the extension \'.det\'. +#' The name of the \'.det\' must include the super-population between \'.\' +#' and the chromosome in the form \'chrNumber.\' \( \'chr1.\'\). +#' +#' @param superPop a \code{character} string representing the super population. +#' +#' @param blockName a \code{character} string representing the id of the block. +#' The blockName should not exist in \'gdsRefAnnotFile\'. +#' Default: \code{"ldBlock"}. +#' +#' @param blockDesc a \code{character} string representing the description of +#' the block. +#' Default: \code{"Not Define"} +#' +#' @param verbose a \code{logical} indicating if message information should be +#' printed. Default: \code{FALSE}. +#' +#' @return \code{OL} when the function is successful. +#' +#' @details +#' +#' More information about GDS file format can be found at the Bioconductor +#' gdsfmt website: +#' https://bioconductor.org/packages/gdsfmt/ +#' +#' @examples +#' +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +# ## Temporary file +#' fileAnnotGDS <- file.path(tempdir(), "ex1_good_small_1KG_Ann_GDS.gds") +#' +#' ## Demo of of output file det from the plink block +#' ## command for chromosome 1 +#' fileLdBlock <- file.path(dirname(fileAnnotGDS), "block.sp.EUR.Ex.chr1.blocks.det") +#' +#' +#' file.copy(file.path(dataDir, "tests", +#' "ex1_NoBlockGene.1KG_Annot_GDS.gds"), fileAnnotGDS) +#' file.copy(file.path(dataDir, "block.sp.EUR.Ex.chr1.blocks.det"), +#' fileLdBlock) +#' +#' +#' +#' ## GDS Reference file +#' fileReferenceGDS <- file.path(dataDir, "tests", +#' "ex1_good_small_1KG.gds") +#' +#' \donttest{ +#' +#' +#' ## Append information associated to blocks +#' addBlockFromDetFile(fileReferenceGDS=fileReferenceGDS, +#' gdsRefAnnotFile=fileAnnotGDS, +#' pathBlock=dirname(fileAnnotGDS), +#' superPop="EUR") +#' +#' gdsAnnot1KG <- openfn.gds(fileAnnotGDS) +#' print(gdsAnnot1KG) +#' +#' closefn.gds(gdsAnnot1KG) +#' } +#' +#' ## Remove temporary file +#' unlink(fileAnnotGDS, force=TRUE) +#' unlink(fileLdBlock, force=TRUE) +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' +#' @importFrom gdsfmt openfn.gds closefn.gds read.gdsn index.gdsn ls.gdsn +#' @importFrom SNPRelate snpgdsOpen +#' @encoding UTF-8 +#' @export +addBlockFromDetFile <- function(fileReferenceGDS, gdsRefAnnotFile, pathBlock, + superPop, blockName="ldBlock", + blockDesc="Not Define", verbose=FALSE) { + if (!(is.character(fileReferenceGDS) && (file.exists(fileReferenceGDS)))) { + stop("The \'fileReferenceGDS\' must be a character string ", + "representing the Reference GDS file. The file must exist.") + } + if(!(is.character(blockName))){ + stop("The \'blockName\' must be a character string ", + "representing the name of the block.") + } + + if(blockName == "ldBlock"){ + blockName <- paste0(blockName, ".", superPop) + } + + gdsRefAnnot <- openfn.gds(gdsRefAnnotFile) + + if(("block.annot" %in% ls.gdsn(gdsRefAnnot))) { + listAnno <- read.gdsn(index.gdsn(gdsRefAnnot, "block.annot")) + if(length(which(gdsRefAnnot$block.id == blockName)) > 0){ + stop("The \'blockName\' already exist in \'gdsRefAnnotFile\'.") + } + } + closefn.gds(gdsRefAnnot) + + gdsReference <- snpgdsOpen(filename=fileReferenceGDS) + + + + ## The verbose must be a logical + validateLogical(verbose, "verbose") + + ## Extract the SNP chromosomes and positions + snpChromosome <- read.gdsn(index.gdsn(gdsReference, "snp.chromosome")) + #snpPosition <- read.gdsn(index.gdsn(gdsReference, "snp.position")) + closefn.gds(gdsReference) + + listFileBlock <- dir(pathBlock, ".det") + listFileBlock <- listFileBlock[grep(paste0("\\.", superPop, "\\."), listFileBlock)] + + listChr <- unique(snpChromosome) + + #listChr <- listChr[order(listChr)] + #listChr <- seq_len(22) + listBlock <- list() + + for(chr in seq_len(length(listChr))) { + if(verbose) { message("chr", listChr[chr], " ",Sys.time()) } + listChrCur <- listFileBlock[grep(paste0("chr",listChr[chr],"\\."), listFileBlock)] + if(length(listChrCur) == 1){ + tmp <- processBlockChr(fileReferenceGDS, file.path(pathBlock, listChrCur)) + listBlock[[chr]] <- tmp$block.snp + if(chr > 1) { + vMax <- max(listBlock[[chr-1]]) + vMin <- min(listBlock[[chr-1]]) + listBlock[[chr]][listBlock[[chr]] > 0] <- + listBlock[[chr]][listBlock[[chr]] > 0] + vMax + if(vMin < 0) { + listBlock[[chr]][listBlock[[chr]] < 0] <- + listBlock[[chr]][listBlock[[chr]] < 0] + vMin + } + } + }else{ + + listBlock[[chr]] <- rep(-1, length(which(snpChromosome == listChr[chr]))) + vMin <- 0 + if(chr > 1){ + vMin <- min(listBlock[[chr-1]]) + } + if(vMin < 0){ + listBlock[[chr]] <- listBlock[[chr]] + vMin + } + } + + } + listBlock <- do.call(c, listBlock) + + gdsRefAnnot <- openfn.gds(gdsRefAnnotFile, readonly = FALSE) + + ## Save the information into the GDS file + addGDS1KGLDBlock(gdsRefAnnot, listBlock, blockName, blockDesc) + closefn.gds(gdsRefAnnot) + ## Success + return(0L) +} #' @title Append information associated to blocks, as indexes, into the #' Population Reference SNV Annotation GDS file diff --git a/R/processStudy.R b/R/processStudy.R index 6a46b0587..33b6ae2bf 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2351,7 +2351,9 @@ inferAncestry <- function(profileFile, pathProfileGDS, genoSource <- arg_match(genoSource) - + if(genoSource == "bam"){ + stop("The bam is not release yet look to get a \'Devel\' version or contact us") + } profileName <- gsub("\\.gz$", "", profileBaseName, ignore.case = TRUE) for(extCur in c( "\\.vcf$", "\\.txt$", "\\.bam", "\\.tsv", "\\.csv")){ profileName <- gsub(extCur, "", profileName, ignore.case = TRUE) @@ -2776,6 +2778,9 @@ inferAncestryGeneAware <- function(profileFile, pathProfileGDS, genoSource <- arg_match(genoSource) + if(genoSource == "bam"){ + stop("The bam is not release yet look to get a \'Devel\' version or contact us") + } profileName <- gsub("\\.gz$", "", profileBaseName, ignore.case = TRUE) for(extCur in c( "\\.vcf$", "\\.txt$", "\\.bam", "\\.tsv", "\\.csv")){ diff --git a/R/tools_internal.R b/R/tools_internal.R index 1fe1d80c9..bb7779939 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -458,7 +458,7 @@ readSNVVCF <- function(fileName, #' \item{\code{chr}}{ a \code{integer} representing a the chromosome from #' fileBlock. #' } -#' \item{\code{block.snp}}{ the a \code{array} of integer +#' \item{\code{block.snp}}{ a \code{array} of integer #' representing the linkage disequilibrium block for #' each SNV in the in the same order than the variant #' in Population reference dataset. @@ -506,43 +506,46 @@ processBlockChr <- function(fileReferenceGDS, fileBlock) { listChr <- as.integer(gsub("chr", "", listChr)) listSNVChr <- read.gdsn(index.gdsn(gdsReference, "snp.chromosome")) listSNVChr <- which(listSNVChr == listChr) - snp.keep <- read.gdsn(index.gdsn(gdsReference, "snp.position"))[listSNVChr] + snpKeep <- read.gdsn(index.gdsn(gdsReference, "snp.position"))[listSNVChr] closefn.gds(gdsReference) - z <- cbind(c(blockChr$BP1, snp.keep, blockChr$BP2+1), + z <- cbind(c(blockChr$BP1, snpKeep, blockChr$BP2+1), c(seq_len(nrow(blockChr)), - rep(0, length(snp.keep)), -1*seq_len(nrow(blockChr)))) + rep(0, length(snpKeep)), -1*seq_len(nrow(blockChr)))) z <- z[order(z[,1]),] - block.snp <- cumsum(z[,2])[z[,2] == 0] + blockSnp <- cumsum(z[,2])[z[,2] == 0] curStart <- 0 activeBlock <- 0 blockState <- 0 - block.inter <- rep(0, length(which(block.snp == 0))) + blockInter <- rep(0, length(which(blockSnp == 0))) k <- 1 - for(i in seq_len(length(block.snp))){ - if(block.snp[i] == 0){ + for(i in seq_len(length(blockSnp))){ + if(blockSnp[i] == 0){ if(activeBlock == 1){ - if(snp.keep[i] - curStart >= 10000) { + if(snpKeep[i] - curStart >= 10000) { blockState <- blockState - 1 - curStart <- snp.keep[i] + curStart <- snpKeep[i] } } else{ blockState <- blockState - 1 - curStart <- snp.keep[i] - curStart <- snp.keep[i] + curStart <- snpKeep[i] activeBlock <- 1 } - block.inter[k] <- blockState + if(blockState == 0){ + blockState <- -1 + } + blockInter[k] <- blockState k <- k + 1 }else{ activeBlock <- 0 } } - block.snp[block.snp == 0] <- block.inter + + blockSnp[blockSnp == 0] <- blockInter res <- list(chr=listChr, - block.snp=block.snp) + block.snp=blockSnp) return(res) } diff --git a/inst/NEWS.md b/inst/NEWS.md index 0279b5efc..a78be26d8 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,10 @@ +CHANGES IN VERSION 1.3.2 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o New functions inferAncestry(), inferAncestryGeneAware() and getRefSuperPop() to simplify ancestry inference + CHANGES IN VERSION 1.3.1 ------------------------ diff --git a/man/addBlockFromDetFile.Rd b/man/addBlockFromDetFile.Rd new file mode 100644 index 000000000..ce1bb05f9 --- /dev/null +++ b/man/addBlockFromDetFile.Rd @@ -0,0 +1,105 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/process1KG.R +\encoding{UTF-8} +\name{addBlockFromDetFile} +\alias{addBlockFromDetFile} +\title{Append information associated to ld blocks, as indexes, into the +Population Reference SNV Annotation GDS file} +\usage{ +addBlockFromDetFile( + fileReferenceGDS, + gdsRefAnnotFile, + pathBlock, + superPop, + blockName = "ldBlock", + blockDesc = "Not Define", + verbose = FALSE +) +} +\arguments{ +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Reference GDS file. The file must exist.} + +\item{gdsRefAnnotFile}{a \code{character} string representing the +file name corresponding the Reference SNV +Annotation GDS file. The function will +open it in write mode and close it after. The file must exist.} + +\item{pathBlock}{a \code{character} string representing the directory +where all the output file det from the plink block command are located. +The directory must not include other file with the extension \'.det\'. +The name of the \'.det\' must include the super-population between \'.\' +and the chromosome in the form \'chrNumber.\' \( \'chr1.\'\).} + +\item{superPop}{a \code{character} string representing the super population.} + +\item{blockName}{a \code{character} string representing the id of the block. +The blockName should not exist in \'gdsRefAnnotFile\'. +Default: \code{"ldBlock"}.} + +\item{blockDesc}{a \code{character} string representing the description of +the block. +Default: \code{"Not Define"}} + +\item{verbose}{a \code{logical} indicating if message information should be +printed. Default: \code{FALSE}.} +} +\value{ +\code{OL} when the function is successful. +} +\description{ +The function appends the information about the ld blocks into +the Population Reference SNV Annotation GDS file. The information is +extracted from the Population Reference GDS file and files \'.det\'. +} +\details{ +More information about GDS file format can be found at the Bioconductor +gdsfmt website: +https://bioconductor.org/packages/gdsfmt/ +} +\examples{ + +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +fileAnnotGDS <- file.path(tempdir(), "ex1_good_small_1KG_Ann_GDS.gds") + +## Demo of of output file det from the plink block +## command for chromosome 1 +fileLdBlock <- file.path(dirname(fileAnnotGDS), "block.sp.EUR.Ex.chr1.blocks.det") + + +file.copy(file.path(dataDir, "tests", + "ex1_NoBlockGene.1KG_Annot_GDS.gds"), fileAnnotGDS) +file.copy(file.path(dataDir, "block.sp.EUR.Ex.chr1.blocks.det"), + fileLdBlock) + + + +## GDS Reference file +fileReferenceGDS <- file.path(dataDir, "tests", + "ex1_good_small_1KG.gds") + + \donttest{ + + + ## Append information associated to blocks + addBlockFromDetFile(fileReferenceGDS=fileReferenceGDS, + gdsRefAnnotFile=fileAnnotGDS, + pathBlock=dirname(fileAnnotGDS), + superPop="EUR") + + gdsAnnot1KG <- openfn.gds(fileAnnotGDS) + print(gdsAnnot1KG) + + closefn.gds(gdsAnnot1KG) +} + +## Remove temporary file +unlink(fileAnnotGDS, force=TRUE) +unlink(fileLdBlock, force=TRUE) + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} diff --git a/man/addGDS1KGLDBlock.Rd b/man/addGDS1KGLDBlock.Rd new file mode 100644 index 000000000..f505842eb --- /dev/null +++ b/man/addGDS1KGLDBlock.Rd @@ -0,0 +1,75 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gdsWrapper_internal.R +\encoding{UTF-8} +\name{addGDS1KGLDBlock} +\alias{addGDS1KGLDBlock} +\title{Append information associated to ld blocks, as indexes, into the +Population Reference SNV Annotation GDS file} +\usage{ +addGDS1KGLDBlock(gds, listBlock, blockName, blockDesc) +} +\arguments{ +\item{gds}{an object of class \link[gdsfmt]{gds.class} +(GDS file), an opened Reference Annotation GDS file.} + +\item{listBlock}{a \code{array} of integer +representing the linkage disequilibrium block for +each SNV in the in the same order than the variant +in Population reference dataset.} + +\item{blockName}{a \code{character} string representing the id of the block. +The blockName should not exist in \'gdsRefAnnotFile\'.} + +\item{blockDesc}{a \code{character} string representing the description of +the block.} +} +\value{ +The integer \code{0L} when successful. +} +\description{ +The function appends the information about the ld blocks into +the Population Reference SNV Annotation GDS file. The information is +extracted from the parameter listBlock. +} +\examples{ + +## Required library for GDS +library(gdsfmt) +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +fileAnnotGDS <- file.path(tempdir(), "ex1_good_small_1KG_Ann_GDS.gds") + + +file.copy(file.path(dataDir, "tests", + "ex1_NoBlockGene.1KG_Annot_GDS.gds"), fileAnnotGDS) + + +fileReferenceGDS <- file.path(dataDir, "tests", + "ex1_good_small_1KG.gds") + \donttest{ + gdsRef <- openfn.gds(fileReferenceGDS) + listBlock <- read.gdsn(index.gdsn(gdsRef, "snp.position")) + listBlock <- rep(-1, length(listBlock)) + closefn.gds(gdsRef) + gdsAnnot1KG <- openfn.gds(fileAnnotGDS, readonly=FALSE) + ## Append information associated to blocks + RAIDS:::addGDS1KGLDBlock(gds=gdsAnnot1KG, + listBlock=listBlock, + blockName="blockEmpty", + blockDesc="Example") + + gdsAnnot1KG <- openfn.gds(fileAnnotGDS) + print(gdsAnnot1KG) + + closefn.gds(gdsAnnot1KG) +} + +## Remove temporary file +unlink(fileAnnotGDS, force=TRUE) + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} diff --git a/man/processBlockChr.Rd b/man/processBlockChr.Rd index acc83d827..95e71bcf0 100644 --- a/man/processBlockChr.Rd +++ b/man/processBlockChr.Rd @@ -22,7 +22,7 @@ a \code{list} containing 2 entries: \item{\code{chr}}{ a \code{integer} representing a the chromosome from fileBlock. } -\item{\code{block.snp}}{ the a \code{array} of integer +\item{\code{block.snp}}{ a \code{array} of integer representing the linkage disequilibrium block for each SNV in the in the same order than the variant in Population reference dataset. From 6c886385d8358b074e66c7af2548736695d91d20 Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 16 Oct 2024 10:58:10 -0400 Subject: [PATCH 318/385] Correct example for addGDS1KGLDBlock --- R/gdsWrapper_internal.R | 1 + man/addGDS1KGLDBlock.Rd | 1 + 2 files changed, 2 insertions(+) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 11bd98eb0..bf838ab14 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -1387,6 +1387,7 @@ appendGDSSampleOnly <- function(gds, listSamples) { #' listBlock=listBlock, #' blockName="blockEmpty", #' blockDesc="Example") +#'. closefn.gds(gdsAnnot1KG) #' #' gdsAnnot1KG <- openfn.gds(fileAnnotGDS) #' print(gdsAnnot1KG) diff --git a/man/addGDS1KGLDBlock.Rd b/man/addGDS1KGLDBlock.Rd index f505842eb..cfbaa1060 100644 --- a/man/addGDS1KGLDBlock.Rd +++ b/man/addGDS1KGLDBlock.Rd @@ -58,6 +58,7 @@ fileReferenceGDS <- file.path(dataDir, "tests", listBlock=listBlock, blockName="blockEmpty", blockDesc="Example") +. closefn.gds(gdsAnnot1KG) gdsAnnot1KG <- openfn.gds(fileAnnotGDS) print(gdsAnnot1KG) From bdbca27f2f46c89f3af3f66a0ce1c4b41192c9a6 Mon Sep 17 00:00:00 2001 From: belleau Date: Wed, 16 Oct 2024 12:01:19 -0400 Subject: [PATCH 319/385] Correct example for addGDS1KGLDBlock --- R/gdsWrapper_internal.R | 3 ++- man/addGDS1KGLDBlock.Rd | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index bf838ab14..4239edc61 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -1387,7 +1387,8 @@ appendGDSSampleOnly <- function(gds, listSamples) { #' listBlock=listBlock, #' blockName="blockEmpty", #' blockDesc="Example") -#'. closefn.gds(gdsAnnot1KG) +#' +#' closefn.gds(gdsAnnot1KG) #' #' gdsAnnot1KG <- openfn.gds(fileAnnotGDS) #' print(gdsAnnot1KG) diff --git a/man/addGDS1KGLDBlock.Rd b/man/addGDS1KGLDBlock.Rd index cfbaa1060..d76efe91b 100644 --- a/man/addGDS1KGLDBlock.Rd +++ b/man/addGDS1KGLDBlock.Rd @@ -58,7 +58,8 @@ fileReferenceGDS <- file.path(dataDir, "tests", listBlock=listBlock, blockName="blockEmpty", blockDesc="Example") -. closefn.gds(gdsAnnot1KG) + + closefn.gds(gdsAnnot1KG) gdsAnnot1KG <- openfn.gds(fileAnnotGDS) print(gdsAnnot1KG) From 6c36cd586b833b443f7b3e8634de8d44270f7128 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 18 Oct 2024 10:48:27 -0400 Subject: [PATCH 320/385] Add a validation to addBlockFromDetFile. --- R/process1KG.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/process1KG.R b/R/process1KG.R index ffd9c5bb8..a88864044 100644 --- a/R/process1KG.R +++ b/R/process1KG.R @@ -1165,8 +1165,8 @@ addBlockFromDetFile <- function(fileReferenceGDS, gdsRefAnnotFile, pathBlock, tmp <- processBlockChr(fileReferenceGDS, file.path(pathBlock, listChrCur)) listBlock[[chr]] <- tmp$block.snp if(chr > 1) { - vMax <- max(listBlock[[chr-1]]) - vMin <- min(listBlock[[chr-1]]) + vMax <- max(listBlock[[chr-1]], 0) + vMin <- min(listBlock[[chr-1]], 0) listBlock[[chr]][listBlock[[chr]] > 0] <- listBlock[[chr]][listBlock[[chr]] > 0] + vMax if(vMin < 0) { From 4d63292383c2135066e7edbae1a0466ee5fdb48e Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Oct 2024 18:36:39 -0400 Subject: [PATCH 321/385] Update vignette --- vignettes/RAIDS.Rmd | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 913f3b098..5dd83da1e 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -133,7 +133,7 @@ These steps are described in detail in the following. ### 1.1 Create a directory structure -First, a specific directory structure should be created. The structure must +First, a specific directory structure should be created. The structure must correspond to this: ``` @@ -150,8 +150,8 @@ workingDirectory/
-This following running example creates a temporary working directory structure -when the example will be run. +This following code creates a temporary working directory structure where the +example will be run. ```{r createDir, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} @@ -306,14 +306,38 @@ data are used to optimize the inference parameters and, with these, the ancestry of the input profile donor is inferred. According to the type of input data (RNA or DNA), a specific function -is available. - -The *inferAncestry()* function is used for DNA profiles while +is available. The *inferAncestry()* function is used for DNA profiles while the *inferAncestryGeneAware()* function is RNA specific. In this example, the profile is from DNA source and requires the use of the *inferAncestry()* function. +The *inferAncestry()* function requires a specific profile input format. The +format is set by the *genoSource* parameter. + +One of those formats is in a VCF format (*genoSource=c("VCF")*). +This format follows the VCF standard +with at least those genotype fields: _GT_, _AD_ and _DP_. +The SNVs must be germline variants and should include the genotype of the +wild-type homozygous at the selected positions in the reference. The VCF file +must be gzipped. + +A generic SNP file can replace the VCF file (*genoSource=c("generic")*). +The format is coma separated and the mandatory columns are: + +* _Chromosome_: The name of the chromosome +* _Position_: The position on the chromosome +* _Ref_: The reference nucleotide +* _Alt_: The aternative nucleotide +* _Count_: The total count +* _File1R_: The count for the reference nucleotide +* _File1A_: The count for the alternative nucleotide + +Beware that the starting position in the **population reference GDS file** is +zero (like BED files). The generic SNP file should also start +at position zero. + + ```{r infere, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ########################################################################### @@ -330,7 +354,7 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && chrInfo <- GenomeInfoDb::seqlengths(genome)[1:25] ####################################################################### - ## The SNP VCF file of the DNA profile donor + ## The demo SNP VCF file of the DNA profile donor ####################################################################### fileDonorVCF <- file.path(dataDir, "example", "snpPileup", "ex1.vcf.gz") From 388d94d7babc57b0c0273d3085b12886490fe98d Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Oct 2024 20:38:25 -0400 Subject: [PATCH 322/385] Update function documentation and correct indents --- R/processStudy.R | 269 ++++++++++++++++++++++++---------- R/processStudy_internal.R | 81 +++++----- man/inferAncestry.Rd | 12 +- man/inferAncestryGeneAware.Rd | 138 ++++++++++++++++- man/profileAncestry.Rd | 4 - man/wrapperAncestry.Rd | 4 - 6 files changed, 367 insertions(+), 141 deletions(-) diff --git a/R/processStudy.R b/R/processStudy.R index 33b6ae2bf..5b7dfb91f 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -396,13 +396,13 @@ pruningSample <- function(gdsReference, listKeepPos <- listGeno ## Select SNVs based on the chromosome - if(!is.null(chr)) { + if (!is.null(chr)) { snpCHR <- read.gdsn(index.gdsn(gdsReference, "snp.chromosome")) listKeepPos <- intersect(which(snpCHR == chr), listKeepPos) } ## Select SNVs based on the minimum allele frequency in the populations - if(!is.null(superPopMinAF)) { + if (!is.null(superPopMinAF)) { listTMP <- NULL for(sp in c("EAS", "EUR", "AFR", "AMR", "SAS")) { snpAF <- read.gdsn(index.gdsn(gdsReference, @@ -413,7 +413,7 @@ pruningSample <- function(gdsReference, listKeepPos <- intersect(listTMP, listKeepPos) } - if(length(listKeepPos) == 0) { + if (length(listKeepPos) == 0) { stop("In pruningSample, the sample ", currentProfile, " doesn't have SNPs after filters\n") } @@ -430,13 +430,13 @@ pruningSample <- function(gdsReference, pruned <- unlist(snpset, use.names=FALSE) ## When TRUE, generate 2 RDS file with the pruned SNVs information - if(keepFile) { + if (keepFile) { saveRDS(pruned, filePruned) saveRDS(snpset, fileObj) } ## When TRUE, add the pruned SNvs information to the Profile GDS file - if(keepPrunedGDS) { + if (keepPrunedGDS) { gdsSample <- openfn.gds(filename=fileGDSSample, readonly=FALSE) addGDSStudyPruning(gdsProfile=gdsSample, pruned=pruned) closefn.gds(gdsfile=gdsSample) @@ -1775,11 +1775,8 @@ computePoolSyntheticAncestryGr <- function(gdsProfile, sampleRM, spRef, #' @encoding UTF-8 #' @export computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, - listFiles, - currentProfile, - spRef, - studyIDSyn, - np=1L, + listFiles, currentProfile, spRef, + studyIDSyn, np=1L, listCatPop=c("EAS", "EUR", "AFR", "AMR", "SAS"), fieldPopIn1KG="superPop", fieldPopInfAnc="SuperPop", @@ -1788,8 +1785,8 @@ computeAncestryFromSyntheticFile <- function(gdsReference, gdsProfile, algorithm=c("exact", "randomized"), eigenCount=32L, missingRate=NaN, verbose=FALSE) { - - if(is.null(pcaList)) { + ## Set parameters when no values given by user + if (is.null(pcaList)) { pcaList <- seq(2, 15, 1) } @@ -2060,7 +2057,6 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, genoSource <- arg_match(genoSource) - r <- runWrapperAncestry(pedStudy, studyDF, pathProfileGDS, pathGeno, pathOut, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, genoSource, studyType="DNA", np=np, verbose) @@ -2107,8 +2103,8 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' super-population assigned to the sample. } #' } #' -#' @param genoSource a \code{character} string with two possible values: -#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +#' @param genoSource a \code{character} string with four possible values: +#' 'snp-pileup', 'generic', 'VCF' or 'bam'. It specifies if the genotype files #' are generated by snp-pileup (Facets) or are a generic format CSV file #' with at least those columns: #' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. @@ -2124,7 +2120,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @param verbose a \code{logical} indicating if messages should be printed #' to show how the different steps in the function. Default: \code{FALSE}. #' -#' @return TODO a \code{list} containing 4 entries: +#' @return a \code{list} containing 4 entries: #' \describe{ #' \item{\code{pcaSample}}{ a \code{list} containing the information related #' to the eigenvectors. The \code{list} contains those 3 entries: @@ -2257,11 +2253,6 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' } #' } #' -#' @details -#' -#' The profileAncestry() generates list \code{list} -#' TODO update the description -#' #' @references #' #' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, @@ -2277,7 +2268,6 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ## Path to the demo 1KG GDS file is located in this package #' dataDir <- system.file("extdata", package="RAIDS") #' -#' #' ################################################################# #' ## The 1KG GDS file and the 1KG SNV Annotation GDS file #' ## need to be located in the same directory @@ -2301,7 +2291,6 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ################################################################# #' pathProfileGDS <- file.path(tempdir(), "out.tmp") #' -#' #' #################################################################### #' ## Fix seed to ensure reproducible results #' #################################################################### @@ -2339,55 +2328,54 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @importFrom rlang arg_match #' @encoding UTF-8 #' @export - inferAncestry <- function(profileFile, pathProfileGDS, - fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, - verbose=FALSE) { + fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic", "VCF", "bam"), + np=1L, verbose=FALSE) { profileBaseName <- basename(profileFile) pathGeno <- dirname(profileFile) genoSource <- arg_match(genoSource) - if(genoSource == "bam"){ - stop("The bam is not release yet look to get a \'Devel\' version or contact us") + ## BAM format is not yet implemented + if (genoSource == "bam") { + stop("The bam is not release yet look to get a \'Devel\' version ", + "or contact us") } - profileName <- gsub("\\.gz$", "", profileBaseName, ignore.case = TRUE) - for(extCur in c( "\\.vcf$", "\\.txt$", "\\.bam", "\\.tsv", "\\.csv")){ + + ## Extract the name of the profile(s) + profileName <- gsub("\\.gz$", "", profileBaseName, ignore.case=TRUE) + for (extCur in c( "\\.vcf$", "\\.txt$", "\\.bam", "\\.tsv", "\\.csv")) { profileName <- gsub(extCur, "", profileName, ignore.case = TRUE) } - #profileName <- "profile" - studyDF <- data.frame(study.id="NotDef", - study.desc="NotDef", - study.platform="NotDef", - stringsAsFactors=FALSE) - pedStudy <- data.frame(Name.ID = c(profileName), - Case.ID = c(profileName), - Sample.Type = c("DNA"), - Diagnosis = "NotDef", - Source = c("ENotDef"), - stringsAsFactors = FALSE) + + ## Create required data frames + studyDF <- data.frame(study.id="NotDef", study.desc="NotDef", + study.platform="NotDef", stringsAsFactors=FALSE) + pedStudy <- data.frame(Name.ID=c(profileName), Case.ID=c(profileName), + Sample.Type=c("DNA"), Diagnosis="NotDef", + Source=c("ENotDef"), stringsAsFactors=FALSE) row.names(pedStudy) <- pedStudy$Name.ID ## Validate parameters validateRunExomeOrRNAAncestry(pedStudy=pedStudy, studyDF=studyDF, - pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut="./", - fileReferenceGDS=fileReferenceGDS, - fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, - syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) - - - if(genoSource %in% c("snp-pileup", "generic", "VCF")){ + pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut="./", + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, + syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) + ## Run ancestry inference + if (genoSource %in% c("snp-pileup", "generic", "VCF")) { r <- wrapperAncestry(pedStudy, studyDF, pathProfileGDS, - pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, genoSource, studyType="LD", np=np, - verbose) + pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, genoSource, studyType="LD", np=np, + verbose) }else{ stop(paste0("The format ", genoSource," is not implemented yet\n")) } + ## Successful return(r) } @@ -2651,8 +2639,8 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' super-population assigned to the sample. } #' } #' -#' @param genoSource a \code{character} string with two possible values: -#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +#' @param genoSource a \code{character} string with four possible values: +#' 'snp-pileup', 'generic', 'VCF' or 'bam'. It specifies if the genotype files #' are generated by snp-pileup (Facets) or are a generic format CSV file #' with at least those columns: #' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. @@ -2672,7 +2660,139 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @param verbose a \code{logical} indicating if messages should be printed #' to show how the different steps in the function. Default: \code{FALSE}. #' -#' @return The integer \code{list} TODO see inferAncestry. +#' @return a \code{list} containing 4 entries: +#' \describe{ +#' \item{\code{pcaSample}}{ a \code{list} containing the information related +#' to the eigenvectors. The \code{list} contains those 3 entries: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +#' the eigenvectors for the reference profiles.} +#' \item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +#' eigenvectors for the current profile projected on the PCA from the +#' reference profiles.} +#' } +#' } +#' \item{\code{paraSample}}{ a \code{list} containing the results with +#' different \code{D} and \code{K} values that lead to optimal parameter +#' selection. The \code{list} contains those entries: +#' \describe{ +#' \item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +#' on all combined synthetic results done with a fixed value of \code{D} (the +#' number of dimensions). The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{median}}{ a \code{numeric} representing the median of the +#' minimum AUROC obtained (within super populations) for all combination of +#' the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +#' AUROC obtained (within super populations) for all combination of the fixed +#' \code{D} value and all tested \code{K} values. } +#' \item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +#' of the minimum AUROC obtained (within super populations) for all +#' combination of the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for a fixed \code{D} value. } +#' } +#' } +#' \item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +#' all combined synthetic results done with different values of \code{D} (the +#' number of dimensions) and \code{K} (the number of neighbors). +#' The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +#' obtained by grouping all the synthetic results by super-populations, for +#' the specified values of \code{D} and \code{K}.} +#' \item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +#' by grouping all the synthetic results for the specified values of \code{D} +#' and \code{K}.} +#' \item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +#' of the confusion matrix obtained by grouping all the synthetic results for +#' the specified values of \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +#' super-population. The \code{data.frame} contains +#' those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{Call}}{ a \code{character} string representing the +#' super-population.} +#' \item{\code{L}}{ a \code{numeric} representing the lower value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' \item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for +#' the fixed values of super-population, \code{D} and \code{K}.} +#' \item{\code{H}}{ a \code{numeric} representing the higher value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +#' (the number of dimensions) for the specific profile.} +#' \item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for the specific profile.} +#' \item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +#' values (the number of dimensions) for the specific profile. More than one +#' \code{D} is possible.} +#' } +#' } +#' \item{\code{KNNSample}}{ a \code{data.frame} containing the inferred +#' ancestry for different values of \code{K} and \code{D}. The +#' \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry. } +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry. } +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry for the specified \code{D} and \code{K} values.} +#' } +#' } +#' \item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred +#' ancestry for each synthetic data for different values of \code{K} and +#' \code{D}. +#' The \code{data.frame} +#' contains those columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current synthetic data.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry. } +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry. } +#' \item{\code{infer.superPop}}{ a \code{character} string representing the +#' inferred ancestry for the specified \code{D} and \code{K} values.} +#' \item{\code{ref.superPop}}{ a \code{character} string representing the known +#' ancestry from the reference} +#' } +#' } +#' \item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +#' ancestry for the current profile. The \code{data.frame} contains those +#' columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry.} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry.} +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry.} +#' } +#' } +#' } #' #' @details #' @@ -2768,10 +2888,10 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @encoding UTF-8 #' @export inferAncestryGeneAware <- function(profileFile, pathProfileGDS, - fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, - blockTypeID, verbose=FALSE) { + fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, + blockTypeID, verbose=FALSE) { profileBaseName <- basename(profileFile) pathGeno <- dirname(profileFile) @@ -2779,7 +2899,8 @@ inferAncestryGeneAware <- function(profileFile, pathProfileGDS, genoSource <- arg_match(genoSource) if(genoSource == "bam"){ - stop("The bam is not release yet look to get a \'Devel\' version or contact us") + stop("The bam is not release yet look to get a \'Devel\' version ", + "or contact us") } profileName <- gsub("\\.gz$", "", profileBaseName, ignore.case = TRUE) @@ -2791,28 +2912,28 @@ inferAncestryGeneAware <- function(profileFile, pathProfileGDS, study.desc="NotDef", study.platform="NotDef", stringsAsFactors=FALSE) - pedStudy <- data.frame(Name.ID = c(profileName), - Case.ID = c(profileName), - Sample.Type = c("RNA"), - Diagnosis = "NotDef", - Source = c("NotDef"), - stringsAsFactors = FALSE) + pedStudy <- data.frame(Name.ID=c(profileName), + Case.ID=c(profileName), + Sample.Type=c("RNA"), + Diagnosis="NotDef", + Source=c("NotDef"), + stringsAsFactors=FALSE) row.names(pedStudy) <- pedStudy$Name.ID ## Validate parameters validateRunExomeOrRNAAncestry(pedStudy=pedStudy, studyDF=studyDF, - pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut="./", - fileReferenceGDS=fileReferenceGDS, - fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, - syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) + pathProfileGDS=pathProfileGDS, pathGeno=pathGeno, pathOut="./", + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileReferenceAnnotGDS, chrInfo=chrInfo, + syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) if(genoSource %in% c("snp-pileup", "generic", "VCF")){ r <- wrapperAncestry(pedStudy, studyDF, pathProfileGDS, - pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, genoSource, studyType="GeneAware", np=np, - blockTypeID=blockTypeID, verbose) + pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, genoSource, studyType="GeneAware", np=np, + blockTypeID=blockTypeID, verbose) }else{ stop(paste0("The format ", genoSource," is not implemented yet\n")) } diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 901a66b5d..d21d83a65 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2432,11 +2432,6 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' } #' } #' -#' @details -#' -#' The profileAncestry() generates list \code{list} -#' TODO update the description -#' #' @references #' #' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, @@ -2545,22 +2540,21 @@ runProfileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, #' @importFrom rlang arg_match #' @encoding UTF-8 #' @keywords internal - profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, - currentProfile, pathProfileGDS, chrInfo, syntheticRefDF, - studyDFSyn, listProfileRef, studyType=c("LD", "GeneAware"), - np=1L, blockTypeID=NULL, verbose=FALSE) { + currentProfile, pathProfileGDS, chrInfo, syntheticRefDF, + studyDFSyn, listProfileRef, studyType=c("LD", "GeneAware"), + np=1L, blockTypeID=NULL, verbose=FALSE) { # This part can be share with runProfileAncestry studyType <- arg_match(studyType) pruningSample(gdsReference=gdsReference, currentProfile=currentProfile, - studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS, np=np) + studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS, np=np) fileGDSProfile <- file.path(pathProfileGDS, - paste0(currentProfile, ".gds")) + paste0(currentProfile, ".gds")) add1KG2SampleGDS(gdsReference=gdsReference, fileProfileGDS=fileGDSProfile, - currentProfile=currentProfile, studyID=studyDF$study.id) + currentProfile=currentProfile, studyID=studyDF$study.id) addStudy1Kg(gdsReference, fileGDSProfile) @@ -2568,19 +2562,19 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, # Change for the old studyType studyTypeLeg <- ifelse(studyType=="LD", "DNA", "RNA") estimateAllelicFraction(gdsReference=gdsReference, gdsProfile=gdsProfile, - currentProfile=currentProfile, studyID=studyDF$study.id, - chrInfo=chrInfo, studyType=studyTypeLeg, gdsRefAnnot=gdsRefAnnot, - blockID=blockTypeID, verbose=verbose) + currentProfile=currentProfile, studyID=studyDF$study.id, + chrInfo=chrInfo, studyType=studyTypeLeg, gdsRefAnnot=gdsRefAnnot, + blockID=blockTypeID, verbose=verbose) closefn.gds(gdsProfile) ## Add information related to the synthetic profiles in Profile GDS file prepSynthetic(fileProfileGDS=fileGDSProfile, - listSampleRef=listProfileRef, profileID=currentProfile, - studyDF=studyDFSyn, prefix="1", verbose=verbose) + listSampleRef=listProfileRef, profileID=currentProfile, + studyDF=studyDFSyn, prefix="1", verbose=verbose) resG <- syntheticGeno(gdsReference=gdsReference, gdsRefAnnot=gdsRefAnnot, - fileProfileGDS=fileGDSProfile, profileID=currentProfile, - listSampleRef=listProfileRef, prefix="1") + fileProfileGDS=fileGDSProfile, profileID=currentProfile, + listSampleRef=listProfileRef, prefix="1") # if(! file.exists(pathOut)) { # dir.create(pathOut) @@ -2603,26 +2597,24 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, ## This variable will contain the results from the PCA analyses ## For each row of the sampleRM matrix resSyn <- lapply(seq_len(nrow(sampleRM)), FUN=function(x, sampleRM, - gdsProfile, studyDFSyn, spRef, - currentProfile) { + gdsProfile, studyDFSyn, spRef, currentProfile) { synthKNN <- computePoolSyntheticAncestryGr(gdsProfile=gdsProfile, - sampleRM=sampleRM[x,], - studyIDSyn=studyDFSyn$study.id, - np=np, spRef=spRef, eigenCount=15L, - verbose=verbose) - + sampleRM=sampleRM[x,], + studyIDSyn=studyDFSyn$study.id, + np=np, spRef=spRef, eigenCount=15L, + verbose=verbose) ## Results are saved # saveRDS(synthKNN$matKNN, file.path(pathOutProfile, - # paste0("KNN.synt.", currentProfile, ".", x, ".rds"))) + # paste0("KNN.synt.", currentProfile, ".", x, ".rds"))) return(synthKNN$matKNN) - }, sampleRM=sampleRM, gdsProfile=gdsProfile, - studyDFSyn=studyDFSyn, spRef=spRef, - currentProfile=currentProfile) + }, sampleRM=sampleRM, gdsProfile=gdsProfile, studyDFSyn=studyDFSyn, + spRef=spRef, currentProfile=currentProfile) + resSyn <- do.call(rbind, resSyn) ## Extract the super-population information from the 1KG GDS file ## for profiles associated to the synthetic study pedSyn <- prepPedSynthetic1KG(gdsReference=gdsReference, - gdsSample=gdsProfile, studyID=studyDFSyn$study.id, popName="superPop") + gdsSample=gdsProfile, studyID=studyDFSyn$study.id, popName="superPop") # idCur <- matrix(unlist(strsplit(resSyn$sample.id, "\\.")), nr=4) @@ -2634,28 +2626,29 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, # listFiles <- file.path(file.path(pathKNN) , listFilesName) resCall <- computeAncestryFromSynthetic(gdsReference=gdsReference, - gdsProfile=gdsProfile, syntheticKNN=resSyn, - pedSyn=pedSyn, - currentProfile=currentProfile, spRef=spRef, - studyIDSyn=studyDFSyn$study.id, np=np) + gdsProfile=gdsProfile, syntheticKNN=resSyn, + pedSyn=pedSyn, currentProfile=currentProfile, spRef=spRef, + studyIDSyn=studyDFSyn$study.id, np=np) # saveRDS(resCall, file.path(pathOut, # paste0(currentProfile, ".infoCall", ".rds"))) # # write.csv(x=resCall$Ancestry, file=file.path(pathOut, - # paste0(currentProfile, ".Ancestry",".csv")), quote=FALSE, + # paste0(currentProfile, ".Ancestry",".csv")), quote=FALSE, # row.names=FALSE) ## Close Profile GDS file (important) closefn.gds(gdsProfile) resSyn[[paste0("ref.superPop")]] <- pedSyn[resSyn$sample.id, "superPop"] - colnames(resSyn) <- c("sample.id", "D", "K", "infer.superPop", "ref.superPop") + colnames(resSyn) <- c("sample.id", "D", "K", "infer.superPop", + "ref.superPop") + res <- list(pcaSample=resCall$pcaSample, # PCA of the profile + 1KG - paraSample=resCall$paraSample, # Result of the parameter selection - KNNSample=resCall$KNNSample$matKNN, # KNN for the profile - KNNSynthetic=resSyn, # KNN results for synthetic data - Ancestry=resCall$Ancestry) # the ancestry call fo the profile + paraSample=resCall$paraSample, # Result of the parameter selection + KNNSample=resCall$KNNSample$matKNN, # KNN for the profile + KNNSynthetic=resSyn, # KNN results for synthetic data + Ancestry=resCall$Ancestry) # the ancestry call fo the profile return(res) } @@ -3455,12 +3448,6 @@ runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' } #' } #' -#' @details -#' -#' The runWrapperAncestry() generates list \code{list} -#' TODO update the description -#' -#' #' @references #' #' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, diff --git a/man/inferAncestry.Rd b/man/inferAncestry.Rd index 09616962f..a139c6f27 100644 --- a/man/inferAncestry.Rd +++ b/man/inferAncestry.Rd @@ -49,8 +49,8 @@ subcontinental population assigned to the sample. } super-population assigned to the sample. } }} -\item{genoSource}{a \code{character} string with two possible values: -'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +\item{genoSource}{a \code{character} string with four possible values: +'snp-pileup', 'generic', 'VCF' or 'bam'. It specifies if the genotype files are generated by snp-pileup (Facets) or are a generic format CSV file with at least those columns: 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. @@ -67,7 +67,7 @@ threads to be used. Default: \code{1L}.} to show how the different steps in the function. Default: \code{FALSE}.} } \value{ -TODO a \code{list} containing 4 entries: +a \code{list} containing 4 entries: \describe{ \item{\code{pcaSample}}{ a \code{list} containing the information related to the eigenvectors. The \code{list} contains those 3 entries: @@ -206,10 +206,6 @@ call on a specific RNA profile. First, the function creates the Profile GDS file for the specific profile using the information from a RDS Sample description file and the Population Reference GDS file. } -\details{ -The profileAncestry() generates list \code{list} -TODO update the description -} \examples{ ## Required library for GDS @@ -218,7 +214,6 @@ library(SNPRelate) ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata", package="RAIDS") - ################################################################# ## The 1KG GDS file and the 1KG SNV Annotation GDS file ## need to be located in the same directory @@ -242,7 +237,6 @@ demoProfileEx1 <- file.path(dataDir, "example", "snpPileup", "ex1.txt.gz") ################################################################# pathProfileGDS <- file.path(tempdir(), "out.tmp") - #################################################################### ## Fix seed to ensure reproducible results #################################################################### diff --git a/man/inferAncestryGeneAware.Rd b/man/inferAncestryGeneAware.Rd index 1c7569287..27c7f9c09 100644 --- a/man/inferAncestryGeneAware.Rd +++ b/man/inferAncestryGeneAware.Rd @@ -50,8 +50,8 @@ subcontinental population assigned to the sample. } super-population assigned to the sample. } }} -\item{genoSource}{a \code{character} string with two possible values: -'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +\item{genoSource}{a \code{character} string with four possible values: +'snp-pileup', 'generic', 'VCF' or 'bam'. It specifies if the genotype files are generated by snp-pileup (Facets) or are a generic format CSV file with at least those columns: 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. @@ -72,7 +72,139 @@ present in the GDS Reference Annotation file.} to show how the different steps in the function. Default: \code{FALSE}.} } \value{ -The integer \code{list} TODO see inferAncestry. +a \code{list} containing 4 entries: +\describe{ +\item{\code{pcaSample}}{ a \code{list} containing the information related +to the eigenvectors. The \code{list} contains those 3 entries: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +the eigenvectors for the reference profiles.} +\item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +eigenvectors for the current profile projected on the PCA from the +reference profiles.} +} +} +\item{\code{paraSample}}{ a \code{list} containing the results with +different \code{D} and \code{K} values that lead to optimal parameter +selection. The \code{list} contains those entries: +\describe{ +\item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +on all combined synthetic results done with a fixed value of \code{D} (the +number of dimensions). The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{median}}{ a \code{numeric} representing the median of the +minimum AUROC obtained (within super populations) for all combination of +the fixed \code{D} value and all tested \code{K} values. } +\item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +AUROC obtained (within super populations) for all combination of the fixed +\code{D} value and all tested \code{K} values. } +\item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +of the minimum AUROC obtained (within super populations) for all +combination of the fixed \code{D} value and all tested \code{K} values. } +\item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for a fixed \code{D} value. } +} +} +\item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +all combined synthetic results done with different values of \code{D} (the +number of dimensions) and \code{K} (the number of neighbors). +The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +obtained by grouping all the synthetic results by super-populations, for +the specified values of \code{D} and \code{K}.} +\item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +by grouping all the synthetic results for the specified values of \code{D} +and \code{K}.} +\item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +of the confusion matrix obtained by grouping all the synthetic results for +the specified values of \code{D} and \code{K}.} +} +} +\item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +super-population. The \code{data.frame} contains +those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{Call}}{ a \code{character} string representing the +super-population.} +\item{\code{L}}{ a \code{numeric} representing the lower value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +\item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for +the fixed values of super-population, \code{D} and \code{K}.} +\item{\code{H}}{ a \code{numeric} representing the higher value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +} +} +\item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +(the number of dimensions) for the specific profile.} +\item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for the specific profile.} +\item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +values (the number of dimensions) for the specific profile. More than one +\code{D} is possible.} +} +} +\item{\code{KNNSample}}{ a \code{data.frame} containing the inferred +ancestry for different values of \code{K} and \code{D}. The +\code{data.frame} contains those columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry. } +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry. } +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry for the specified \code{D} and \code{K} values.} +} +} +\item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred +ancestry for each synthetic data for different values of \code{K} and +\code{D}. +The \code{data.frame} +contains those columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current synthetic data.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry. } +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry. } +\item{\code{infer.superPop}}{ a \code{character} string representing the +inferred ancestry for the specified \code{D} and \code{K} values.} +\item{\code{ref.superPop}}{ a \code{character} string representing the known +ancestry from the reference} +} +} +\item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +ancestry for the current profile. The \code{data.frame} contains those +columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry.} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry.} +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry.} +} +} +} } \description{ This function runs most steps leading to the ancestry inference diff --git a/man/profileAncestry.Rd b/man/profileAncestry.Rd index 71d179689..3f2bfef23 100644 --- a/man/profileAncestry.Rd +++ b/man/profileAncestry.Rd @@ -221,10 +221,6 @@ call on a specific profile. First, the function creates the Profile GDS file for the specific profile using the information from a RDS Sample description file and the Population reference GDS file. } -\details{ -The profileAncestry() generates list \code{list} -TODO update the description -} \examples{ ## Required library for GDS diff --git a/man/wrapperAncestry.Rd b/man/wrapperAncestry.Rd index 2025fbcda..291dbd32a 100644 --- a/man/wrapperAncestry.Rd +++ b/man/wrapperAncestry.Rd @@ -234,10 +234,6 @@ call on a specific profile. First, the function creates the Profile GDS file for the specific profile using the information from a RDS Sample description file and the Population reference GDS file. } -\details{ -The runWrapperAncestry() generates list \code{list} -TODO update the description -} \examples{ ## Required library for GDS From 5025818dd4bf1a63eb121a60cf7c25de3d2b0393 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Mon, 21 Oct 2024 20:54:03 -0400 Subject: [PATCH 323/385] Update vignette --- vignettes/RAIDS.Rmd | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 5dd83da1e..2501ef036 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -116,7 +116,7 @@ The main steps are: **Step 1.** Set-up and provide population reference files -**Step 2** Sample the reference data for donor genotypes, to be used for synthesis and optimize ancestry inference parameters +**Step 2** Sample the reference data for donor genotypes to be used for synthesis and optimize ancestry inference parameters **Step 3** Infer ancestry for the subjects of the external study @@ -238,6 +238,9 @@ file.copy(fileAnnotGDS, file.path(pathWorkingDirectoryData, "refGDS")) ### 2.1 Set-up required directories +All required directories need to be created. In addition, the path to +the reference files are kept in variables that will be used later. + ```{r installRaids, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# @@ -295,23 +298,21 @@ dataRef <- select1KGPopForSynthetic(fileReferenceGDS=refGenotype, ``` -The output object is going to be used later at the ancestry inference step. +The output object is going to be used later.
### 2.3 Perform the ancestry inference -Within a single function call, data synthesis is performed, the synthetic +Ancestry inference can be done in one function call. Within a single function +call, data synthesis is performed, the synthetic data are used to optimize the inference parameters and, with these, the ancestry of the input profile donor is inferred. According to the type of input data (RNA or DNA), a specific function -is available. The *inferAncestry()* function is used for DNA profiles while +should be called. The *inferAncestry()* function is used for DNA profiles while the *inferAncestryGeneAware()* function is RNA specific. -In this example, the profile is from DNA source and requires the use of the -*inferAncestry()* function. - The *inferAncestry()* function requires a specific profile input format. The format is set by the *genoSource* parameter. @@ -337,6 +338,9 @@ Beware that the starting position in the **population reference GDS file** is zero (like BED files). The generic SNP file should also start at position zero. +In this example, the profile is from DNA source and requires the use of the +*inferAncestry()* function. + ```{r infere, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} From 11999839d9e74185bea4e0456e5fa185bf0331eb Mon Sep 17 00:00:00 2001 From: belleau Date: Tue, 22 Oct 2024 16:00:51 -0400 Subject: [PATCH 324/385] Increase version --- DESCRIPTION | 2 +- inst/NEWS.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 26f6ba1aa..5b3c72c90 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 1.3.2 +Version: 1.3.3 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index a78be26d8..9cbf360fc 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,10 @@ +CHANGES IN VERSION 1.3.3 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o More comprehensive vignette + CHANGES IN VERSION 1.3.2 ------------------------ From 6b32a2c6736051fb9bf95cd88bd7bd4d3435beca Mon Sep 17 00:00:00 2001 From: J Wokaty Date: Tue, 29 Oct 2024 11:24:12 -0400 Subject: [PATCH 325/385] bump x.y.z version to even y prior to creation of RELEASE_3_20 branch --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 5b3c72c90..e43edcbd8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 1.3.3 +Version: 1.4.0 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", From bb243c99fc6f210ef222eec367e6d918abe3bc86 Mon Sep 17 00:00:00 2001 From: J Wokaty Date: Tue, 29 Oct 2024 11:24:12 -0400 Subject: [PATCH 326/385] bump x.y.z version to odd y following creation of RELEASE_3_20 branch --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index e43edcbd8..b24058d6e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 1.4.0 +Version: 1.5.0 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", From 7ba504a57ada88e8951faae34f10a88530ee61ca Mon Sep 17 00:00:00 2001 From: adeschen Date: Wed, 9 Apr 2025 18:13:44 -0400 Subject: [PATCH 327/385] Update title in DESCRIPTION file --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 5b3c72c90..9008aed1f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: RAIDS Type: Package -Title: Accurate Inference of Genetic Ancestry from Cancer Sequences +Title: Robust Ancestry Inference using Data Synthesis Description: This package implements specialized algorithms that enable genetic ancestry inference from various cancer sequences sources (RNA, Exome and Whole-Genome sequences). This package also implements a From 00c1ba27155372d144b3c0f3dfd0f37e4e55ffdf Mon Sep 17 00:00:00 2001 From: adeschen Date: Wed, 9 Apr 2025 19:33:41 -0400 Subject: [PATCH 328/385] Update vignette title --- vignettes/RAIDS.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 2501ef036..db481ed17 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -1,5 +1,5 @@ --- -title: "Accurate Inference of Genetic Ancestry from Cancer-derived Sequences" +title: "Robust Ancestry Inference using Data Synthesis" author: Pascal Belleau, Astrid Deschênes and Alexander Krasnitz output: BiocStyle::html_document: @@ -12,7 +12,7 @@ urlcolor: darkred linkcolor: darkred bibliography: aicsBiblio.bibtex vignette: > - %\VignetteIndexEntry{Accurate Inference of Genetic Ancestry from Cancer-derived Sequences} + %\VignetteIndexEntry{Robust Ancestry Inference using Data Synthesis} %\VignettePackage{RAIDS} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} From d7bdaeabd77e1695778d6631c49a9aa69e542095 Mon Sep 17 00:00:00 2001 From: adeschen Date: Wed, 9 Apr 2025 20:40:52 -0400 Subject: [PATCH 329/385] Update check-bioc --- .github/workflows/check-bioc.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index b14113fcf..4ae3a6cdc 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -51,8 +51,8 @@ jobs: fail-fast: false matrix: config: - - { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - ## - { os: ubuntu-latest, r: '4.4.1', bioc: '3.20', cont: "bioconductor/bioconductor_docker:RELEASE_3_20", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + ##- { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + - { os: ubuntu-latest, r: '4.4.1', bioc: '3.20', cont: "bioconductor/bioconductor_docker:RELEASE_3_20", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} - { os: macOS-latest, r: '4.4.1', bioc: '3.20'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} From 33e0327dcbdc8e9bde0cc21836089d7b49f4939d Mon Sep 17 00:00:00 2001 From: belleau Date: Thu, 10 Apr 2025 08:59:31 -0400 Subject: [PATCH 330/385] Add function extractNucleotide and processPileupChrBin --- DESCRIPTION | 3 +- NAMESPACE | 3 + R/tools_internal.R | 164 +++++++++++++++++++++++++++++++++++++ man/extractNucleotide.Rd | 37 +++++++++ man/processPileupChrBin.Rd | 59 +++++++++++++ 5 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 man/extractNucleotide.Rd create mode 100644 man/processPileupChrBin.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 5b3c72c90..2edfe4e44 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -28,7 +28,8 @@ Depends: R (>= 4.2.0), SNPRelate, stats, utils, - GENESIS + GENESIS, + dplyr Imports: S4Vectors, GenomicRanges, ensembldb, diff --git a/NAMESPACE b/NAMESPACE index 406f6e41f..d43613aca 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -63,6 +63,9 @@ importFrom(SNPRelate,snpgdsPCASampLoading) importFrom(VariantAnnotation,geno) importFrom(VariantAnnotation,readVcf) importFrom(class,knn) +importFrom(dplyr,"%>%") +importFrom(dplyr,group_by) +importFrom(dplyr,summarize) importFrom(ensembldb,exonsBy) importFrom(ensembldb,genes) importFrom(ensembldb,toSAF) diff --git a/R/tools_internal.R b/R/tools_internal.R index bb7779939..5bd7459b6 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -439,6 +439,170 @@ readSNVVCF <- function(fileName, return(matSample) } +#' @title Read a VCF file with the genotypes use for the ancestry call +#' +#' @description The function reads VCF file and +#' returns a data frame +#' containing the information about the read counts for the SNVs present in +#' the file. +#' +#' @param nucleotide a \code{vector} of a \code{character} string representing A, C, G or T +#' +#' +#' @param count a \code{vector} of \code{numeric} with count for the nucleotide +#' +#' @param curNucleoa \code{character} string representing A, C, G or T +#' +#' @return a \code{numeric} +#' +#' @examples +#' +#' +#' ## Directory where demo SNP-pileup file +#' dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") +#' +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @encoding UTF-8 +#' @keywords internal +extractNucleotide <- function(nucleotide, + count, + curNucleo) { + tmp <- which(nucleotide == curNucleo) + res<-0 + if(length(tmp) == 1) res <- count[tmp] + return(res) +} + + +#' @title Read a VCF file with the genotypes use for the ancestry call +#' +#' @description The function reads VCF file and +#' returns a data frame +#' containing the information about the read counts for the SNVs present in +#' the file. +#' +#' @param chr a \code{character} string representing the name, including +#' the path, of a VCF file containing the SNV read counts. +#' The VCF must contain those genotype fields: GT, AD, DP. +#' +#' +#' @param resPileup result from pileup +#' +#' @param varDf a \code{data.frame} representing the position to keep +#' +#' @param verbose a \code{logical} indicating if messages should be printed +#' to show how the different steps in the function. Default: \code{FALSE}. +#' +#' @return a \code{data.frame} containing at least: +#' \describe{ +#' \item{seqnames}{ a \code{character} representing the name of +#' the chromosome} +#' \item{pos}{ a \code{numeric} representing the position on the +#' chromosome} +#' \item{REF}{ a \code{character} string representing the reference nucleotide} +#' \item{ALT}{ a \code{character} string representing the alternative +#' nucleotide} +#' \item{A}{ a \code{numeric} representing the count for +#' the A nucleotide} +#' \item{C}{ a \code{numeric} representing the count for +#' the C nucleotide} +#' \item{G}{ a \code{numeric} representing the count for +#' the G nucleotide} +#' \item{T}{ a \code{numeric} representing the count for +#' the T nucleotide} +#' \item{count}{ a \code{numeric} representing the total count} +#' } +#' +#' @examples +#' +#' ## Directory where demo SNP-pileup file +#' dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") +#' +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom dplyr group_by summarize %>% +#' @importFrom rlang .data +#' @encoding UTF-8 +#' @keywords internal +processPileupChrBin <- function(chr, + resPileup, varDf, + verbose=FALSE) { + + resCur <- NULL + if(chr %in% names(varDf)){ + + keep <- which(resPileup$seqnames == chr) + + if(length(keep) > 0){ + # restrict the resPileup to the chromosome chr + snpO <- resPileup[keep,] + rm(keep) + + # restrict. varDf to the region overlapping snpO + vcfCur <- varDf[[chr]][varDf[[chr]]$start >= min(snpO$pos) & + varDf[[chr]]$start <= max(snpO$pos),] + + if(nrow(vcfCur) > 0){ + + # Get the positions to keep in resPileup (snpO) + tmpTime <- system.time({z <- cbind( c(vcfCur$start, + snpO$pos, + vcfCur$start), + c(rep(-1, nrow(vcfCur)), + rep(0, nrow(snpO)), + rep(1, nrow(vcfCur))), + c(seq_len(nrow(vcfCur)), + seq_len(nrow(snpO)), + seq_len(nrow(vcfCur))) + ) + z <- z[order(z[,1]),] + listKeep <- which(cumsum(z[,2]) < 0 & z[,2]==0)}) + if(verbose) {message("processPileupChrBin selected pos user ", + round(tmpTime[1],3), + " system ", round(tmpTime[2],3), + " elapsed ", round(tmpTime[3],3))} + + # print("Match ") + # summarize by possition with the for base + tmpTime <- system.time(resCur <- as.data.frame(snpO[z[listKeep, 3],] %>% + group_by(.data$pos) %>% + summarize(seqnames=.data$seqnames[1], + A=extractNucleotide(.data$nucleotide,.data$count, "A"), + C=extractNucleotide(.data$nucleotide,.data$count, "C"), + G=extractNucleotide(.data$nucleotide,.data$count, "G"), + T=extractNucleotide(.data$nucleotide,.data$count, "T"), + count=sum(.data$count)))) + if(verbose) {message("processPileupChrBin extracted nucleotides user ", + round(tmpTime[1],3), + " system ", round(tmpTime[2],3), + " elapsed ", round(tmpTime[3],3))} + # print("Second Z") + # Add the reference allele and the alternative allele + tmpTime <- system.time({z <- cbind(c(resCur$pos, vcfCur$start, resCur$pos), + c(rep(-1,nrow(resCur)),rep(0, nrow(vcfCur)),rep(1, nrow(resCur))), + c(seq_len(nrow(resCur)), seq_len(nrow(vcfCur)), seq_len(nrow(resCur)))) + z <- z[order(z[,1]),] + listKeep <- which(cumsum(z[,2]) < 0 & z[,2]==0) + resCur$REF <- rep("N", nrow(resCur)) + resCur$ALT <- rep("N", nrow(resCur)) + resCur$REF[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "REF"] + resCur$ALT[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "ALT"] + resCur <- resCur[,c("seqnames", "pos", "REF", "ALT", "A", "C", "G", "T", "count")]}) + + if(verbose) {message("processPileupChrBin add ref and alt allele user ", + round(tmpTime[1],3), + " system ", round(tmpTime[2],3), + " elapsed ", round(tmpTime[3],3))} + } + } + } + return(resCur) +} + + + + #' @title The function create a vector of integer representing the linkage #' disequilibrium block for each SNV in the in the same order #' than the variant in Population reference dataset. diff --git a/man/extractNucleotide.Rd b/man/extractNucleotide.Rd new file mode 100644 index 000000000..8846db7e4 --- /dev/null +++ b/man/extractNucleotide.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tools_internal.R +\encoding{UTF-8} +\name{extractNucleotide} +\alias{extractNucleotide} +\title{Read a VCF file with the genotypes use for the ancestry call} +\usage{ +extractNucleotide(nucleotide, count, curNucleo) +} +\arguments{ +\item{nucleotide}{a \code{vector} of a \code{character} string representing A, C, G or T} + +\item{count}{a \code{vector} of \code{numeric} with count for the nucleotide} + +\item{curNucleoa}{\code{character} string representing A, C, G or T} +} +\value{ +a \code{numeric} +} +\description{ +The function reads VCF file and +returns a data frame +containing the information about the read counts for the SNVs present in +the file. +} +\examples{ + + +## Directory where demo SNP-pileup file +dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") + + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} diff --git a/man/processPileupChrBin.Rd b/man/processPileupChrBin.Rd new file mode 100644 index 000000000..3bc8f899c --- /dev/null +++ b/man/processPileupChrBin.Rd @@ -0,0 +1,59 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tools_internal.R +\encoding{UTF-8} +\name{processPileupChrBin} +\alias{processPileupChrBin} +\title{Read a VCF file with the genotypes use for the ancestry call} +\usage{ +processPileupChrBin(chr, resPileup, varDf, verbose = FALSE) +} +\arguments{ +\item{chr}{a \code{character} string representing the name, including +the path, of a VCF file containing the SNV read counts. +The VCF must contain those genotype fields: GT, AD, DP.} + +\item{resPileup}{result from pileup} + +\item{varDf}{a \code{data.frame} representing the position to keep} + +\item{verbose}{a \code{logical} indicating if messages should be printed +to show how the different steps in the function. Default: \code{FALSE}.} +} +\value{ +a \code{data.frame} containing at least: +\describe{ +\item{seqnames}{ a \code{character} representing the name of +the chromosome} +\item{pos}{ a \code{numeric} representing the position on the +chromosome} +\item{REF}{ a \code{character} string representing the reference nucleotide} +\item{ALT}{ a \code{character} string representing the alternative +nucleotide} +\item{A}{ a \code{numeric} representing the count for +the A nucleotide} +\item{C}{ a \code{numeric} representing the count for +the C nucleotide} +\item{G}{ a \code{numeric} representing the count for +the G nucleotide} +\item{T}{ a \code{numeric} representing the count for +the T nucleotide} +\item{count}{ a \code{numeric} representing the total count} +} +} +\description{ +The function reads VCF file and +returns a data frame +containing the information about the read counts for the SNVs present in +the file. +} +\examples{ + +## Directory where demo SNP-pileup file +dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") + + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} From f2ae83d27f45034a51e776c6b880fad7a8f2d0aa Mon Sep 17 00:00:00 2001 From: adeschen Date: Thu, 10 Apr 2025 11:53:26 -0400 Subject: [PATCH 331/385] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index abd516b6d..f5867a03e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ -# Accurate genetic ancestry inference from cancer-derived molecular data with **RAIDS** # +# Robust genetic ancestry inference from challenging molecular data with **RAIDS** # The Robust Ancestry Inference using Data Synthesis (**RAIDS**) package enables accurate and robust inference of genetic From b2d024a4d70a65b803334e9d345b5dfb2425fd32 Mon Sep 17 00:00:00 2001 From: adeschen Date: Thu, 10 Apr 2025 14:03:40 -0400 Subject: [PATCH 332/385] Update doc for extractNucleotid() function --- R/tools_internal.R | 42 ++++++++++++++++++++-------------------- man/extractNucleotide.Rd | 28 ++++++++++++++++----------- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/R/tools_internal.R b/R/tools_internal.R index 5bd7459b6..79011e6c3 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -1,6 +1,3 @@ - - - #' @title Validate that the input parameter is a GDS object #' #' @description This function validates that the input parameter inherits @@ -439,37 +436,40 @@ readSNVVCF <- function(fileName, return(matSample) } -#' @title Read a VCF file with the genotypes use for the ancestry call +#' @title Filtering the read counts for a specific nucleotide #' -#' @description The function reads VCF file and -#' returns a data frame -#' containing the information about the read counts for the SNVs present in -#' the file. +#' @description The function returns the read counts for the specific +#' nucleotide or zero when read counts are not available. #' -#' @param nucleotide a \code{vector} of a \code{character} string representing A, C, G or T +#' @param nucleotide a \code{vector} of a \code{character} strings +#' representing the nucleotides (ex: A, C, G or T). #' #' -#' @param count a \code{vector} of \code{numeric} with count for the nucleotide +#' @param count a \code{vector} of \code{numeric} representing the counts for +#' each nucleotide listed in \code{nucleotide} parameter. #' -#' @param curNucleoa \code{character} string representing A, C, G or T +#' @param curNucleo a \code{character} strings representing the nucleotide +#' that will be retained (ex: A, C, G or T). #' -#' @return a \code{numeric} +#' @return a \code{numeric} representing the counts for the selected +#' nucleotide. The default value is \code{0}. #' #' @examples #' +#' ## Nucleotides vector +#' nuc <- c("A", "G", "C", "T") +#' +#' ## Count vector +#' cnt <- c(100, 200, 4, 32) #' -#' ## Directory where demo SNP-pileup file -#' dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") -#' -#' +#' ## Return the count for the nucleotide "G" +#' RAIDS:::extractNucleotide(nucleotide=nuc, count=cnt, curNucleo="G") +#' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @encoding UTF-8 #' @keywords internal -extractNucleotide <- function(nucleotide, - count, - curNucleo) { - tmp <- which(nucleotide == curNucleo) - res<-0 +extractNucleotide <- function(nucleotide, count, curNucleo) { + res <- 0 if(length(tmp) == 1) res <- count[tmp] return(res) } diff --git a/man/extractNucleotide.Rd b/man/extractNucleotide.Rd index 8846db7e4..3d17a7708 100644 --- a/man/extractNucleotide.Rd +++ b/man/extractNucleotide.Rd @@ -3,32 +3,38 @@ \encoding{UTF-8} \name{extractNucleotide} \alias{extractNucleotide} -\title{Read a VCF file with the genotypes use for the ancestry call} +\title{Filtering the read counts for a specific nucleotide} \usage{ extractNucleotide(nucleotide, count, curNucleo) } \arguments{ -\item{nucleotide}{a \code{vector} of a \code{character} string representing A, C, G or T} +\item{nucleotide}{a \code{vector} of a \code{character} strings +representing the nucleotides (ex: A, C, G or T).} -\item{count}{a \code{vector} of \code{numeric} with count for the nucleotide} +\item{count}{a \code{vector} of \code{numeric} representing the counts for +each nucleotide listed in \code{nucleotide} parameter.} -\item{curNucleoa}{\code{character} string representing A, C, G or T} +\item{curNucleo}{a \code{character} strings representing the nucleotide +that will be retained (ex: A, C, G or T).} } \value{ -a \code{numeric} +a \code{numeric} representing the counts for the selected +nucleotide. The default value is \code{0}. } \description{ -The function reads VCF file and -returns a data frame -containing the information about the read counts for the SNVs present in -the file. +The function returns the read counts for the specific +nucleotide or zero when read counts are not available. } \examples{ +## Nucleotides vector +nuc <- c("A", "G", "C", "T") -## Directory where demo SNP-pileup file -dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") +## Count vector +cnt <- c(100, 200, 4, 32) +## Return the count for the nucleotide "G" +RAIDS:::extractNucleotide(nucleotide=nuc, count=cnt, curNucleo="G") } \author{ From 34eb2fef5b4304211fc8f11459ae8bab2bcaa7b8 Mon Sep 17 00:00:00 2001 From: adeschen Date: Thu, 10 Apr 2025 14:37:57 -0400 Subject: [PATCH 333/385] Correct extractNucleotide() function --- R/tools_internal.R | 3 +++ 1 file changed, 3 insertions(+) diff --git a/R/tools_internal.R b/R/tools_internal.R index 79011e6c3..f781df226 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -469,9 +469,12 @@ readSNVVCF <- function(fileName, #' @encoding UTF-8 #' @keywords internal extractNucleotide <- function(nucleotide, count, curNucleo) { + + tmp <- which(nucleotide == curNucleo) res <- 0 if(length(tmp) == 1) res <- count[tmp] return(res) + } From bf8e02bc406b4a205e4a204f08288bbce41b1140 Mon Sep 17 00:00:00 2001 From: adeschen Date: Thu, 10 Apr 2025 15:31:38 -0400 Subject: [PATCH 334/385] Adding tests for extractNucleotide() function --- tests/testthat/test-tools_internal.R | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/testthat/test-tools_internal.R b/tests/testthat/test-tools_internal.R index 5b0d84b0f..4c321c74b 100644 --- a/tests/testthat/test-tools_internal.R +++ b/tests/testthat/test-tools_internal.R @@ -142,3 +142,31 @@ test_that("validatePositiveIntegerVector() must return expected results when all expect_identical(result1, 0L) }) + +############################################################################# +### Tests extractNucleotide() results +############################################################################# + +context("extractNucleotide() results") + + +test_that("extractNucleotide() must return expected results when all input are valid", { + + nuc <- c("A", "G", "C", "T") + cnt <- c(100, 200, 4, 32) + result1 <- RAIDS:::extractNucleotide(nucleotide=nuc, count=cnt, + curNucleo="C") + + expect_identical(result1, 4) +}) + + +test_that("extractNucleotide() must return expected results when nucleotide not present in the input", { + + nuc <- c("A", "G", "T") + cnt <- c(100, 200, 32) + result1 <- RAIDS:::extractNucleotide(nucleotide=nuc, count=cnt, + curNucleo="C") + + expect_identical(result1, 0) +}) From 30c59978b6f99621c8d62c1c1e9cf75d5f07fed9 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 11 Apr 2025 12:43:17 -0400 Subject: [PATCH 335/385] Add function readSNVBAM --- DESCRIPTION | 3 +- NAMESPACE | 4 ++ R/tools_internal.R | 151 +++++++++++++++++++++++++++++++++++++++++++++ man/readSNVBAM.Rd | 60 ++++++++++++++++++ 4 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 man/readSNVBAM.Rd diff --git a/DESCRIPTION b/DESCRIPTION index e9b173716..a3d023314 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -29,7 +29,8 @@ Depends: R (>= 4.2.0), stats, utils, GENESIS, - dplyr + dplyr, + Rsamtools Imports: S4Vectors, GenomicRanges, ensembldb, diff --git a/NAMESPACE b/NAMESPACE index d43613aca..6baaacb71 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -50,6 +50,10 @@ importFrom(GenomicRanges,start) importFrom(GenomicRanges,width) importFrom(IRanges,IRanges) importFrom(MatrixGenerics,rowRanges) +importFrom(Rsamtools,BamFile) +importFrom(Rsamtools,PileupParam) +importFrom(Rsamtools,ScanBamParam) +importFrom(Rsamtools,pileup) importFrom(S4Vectors,Rle) importFrom(S4Vectors,aggregate) importFrom(S4Vectors,isSingleNumber) diff --git a/R/tools_internal.R b/R/tools_internal.R index 5bd7459b6..be075782b 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -600,6 +600,157 @@ processPileupChrBin <- function(chr, return(resCur) } +#' @title Read a VCF file with the genotypes use for the ancestry call +#' +#' @description The function reads VCF file and +#' returns a data frame +#' containing the information about the read counts for the SNVs present in +#' the file. +#' +#' @param fileName a \code{character} string representing the name, including +#' the path, of a BAM file with the index file in the same directory +#' +#' +#' @param paramSNVBAM a \code{data.frame} representing the position to keep +#' +#' @param varSelected a \code{data.frame} representing the position to keep +#' +#' @param verbose a \code{logical} indicating if messages should be printed +#' to show how the different steps in the function. Default: \code{FALSE}. +#' +#' @return a \code{data.frame} containing at least: +#' \describe{ +#' \item{Chromosome}{ a \code{numeric} representing the name of +#' the chromosome} +#' \item{Position}{ a \code{numeric} representing the position on the +#' chromosome} +#' \item{Ref}{ a \code{character} string representing the reference nucleotide} +#' \item{Alt}{ a \code{character} string representing the alternative +#' nucleotide} +#' \item{File1R}{ a \code{numeric} representing the count for +#' the reference nucleotide} +#' \item{File1A}{ a \code{numeric} representing the count for the +#' alternative nucleotide} +#' \item{count}{ a \code{numeric} representing the total count} +#' } +#' +#' @examples +#' +#' +#' ## Directory where demo SNP-pileup file +#' dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") +#' +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom Rsamtools BamFile ScanBamParam PileupParam pileup +#' @importFrom MatrixGenerics rowRanges +#' @importFrom GenomicRanges seqnames start width +#' @encoding UTF-8 +#' @keywords internal +readSNVBAM <- function(fileName, + varSelected, + paramSNVBAM=list(ScanBamParam=NULL, + PileupParam=NULL, + yieldSize=5000000), + verbose=FALSE) { + + myBf <- BamFile(fileName, yieldSize=paramSNVBAM$yieldSize) + bf <- open(myBf) + # temporary before create a parameters class + if(is.null(paramSNVBAM$ScanBamParam)){ + sbp <- ScanBamParam() # which=vcf_granges + } + if(is.null(paramSNVBAM$ScanBamParam)){ + pup <- PileupParam(max_depth=5000, + min_base_quality=20, + min_mapq=15, + min_nucleotide_depth=1, + min_minor_allele_depth=0, + distinguish_strands=FALSE, + distinguish_nucleotides=TRUE, + ignore_query_Ns=TRUE, + include_deletions=FALSE, + include_insertions=FALSE) + } + + + + i<-1 + res <- list() + vcfChr <- list() + k<-0 + + repeat { + tmpTime <- system.time(resPileup <- pileup(bf, + pileupParam = pup, + ScanBamParam=sbp)) + if(verbose) {message("readSNVBAM pileup user ", + round(tmpTime[1],3), + " system ", round(tmpTime[2],3), + " elapsed ", round(tmpTime[3],3))} + + listChr <- unique(as.character(resPileup$seqnames)) + #print(paste0("nb Chr ", length(listChr))) + res[[i]] <- NULL + if(length(listChr) > 0 ){ + if(sum(!(listChr %in% names(varSelected))) == length(listChr)){ + # message("End chromosome") + break + } + # print(paste0("Current chr ", listChr)) + tmp <- lapply(listChr, + FUN=function(x, res, varSelected){ + return(processPileupChrBin(chr=x, res, varDf=varSelected, verbose=verbose)) + }, + res=resPileup, + varSelected=varSelected) + # print("aye2") + if(length(tmp) > 0){ + res[[i]] <- do.call(rbind, tmp) + i <- i + 1 + #message(nrow(res[[i]]), " rows in result data.frame") + } + # print("aye3") + } + + if(nrow(resPileup) == 0L){ + k <- k + 1 + # print(paste0("Break ", k)) + if(k > 20){ + break + } + }else{ + k <- 0 + # i <- i + 1 + } + + } + + resSNP <- do.call(rbind,res) + close(bf) + + + resSNP <- do.call(rbind, lapply(seq_len(nrow(resSNP)), + FUN=function(x, resSNP){ + + df <- data.frame(Chromosome=resSNP[x, "seqnames"], + Position=resSNP[x, "pos"], + Ref=resSNP[x, "REF"], + Alt=resSNP[x, "ALT"], + File1R=resSNP[x, resSNP[x, "REF"]], + File1A=resSNP[x, resSNP[x, "ALT"]], + count=resSNP[x, "count"], + A=resSNP[x, "A"], + C=resSNP[x, "C"], + G=resSNP[x, "G"], + T=resSNP[x, "T"], + stringsAsFactors = FALSE) + return(df) + }, + resSNP=resSNP)) + + return(resSNP) +} diff --git a/man/readSNVBAM.Rd b/man/readSNVBAM.Rd new file mode 100644 index 000000000..c72955db5 --- /dev/null +++ b/man/readSNVBAM.Rd @@ -0,0 +1,60 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tools_internal.R +\encoding{UTF-8} +\name{readSNVBAM} +\alias{readSNVBAM} +\title{Read a VCF file with the genotypes use for the ancestry call} +\usage{ +readSNVBAM( + fileName, + varSelected, + paramSNVBAM = list(ScanBamParam = NULL, PileupParam = NULL, yieldSize = 5e+06), + verbose = FALSE +) +} +\arguments{ +\item{fileName}{a \code{character} string representing the name, including +the path, of a BAM file with the index file in the same directory} + +\item{varSelected}{a \code{data.frame} representing the position to keep} + +\item{paramSNVBAM}{a \code{data.frame} representing the position to keep} + +\item{verbose}{a \code{logical} indicating if messages should be printed +to show how the different steps in the function. Default: \code{FALSE}.} +} +\value{ +a \code{data.frame} containing at least: +\describe{ +\item{Chromosome}{ a \code{numeric} representing the name of +the chromosome} +\item{Position}{ a \code{numeric} representing the position on the +chromosome} +\item{Ref}{ a \code{character} string representing the reference nucleotide} +\item{Alt}{ a \code{character} string representing the alternative +nucleotide} +\item{File1R}{ a \code{numeric} representing the count for +the reference nucleotide} +\item{File1A}{ a \code{numeric} representing the count for the +alternative nucleotide} +\item{count}{ a \code{numeric} representing the total count} +} +} +\description{ +The function reads VCF file and +returns a data frame +containing the information about the read counts for the SNVs present in +the file. +} +\examples{ + + +## Directory where demo SNP-pileup file +dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") + + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} From 8cc8b65e271b6c5b2c75972632ee0294be84d0bb Mon Sep 17 00:00:00 2001 From: adeschen Date: Fri, 11 Apr 2025 13:28:56 -0400 Subject: [PATCH 336/385] Update doc and format processPileupChrBin() function --- R/tools_internal.R | 142 ++++++++++++++++++------------------- man/processPileupChrBin.Rd | 29 +++----- 2 files changed, 79 insertions(+), 92 deletions(-) diff --git a/R/tools_internal.R b/R/tools_internal.R index 8978ccc66..ca2f9dfe7 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -478,42 +478,34 @@ extractNucleotide <- function(nucleotide, count, curNucleo) { } -#' @title Read a VCF file with the genotypes use for the ancestry call +#' @title Extract SNV information from pileup file for a selected chromosome #' -#' @description The function reads VCF file and -#' returns a data frame +#' @description The function reads pileup file and +#' returns a \code{data.frame} #' containing the information about the read counts for the SNVs present in -#' the file. -#' -#' @param chr a \code{character} string representing the name, including -#' the path, of a VCF file containing the SNV read counts. -#' The VCF must contain those genotype fields: GT, AD, DP. +#' the selected chromosome. #' +#' @param chr a \code{character} string representing the name of the +#' chromosome to keep #' -#' @param resPileup result from pileup +#' @param resPileup a \code{data.frame} as generated by the \code{pileup} +#' function from \code{Rsamtools} package #' -#' @param varDf a \code{data.frame} representing the position to keep +#' @param varDf a \code{data.frame} representing the positions to keep #' #' @param verbose a \code{logical} indicating if messages should be printed -#' to show how the different steps in the function. Default: \code{FALSE}. #' #' @return a \code{data.frame} containing at least: #' \describe{ -#' \item{seqnames}{ a \code{character} representing the name of -#' the chromosome} -#' \item{pos}{ a \code{numeric} representing the position on the -#' chromosome} +#' \item{seqnames}{ a \code{character} representing the name of the chromosome} +#' \item{pos}{ a \code{numeric} representing the position on the chromosome} #' \item{REF}{ a \code{character} string representing the reference nucleotide} #' \item{ALT}{ a \code{character} string representing the alternative #' nucleotide} -#' \item{A}{ a \code{numeric} representing the count for -#' the A nucleotide} -#' \item{C}{ a \code{numeric} representing the count for -#' the C nucleotide} -#' \item{G}{ a \code{numeric} representing the count for -#' the G nucleotide} -#' \item{T}{ a \code{numeric} representing the count for -#' the T nucleotide} +#' \item{A}{ a \code{numeric} representing the count for the A nucleotide} +#' \item{C}{ a \code{numeric} representing the count for the C nucleotide} +#' \item{G}{ a \code{numeric} representing the count for the G nucleotide} +#' \item{T}{ a \code{numeric} representing the count for the T nucleotide} #' \item{count}{ a \code{numeric} representing the total count} #' } #' @@ -528,16 +520,20 @@ extractNucleotide <- function(nucleotide, count, curNucleo) { #' @importFrom rlang .data #' @encoding UTF-8 #' @keywords internal -processPileupChrBin <- function(chr, - resPileup, varDf, - verbose=FALSE) { +processPileupChrBin <- function(chr, resPileup, varDf, verbose) { resCur <- NULL - if(chr %in% names(varDf)){ + + ## Assign FALSE to verbose by default + if (is.null(verbose)) { + verbose <- FALSE + } + + if (chr %in% names(varDf)) { keep <- which(resPileup$seqnames == chr) - if(length(keep) > 0){ + if (length(keep) > 0) { # restrict the resPileup to the chromosome chr snpO <- resPileup[keep,] rm(keep) @@ -546,57 +542,55 @@ processPileupChrBin <- function(chr, vcfCur <- varDf[[chr]][varDf[[chr]]$start >= min(snpO$pos) & varDf[[chr]]$start <= max(snpO$pos),] - if(nrow(vcfCur) > 0){ + if (nrow(vcfCur) > 0) { # Get the positions to keep in resPileup (snpO) - tmpTime <- system.time({z <- cbind( c(vcfCur$start, - snpO$pos, - vcfCur$start), - c(rep(-1, nrow(vcfCur)), - rep(0, nrow(snpO)), - rep(1, nrow(vcfCur))), - c(seq_len(nrow(vcfCur)), - seq_len(nrow(snpO)), - seq_len(nrow(vcfCur))) - ) - z <- z[order(z[,1]),] - listKeep <- which(cumsum(z[,2]) < 0 & z[,2]==0)}) - if(verbose) {message("processPileupChrBin selected pos user ", - round(tmpTime[1],3), - " system ", round(tmpTime[2],3), - " elapsed ", round(tmpTime[3],3))} - - # print("Match ") - # summarize by possition with the for base + tmpTime <- system.time( {z <- cbind( c(vcfCur$start, + snpO$pos, vcfCur$start), + c(rep(-1, nrow(vcfCur)), rep(0, nrow(snpO)), + rep(1, nrow(vcfCur))), + c(seq_len(nrow(vcfCur)), seq_len(nrow(snpO)), + seq_len(nrow(vcfCur)))) + z <- z[order(z[,1]),] + listKeep <- which(cumsum(z[,2]) < 0 & z[,2]==0)} ) + + if (verbose) { + message("processPileupChrBin selected pos user ", + round(tmpTime[1],3), " system ", round(tmpTime[2],3), + " elapsed ", round(tmpTime[3],3)) } + + # summarize by position with the for base tmpTime <- system.time(resCur <- as.data.frame(snpO[z[listKeep, 3],] %>% - group_by(.data$pos) %>% - summarize(seqnames=.data$seqnames[1], - A=extractNucleotide(.data$nucleotide,.data$count, "A"), - C=extractNucleotide(.data$nucleotide,.data$count, "C"), - G=extractNucleotide(.data$nucleotide,.data$count, "G"), - T=extractNucleotide(.data$nucleotide,.data$count, "T"), - count=sum(.data$count)))) - if(verbose) {message("processPileupChrBin extracted nucleotides user ", - round(tmpTime[1],3), - " system ", round(tmpTime[2],3), - " elapsed ", round(tmpTime[3],3))} - # print("Second Z") + group_by(.data$pos) %>% + summarize(seqnames=.data$seqnames[1], + A=extractNucleotide(.data$nucleotide,.data$count, "A"), + C=extractNucleotide(.data$nucleotide,.data$count, "C"), + G=extractNucleotide(.data$nucleotide,.data$count, "G"), + T=extractNucleotide(.data$nucleotide,.data$count, "T"), + count=sum(.data$count)))) + + if (verbose) { + message("processPileupChrBin extracted nucleotides user ", + round(tmpTime[1],3), " system ", round(tmpTime[2],3), + " elapsed ", round(tmpTime[3],3)) } + # Add the reference allele and the alternative allele tmpTime <- system.time({z <- cbind(c(resCur$pos, vcfCur$start, resCur$pos), - c(rep(-1,nrow(resCur)),rep(0, nrow(vcfCur)),rep(1, nrow(resCur))), - c(seq_len(nrow(resCur)), seq_len(nrow(vcfCur)), seq_len(nrow(resCur)))) - z <- z[order(z[,1]),] - listKeep <- which(cumsum(z[,2]) < 0 & z[,2]==0) - resCur$REF <- rep("N", nrow(resCur)) - resCur$ALT <- rep("N", nrow(resCur)) - resCur$REF[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "REF"] - resCur$ALT[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "ALT"] - resCur <- resCur[,c("seqnames", "pos", "REF", "ALT", "A", "C", "G", "T", "count")]}) - - if(verbose) {message("processPileupChrBin add ref and alt allele user ", - round(tmpTime[1],3), - " system ", round(tmpTime[2],3), - " elapsed ", round(tmpTime[3],3))} + c(rep(-1, nrow(resCur)), rep(0, nrow(vcfCur)), rep(1, nrow(resCur))), + c(seq_len(nrow(resCur)), seq_len(nrow(vcfCur)), seq_len(nrow(resCur)))) + z <- z[order(z[,1]),] + listKeep <- which(cumsum(z[,2]) < 0 & z[,2]==0) + resCur$REF <- rep("N", nrow(resCur)) + resCur$ALT <- rep("N", nrow(resCur)) + resCur$REF[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "REF"] + resCur$ALT[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "ALT"] + resCur <- resCur[,c("seqnames", "pos", "REF", "ALT", "A", + "C", "G", "T", "count")]} ) + + if(verbose) { + message("processPileupChrBin add ref and alt allele user ", + round(tmpTime[1],3), " system ", round(tmpTime[2],3), + " elapsed ", round(tmpTime[3],3)) } } } } diff --git a/man/processPileupChrBin.Rd b/man/processPileupChrBin.Rd index 3bc8f899c..3a87ea6d0 100644 --- a/man/processPileupChrBin.Rd +++ b/man/processPileupChrBin.Rd @@ -5,7 +5,7 @@ \alias{processPileupChrBin} \title{Read a VCF file with the genotypes use for the ancestry call} \usage{ -processPileupChrBin(chr, resPileup, varDf, verbose = FALSE) +processPileupChrBin(chr, resPileup, varDf, verbose) } \arguments{ \item{chr}{a \code{character} string representing the name, including @@ -14,37 +14,30 @@ The VCF must contain those genotype fields: GT, AD, DP.} \item{resPileup}{result from pileup} -\item{varDf}{a \code{data.frame} representing the position to keep} +\item{varDf}{a \code{data.frame} representing the positions to keep} -\item{verbose}{a \code{logical} indicating if messages should be printed -to show how the different steps in the function. Default: \code{FALSE}.} +\item{verbose}{a \code{logical} indicating if messages should be printed} } \value{ a \code{data.frame} containing at least: \describe{ -\item{seqnames}{ a \code{character} representing the name of -the chromosome} -\item{pos}{ a \code{numeric} representing the position on the -chromosome} +\item{seqnames}{ a \code{character} representing the name of the chromosome} +\item{pos}{ a \code{numeric} representing the position on the chromosome} \item{REF}{ a \code{character} string representing the reference nucleotide} \item{ALT}{ a \code{character} string representing the alternative nucleotide} -\item{A}{ a \code{numeric} representing the count for -the A nucleotide} -\item{C}{ a \code{numeric} representing the count for -the C nucleotide} -\item{G}{ a \code{numeric} representing the count for -the G nucleotide} -\item{T}{ a \code{numeric} representing the count for -the T nucleotide} +\item{A}{ a \code{numeric} representing the count for the A nucleotide} +\item{C}{ a \code{numeric} representing the count for the C nucleotide} +\item{G}{ a \code{numeric} representing the count for the G nucleotide} +\item{T}{ a \code{numeric} representing the count for the T nucleotide} \item{count}{ a \code{numeric} representing the total count} } } \description{ The function reads VCF file and -returns a data frame +returns a \code{data.frame} containing the information about the read counts for the SNVs present in -the file. +the VCF. } \examples{ From 5b04cad74d6be32cc1f03090c9b919febc88d0d0 Mon Sep 17 00:00:00 2001 From: krasnitz Date: Fri, 11 Apr 2025 13:33:30 -0400 Subject: [PATCH 337/385] Update RAIDS.Rmd From 26c72ca4b9d25f96a75bb2449780b96c5dd91137 Mon Sep 17 00:00:00 2001 From: adeschen Date: Fri, 11 Apr 2025 14:26:34 -0400 Subject: [PATCH 338/385] Add unit test for processPileupChrBin() function --- tests/testthat/test-tools_internal.R | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/testthat/test-tools_internal.R b/tests/testthat/test-tools_internal.R index 4c321c74b..02175fd92 100644 --- a/tests/testthat/test-tools_internal.R +++ b/tests/testthat/test-tools_internal.R @@ -170,3 +170,20 @@ test_that("extractNucleotide() must return expected results when nucleotide not expect_identical(result1, 0) }) + + +############################################################################# +### Tests processPileupChrBin() results +############################################################################# + +context("processPileupChrBin() results") + + +test_that("processPileupChrBin() must return NULL when chromosome absent", { + + varDf <- c("chr1"=c(1,2,3), "chr2"=c(1,3,5)) + result1 <- RAIDS:::processPileupChrBin(chr="chr3", resPileup=NULL, + varDf=varDf, verbose=FALSE) + + expect_identical(result1, NULL) +}) \ No newline at end of file From dd2ee0427ca637aeee707bd4088734850affabf1 Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 11 Apr 2025 16:07:00 -0400 Subject: [PATCH 339/385] Add function generateProfileGDS --- R/gdsWrapper_internal.R | 299 ++++++++++++++++++++++++++++++++++++++ R/processStudy.R | 26 ++-- man/generateProfileGDS.Rd | 146 +++++++++++++++++++ 3 files changed, 458 insertions(+), 13 deletions(-) create mode 100644 man/generateProfileGDS.Rd diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 4239edc61..a9a651eb8 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -551,6 +551,305 @@ generateGDS1KGgenotypeFromSNPPileup <- function(pathGeno, return(0L) } +#' @title Append the genotype information from a profile into the associated +#' Profile GDS File +#' +#' @description This function append the genotype information from a specific +#' profile into the Profile GDS file. The genotype information is extracted +#' from a SNV file as generated by SNP-pileup or other tools. +#' +#' @param profileFile a \code{character} string representing the path and the +#' file name of the genotype file or the bam if genoSource is snp-pileup the +#' fine extension must be .txt.gz, if VCF the extension must be .vcf.gz +#' +#' @param profileName a \code{character} string representing the profileName +#' +#' @param listPos a \code{data.frame} containing 2 columns. The first column, +#' called "snp.chromosome" contains the name of the chromosome where the +#' SNV is located. The second column, called "snp.position" contains the +#' position of the SNV on the chromosome. +#' +#' @param offset a \code{integer} to adjust if the genome start at 0 or 1. +#' +#' @param minCov a single positive \code{integer} representing the minimum +#' coverage needed to keep the SNVs in the analysis. Default: \code{10}. +#' +#' @param minProb a single positive \code{numeric} between 0 and 1 +#' representing the probability that the base change at the SNV position +#' is not an error. +#' Default: \code{0.999}. +#' +#' @param seqError a single positive \code{numeric} between 0 and 1 +#' representing the sequencing error rate. Default: \code{0.001}. +#' +#' @param dfPedProfile a \code{data.frame} with the information about +#' the sample(s). +#' Those are mandatory columns: "Name.ID", +#' "Case.ID", "Sample.Type", "Diagnosis" and "Source". All columns must be in +#' \code{character} strings format. The \code{data.frame} +#' must contain the information for all the samples passed in the +#' \code{listSamples} parameter. +#' +#' @param batch a single positive \code{integer} representing the current +#' identifier for the batch. Beware, this field is not stored anymore. +#' +#' @param studyDF a \code{data.frame} containing the information about the +#' study associated to the analysed sample(s). The \code{data.frame} must have +#' those 3 columns: "study.id", "study.desc", "study.platform". All columns +#' must be in \code{character} strings. +#' +#' @param pathProfileGDS a \code{character} string representing the path to +#' the directory where the GDS Sample files will be created. +#' +#' @param genoSource a \code{character} string with two possible values: +#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +#' are generated by snp-pileup (Facets) or are a generic format CSV file +#' with at least those columns: +#' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +#' The 'Count' is the depth at the specified position; +#' 'FileR' is the depth of the reference allele and +#' 'File1A' is the depth of the specific alternative allele. +#' Finally the file can be a VCF file with at least those genotype +#' fields: GT, AD, DP. +#' +#' @param verbose a \code{logical} indicating if the function must print +#' messages when running. +#' +#' @return The function returns \code{0L} when successful. +#' +#' @examples +#' +#' ## Current directory +#' dataDir <- file.path(tempdir()) +#' +#' ## Copy required file into current directory +#' file.copy(from=file.path(system.file("extdata/tests", package="RAIDS"), +#' "ex1.txt.gz"), to=dataDir) +#' +#' ## The data.frame containing the information about the study +#' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" +#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) +#' studyDF <- data.frame(study.id = "MYDATA", +#' study.desc = "Description", +#' study.platform = "PLATFORM", +#' stringsAsFactors = FALSE) +#' +#' ## The data.frame containing the information about the samples +#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) +#' samplePED <- data.frame(Name.ID=c("ex1", "ex2"), +#' Case.ID=c("Patient_h11", "Patient_h12"), +#' Diagnosis=rep("Cancer", 2), +#' Sample.Type=rep("Primary Tumor", 2), +#' Source=rep("Databank B", 2), stringsAsFactors=FALSE) +#' rownames(samplePED) <- samplePED$Name.ID +#' +#' ## List of SNV positions +#' listPositions <- data.frame(snp.chromosome=c(rep(1, 10)), +#' snp.position=c(3467333, 3467428, 3469375, 3469387, 3469502, 3469527, +#' 3469737, 3471497, 3471565, 3471618)) +#' +#' ## Append genotype information to the Profile GDS file +#' result <- RAIDS:::generateProfileGDS(profileFile=file.path(dataDir, "ex1.txt.gz"), +#' profileName="ex1", listPos=listPositions, +#' offset=-1, minCov=10, minProb=0.999, seqError=0.001, +#' dfPedProfile=samplePED, batch=1, studyDF=studyDF, +#' pathProfileGDS=dataDir, genoSource="snp-pileup", +#' verbose=FALSE) +#' +#' ## The function returns OL when successful +#' result +#' +#' ## The Profile GDS file 'ex1.gds' has been created in the +#' ## specified directory +#' list.files(dataDir) +#' +#' ## Unlink Profile GDS file (created for demo purpose) +#' unlink(file.path(dataDir, "ex1.gds")) +#' unlink(file.path(dataDir, "ex1.txt.gz")) +#' +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt add.gdsn write.gdsn openfn.gds +#' @importFrom stats qbinom +#' @importFrom utils read.csv +#' @encoding UTF-8 +#' @keywords internal +generateProfileGDS <- function(profileFile, profileName, + listPos, offset, minCov=10, minProb=0.999, + seqError=0.001, dfPedProfile, batch, studyDF, pathProfileGDS, + genoSource, verbose) { + + # File with the description of the SNP keep + # if(genoSource == "VCF"){ + # listMat <- dir(pathGeno, pattern = ".+.vcf.gz") + # listSampleFile <- gsub(".vcf.gz", "", listMat) + # }else{ + # listMat <- dir(pathGeno, pattern = ".+.txt.gz") + # listSampleFile <- gsub(".txt.gz", "", listMat) + # } + + + g <- as.matrix(rep(-1, nrow(listPos))) + + # for(i in seq_len(length(listSamples))) { + #pos <- which(listSampleFile == listSamples[i]) + + if(verbose) { message("generateProfileGDS start ", " ", Sys.time()) } + +# if(length(pos) == 1) { + + # + if(genoSource == "snp-pileup") { + matSample <- readSNVPileupFile(profileFile, offset) + } else if(genoSource == "generic") { + matSample <- readSNVFileGeneric(profileFile, offset) + } else if(genoSource == "VCF") { + # tmpProfile <- gsub(".vcf.gz", "",listMat[pos]) + matSample <- readSNVVCF(profileFile, + profileName=profileName, offset) + } else if(genoSource == "bam"){ + #tmpProfile <- gsub(".vcf.gz", "",listMat[pos]) + } + # matAll <- merge(matSample[,c( "Chromosome", "Position", + # "File1R", "File1A", + # "count" )], + # listPos, + # by.x = c("Chromosome", "Position"), + # by.y = c("snp.chromosome", "snp.position"), + # all.y = TRUE, + # all.x = FALSE) + # + # below same as the merge above but faster + + z <- cbind(c(listPos$snp.chromosome, matSample$Chromosome, + matSample$Chromosome), + c(listPos$snp.position, matSample$Position, + matSample$Position), + c(rep(1,nrow(listPos)), rep(0,nrow(matSample)), + rep(2,nrow(matSample))), + c(rep(0,nrow(listPos)), matSample[, "File1R"], + -1 * matSample[, "File1R"]), + c(rep(0,nrow(listPos)), matSample[, "File1A"], + -1 * matSample[, "File1A"]), + c(rep(0,nrow(listPos)), matSample[, "count"], + -1 * matSample[, "count"])) + rm(matSample) + z <- z[order(z[,1], z[,2], z[,3]),] + + matAll <- data.frame(Chromosome=z[z[, 3] == 1, 1], + Position=z[z[, 3] == 1, 2], File1R=cumsum(z[, 4])[z[, 3] == 1], + File1A=cumsum(z[,5])[z[, 3] == 1], + count=cumsum(z[, 6])[z[, 3] == 1]) + rm(z) + + if(is.null(pathProfileGDS)){ + stop("pathProfileGDS is NULL in ", + "generateGDS1KGgenotypeFromSNPPileup\n") + } else{ + if(! dir.exists(pathProfileGDS)) { + dir.create(pathProfileGDS) + } + } + fileGDSSample <- file.path(pathProfileGDS, + paste0(profileName, ".gds")) + if(file.exists(fileGDSSample)) { + gdsSample <- openfn.gds(fileGDSSample, readonly=FALSE) + } else{ + gdsSample <- createfn.gds(fileGDSSample) + } + + if (! "Ref.count" %in% ls.gdsn(gdsSample)) { + var.Ref <- add.gdsn(gdsSample, "Ref.count", matAll$File1R, + valdim=c( nrow(listPos), 1), + storage="sp.int16") + var.Alt <- add.gdsn(gdsSample, "Alt.count", matAll$File1A, + valdim=c( nrow(listPos), 1), + storage="sp.int16") + var.Count <- add.gdsn(gdsSample, "Total.count", + matAll$count, valdim=c( nrow(listPos), 1), + storage="sp.int16") + } else { + # you must append + var.Ref <- append.gdsn(index.gdsn(gdsSample, "Ref.count"), + matAll$File1R) + var.Alt <- append.gdsn(index.gdsn(gdsSample, "Alt.count"), + matAll$File1A) + var.Count <- append.gdsn(index.gdsn(gdsSample, "Total.count"), + matAll$count) + } + + listSampleGDS <- addStudyGDSSample(gdsSample, + pedProfile=dfPedProfile, batch=batch, + listSamples=c(profileName), studyDF=studyDF, verbose=verbose) + + listCount <- table(matAll$count[matAll$count >= minCov]) + cutOffA <- + data.frame(count=unlist(vapply(as.integer(names(listCount)), + FUN=function(x, minProb, eProb){ + return(max(2,qbinom(minProb, x, eProb))) }, + FUN.VALUE=numeric(1), minProb=minProb, eProb=2 * seqError)), + allele=unlist(vapply(as.integer(names(listCount)), + FUN=function(x, minProb, eProb){ + return(max(2,qbinom(minProb, x, eProb))) }, + FUN.VALUE=numeric(1), minProb=minProb, eProb=seqError))) + + row.names(cutOffA) <- names(listCount) + # Initialize the genotype array at -1 + + # Select the position where the coverage of the 2 alleles is enough + listCov <- which(rowSums(matAll[, c("File1R", "File1A")]) >= minCov) + + matAllC <- matAll[listCov,] + + # The difference depth - (nb Ref + nb Alt) can be realistically + # explain by sequencing error + listCov <- listCov[(matAllC$count - + (matAllC$File1R + matAllC$File1A)) < + cutOffA[as.character(matAllC$count), "count"]] + + matAllC <- matAll[listCov,] + rm(matAll) + + g <- as.matrix(rep(-1, nrow(listPos))) + # The sample is homozygote if the other known allele have a + # coverage of 0 + g[listCov][which(matAllC$File1A == 0)] <- 0 + g[listCov][which(matAllC$File1R == 0)] <- 2 + + # The sample is heterozygote if explain the coverage of + # the minor allele by sequencing error is not realistic. + g[listCov][which(matAllC$File1A >= + cutOffA[as.character(matAllC$count), "allele"] & + matAllC$File1R >= cutOffA[as.character(matAllC$count), + "allele"])] <- 1 + + #g <- as.matrix(g) + if("geno.ref" %in% ls.gdsn(gdsSample)){ + var.geno <- index.gdsn(gdsSample, "geno.ref") + + compression.gdsn(var.geno, compress="") + append.gdsn(var.geno, g, check=TRUE) + compression.gdsn(var.geno, compress="LZMA_RA.fast") + readmode.gdsn(var.geno) + + }else{ + var.geno <- add.gdsn(gdsSample, "geno.ref", + valdim=c(length(g), 1), + g, storage="bit2", compress = "LZMA_RA.fast") + readmode.gdsn(var.geno) + } + + rm(g) + closefn.gds(gdsfile=gdsSample) + + if (verbose) { + message("End ", profileName, " ", Sys.time()) + } + + ## Success + return(0L) +} + #' @title Add information related to a specific study and specific samples #' into a GDS Sample file diff --git a/R/processStudy.R b/R/processStudy.R index 5b7dfb91f..645eb4728 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2331,7 +2331,7 @@ runExomeAncestry <- function(pedStudy, studyDF, pathProfileGDS, inferAncestry <- function(profileFile, pathProfileGDS, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic", "VCF", "bam"), + genoSource=c("snp-pileup", "generic", "VCF", "bam"), np=1L, verbose=FALSE) { profileBaseName <- basename(profileFile) @@ -2341,16 +2341,16 @@ inferAncestry <- function(profileFile, pathProfileGDS, ## BAM format is not yet implemented if (genoSource == "bam") { - stop("The bam is not release yet look to get a \'Devel\' version ", + stop("The bam is not release yet look to get a \'Devel\' version ", "or contact us") } - + ## Extract the name of the profile(s) profileName <- gsub("\\.gz$", "", profileBaseName, ignore.case=TRUE) for (extCur in c( "\\.vcf$", "\\.txt$", "\\.bam", "\\.tsv", "\\.csv")) { profileName <- gsub(extCur, "", profileName, ignore.case = TRUE) } - + ## Create required data frames studyDF <- data.frame(study.id="NotDef", study.desc="NotDef", study.platform="NotDef", stringsAsFactors=FALSE) @@ -2375,7 +2375,7 @@ inferAncestry <- function(profileFile, pathProfileGDS, }else{ stop(paste0("The format ", genoSource," is not implemented yet\n")) } - + ## Successful return(r) } @@ -2730,7 +2730,7 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' \item{\code{L}}{ a \code{numeric} representing the lower value of the 95% #' confidence interval for the AUROC obtained for the fixed values of #' super-population, \code{D} and \code{K}.} -#' \item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for +#' \item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for #' the fixed values of super-population, \code{D} and \code{K}.} #' \item{\code{H}}{ a \code{numeric} representing the higher value of the 95% #' confidence interval for the AUROC obtained for the fixed values of @@ -2746,8 +2746,8 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' \code{D} is possible.} #' } #' } -#' \item{\code{KNNSample}}{ a \code{data.frame} containing the inferred -#' ancestry for different values of \code{K} and \code{D}. The +#' \item{\code{KNNSample}}{ a \code{data.frame} containing the inferred +#' ancestry for different values of \code{K} and \code{D}. The #' \code{data.frame} contains those columns: #' \describe{ #' \item{\code{sample.id}}{ a \code{character} string representing the unique @@ -2760,11 +2760,11 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' ancestry for the specified \code{D} and \code{K} values.} #' } #' } -#' \item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred -#' ancestry for each synthetic data for different values of \code{K} and +#' \item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred +#' ancestry for each synthetic data for different values of \code{K} and #' \code{D}. #' The \code{data.frame} -#' contains those columns: +#' contains those columns: #' \describe{ #' \item{\code{sample.id}}{ a \code{character} string representing the unique #' identifier of the current synthetic data.} @@ -2772,7 +2772,7 @@ runRNAAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' number of dimensions) used to infer the ancestry. } #' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the #' number of neighbors) used to infer the ancestry. } -#' \item{\code{infer.superPop}}{ a \code{character} string representing the +#' \item{\code{infer.superPop}}{ a \code{character} string representing the #' inferred ancestry for the specified \code{D} and \code{K} values.} #' \item{\code{ref.superPop}}{ a \code{character} string representing the known #' ancestry from the reference} @@ -2899,7 +2899,7 @@ inferAncestryGeneAware <- function(profileFile, pathProfileGDS, genoSource <- arg_match(genoSource) if(genoSource == "bam"){ - stop("The bam is not release yet look to get a \'Devel\' version ", + stop("The bam is not release yet look to get a \'Devel\' version ", "or contact us") } diff --git a/man/generateProfileGDS.Rd b/man/generateProfileGDS.Rd new file mode 100644 index 000000000..51823f26a --- /dev/null +++ b/man/generateProfileGDS.Rd @@ -0,0 +1,146 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gdsWrapper_internal.R +\encoding{UTF-8} +\name{generateProfileGDS} +\alias{generateProfileGDS} +\title{Append the genotype information from a profile into the associated +Profile GDS File} +\usage{ +generateProfileGDS( + profileFile, + profileName, + listPos, + offset, + minCov = 10, + minProb = 0.999, + seqError = 0.001, + dfPedProfile, + batch, + studyDF, + pathProfileGDS, + genoSource, + verbose +) +} +\arguments{ +\item{profileFile}{a \code{character} string representing the path and the +file name of the genotype file or the bam if genoSource is snp-pileup the +fine extension must be .txt.gz, if VCF the extension must be .vcf.gz} + +\item{profileName}{a \code{character} string representing the profileName} + +\item{listPos}{a \code{data.frame} containing 2 columns. The first column, +called "snp.chromosome" contains the name of the chromosome where the +SNV is located. The second column, called "snp.position" contains the +position of the SNV on the chromosome.} + +\item{offset}{a \code{integer} to adjust if the genome start at 0 or 1.} + +\item{minCov}{a single positive \code{integer} representing the minimum +coverage needed to keep the SNVs in the analysis. Default: \code{10}.} + +\item{minProb}{a single positive \code{numeric} between 0 and 1 +representing the probability that the base change at the SNV position +is not an error. +Default: \code{0.999}.} + +\item{seqError}{a single positive \code{numeric} between 0 and 1 +representing the sequencing error rate. Default: \code{0.001}.} + +\item{dfPedProfile}{a \code{data.frame} with the information about +the sample(s). +Those are mandatory columns: "Name.ID", +"Case.ID", "Sample.Type", "Diagnosis" and "Source". All columns must be in +\code{character} strings format. The \code{data.frame} +must contain the information for all the samples passed in the +\code{listSamples} parameter.} + +\item{batch}{a single positive \code{integer} representing the current +identifier for the batch. Beware, this field is not stored anymore.} + +\item{studyDF}{a \code{data.frame} containing the information about the +study associated to the analysed sample(s). The \code{data.frame} must have +those 3 columns: "study.id", "study.desc", "study.platform". All columns +must be in \code{character} strings.} + +\item{pathProfileGDS}{a \code{character} string representing the path to +the directory where the GDS Sample files will be created.} + +\item{genoSource}{a \code{character} string with two possible values: +'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +are generated by snp-pileup (Facets) or are a generic format CSV file +with at least those columns: +'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +The 'Count' is the depth at the specified position; +'FileR' is the depth of the reference allele and +'File1A' is the depth of the specific alternative allele. +Finally the file can be a VCF file with at least those genotype +fields: GT, AD, DP.} + +\item{verbose}{a \code{logical} indicating if the function must print +messages when running.} +} +\value{ +The function returns \code{0L} when successful. +} +\description{ +This function append the genotype information from a specific +profile into the Profile GDS file. The genotype information is extracted +from a SNV file as generated by SNP-pileup or other tools. +} +\examples{ + +## Current directory +dataDir <- file.path(tempdir()) + +## Copy required file into current directory +file.copy(from=file.path(system.file("extdata/tests", package="RAIDS"), + "ex1.txt.gz"), to=dataDir) + +## The data.frame containing the information about the study +## The 3 mandatory columns: "study.id", "study.desc", "study.platform" +## The entries should be strings, not factors (stringsAsFactors=FALSE) +studyDF <- data.frame(study.id = "MYDATA", + study.desc = "Description", + study.platform = "PLATFORM", + stringsAsFactors = FALSE) + +## The data.frame containing the information about the samples +## The entries should be strings, not factors (stringsAsFactors=FALSE) +samplePED <- data.frame(Name.ID=c("ex1", "ex2"), + Case.ID=c("Patient_h11", "Patient_h12"), + Diagnosis=rep("Cancer", 2), + Sample.Type=rep("Primary Tumor", 2), + Source=rep("Databank B", 2), stringsAsFactors=FALSE) +rownames(samplePED) <- samplePED$Name.ID + +## List of SNV positions +listPositions <- data.frame(snp.chromosome=c(rep(1, 10)), + snp.position=c(3467333, 3467428, 3469375, 3469387, 3469502, 3469527, + 3469737, 3471497, 3471565, 3471618)) + +## Append genotype information to the Profile GDS file +result <- RAIDS:::generateProfileGDS(profileFile=file.path(dataDir, "ex1.txt.gz"), + profileName="ex1", listPos=listPositions, + offset=-1, minCov=10, minProb=0.999, seqError=0.001, + dfPedProfile=samplePED, batch=1, studyDF=studyDF, + pathProfileGDS=dataDir, genoSource="snp-pileup", + verbose=FALSE) + +## The function returns OL when successful +result + +## The Profile GDS file 'ex1.gds' has been created in the +## specified directory +list.files(dataDir) + +## Unlink Profile GDS file (created for demo purpose) +unlink(file.path(dataDir, "ex1.gds")) +unlink(file.path(dataDir, "ex1.txt.gz")) + + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} From 2d91898a3c5291a3ea9a6d6309bfc44326391a49 Mon Sep 17 00:00:00 2001 From: adeschen Date: Fri, 11 Apr 2025 16:47:56 -0400 Subject: [PATCH 340/385] Update example in doc for processPileupChrBin() function --- R/tools_internal.R | 28 ++++++++++++++++++++++------ man/processPileupChrBin.Rd | 36 ++++++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/R/tools_internal.R b/R/tools_internal.R index ca2f9dfe7..edda78cf8 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -491,7 +491,8 @@ extractNucleotide <- function(nucleotide, count, curNucleo) { #' @param resPileup a \code{data.frame} as generated by the \code{pileup} #' function from \code{Rsamtools} package #' -#' @param varDf a \code{data.frame} representing the positions to keep +#' @param varDf a \code{list} containing a \code{data.frame} representing +#' the positions to keep for each chromosome. #' #' @param verbose a \code{logical} indicating if messages should be printed #' @@ -511,10 +512,25 @@ extractNucleotide <- function(nucleotide, count, curNucleo) { #' #' @examples #' -#' ## Directory where demo SNP-pileup file -#' dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") -#' -#' +#' ## Demo pileup result data.frame +#' resDemo <- data.frame(seqnames=rep("chr14", 10), +#' pos=c(19069583, 19069584, 19069586, 19069588, 19069589, 19069590, +#' 19069591, 19069592, 19069609, 19069760), +#' strand=c(rep("+", 5), rep("-", 5)), +#' nucleotide=c("T", "G", "G", "C", "A", "A", "C", "T", "T", "G"), +#' count=c(5, 3, 2, 4, 1, 2, 1, 8, 7, 4)) +#' resDemo$seqnames <- factor(resDemo$seqnames) +#' resDemo$strand <- factor(resDemo$strand) +#' resDemo$nucleotide <- factor(resDemo$nucleotide) +#' +#' ## Position to keep in a data.frame format +#' varInfo <- list("chr14"=data.frame(chr=c("chr14", "chr14"), +#' start=c(19069584, 19069609), REF=c("A", "G"), ALT=c("T", "A"))) +#' +#' ## Extract information from pileup for selected positions +#' RAIDS:::processPileupChrBin(chr="chr14", resPileup=resDemo, varDf=varInfo, +#' verbose=FALSE) +#' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom dplyr group_by summarize %>% #' @importFrom rlang .data @@ -540,7 +556,7 @@ processPileupChrBin <- function(chr, resPileup, varDf, verbose) { # restrict. varDf to the region overlapping snpO vcfCur <- varDf[[chr]][varDf[[chr]]$start >= min(snpO$pos) & - varDf[[chr]]$start <= max(snpO$pos),] + varDf[[chr]]$start <= max(snpO$pos),, drop=FALSE] if (nrow(vcfCur) > 0) { diff --git a/man/processPileupChrBin.Rd b/man/processPileupChrBin.Rd index 3a87ea6d0..7057b93aa 100644 --- a/man/processPileupChrBin.Rd +++ b/man/processPileupChrBin.Rd @@ -3,18 +3,19 @@ \encoding{UTF-8} \name{processPileupChrBin} \alias{processPileupChrBin} -\title{Read a VCF file with the genotypes use for the ancestry call} +\title{Extract SNV information from pileup file for a selected chromosome} \usage{ processPileupChrBin(chr, resPileup, varDf, verbose) } \arguments{ -\item{chr}{a \code{character} string representing the name, including -the path, of a VCF file containing the SNV read counts. -The VCF must contain those genotype fields: GT, AD, DP.} +\item{chr}{a \code{character} string representing the name of the +chromosome to keep} -\item{resPileup}{result from pileup} +\item{resPileup}{a \code{data.frame} as generated by the \code{pileup} +function from \code{Rsamtools} package} -\item{varDf}{a \code{data.frame} representing the positions to keep} +\item{varDf}{a \code{list} containing a \code{data.frame} representing +the positions to keep for each chromosome.} \item{verbose}{a \code{logical} indicating if messages should be printed} } @@ -34,16 +35,31 @@ nucleotide} } } \description{ -The function reads VCF file and +The function reads pileup file and returns a \code{data.frame} containing the information about the read counts for the SNVs present in -the VCF. +the selected chromosome. } \examples{ -## Directory where demo SNP-pileup file -dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") +## Demo pileup result data.frame +resDemo <- data.frame(seqnames=rep("chr14", 10), + pos=c(19069583, 19069584, 19069586, 19069588, 19069589, 19069590, + 19069591, 19069592, 19069609, 19069760), + strand=c(rep("+", 5), rep("-", 5)), + nucleotide=c("T", "G", "G", "C", "A", "A", "C", "T", "T", "G"), + count=c(5, 3, 2, 4, 1, 2, 1, 8, 7, 4)) +resDemo$seqnames <- factor(resDemo$seqnames) +resDemo$strand <- factor(resDemo$strand) +resDemo$nucleotide <- factor(resDemo$nucleotide) +## Position to keep in a data.frame format +varInfo <- list("chr14"=data.frame(chr=c("chr14", "chr14"), + start=c(19069584, 19069609), REF=c("A", "G"), ALT=c("T", "A"))) + +## Extract information from pileup for selected positions +RAIDS:::processPileupChrBin(chr="chr14", resPileup=resDemo, varDf=varInfo, + verbose=FALSE) } \author{ From f9c7db5deb437e8f6ac3ed2a21543b0e19b984af Mon Sep 17 00:00:00 2001 From: belleau Date: Fri, 11 Apr 2025 17:14:42 -0400 Subject: [PATCH 341/385] Update to version 1.5.1 --- DESCRIPTION | 2 +- inst/NEWS.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 094c9506a..58f5ea55c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 1.5.0 +Version: 1.5.1 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", diff --git a/inst/NEWS.md b/inst/NEWS.md index 9cbf360fc..2b8284282 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -1,3 +1,10 @@ +CHANGES IN VERSION 1.5.1 +------------------------ + +SIGNIFICANT USER-VISIBLE CHANGES + + o Intagration of Rsamtools + CHANGES IN VERSION 1.3.3 ------------------------ From 3c005df91719af654a966002a15e9406d9774950 Mon Sep 17 00:00:00 2001 From: krasnitz Date: Fri, 11 Apr 2025 17:35:13 -0400 Subject: [PATCH 342/385] Update RAIDS.Rmd --- vignettes/RAIDS.Rmd | 101 +++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 58 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index db481ed17..2e489d9f9 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -58,27 +58,17 @@ the following: # Introduction -Multiple methods have been implemented to infer ancestry from germline DNA -sequence [@Price2006; @Pritchard2000; @Alexander2009]. However, genotyping of -DNA from matched normal specimens is not part of standard clinical practice -and is not performed routinely outside academic clinical centers. -In sum, matched germline DNA sequence is often missing for cancer-derived -molecular data. In such cases, having the possibility to infer ancestry -from tumor-derived data would be beneficial. - -The **RAIDS** package implements an inference procedure that has been -specifically developed to accurately infer genetic ancestry from -cancer-derived sequences. The current version can handle cancer-derived +The **RAIDS** (Robust Ancerstry Inference using Data Synthesis) package enables accurate and robust inference of genetic ancestry from human molecular data other than whole-genome or whole-exome sequences of cancer-free DNA. The current version can handle sequences of: -* tumor exomes +* whole genomes +* whole exomes * targeted gene panels -* RNA +* RNA, -The **RAIDS** package implements a data synthesis method that, for any given -cancer-derived sequence profile, enables -on the one hand, profile-specific inference -parameter optimization and on the other hand, a profile-specific inference +including those from cancer-derived nucleic acids. The **RAIDS** package implements a data synthesis method that, for any given +molecular profile, enables, on the one hand, profile-specific inference +parameter optimization and, on the other hand, a profile-specific inference accuracy estimate.
@@ -103,12 +93,11 @@ BiocManager::install("RAIDS")
-# Main Steps +# Using RAIDS: step-by-step explanation -This is an overview of the genetic ancestry inference from cancer-derived -molecular data: +This is an overview of the RAIDS inferential framework: -```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference process.", out.width='130%', results='asis', warning=FALSE, message=FALSE} +```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference procedure.", out.width='130%', results='asis', warning=FALSE, message=FALSE} knitr::include_graphics("MainSteps_v05.png") ``` @@ -116,11 +105,11 @@ The main steps are: **Step 1.** Set-up and provide population reference files -**Step 2** Sample the reference data for donor genotypes to be used for synthesis and optimize ancestry inference parameters +**Step 2** Sample the reference data for donors whose genotypes will be used for synthesis and optimize ancestry inference parameters using synthetic data -**Step 3** Infer ancestry for the subjects of the external study +**Step 3** Infer ancestry -**Step 4** Present and interpret the results +**Step 4** Summarize and visualize the results These steps are described in detail in the following. @@ -131,10 +120,9 @@ These steps are described in detail in the following. ## Step 1. Set-up and provide population reference files -### 1.1 Create a directory structure +### 1.1 Create a working directory structure -First, a specific directory structure should be created. The structure must -correspond to this: +First, the following working directory structure should be created: ``` @@ -150,7 +138,7 @@ workingDirectory/
-This following code creates a temporary working directory structure where the +The following code creates a temporary working directory structure where the example will be run. @@ -176,9 +164,9 @@ if (!dir.exists(pathWorkingDirectory)) { ### 1.2 Download the population reference files -The population reference files should be downloaded in the *data/refGDS* +The population reference files should be downloaded into the *data/refGDS* sub-directory. This following code downloads the complete pre-processed files -for 1000 Genomes (1KG), in hg38. The size of the 1KG GDS file is 15GB. +for 1000 Genomes (1KG), for the hg38 build of the human genome, in the GDS format. The size of the 1KG GDS file is 15GB. ``` @@ -196,15 +184,13 @@ cd -
-For demonstration purpose, a small +For illustrative purposes, a small **population reference GDS file** (called _ex1_good_small_1KG.gds_) and a small **population reference SNV Annotation GDS file** (called _ex1_good_small_1KG_Annot.gds_) are -included in this package. Beware that those two files should not be used to -run a real ancestry inference. The results obtained with those files won't be -reliable. +included in this package. Please note that these "mini-reference" files are for illustrative purposes only and cannot be used to infer genetic ancestry reliably. -In this running example, the demonstration files are copied in the required +In this example, the mini-reference files are copied to the *data/refGDS* directory. ```{r copyRefFile, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} @@ -217,8 +203,8 @@ library(RAIDS) ############################################################################# ## The population reference GDS file and SNV Annotation GDS file ## need to be located in the same sub-directory. -## Note that the population reference GDS file used for this example is a -## simplified version and CANNOT be used for any real analysis +## Note that the mini-reference GDS file used for this example is +## NOT sufficient for reliable inference ############################################################################# ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata", package="RAIDS") @@ -236,10 +222,10 @@ file.copy(fileAnnotGDS, file.path(pathWorkingDirectoryData, "refGDS")) ## Step 2 Ancestry inference with RAIDS -### 2.1 Set-up required directories +### 2.1 Set-up the required directories -All required directories need to be created. In addition, the path to -the reference files are kept in variables that will be used later. +All required directories are created at this point. In addition, the paths to +the reference files are stored in variables for later use. ```{r installRaids, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} @@ -269,47 +255,46 @@ if (!dir.exists(pathProfileGDS)) {
-### 2.2 Sample reference donor profiles from the reference data +### 2.2 Sample the reference data for donors whose genotypes will be used for synthesis and optimize ancestry inference parameters using synthetic data -With the 1KG reference, we recommend sampling 30 donor profiles per population. +With the 1KG reference, we recommend sampling 30 donor profiles per +sub-continental population. For reproducibility, be sure to use the same random-number generator seed. -In the following code, only 2 profiles per population are sampled from the +In the following code, only 2 individual profiles per +sub-continental population are sampled from the demo population GDS file: ```{r sampling, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# -## Fix seed to ensure reproducible results +## Set up the following random number generator seed to reproduce the expected results ############################################################################# set.seed(3043) ############################################################################# -## Select the profiles from the population reference GDS file for -## the synthetic data. -## Here we select 2 profiles from the simplified 1KG GDS for each -## subcontinental-level. -## Normally, we would use 30 profiles for each subcontinental-level. -## The 1KG files in this example only have 6 profiles for each -## subcontinental-level (for demo purpose only). +## Choose the profiles from the population reference GDS file for +## data synthesis. +## Here we choose 2 profiles perm subcontinental population from the mini 1KG GDS file. +## Normally, we would use 30 randomly chosen profiles per subcontinental population. ############################################################################# dataRef <- select1KGPopForSynthetic(fileReferenceGDS=refGenotype, nbProfiles=2L) ``` -The output object is going to be used later. +
-### 2.3 Perform the ancestry inference +### 2.3 Infer ancestry -Ancestry inference can be done in one function call. Within a single function +Within a single function call, data synthesis is performed, the synthetic data are used to optimize the inference parameters and, with these, the -ancestry of the input profile donor is inferred. +ancestry is inferred from the input sequence profile. -According to the type of input data (RNA or DNA), a specific function +According to the type of input data (RNA or DNA sequence), a specific function should be called. The *inferAncestry()* function is used for DNA profiles while the *inferAncestryGeneAware()* function is RNA specific. @@ -324,7 +309,7 @@ wild-type homozygous at the selected positions in the reference. The VCF file must be gzipped. A generic SNP file can replace the VCF file (*genoSource=c("generic")*). -The format is coma separated and the mandatory columns are: +The format is comma separated and the mandatory columns are: * _Chromosome_: The name of the chromosome * _Position_: The position on the chromosome @@ -459,7 +444,7 @@ createAUROCGraph(dfAUROC=resOut$paraSample$dfAUROC, title="Example ex1") ``` In this specific example, the performances are lower than expected -with a real profile and a complete reference population file. +with a realistic sequence profile and a complete reference population file.

From 9969cfc715b747be185674a24dc1cffca6c36060 Mon Sep 17 00:00:00 2001 From: belleau Date: Sun, 13 Apr 2025 14:49:33 -0400 Subject: [PATCH 343/385] Add function createProfile and adapted the rest --- R/gdsWrapper_internal.R | 12 +- R/processStudy.R | 4 +- R/processStudy_internal.R | 256 +++++++++++++++++++++++++++++++++++-- R/tools_internal.R | 40 +++--- man/createProfile.Rd | 149 +++++++++++++++++++++ man/generateProfileGDS.Rd | 3 + man/processPileupChrBin.Rd | 14 +- man/readSNVBAM.Rd | 2 +- man/wrapperAncestry.Rd | 23 ++-- 9 files changed, 452 insertions(+), 51 deletions(-) create mode 100644 man/createProfile.Rd diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index a9a651eb8..e052790c4 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -612,6 +612,8 @@ generateGDS1KGgenotypeFromSNPPileup <- function(pathGeno, #' Finally the file can be a VCF file with at least those genotype #' fields: GT, AD, DP. #' +#' @param paramProfileGDS a \code{list} parameters ... +#' #' @param verbose a \code{logical} indicating if the function must print #' messages when running. #' @@ -677,7 +679,7 @@ generateGDS1KGgenotypeFromSNPPileup <- function(pathGeno, generateProfileGDS <- function(profileFile, profileName, listPos, offset, minCov=10, minProb=0.999, seqError=0.001, dfPedProfile, batch, studyDF, pathProfileGDS, - genoSource, verbose) { + genoSource, paramProfileGDS, verbose) { # File with the description of the SNP keep # if(genoSource == "VCF"){ @@ -708,7 +710,13 @@ generateProfileGDS <- function(profileFile, profileName, matSample <- readSNVVCF(profileFile, profileName=profileName, offset) } else if(genoSource == "bam"){ - #tmpProfile <- gsub(".vcf.gz", "",listMat[pos]) + listPos$start <- listPos$start - offset + matSample <- readSNVBAM(fileName=profileFile, + varSelected=listPos, + paramSNVBAM=paramProfileGDS, + verbose=verbose) + listPos$start <- listPos$start + offset + colnames(listPos)[1:2] <- c("snp.chromosome", "snp.position") } # matAll <- merge(matSample[,c( "Chromosome", "Position", # "File1R", "File1A", diff --git a/R/processStudy.R b/R/processStudy.R index 645eb4728..af89c042e 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2369,7 +2369,7 @@ inferAncestry <- function(profileFile, pathProfileGDS, ## Run ancestry inference if (genoSource %in% c("snp-pileup", "generic", "VCF")) { r <- wrapperAncestry(pedStudy, studyDF, pathProfileGDS, - pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, + profileFile, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, genoSource, studyType="LD", np=np, verbose) }else{ @@ -2931,7 +2931,7 @@ inferAncestryGeneAware <- function(profileFile, pathProfileGDS, if(genoSource %in% c("snp-pileup", "generic", "VCF")){ r <- wrapperAncestry(pedStudy, studyDF, pathProfileGDS, - pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, + profileFile, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, genoSource, studyType="GeneAware", np=np, blockTypeID=blockTypeID, verbose) }else{ diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index d21d83a65..761dfd9e7 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2607,9 +2607,9 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, # saveRDS(synthKNN$matKNN, file.path(pathOutProfile, # paste0("KNN.synt.", currentProfile, ".", x, ".rds"))) return(synthKNN$matKNN) - }, sampleRM=sampleRM, gdsProfile=gdsProfile, studyDFSyn=studyDFSyn, + }, sampleRM=sampleRM, gdsProfile=gdsProfile, studyDFSyn=studyDFSyn, spRef=spRef, currentProfile=currentProfile) - + resSyn <- do.call(rbind, resSyn) ## Extract the super-population information from the 1KG GDS file ## for profiles associated to the synthetic study @@ -2641,9 +2641,9 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, closefn.gds(gdsProfile) resSyn[[paste0("ref.superPop")]] <- pedSyn[resSyn$sample.id, "superPop"] - colnames(resSyn) <- c("sample.id", "D", "K", "infer.superPop", + colnames(resSyn) <- c("sample.id", "D", "K", "infer.superPop", "ref.superPop") - + res <- list(pcaSample=resCall$pcaSample, # PCA of the profile + 1KG paraSample=resCall$paraSample, # Result of the parameter selection KNNSample=resCall$KNNSample$matKNN, # KNN for the profile @@ -3236,6 +3236,224 @@ runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, return(0L) } +#' @title Create the Profile GDS file(s) for one or multiple specific profiles +#' using the information from a RDS Sample description file and the 1KG +#' GDS file +#' +#' @description The function uses the information for the Reference GDS file +#' and the RDS Sample Description file to create the Profile GDS file. One +#' Profile GDS file is created per profile. One Profile GDS file will be +#' created for each entry present in the \code{listProfiles} parameter. +#' +#' @param profileFile a \code{character} string representing the path to the +#' file: with genotype and the allele information of the profile A profile would have an +#' associated file called +#' if genoSource is "VCF", then "*vcf.gz", +#' if genoSource is "generic", then "*.txt.gz" +#' if genoSource is "snp-pileup", then "*.txt.gz". +#' if genoSource is "bam", then "*.bam" and "*.bai". +#' +#' @param profileName a \code{character} string representing the the profile Name.ID +#' +#' @param filePedRDS a \code{character} string representing the path to the +#' RDS file that contains the information about the sample to analyse. +#' The RDS file must +#' include a \code{data.frame} with those mandatory columns: "Name.ID", +#' "Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +#' \code{character} strings. The \code{data.frame} +#' must contain the information for all the samples passed in the +#' \code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +#' can be defined. +#' +#' @param pedStudy a \code{data.frame} with those mandatory columns: "Name.ID", +#' "Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +#' \code{character} strings (no factor). The \code{data.frame} +#' must contain the information for all the samples passed in the +#' \code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +#' can be defined. +#' +#' @param fileNameGDS a \code{character} string representing the file name of +#' the Reference GDS file. The file must exist. +#' +#' @param batch a single positive \code{integer} representing the current +#' identifier for the batch. Beware, this field is not stored anymore. +#' Default: \code{1}. +#' +#' @param studyDF a \code{data.frame} containing the information about the +#' study associated to the analysed sample(s). The \code{data.frame} must have +#' those 3 columns: "study.id", "study.desc", "study.platform". All columns +#' must be in \code{character} strings (no factor). +#' +#' @param listProfiles a \code{vector} of \code{character} string corresponding +#' to the profile identifiers that will have a Profile GDS file created. The +#' profile identifiers must be present in the "Name.ID" column of the Profile +#' RDS file passed to the \code{filePedRDS} parameter. +#' If \code{NULL}, all profiles present in the \code{filePedRDS} are selected. +#' Default: \code{NULL}. +#' +#' @param pathProfileGDS a \code{character} string representing the path to +#' the directory where the Profile GDS files will be created. +#' Default: \code{NULL}. +#' +#' @param genoSource a \code{character} string with two possible values: +#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +#' are generated by snp-pileup (Facets) or are a generic format CSV file +#' with at least those columns: +#' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +#' The 'Count' is the depth at the specified position; +#' 'FileR' is the depth of the reference allele and +#' 'File1A' is the depth of the specific alternative allele. +#' Finally the file can be a VCF file with at least those genotype +#' fields: GT, AD, DP. +#' +#' @param verbose a \code{logical} indicating if message information should be +#' printed. Default: \code{FALSE}. +#' +#' @return The function returns \code{0L} when successful. +#' +#' @examples +#' +#' ## Path to the demo 1KG GDS file is located in this package +#' dataDir <- system.file("extdata/tests", package="RAIDS") +#' fileGDS <- file.path(dataDir, "ex1_good_small_1KG.gds") +#' +#' ## The data.frame containing the information about the study +#' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" +#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) +#' studyDF <- data.frame(study.id = "MYDATA", +#' study.desc = "Description", +#' study.platform = "PLATFORM", +#' stringsAsFactors = FALSE) +#' +#' ## The data.frame containing the information about the samples +#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) +#' samplePED <- data.frame(Name.ID=c("ex1"), +#' Case.ID=c("Patient_h11"), +#' Diagnosis=rep("Cancer"), +#' Sample.Type=c("Primary Tumor"), +#' Source=c("Databank B"), stringsAsFactors=FALSE, +#' drop=FALSE) +#' rownames(samplePED) <- samplePED$Name.ID +#' +#' ## Create the Profile GDS File for samples in 'listSamples' vector +#' ## (in this case, samples "ex1") +#' ## The Profile GDS file is created in the pathProfileGDS directory +#' result <- RAIDS:::createProfile(profileFile=file.path(dataDir, "ex1.txt.gz"), +#' profileName="ex1", +#' pedStudy=samplePED, fileNameGDS=fileGDS, +#' studyDF=studyDF, listProfiles=c("ex1"), +#' pathProfileGDS=tempdir(), +#' genoSource="snp-pileup", +#' verbose=FALSE) +#' +#' ## The function returns OL when successful +#' result +#' +#' ## The Profile GDS file 'ex1.gds' has been created in the +#' ## specified directory +#' list.files(tempdir()) +#' +#' ## Remove Profile GDS file (created for demo purpose) +#' unlink(file.path(tempdir(), "ex1.gds"), force=TRUE) +#' +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom gdsfmt createfn.gds put.attr.gdsn closefn.gds read.gdsn +#' @importFrom S4Vectors isSingleNumber +#' @importFrom rlang arg_match +#' @encoding UTF-8 +#' @keywords internal + +createProfile <- function(profileFile, profileName, + filePedRDS=NULL, pedStudy=NULL, fileNameGDS, + batch=1, studyDF, listProfiles=NULL, + pathProfileGDS=NULL, + genoSource=c("snp-pileup", "generic", "VCF", "bam"), + paramProfile=list(ScanBamParam=NULL, + PileupParam=NULL, + yieldSize=5000000), + verbose=FALSE) { + + ## When filePedRDS is defined and pedStudy is null + if (!(is.null(filePedRDS)) && is.null(pedStudy)) { + ## The filePedRDS must be a character string and the file must exists + if (!(is.character(filePedRDS) && (file.exists(filePedRDS)))) { + stop("The \'filePedRDS\' must be a character string representing", + " the RDS Sample information file. The file must exist.") + } + ## Open the RDS Sample information file + pedStudy <- readRDS(file=filePedRDS) + } else if (!(is.null(filePedRDS) || is.null(pedStudy))) { + stop("Both \'filePedRDS\' and \'pedStudy\' parameters cannot be ", + "defined at the same time.") + } else if (is.null(filePedRDS) && is.null(pedStudy)) { + stop("One of the parameter \'fineNamePED\' of \'pedStudy\' must ", + "be defined.") + } + + ## Validate input parameters + # validateCreateStudy2GDS1KG(pathGeno=pathGeno, pedStudy=pedStudy, + # fileNameGDS=fileNameGDS, batch=batch, studyDF=studyDF, + # listProfiles=listProfiles, pathProfileGDS=pathProfileGDS, + # genoSource=genoSource, verbose=verbose) + + genoSource <- arg_match(genoSource) + + ## Read the Reference GDS file + gdsReference <- snpgdsOpen(filename=fileNameGDS) + + ## Extract the chromosome and position information for all SNPs in 1KG GDS + + listPos <- NULL + if(genoSource == "bam"){ + alDf <- read.gdsn(index.gdsn(gdsReference, "snp.allele")) + alDf <- matrix(unlist(strsplit(alDf,"\\/")),nrow=2) + listPos <- data.frame(chr = paste0("chr",read.gdsn(index.gdsn(gdsReference, "snp.chromosome"))), + start = read.gdsn(index.gdsn(gdsReference, "snp.position")), + REF = alDf[1,], + ALT = alDf[2,], + stringsAsFactors = FALSE + ) + listChr <- unique(listPos$chr) + # We can optimize + listPos <- lapply(listChr, + FUN=function(x, varDf){ + return(varDf[which(varDf$chr == x),]) + }, + varDf=listPos) + names(listPos) <- listChr + rm(alDf,listChr) + } else{ + listPos <- data.frame(snp.chromosome=read.gdsn(index.gdsn(node=gdsReference, "snp.chromosome")), + snp.position=read.gdsn(index.gdsn(node=gdsReference, "snp.position"))) + } + ## Create a data.frame containing the information + + # Need to reformat for bam in varDf + + if(verbose) { + message("Start ", Sys.time()) + message("Sample info DONE ", Sys.time()) + } + + generateProfileGDS(profileFile=profileFile, profileName=profileName, + listPos=listPos, offset=-1, minCov=10, + minProb=0.999, seqError=0.001, dfPedProfile=pedStudy, batch=batch, + studyDF=studyDF, pathProfileGDS=pathProfileGDS, + genoSource=genoSource, paramProfileGDS=paramProfile, verbose=verbose) + + if(verbose) { + message("Genotype DONE ", Sys.time()) + } + + ## Close 1KG GDS file + closefn.gds(gdsReference) + + ## Return successful code + return(0L) +} + + #' @title Run most steps leading to the ancestry inference call #' on a specific profile (RNA or DNA) #' @@ -3312,6 +3530,8 @@ runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' type used to extract the block identifiers. The block type must be #' present in the GDS Reference Annotation file. #' +#' @param paramAncestry a \code{list} parameters ... +#' #' @param verbose a \code{logical} indicating if messages should be printed #' to show how the different steps in the function. Default: \code{FALSE}. #' @@ -3541,20 +3761,38 @@ runWrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, #' @encoding UTF-8 #' @keywords internal wrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, - pathGeno, fileReferenceGDS, fileReferenceAnnotGDS, + profileFile, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, genoSource=c("snp-pileup", "generic", "VCF"), studyType=c("LD", "GeneAware"), np=1L, blockTypeID=NULL, + paramAncestry=list(ScanBamParam=NULL, + PileupParam=NULL, + yieldSize=5000000), verbose=FALSE) { genoSource <- arg_match(genoSource) listProfiles <- pedStudy[, "Name.ID"] + # createProfile <- function(profileFile, profileName, + # filePedRDS=NULL, pedStudy=NULL, fileNameGDS, + # batch=1, studyDF, listProfiles=NULL, + # pathProfileGDS=NULL, + # genoSource=c("snp-pileup", "generic", "VCF", "bam"), + # paramProfile=list(ScanBamParam=NULL, + # PileupParam=NULL, + # yieldSize=5000000), + # verbose=FALSE) + createProfile(profileFile=profileFile, profileName=pedStudy$Name.ID[1], + pedStudy=pedStudy, fileNameGDS=fileReferenceGDS, + studyDF=studyDF, pathProfileGDS=pathProfileGDS, + genoSource=genoSource, paramProfile=paramAncestry, + verbose=verbose) + # createStudy2GDS1KG(pathGeno=pathGeno, pedStudy=pedStudy, + # fileNameGDS=fileReferenceGDS, listProfiles=listProfiles, + # studyDF=studyDF, pathProfileGDS=pathProfileGDS, genoSource=genoSource, + # verbose=verbose) + - createStudy2GDS1KG(pathGeno=pathGeno, pedStudy=pedStudy, - fileNameGDS=fileReferenceGDS, listProfiles=listProfiles, - studyDF=studyDF, pathProfileGDS=pathProfileGDS, genoSource=genoSource, - verbose=verbose) ## Open the 1KG GDS file (demo version) gdsReference <- snpgdsOpen(fileReferenceGDS) diff --git a/R/tools_internal.R b/R/tools_internal.R index ca2f9dfe7..dc1aa5086 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -438,33 +438,33 @@ readSNVVCF <- function(fileName, #' @title Filtering the read counts for a specific nucleotide #' -#' @description The function returns the read counts for the specific +#' @description The function returns the read counts for the specific #' nucleotide or zero when read counts are not available. #' -#' @param nucleotide a \code{vector} of a \code{character} strings +#' @param nucleotide a \code{vector} of a \code{character} strings #' representing the nucleotides (ex: A, C, G or T). #' #' -#' @param count a \code{vector} of \code{numeric} representing the counts for -#' each nucleotide listed in \code{nucleotide} parameter. +#' @param count a \code{vector} of \code{numeric} representing the counts for +#' each nucleotide listed in \code{nucleotide} parameter. #' -#' @param curNucleo a \code{character} strings representing the nucleotide +#' @param curNucleo a \code{character} strings representing the nucleotide #' that will be retained (ex: A, C, G or T). #' -#' @return a \code{numeric} representing the counts for the selected +#' @return a \code{numeric} representing the counts for the selected #' nucleotide. The default value is \code{0}. #' #' @examples #' #' ## Nucleotides vector #' nuc <- c("A", "G", "C", "T") -#' +#' #' ## Count vector #' cnt <- c(100, 200, 4, 32) #' #' ## Return the count for the nucleotide "G" #' RAIDS:::extractNucleotide(nucleotide=nuc, count=cnt, curNucleo="G") -#' +#' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @encoding UTF-8 #' @keywords internal @@ -474,7 +474,7 @@ extractNucleotide <- function(nucleotide, count, curNucleo) { res <- 0 if(length(tmp) == 1) res <- count[tmp] return(res) - + } @@ -485,10 +485,10 @@ extractNucleotide <- function(nucleotide, count, curNucleo) { #' containing the information about the read counts for the SNVs present in #' the selected chromosome. #' -#' @param chr a \code{character} string representing the name of the +#' @param chr a \code{character} string representing the name of the #' chromosome to keep #' -#' @param resPileup a \code{data.frame} as generated by the \code{pileup} +#' @param resPileup a \code{data.frame} as generated by the \code{pileup} #' function from \code{Rsamtools} package #' #' @param varDf a \code{data.frame} representing the positions to keep @@ -523,12 +523,12 @@ extractNucleotide <- function(nucleotide, count, curNucleo) { processPileupChrBin <- function(chr, resPileup, varDf, verbose) { resCur <- NULL - + ## Assign FALSE to verbose by default if (is.null(verbose)) { verbose <- FALSE } - + if (chr %in% names(varDf)) { keep <- which(resPileup$seqnames == chr) @@ -547,13 +547,13 @@ processPileupChrBin <- function(chr, resPileup, varDf, verbose) { # Get the positions to keep in resPileup (snpO) tmpTime <- system.time( {z <- cbind( c(vcfCur$start, snpO$pos, vcfCur$start), - c(rep(-1, nrow(vcfCur)), rep(0, nrow(snpO)), + c(rep(-1, nrow(vcfCur)), rep(0, nrow(snpO)), rep(1, nrow(vcfCur))), c(seq_len(nrow(vcfCur)), seq_len(nrow(snpO)), seq_len(nrow(vcfCur)))) z <- z[order(z[,1]),] listKeep <- which(cumsum(z[,2]) < 0 & z[,2]==0)} ) - + if (verbose) { message("processPileupChrBin selected pos user ", round(tmpTime[1],3), " system ", round(tmpTime[2],3), @@ -561,19 +561,19 @@ processPileupChrBin <- function(chr, resPileup, varDf, verbose) { # summarize by position with the for base tmpTime <- system.time(resCur <- as.data.frame(snpO[z[listKeep, 3],] %>% - group_by(.data$pos) %>% + group_by(.data$pos) %>% summarize(seqnames=.data$seqnames[1], A=extractNucleotide(.data$nucleotide,.data$count, "A"), C=extractNucleotide(.data$nucleotide,.data$count, "C"), G=extractNucleotide(.data$nucleotide,.data$count, "G"), T=extractNucleotide(.data$nucleotide,.data$count, "T"), count=sum(.data$count)))) - + if (verbose) { message("processPileupChrBin extracted nucleotides user ", round(tmpTime[1],3), " system ", round(tmpTime[2],3), " elapsed ", round(tmpTime[3],3)) } - + # Add the reference allele and the alternative allele tmpTime <- system.time({z <- cbind(c(resCur$pos, vcfCur$start, resCur$pos), c(rep(-1, nrow(resCur)), rep(0, nrow(vcfCur)), rep(1, nrow(resCur))), @@ -584,7 +584,7 @@ processPileupChrBin <- function(chr, resPileup, varDf, verbose) { resCur$ALT <- rep("N", nrow(resCur)) resCur$REF[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "REF"] resCur$ALT[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "ALT"] - resCur <- resCur[,c("seqnames", "pos", "REF", "ALT", "A", + resCur <- resCur[,c("seqnames", "pos", "REF", "ALT", "A", "C", "G", "T", "count")]} ) if(verbose) { @@ -608,7 +608,7 @@ processPileupChrBin <- function(chr, resPileup, varDf, verbose) { #' the path, of a BAM file with the index file in the same directory #' #' -#' @param paramSNVBAM a \code{data.frame} representing the position to keep +#' @param paramSNVBAM a \code{data.frame} representing #' #' @param varSelected a \code{data.frame} representing the position to keep #' diff --git a/man/createProfile.Rd b/man/createProfile.Rd new file mode 100644 index 000000000..d03a55d8a --- /dev/null +++ b/man/createProfile.Rd @@ -0,0 +1,149 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/processStudy_internal.R +\encoding{UTF-8} +\name{createProfile} +\alias{createProfile} +\title{Create the Profile GDS file(s) for one or multiple specific profiles +using the information from a RDS Sample description file and the 1KG +GDS file} +\usage{ +createProfile( + profileFile, + profileName, + filePedRDS = NULL, + pedStudy = NULL, + fileNameGDS, + batch = 1, + studyDF, + listProfiles = NULL, + pathProfileGDS = NULL, + genoSource = c("snp-pileup", "generic", "VCF", "bam"), + paramProfile = list(ScanBamParam = NULL, PileupParam = NULL, yieldSize = 5e+06), + verbose = FALSE +) +} +\arguments{ +\item{profileFile}{a \code{character} string representing the path to the +file: with genotype and the allele information of the profile A profile would have an +associated file called +if genoSource is "VCF", then "\emph{vcf.gz", +if genoSource is "generic", then "}.txt.gz" +if genoSource is "snp-pileup", then "\emph{.txt.gz". +if genoSource is "bam", then "}.bam" and "*.bai".} + +\item{profileName}{a \code{character} string representing the the profile Name.ID} + +\item{filePedRDS}{a \code{character} string representing the path to the +RDS file that contains the information about the sample to analyse. +The RDS file must +include a \code{data.frame} with those mandatory columns: "Name.ID", +"Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +\code{character} strings. The \code{data.frame} +must contain the information for all the samples passed in the +\code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +can be defined.} + +\item{pedStudy}{a \code{data.frame} with those mandatory columns: "Name.ID", +"Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +\code{character} strings (no factor). The \code{data.frame} +must contain the information for all the samples passed in the +\code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +can be defined.} + +\item{fileNameGDS}{a \code{character} string representing the file name of +the Reference GDS file. The file must exist.} + +\item{batch}{a single positive \code{integer} representing the current +identifier for the batch. Beware, this field is not stored anymore. +Default: \code{1}.} + +\item{studyDF}{a \code{data.frame} containing the information about the +study associated to the analysed sample(s). The \code{data.frame} must have +those 3 columns: "study.id", "study.desc", "study.platform". All columns +must be in \code{character} strings (no factor).} + +\item{listProfiles}{a \code{vector} of \code{character} string corresponding +to the profile identifiers that will have a Profile GDS file created. The +profile identifiers must be present in the "Name.ID" column of the Profile +RDS file passed to the \code{filePedRDS} parameter. +If \code{NULL}, all profiles present in the \code{filePedRDS} are selected. +Default: \code{NULL}.} + +\item{pathProfileGDS}{a \code{character} string representing the path to +the directory where the Profile GDS files will be created. +Default: \code{NULL}.} + +\item{genoSource}{a \code{character} string with two possible values: +'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +are generated by snp-pileup (Facets) or are a generic format CSV file +with at least those columns: +'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +The 'Count' is the depth at the specified position; +'FileR' is the depth of the reference allele and +'File1A' is the depth of the specific alternative allele. +Finally the file can be a VCF file with at least those genotype +fields: GT, AD, DP.} + +\item{verbose}{a \code{logical} indicating if message information should be +printed. Default: \code{FALSE}.} +} +\value{ +The function returns \code{0L} when successful. +} +\description{ +The function uses the information for the Reference GDS file +and the RDS Sample Description file to create the Profile GDS file. One +Profile GDS file is created per profile. One Profile GDS file will be +created for each entry present in the \code{listProfiles} parameter. +} +\examples{ + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata/tests", package="RAIDS") +fileGDS <- file.path(dataDir, "ex1_good_small_1KG.gds") + +## The data.frame containing the information about the study +## The 3 mandatory columns: "study.id", "study.desc", "study.platform" +## The entries should be strings, not factors (stringsAsFactors=FALSE) +studyDF <- data.frame(study.id = "MYDATA", + study.desc = "Description", + study.platform = "PLATFORM", + stringsAsFactors = FALSE) + +## The data.frame containing the information about the samples +## The entries should be strings, not factors (stringsAsFactors=FALSE) +samplePED <- data.frame(Name.ID=c("ex1"), + Case.ID=c("Patient_h11"), + Diagnosis=rep("Cancer"), + Sample.Type=c("Primary Tumor"), + Source=c("Databank B"), stringsAsFactors=FALSE, + drop=FALSE) +rownames(samplePED) <- samplePED$Name.ID + +## Create the Profile GDS File for samples in 'listSamples' vector +## (in this case, samples "ex1") +## The Profile GDS file is created in the pathProfileGDS directory +result <- RAIDS:::createProfile(profileFile=file.path(dataDir, "ex1.txt.gz"), + profileName="ex1", + pedStudy=samplePED, fileNameGDS=fileGDS, + studyDF=studyDF, listProfiles=c("ex1"), + pathProfileGDS=tempdir(), + genoSource="snp-pileup", + verbose=FALSE) + +## The function returns OL when successful +result + +## The Profile GDS file 'ex1.gds' has been created in the +## specified directory +list.files(tempdir()) + +## Remove Profile GDS file (created for demo purpose) +unlink(file.path(tempdir(), "ex1.gds"), force=TRUE) + + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} diff --git a/man/generateProfileGDS.Rd b/man/generateProfileGDS.Rd index 51823f26a..bfa95cd9f 100644 --- a/man/generateProfileGDS.Rd +++ b/man/generateProfileGDS.Rd @@ -19,6 +19,7 @@ generateProfileGDS( studyDF, pathProfileGDS, genoSource, + paramProfileGDS, verbose ) } @@ -77,6 +78,8 @@ The 'Count' is the depth at the specified position; Finally the file can be a VCF file with at least those genotype fields: GT, AD, DP.} +\item{paramProfileGDS}{a \code{list} parameters ...} + \item{verbose}{a \code{logical} indicating if the function must print messages when running.} } diff --git a/man/processPileupChrBin.Rd b/man/processPileupChrBin.Rd index 3a87ea6d0..6cf91c5d1 100644 --- a/man/processPileupChrBin.Rd +++ b/man/processPileupChrBin.Rd @@ -3,16 +3,16 @@ \encoding{UTF-8} \name{processPileupChrBin} \alias{processPileupChrBin} -\title{Read a VCF file with the genotypes use for the ancestry call} +\title{Extract SNV information from pileup file for a selected chromosome} \usage{ processPileupChrBin(chr, resPileup, varDf, verbose) } \arguments{ -\item{chr}{a \code{character} string representing the name, including -the path, of a VCF file containing the SNV read counts. -The VCF must contain those genotype fields: GT, AD, DP.} +\item{chr}{a \code{character} string representing the name of the +chromosome to keep} -\item{resPileup}{result from pileup} +\item{resPileup}{a \code{data.frame} as generated by the \code{pileup} +function from \code{Rsamtools} package} \item{varDf}{a \code{data.frame} representing the positions to keep} @@ -34,10 +34,10 @@ nucleotide} } } \description{ -The function reads VCF file and +The function reads pileup file and returns a \code{data.frame} containing the information about the read counts for the SNVs present in -the VCF. +the selected chromosome. } \examples{ diff --git a/man/readSNVBAM.Rd b/man/readSNVBAM.Rd index c72955db5..286826430 100644 --- a/man/readSNVBAM.Rd +++ b/man/readSNVBAM.Rd @@ -18,7 +18,7 @@ the path, of a BAM file with the index file in the same directory} \item{varSelected}{a \code{data.frame} representing the position to keep} -\item{paramSNVBAM}{a \code{data.frame} representing the position to keep} +\item{paramSNVBAM}{a \code{data.frame} representing} \item{verbose}{a \code{logical} indicating if messages should be printed to show how the different steps in the function. Default: \code{FALSE}.} diff --git a/man/wrapperAncestry.Rd b/man/wrapperAncestry.Rd index 291dbd32a..22cb21a71 100644 --- a/man/wrapperAncestry.Rd +++ b/man/wrapperAncestry.Rd @@ -10,7 +10,7 @@ wrapperAncestry( pedStudy, studyDF, pathProfileGDS, - pathGeno, + profileFile, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, @@ -19,6 +19,7 @@ wrapperAncestry( studyType = c("LD", "GeneAware"), np = 1L, blockTypeID = NULL, + paramAncestry = list(ScanBamParam = NULL, PileupParam = NULL, yieldSize = 5e+06), verbose = FALSE ) } @@ -39,15 +40,6 @@ must be in \code{character} strings (no factor).} the directory where the GDS Profile files will be created. Default: \code{NULL}.} -\item{pathGeno}{a \code{character} string representing the path to the -directory containing the VCF output of SNP-pileup for each sample. The -SNP-pileup files must be compressed (gz files) and have the name identifiers -of the samples. A sample with "Name.ID" identifier would have an -associated file called -if genoSource is "VCF", then "Name.ID.vcf.gz", -if genoSource is "generic", then "Name.ID.generic.txt.gz" -if genoSource is "snp-pileup", then "Name.ID.txt.gz".} - \item{fileReferenceGDS}{a \code{character} string representing the file name of the Reference GDS file. The file must exist.} @@ -91,8 +83,19 @@ threads to be used. Default: \code{1L}.} type used to extract the block identifiers. The block type must be present in the GDS Reference Annotation file.} +\item{paramAncestry}{a \code{list} parameters ...} + \item{verbose}{a \code{logical} indicating if messages should be printed to show how the different steps in the function. Default: \code{FALSE}.} + +\item{pathGeno}{a \code{character} string representing the path to the +directory containing the VCF output of SNP-pileup for each sample. The +SNP-pileup files must be compressed (gz files) and have the name identifiers +of the samples. A sample with "Name.ID" identifier would have an +associated file called +if genoSource is "VCF", then "Name.ID.vcf.gz", +if genoSource is "generic", then "Name.ID.generic.txt.gz" +if genoSource is "snp-pileup", then "Name.ID.txt.gz".} } \value{ a \code{list} containing 4 entries: From f0747f04d6bb0b7dec5d2e9f32cb64cf87a15879 Mon Sep 17 00:00:00 2001 From: adeschen Date: Mon, 14 Apr 2025 13:10:04 -0400 Subject: [PATCH 344/385] Update vignette step 1 --- vignettes/RAIDS.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 2e489d9f9..ae5f05a6b 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -103,7 +103,7 @@ knitr::include_graphics("MainSteps_v05.png") The main steps are: -**Step 1.** Set-up and provide population reference files +**Step 1.** Set-up working directory and provide population reference files **Step 2** Sample the reference data for donors whose genotypes will be used for synthesis and optimize ancestry inference parameters using synthetic data From a130c66f61e206024e62f69f25b3cb88a4e576f4 Mon Sep 17 00:00:00 2001 From: adeschen Date: Mon, 14 Apr 2025 13:29:12 -0400 Subject: [PATCH 345/385] Update vignette --- vignettes/RAIDS.Rmd | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index ae5f05a6b..928cde473 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -117,7 +117,7 @@ These steps are described in detail in the following.
-## Step 1. Set-up and provide population reference files +## Step 1. Set-up working directory and provide population reference files ### 1.1 Create a working directory structure @@ -146,6 +146,7 @@ example will be run. ############################################################################# ## Create a temporary working directory structure +## using the tempdir() function ############################################################################# pathWorkingDirectory <- file.path(tempdir(), "workingDirectory") pathWorkingDirectoryData <- file.path(pathWorkingDirectory, "data") @@ -166,7 +167,8 @@ if (!dir.exists(pathWorkingDirectory)) { The population reference files should be downloaded into the *data/refGDS* sub-directory. This following code downloads the complete pre-processed files -for 1000 Genomes (1KG), for the hg38 build of the human genome, in the GDS format. The size of the 1KG GDS file is 15GB. +for 1000 Genomes (1KG), for the hg38 build of the human genome, in the GDS +format. The size of the 1KG GDS file is 15GB. ``` @@ -202,9 +204,9 @@ library(RAIDS) ############################################################################# ## The population reference GDS file and SNV Annotation GDS file -## need to be located in the same sub-directory. +## need to be located in the same sub-directory. ## Note that the mini-reference GDS file used for this example is -## NOT sufficient for reliable inference +## NOT sufficient for reliable inference. ############################################################################# ## Path to the demo 1KG GDS file is located in this package dataDir <- system.file("extdata", package="RAIDS") @@ -265,18 +267,21 @@ In the following code, only 2 individual profiles per sub-continental population are sampled from the demo population GDS file: -```{r sampling, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} +```{r samplingProfiles, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} ############################################################################# -## Set up the following random number generator seed to reproduce the expected results +## Set up the following random number generator seed to reproduce +## the expected results ############################################################################# set.seed(3043) ############################################################################# ## Choose the profiles from the population reference GDS file for -## data synthesis. -## Here we choose 2 profiles perm subcontinental population from the mini 1KG GDS file. -## Normally, we would use 30 randomly chosen profiles per subcontinental population. +## data synthesis. +## Here we choose 2 profiles per subcontinental population +## from the mini 1KG GDS file. +## Normally, we would use 30 randomly chosen profiles per +## subcontinental population. ############################################################################# dataRef <- select1KGPopForSynthetic(fileReferenceGDS=refGenotype, nbProfiles=2L) @@ -284,13 +289,11 @@ dataRef <- select1KGPopForSynthetic(fileReferenceGDS=refGenotype, ``` -
### 2.3 Infer ancestry -Within a single function -call, data synthesis is performed, the synthetic +Within a single function call, data synthesis is performed, the synthetic data are used to optimize the inference parameters and, with these, the ancestry is inferred from the input sequence profile. From 643a443a0703031fb50d9a61dd9eee254faa4526 Mon Sep 17 00:00:00 2001 From: adeschen Date: Mon, 14 Apr 2025 13:56:36 -0400 Subject: [PATCH 346/385] Update vignette --- vignettes/RAIDS.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 928cde473..66a74e4f4 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -305,8 +305,8 @@ The *inferAncestry()* function requires a specific profile input format. The format is set by the *genoSource* parameter. One of those formats is in a VCF format (*genoSource=c("VCF")*). -This format follows the VCF standard -with at least those genotype fields: _GT_, _AD_ and _DP_. +This format follows the VCF standard with at least those genotype +fields: _GT_, _AD_ and _DP_. The SNVs must be germline variants and should include the genotype of the wild-type homozygous at the selected positions in the reference. The VCF file must be gzipped. From 2eb8e602a066738833e143dc4d7122606a823519 Mon Sep 17 00:00:00 2001 From: belleau Date: Mon, 14 Apr 2025 19:15:39 -0400 Subject: [PATCH 347/385] Tuning the functions for Rsamtools part 2 --- R/gdsWrapper_internal.R | 10 ++- R/processStudy.R | 28 +++--- R/processStudy_internal.R | 161 ++++++++++++++++++++++++++++++++--- R/tools_internal.R | 138 +++++++++++++++++++----------- man/createProfile.Rd | 2 +- man/processPileupChrBin.Rd | 10 +-- man/readSNVBAM.Rd | 7 +- man/validatecreateProfile.Rd | 90 ++++++++++++++++++++ man/wrapperAncestry.Rd | 6 +- 9 files changed, 367 insertions(+), 85 deletions(-) create mode 100644 man/validatecreateProfile.Rd diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index e052790c4..e7503cb1c 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -691,7 +691,7 @@ generateProfileGDS <- function(profileFile, profileName, # } - g <- as.matrix(rep(-1, nrow(listPos))) + # for(i in seq_len(length(listSamples))) { #pos <- which(listSampleFile == listSamples[i]) @@ -710,13 +710,15 @@ generateProfileGDS <- function(profileFile, profileName, matSample <- readSNVVCF(profileFile, profileName=profileName, offset) } else if(genoSource == "bam"){ - listPos$start <- listPos$start - offset + matSample <- readSNVBAM(fileName=profileFile, varSelected=listPos, paramSNVBAM=paramProfileGDS, + offset, verbose=verbose) - listPos$start <- listPos$start + offset + listPos <- do.call(rbind, listPos) colnames(listPos)[1:2] <- c("snp.chromosome", "snp.position") + } # matAll <- merge(matSample[,c( "Chromosome", "Position", # "File1R", "File1A", @@ -729,6 +731,8 @@ generateProfileGDS <- function(profileFile, profileName, # # below same as the merge above but faster + if(verbose) {message("End read ", Sys.time())} + g <- as.matrix(rep(-1, nrow(listPos))) z <- cbind(c(listPos$snp.chromosome, matSample$Chromosome, matSample$Chromosome), c(listPos$snp.position, matSample$Position, diff --git a/R/processStudy.R b/R/processStudy.R index af89c042e..bf877d47f 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2340,10 +2340,10 @@ inferAncestry <- function(profileFile, pathProfileGDS, genoSource <- arg_match(genoSource) ## BAM format is not yet implemented - if (genoSource == "bam") { - stop("The bam is not release yet look to get a \'Devel\' version ", - "or contact us") - } + # if (genoSource == "bam") { + # stop("The bam is not release yet look to get a \'Devel\' version ", + # "or contact us") + # } ## Extract the name of the profile(s) profileName <- gsub("\\.gz$", "", profileBaseName, ignore.case=TRUE) @@ -2367,11 +2367,11 @@ inferAncestry <- function(profileFile, pathProfileGDS, syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) ## Run ancestry inference - if (genoSource %in% c("snp-pileup", "generic", "VCF")) { + if (genoSource %in% c("snp-pileup", "generic", "VCF", "bam")) { r <- wrapperAncestry(pedStudy, studyDF, pathProfileGDS, profileFile, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, genoSource, studyType="LD", np=np, - verbose) + chrInfo, syntheticRefDF, genoSource=genoSource, studyType="LD", np=np, + verbose=verbose) }else{ stop(paste0("The format ", genoSource," is not implemented yet\n")) } @@ -2898,10 +2898,10 @@ inferAncestryGeneAware <- function(profileFile, pathProfileGDS, genoSource <- arg_match(genoSource) - if(genoSource == "bam"){ - stop("The bam is not release yet look to get a \'Devel\' version ", - "or contact us") - } + # if(genoSource == "bam"){ + # stop("The bam is not release yet look to get a \'Devel\' version ", + # "or contact us") + # } profileName <- gsub("\\.gz$", "", profileBaseName, ignore.case = TRUE) for(extCur in c( "\\.vcf$", "\\.txt$", "\\.bam", "\\.tsv", "\\.csv")){ @@ -2928,12 +2928,12 @@ inferAncestryGeneAware <- function(profileFile, pathProfileGDS, syntheticRefDF=syntheticRefDF, genoSource=genoSource, verbose=verbose) - if(genoSource %in% c("snp-pileup", "generic", "VCF")){ + if(genoSource %in% c("snp-pileup", "generic", "VCF", "bam")){ r <- wrapperAncestry(pedStudy, studyDF, pathProfileGDS, profileFile, fileReferenceGDS, fileReferenceAnnotGDS, - chrInfo, syntheticRefDF, genoSource, studyType="GeneAware", np=np, - blockTypeID=blockTypeID, verbose) + chrInfo, syntheticRefDF, genoSource=genoSource, studyType="GeneAware", np=np, + blockTypeID=blockTypeID, verbose=verbose) }else{ stop(paste0("The format ", genoSource," is not implemented yet\n")) } diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 761dfd9e7..897f7baf6 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -600,6 +600,133 @@ validateCreateStudy2GDS1KG <- function(pathGeno, pedStudy, fileNameGDS, batch, return(0L) } +#' @title Validate input parameters for createProfile() function +#' +#' @description This function validates the input parameters for the +#' \code{\link{createStudy2GDS1KG}} function. +#' +#' @param pedStudy a \code{data.frame} with those mandatory columns: "Name.ID", +#' "Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +#' \code{character} strings (no factor). The \code{data.frame} +#' must contain the information for all the samples passed in the +#' \code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +#' can be defined. +#' +#' @param fileNameGDS a \code{character} string representing the file name of +#' the Population Reference GDS file. The file must exist. +#' +#' @param batch a single positive \code{integer} representing the current +#' identifier for the batch. Beware, this field is not stored anymore. +#' +#' @param studyDF a \code{data.frame} containing the information about the +#' study associated to the analysed sample(s). The \code{data.frame} must have +#' those 3 columns: "study.id", "study.desc", "study.platform". All columns +#' must be in \code{character} strings (no factor). +#' +#' @param listProfiles a \code{vector} of \code{character} string corresponding +#' to the profile identifiers that will have a GDS Sample file created. The +#' profile identifiers must be present in the "Name.ID" column of the RDS file +#' passed to the \code{filePedRDS} parameter. +#' If \code{NULL}, all profiles in the \code{filePedRDS} are selected. +#' +#' @param pathProfileGDS a \code{character} string representing the path to +#' the directory where the Profile GDS files will be created. +#' +#' @param verbose a \code{logical} indicating if message information should be +#' printed. +#' +#' @return The function returns \code{0L} when successful. +#' +#' @examples +#' +#' ## Path to the demo pedigree file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ## Demo 1KG Population Reference GDS file +#' gds1KG <- file.path(dataDir, "PopulationReferenceDemo.gds") +#' +#' ## The data.frame containing the information about the study +#' ## The 3 mandatory columns: "study.id", "study.desc", "study.platform" +#' ## The entries should be strings, not factors (stringsAsFactors=FALSE) +#' studyInfo <- data.frame(study.id="Pancreatic.WES", +#' study.desc="Pancreatic study", +#' study.platform="WES", +#' stringsAsFactors=FALSE) +#' +#' ## PED Study +#' ped <- data.frame(Name.ID=c("Sample_01", "Sample_02"), +#' Case.ID=c("TCGA-H01", "TCGA-H02"), +#' Sample.Type=c("DNA", "DNA"), +#' Diagnosis=c("Cancer", "Cancer"), Source=c("TCGA", "TCGA")) +#' +#' ## The validation should be successful +#' RAIDS:::validateCreateStudy2GDS1KG(pathGeno=dataDir, pedStudy=ped, +#' fileNameGDS=gds1KG, batch=1, studyDF=studyInfo, +#' listProfiles=c("Sample_01", "Sample_02"), +#' pathProfileGDS=dataDir, +#' genoSource="snp-pileup", verbose=TRUE) +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom S4Vectors isSingleNumber +#' @encoding UTF-8 +#' @keywords internal +validatecreateProfile <- function(pedStudy, + fileNameGDS, batch, + studyDF, listProfiles, pathProfileGDS, + genoSource, verbose) { + # profileFile, profileName, + # filePedRDS=NULL, pedStudy=NULL, fileNameGDS, + # batch=1, studyDF, listProfiles=NULL, + # pathProfileGDS=NULL, + # genoSource=c("snp-pileup", "generic", "VCF", "bam"), + # paramProfile=list(ScanBamParam=NULL, + # PileupParam=NULL, + # yieldSize=10000000), + # verbose=FALSE + ## The pathGeno must be a existing directory + + + ## The PED study must have the mandatory columns + validatePEDStudyParameter(pedStudy=pedStudy) + + ## The fileNameGDS must be a character string and the file must exists + if (!(is.character(fileNameGDS) && (file.exists(fileNameGDS)))) { + stop("The \'fileNameGDS\' must be a character string representing ", + "the Population Reference GDS file. The file must exist.") + } + + ## The batch must be a single numeric + if(!(isSingleNumber(batch))) { + stop("The \'batch\' must be a single integer.") + } + + ## The Study DF must have the mandatory columns + validateStudyDataFrameParameter(studyDF=studyDF) + + ## The listProfiles must be a vector of character string + if (!(is.character(listProfiles) || is.null(listProfiles))) { # + stop("The \'listProfiles\' must be a vector ", + "of character strings (1 entry or more) or NULL.") + } + + + ## The pathProfileGDS must be a character string + if (!is.character(pathProfileGDS)) { + stop("The \'pathProfileGDS\' must be a character string representing", + " the path where the Profile GDS files will be generated.") + } + + ## The genoSource must be a character string + if(!(is.character(genoSource))) { + stop("The \'genoSource\' parameter must be a character string.") + } + + ## The verbose parameter must be a logical + validateLogical(logical=verbose, "verbose") + + return(0L) +} + #' @title Validate input parameters for computeAncestryFromSyntheticFile() #' function @@ -3371,7 +3498,7 @@ createProfile <- function(profileFile, profileName, genoSource=c("snp-pileup", "generic", "VCF", "bam"), paramProfile=list(ScanBamParam=NULL, PileupParam=NULL, - yieldSize=5000000), + yieldSize=10000000), verbose=FALSE) { ## When filePedRDS is defined and pedStudy is null @@ -3392,10 +3519,10 @@ createProfile <- function(profileFile, profileName, } ## Validate input parameters - # validateCreateStudy2GDS1KG(pathGeno=pathGeno, pedStudy=pedStudy, - # fileNameGDS=fileNameGDS, batch=batch, studyDF=studyDF, - # listProfiles=listProfiles, pathProfileGDS=pathProfileGDS, - # genoSource=genoSource, verbose=verbose) + validatecreateProfile( pedStudy=pedStudy, + fileNameGDS=fileNameGDS, batch=batch, studyDF=studyDF, + listProfiles=listProfiles, pathProfileGDS=pathProfileGDS, + genoSource=genoSource, verbose=verbose) genoSource <- arg_match(genoSource) @@ -3408,7 +3535,7 @@ createProfile <- function(profileFile, profileName, if(genoSource == "bam"){ alDf <- read.gdsn(index.gdsn(gdsReference, "snp.allele")) alDf <- matrix(unlist(strsplit(alDf,"\\/")),nrow=2) - listPos <- data.frame(chr = paste0("chr",read.gdsn(index.gdsn(gdsReference, "snp.chromosome"))), + listPos <- data.frame(chr = read.gdsn(index.gdsn(gdsReference, "snp.chromosome")), start = read.gdsn(index.gdsn(gdsReference, "snp.position")), REF = alDf[1,], ALT = alDf[2,], @@ -3421,7 +3548,7 @@ createProfile <- function(profileFile, profileName, return(varDf[which(varDf$chr == x),]) }, varDf=listPos) - names(listPos) <- listChr + names(listPos) <- paste0("chr", listChr) rm(alDf,listChr) } else{ listPos <- data.frame(snp.chromosome=read.gdsn(index.gdsn(node=gdsReference, "snp.chromosome")), @@ -3513,7 +3640,7 @@ createProfile <- function(profileFile, profileName, #' way the estimation of the allelic fraction is done. Default: \code{"DNA"}. #' #' @param genoSource a \code{character} string with two possible values: -#' 'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +#' 'snp-pileup', 'generic' or 'VCF', "bam". It specifies if the genotype files #' are generated by snp-pileup (Facets) or are a generic format CSV file #' with at least those columns: #' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. @@ -3763,13 +3890,17 @@ createProfile <- function(profileFile, profileName, wrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, profileFile, fileReferenceGDS, fileReferenceAnnotGDS, chrInfo, syntheticRefDF, - genoSource=c("snp-pileup", "generic", "VCF"), + genoSource=c("snp-pileup", "generic", "VCF", "bam"), studyType=c("LD", "GeneAware"), np=1L, blockTypeID=NULL, paramAncestry=list(ScanBamParam=NULL, PileupParam=NULL, - yieldSize=5000000), + yieldSize=10000000), verbose=FALSE) { + if(genoSource == "bam") { + message("Process from bam is a new feature;", + " if you have an issue, please let us know") + } genoSource <- arg_match(genoSource) listProfiles <- pedStudy[, "Name.ID"] @@ -3782,6 +3913,16 @@ wrapperAncestry <- function(pedStudy, studyDF, pathProfileGDS, # PileupParam=NULL, # yieldSize=5000000), # verbose=FALSE) + if(is.character(listProfiles)){ + for(profileCur in listProfiles){ + if(file.exists(file.path(pathProfileGDS, paste0(profileCur, ".gds")))){ + stop(paste0("The gds file for ", profileCur, " already exist.")) + } + } + } + if(file.exists(file.path(pathProfileGDS, paste0(pedStudy$Name.ID[1], ".gds")))){ + stop(paste0("The gds file for ", pedStudy$Name.ID[1], " already exist.")) + } createProfile(profileFile=profileFile, profileName=pedStudy$Name.ID[1], pedStudy=pedStudy, fileNameGDS=fileReferenceGDS, studyDF=studyDF, pathProfileGDS=pathProfileGDS, diff --git a/R/tools_internal.R b/R/tools_internal.R index ba3423900..af8dde9fc 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -491,7 +491,7 @@ extractNucleotide <- function(nucleotide, count, curNucleo) { #' @param resPileup a \code{data.frame} as generated by the \code{pileup} #' function from \code{Rsamtools} package #' -#' @param varDf a \code{list} containing a \code{data.frame} representing +#' @param varDf a \code{list} containing a \code{data.frame} representing #' the positions to keep for each chromosome. #' #' @param verbose a \code{logical} indicating if messages should be printed @@ -513,24 +513,24 @@ extractNucleotide <- function(nucleotide, count, curNucleo) { #' @examples #' #' ## Demo pileup result data.frame -#' resDemo <- data.frame(seqnames=rep("chr14", 10), -#' pos=c(19069583, 19069584, 19069586, 19069588, 19069589, 19069590, -#' 19069591, 19069592, 19069609, 19069760), -#' strand=c(rep("+", 5), rep("-", 5)), +#' resDemo <- data.frame(seqnames=rep("chr14", 10), +#' pos=c(19069583, 19069584, 19069586, 19069588, 19069589, 19069590, +#' 19069591, 19069592, 19069609, 19069760), +#' strand=c(rep("+", 5), rep("-", 5)), #' nucleotide=c("T", "G", "G", "C", "A", "A", "C", "T", "T", "G"), #' count=c(5, 3, 2, 4, 1, 2, 1, 8, 7, 4)) #' resDemo$seqnames <- factor(resDemo$seqnames) #' resDemo$strand <- factor(resDemo$strand) #' resDemo$nucleotide <- factor(resDemo$nucleotide) -#' +#' #' ## Position to keep in a data.frame format -#' varInfo <- list("chr14"=data.frame(chr=c("chr14", "chr14"), +#' varInfo <- list("chr14"=data.frame(chr=c("chr14", "chr14"), #' start=c(19069584, 19069609), REF=c("A", "G"), ALT=c("T", "A"))) -#' +#' #' ## Extract information from pileup for selected positions #' RAIDS:::processPileupChrBin(chr="chr14", resPileup=resDemo, varDf=varInfo, #' verbose=FALSE) -#' +#' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom dplyr group_by summarize %>% #' @importFrom rlang .data @@ -572,6 +572,7 @@ processPileupChrBin <- function(chr, resPileup, varDf, verbose) { if (verbose) { message("processPileupChrBin selected pos user ", + chr, " ", round(tmpTime[1],3), " system ", round(tmpTime[2],3), " elapsed ", round(tmpTime[3],3)) } @@ -589,27 +590,32 @@ processPileupChrBin <- function(chr, resPileup, varDf, verbose) { message("processPileupChrBin extracted nucleotides user ", round(tmpTime[1],3), " system ", round(tmpTime[2],3), " elapsed ", round(tmpTime[3],3)) } - - # Add the reference allele and the alternative allele - tmpTime <- system.time({z <- cbind(c(resCur$pos, vcfCur$start, resCur$pos), - c(rep(-1, nrow(resCur)), rep(0, nrow(vcfCur)), rep(1, nrow(resCur))), - c(seq_len(nrow(resCur)), seq_len(nrow(vcfCur)), seq_len(nrow(resCur)))) - z <- z[order(z[,1]),] - listKeep <- which(cumsum(z[,2]) < 0 & z[,2]==0) - resCur$REF <- rep("N", nrow(resCur)) - resCur$ALT <- rep("N", nrow(resCur)) - resCur$REF[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "REF"] - resCur$ALT[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "ALT"] - resCur <- resCur[,c("seqnames", "pos", "REF", "ALT", "A", - "C", "G", "T", "count")]} ) - - if(verbose) { - message("processPileupChrBin add ref and alt allele user ", - round(tmpTime[1],3), " system ", round(tmpTime[2],3), - " elapsed ", round(tmpTime[3],3)) } + if(length(listKeep) > 0){ + # Add the reference allele and the alternative allele + tmpTime <- system.time({z <- cbind(c(resCur$pos, vcfCur$start, resCur$pos), + c(rep(-1, nrow(resCur)), rep(0, nrow(vcfCur)), rep(1, nrow(resCur))), + c(seq_len(nrow(resCur)), seq_len(nrow(vcfCur)), seq_len(nrow(resCur)))) + z <- z[order(z[,1]),] + listKeep <- which(cumsum(z[,2]) < 0 & z[,2]==0) + resCur$REF <- rep("N", nrow(resCur)) + resCur$ALT <- rep("N", nrow(resCur)) + resCur$REF[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "REF"] + resCur$ALT[z[listKeep-1,3]] <- vcfCur[z[listKeep,3], "ALT"] + resCur <- resCur[,c("seqnames", "pos", "REF", "ALT", "A", + "C", "G", "T", "count")]} ) + + if(verbose) { + message("processPileupChrBin add ref and alt allele user ", + round(tmpTime[1],3), " system ", round(tmpTime[2],3), + " elapsed ", round(tmpTime[3],3)) } + } else{ + resCur <- NULL + } } } } + if(verbose) {message("readSNVBAM processPileupChrBin before return ", + Sys.time())} return(resCur) } @@ -628,6 +634,10 @@ processPileupChrBin <- function(chr, resPileup, varDf, verbose) { #' #' @param varSelected a \code{data.frame} representing the position to keep #' +#' @param offset a \code{integer} representing the offset to be added to the +#' position of the SNVs. The value of offset +#' is added to the position present in the file. Default: \code{0L}. +#' #' @param verbose a \code{logical} indicating if messages should be printed #' to show how the different steps in the function. Default: \code{FALSE}. #' @@ -662,10 +672,23 @@ processPileupChrBin <- function(chr, resPileup, varDf, verbose) { #' @keywords internal readSNVBAM <- function(fileName, varSelected, + offset = 0L, paramSNVBAM=list(ScanBamParam=NULL, PileupParam=NULL, - yieldSize=5000000), + yieldSize=10000000), verbose=FALSE) { + # Note the offset is apply to the ref not the sequemce (snp-pileup and vcf) + listChr <- names(varSelected) + varSelected <- lapply(seq_len(length(varSelected)), + FUN=function(x, varSelected){ + varSelected[[x]]$chr <- paste0("chr", varSelected[[x]]$chr) + varSelected[[x]]$start <- varSelected[[x]]$start - offset + return(varSelected[[x]]) + }, + varSelected=varSelected) + names(varSelected) <- listChr + #varSelected$chr <- paste0("chr", varSelected$chr) + #varSelected$start <- varSelected$start - offset myBf <- BamFile(fileName, yieldSize=paramSNVBAM$yieldSize) bf <- open(myBf) @@ -694,6 +717,8 @@ readSNVBAM <- function(fileName, k<-0 repeat { + if(verbose) {message("readSNVBAM pileup user ", + k, " i ", i)} tmpTime <- system.time(resPileup <- pileup(bf, pileupParam = pup, ScanBamParam=sbp)) @@ -703,20 +728,34 @@ readSNVBAM <- function(fileName, " elapsed ", round(tmpTime[3],3))} listChr <- unique(as.character(resPileup$seqnames)) + + #print(paste0("nb Chr ", length(listChr))) res[[i]] <- NULL if(length(listChr) > 0 ){ + tmpChr <- grep("chr", listChr) + if(length(tmpChr) != length(listChr)){ + listChg <- listChr[-1* tmpChr] + for(i in seq_len(length(listChg))){ + resPileup$seqnames[resPileup$seqnames == listChg[i]] = paste0("chr", listChg[i]) + } + listChr <- unique(as.character(resPileup$seqnames)) + } if(sum(!(listChr %in% names(varSelected))) == length(listChr)){ # message("End chromosome") break } # print(paste0("Current chr ", listChr)) + if(verbose) {message("readSNVBAM processPileupChrBin start ", + Sys.time())} tmp <- lapply(listChr, FUN=function(x, res, varSelected){ return(processPileupChrBin(chr=x, res, varDf=varSelected, verbose=verbose)) }, res=resPileup, varSelected=varSelected) + if(verbose) {message("readSNVBAM processPileupChrBin end ", + Sys.time())} # print("aye2") if(length(tmp) > 0){ res[[i]] <- do.call(rbind, tmp) @@ -736,32 +775,35 @@ readSNVBAM <- function(fileName, k <- 0 # i <- i + 1 } - + if(verbose) {message("readSNVBAM pileup end repeat ", + Sys.time())} } - + if(verbose) {message("readSNVBAM pileup Done ", + Sys.time())} resSNP <- do.call(rbind,res) close(bf) + if(verbose) {message("readSNVBAM pileup user ", + k, " i ", i)} + + resSNP$File1R <- rep(0, nrow(resSNP)) + resSNP$File1A <- rep(0, nrow(resSNP)) + for(nuc in c("A", "C", "G", "T")){ + tmp <- which(resSNP$REF == nuc) + if(length(tmp) > 0){ + resSNP$File1R[tmp] <- resSNP[tmp, nuc] + } + tmp <- which(resSNP$ALT == nuc) + if(length(tmp) > 0){ + resSNP$File1A[tmp] <- resSNP[tmp, nuc] + } + } + resSNP <- resSNP[, c("seqnames", "pos", "REF", "ALT", "File1R", "File1A", "count", "A", "C", "G", "T")] + colnames(resSNP) <- c("Chromosome", "Position", "Ref", "Alt", "File1R", "File1A", "count", "A", "C", "G", "T") - resSNP <- do.call(rbind, lapply(seq_len(nrow(resSNP)), - FUN=function(x, resSNP){ - - df <- data.frame(Chromosome=resSNP[x, "seqnames"], - Position=resSNP[x, "pos"], - Ref=resSNP[x, "REF"], - Alt=resSNP[x, "ALT"], - File1R=resSNP[x, resSNP[x, "REF"]], - File1A=resSNP[x, resSNP[x, "ALT"]], - count=resSNP[x, "count"], - A=resSNP[x, "A"], - C=resSNP[x, "C"], - G=resSNP[x, "G"], - T=resSNP[x, "T"], - stringsAsFactors = FALSE) - return(df) - }, - resSNP=resSNP)) + if(verbose) {message("readSNVBAM pileup format Done ", + Sys.time())} return(resSNP) } diff --git a/man/createProfile.Rd b/man/createProfile.Rd index d03a55d8a..d07cc4e78 100644 --- a/man/createProfile.Rd +++ b/man/createProfile.Rd @@ -18,7 +18,7 @@ createProfile( listProfiles = NULL, pathProfileGDS = NULL, genoSource = c("snp-pileup", "generic", "VCF", "bam"), - paramProfile = list(ScanBamParam = NULL, PileupParam = NULL, yieldSize = 5e+06), + paramProfile = list(ScanBamParam = NULL, PileupParam = NULL, yieldSize = 1e+07), verbose = FALSE ) } diff --git a/man/processPileupChrBin.Rd b/man/processPileupChrBin.Rd index 7057b93aa..924aaf126 100644 --- a/man/processPileupChrBin.Rd +++ b/man/processPileupChrBin.Rd @@ -43,10 +43,10 @@ the selected chromosome. \examples{ ## Demo pileup result data.frame -resDemo <- data.frame(seqnames=rep("chr14", 10), - pos=c(19069583, 19069584, 19069586, 19069588, 19069589, 19069590, - 19069591, 19069592, 19069609, 19069760), - strand=c(rep("+", 5), rep("-", 5)), +resDemo <- data.frame(seqnames=rep("chr14", 10), + pos=c(19069583, 19069584, 19069586, 19069588, 19069589, 19069590, + 19069591, 19069592, 19069609, 19069760), + strand=c(rep("+", 5), rep("-", 5)), nucleotide=c("T", "G", "G", "C", "A", "A", "C", "T", "T", "G"), count=c(5, 3, 2, 4, 1, 2, 1, 8, 7, 4)) resDemo$seqnames <- factor(resDemo$seqnames) @@ -54,7 +54,7 @@ resDemo$strand <- factor(resDemo$strand) resDemo$nucleotide <- factor(resDemo$nucleotide) ## Position to keep in a data.frame format -varInfo <- list("chr14"=data.frame(chr=c("chr14", "chr14"), +varInfo <- list("chr14"=data.frame(chr=c("chr14", "chr14"), start=c(19069584, 19069609), REF=c("A", "G"), ALT=c("T", "A"))) ## Extract information from pileup for selected positions diff --git a/man/readSNVBAM.Rd b/man/readSNVBAM.Rd index 286826430..dbd4be2ee 100644 --- a/man/readSNVBAM.Rd +++ b/man/readSNVBAM.Rd @@ -8,7 +8,8 @@ readSNVBAM( fileName, varSelected, - paramSNVBAM = list(ScanBamParam = NULL, PileupParam = NULL, yieldSize = 5e+06), + offset = 0L, + paramSNVBAM = list(ScanBamParam = NULL, PileupParam = NULL, yieldSize = 1e+07), verbose = FALSE ) } @@ -18,6 +19,10 @@ the path, of a BAM file with the index file in the same directory} \item{varSelected}{a \code{data.frame} representing the position to keep} +\item{offset}{a \code{integer} representing the offset to be added to the +position of the SNVs. The value of offset +is added to the position present in the file. Default: \code{0L}.} + \item{paramSNVBAM}{a \code{data.frame} representing} \item{verbose}{a \code{logical} indicating if messages should be printed diff --git a/man/validatecreateProfile.Rd b/man/validatecreateProfile.Rd new file mode 100644 index 000000000..81142bd9e --- /dev/null +++ b/man/validatecreateProfile.Rd @@ -0,0 +1,90 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/processStudy_internal.R +\encoding{UTF-8} +\name{validatecreateProfile} +\alias{validatecreateProfile} +\title{Validate input parameters for createProfile() function} +\usage{ +validatecreateProfile( + pedStudy, + fileNameGDS, + batch, + studyDF, + listProfiles, + pathProfileGDS, + genoSource, + verbose +) +} +\arguments{ +\item{pedStudy}{a \code{data.frame} with those mandatory columns: "Name.ID", +"Case.ID", "Sample.Type", "Diagnosis", "Source". All columns must be in +\code{character} strings (no factor). The \code{data.frame} +must contain the information for all the samples passed in the +\code{listSamples} parameter. Only \code{filePedRDS} or \code{pedStudy} +can be defined.} + +\item{fileNameGDS}{a \code{character} string representing the file name of +the Population Reference GDS file. The file must exist.} + +\item{batch}{a single positive \code{integer} representing the current +identifier for the batch. Beware, this field is not stored anymore.} + +\item{studyDF}{a \code{data.frame} containing the information about the +study associated to the analysed sample(s). The \code{data.frame} must have +those 3 columns: "study.id", "study.desc", "study.platform". All columns +must be in \code{character} strings (no factor).} + +\item{listProfiles}{a \code{vector} of \code{character} string corresponding +to the profile identifiers that will have a GDS Sample file created. The +profile identifiers must be present in the "Name.ID" column of the RDS file +passed to the \code{filePedRDS} parameter. +If \code{NULL}, all profiles in the \code{filePedRDS} are selected.} + +\item{pathProfileGDS}{a \code{character} string representing the path to +the directory where the Profile GDS files will be created.} + +\item{verbose}{a \code{logical} indicating if message information should be +printed.} +} +\value{ +The function returns \code{0L} when successful. +} +\description{ +This function validates the input parameters for the +\code{\link{createStudy2GDS1KG}} function. +} +\examples{ + +## Path to the demo pedigree file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +## Demo 1KG Population Reference GDS file +gds1KG <- file.path(dataDir, "PopulationReferenceDemo.gds") + +## The data.frame containing the information about the study +## The 3 mandatory columns: "study.id", "study.desc", "study.platform" +## The entries should be strings, not factors (stringsAsFactors=FALSE) +studyInfo <- data.frame(study.id="Pancreatic.WES", + study.desc="Pancreatic study", + study.platform="WES", + stringsAsFactors=FALSE) + +## PED Study +ped <- data.frame(Name.ID=c("Sample_01", "Sample_02"), + Case.ID=c("TCGA-H01", "TCGA-H02"), + Sample.Type=c("DNA", "DNA"), + Diagnosis=c("Cancer", "Cancer"), Source=c("TCGA", "TCGA")) + +## The validation should be successful +RAIDS:::validateCreateStudy2GDS1KG(pathGeno=dataDir, pedStudy=ped, + fileNameGDS=gds1KG, batch=1, studyDF=studyInfo, + listProfiles=c("Sample_01", "Sample_02"), + pathProfileGDS=dataDir, + genoSource="snp-pileup", verbose=TRUE) + +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} +\keyword{internal} diff --git a/man/wrapperAncestry.Rd b/man/wrapperAncestry.Rd index 22cb21a71..cda691b48 100644 --- a/man/wrapperAncestry.Rd +++ b/man/wrapperAncestry.Rd @@ -15,11 +15,11 @@ wrapperAncestry( fileReferenceAnnotGDS, chrInfo, syntheticRefDF, - genoSource = c("snp-pileup", "generic", "VCF"), + genoSource = c("snp-pileup", "generic", "VCF", "bam"), studyType = c("LD", "GeneAware"), np = 1L, blockTypeID = NULL, - paramAncestry = list(ScanBamParam = NULL, PileupParam = NULL, yieldSize = 5e+06), + paramAncestry = list(ScanBamParam = NULL, PileupParam = NULL, yieldSize = 1e+07), verbose = FALSE ) } @@ -62,7 +62,7 @@ super-population assigned to the sample. } }} \item{genoSource}{a \code{character} string with two possible values: -'snp-pileup', 'generic' or 'VCF'. It specifies if the genotype files +'snp-pileup', 'generic' or 'VCF', "bam". It specifies if the genotype files are generated by snp-pileup (Facets) or are a generic format CSV file with at least those columns: 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. From ed557ddca1c3f9bc8e4bc65a33c969964d07c30e Mon Sep 17 00:00:00 2001 From: A Wokaty Date: Tue, 15 Apr 2025 13:22:03 -0400 Subject: [PATCH 348/385] bump x.y.z version to even y prior to creation of RELEASE_3_21 branch --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 58f5ea55c..331695368 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 1.5.1 +Version: 1.6.0 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", From b3b3d8c9a26423a2b7a9c6d2ddc4fe1ee7f56b05 Mon Sep 17 00:00:00 2001 From: A Wokaty Date: Tue, 15 Apr 2025 13:22:03 -0400 Subject: [PATCH 349/385] bump x.y.z version to odd y following creation of RELEASE_3_21 branch --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 331695368..6d591627e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 1.6.0 +Version: 1.7.0 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", From dc807488b79a7e34c93b4be13d7751d3e379bab1 Mon Sep 17 00:00:00 2001 From: krasnitz Date: Tue, 15 Apr 2025 16:24:08 -0400 Subject: [PATCH 350/385] Update RAIDS.Rmd --- vignettes/RAIDS.Rmd | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 66a74e4f4..516512ade 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -301,30 +301,27 @@ According to the type of input data (RNA or DNA sequence), a specific function should be called. The *inferAncestry()* function is used for DNA profiles while the *inferAncestryGeneAware()* function is RNA specific. -The *inferAncestry()* function requires a specific profile input format. The -format is set by the *genoSource* parameter. +The *inferAncestry()* function requires a specific input format for individual +genotyping profiles. The format is set by the *genoSource* parameter. -One of those formats is in a VCF format (*genoSource=c("VCF")*). -This format follows the VCF standard with at least those genotype -fields: _GT_, _AD_ and _DP_. +One of the allowed formats is VCF (*genoSource=c("VCF")*), with the following +mandatory fields: _GT_, _AD_ and _DP_. The SNVs must be germline variants and should include the genotype of the wild-type homozygous at the selected positions in the reference. The VCF file must be gzipped. -A generic SNP file can replace the VCF file (*genoSource=c("generic")*). -The format is comma separated and the mandatory columns are: +Also allowed is a "generic" file format (*genoSource=c("generic")*), specified as +a comma-separated table The following columns are mandatory: * _Chromosome_: The name of the chromosome * _Position_: The position on the chromosome * _Ref_: The reference nucleotide * _Alt_: The aternative nucleotide -* _Count_: The total count -* _File1R_: The count for the reference nucleotide -* _File1A_: The count for the alternative nucleotide +* _Count_: The total read count +* _File1R_: Read count for the reference nucleotide +* _File1A_: Read count for the alternative nucleotide -Beware that the starting position in the **population reference GDS file** is -zero (like BED files). The generic SNP file should also start -at position zero. +Note that the start position in each chromosome is 0. In this example, the profile is from DNA source and requires the use of the *inferAncestry()* function. @@ -368,7 +365,7 @@ A profile GDS file is created in the *pathProfileGDS* directory while all the ancestry and optimal parameters information are integrated in the output object. -At last, all temporary files created in this example should be deleted. +Finally, all temporary files created in this example should be deleted. ```{r removeTmp, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} @@ -406,12 +403,13 @@ names(resOut) ### 3.1 Inspect the inference and the optimal parameters -For the global ancestry inference using PCA followed by nearest neighbor -classification these parameters are *D* (the number of the top principal -directions retained) and *k* (the number of nearest neighbors). +Global ancestry is inferred inference using principal-component decomposition +followed by nearest neighbor classification. Two parameters are defined and optimized: +*D*, the number of the top principal directions retained and *k*, the number of nearest +neighbors. The information is stored in the *Ancestry* entry as a *data.frame* object. -It is a contains those columns: +It contains the following columns: * _sample.id_: The unique identifier of the sample * _D_: The optimal PCA dimension value used to infer the ancestry @@ -446,7 +444,7 @@ createAUROCGraph(dfAUROC=resOut$paraSample$dfAUROC, title="Example ex1") ``` -In this specific example, the performances are lower than expected +In this illustrative example, the performance estimates are lower than expected with a realistic sequence profile and a complete reference population file.
@@ -471,7 +469,7 @@ the reference dataset, are required: - The population reference SNV Retained VCF file (optional) -The format of those files are described +The formats of those files are described in the [Population reference dataset GDS files](Create_Reference_GDS_File.html) vignette. From b48574a0b39bad8c5874fa292645f5877fa1387a Mon Sep 17 00:00:00 2001 From: krasnitz Date: Tue, 15 Apr 2025 17:18:09 -0400 Subject: [PATCH 351/385] Update RAIDS.Rmd --- vignettes/RAIDS.Rmd | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 516512ade..c849c3d44 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -66,10 +66,11 @@ sequences of: * targeted gene panels * RNA, -including those from cancer-derived nucleic acids. The **RAIDS** package implements a data synthesis method that, for any given +including those from cancer-derived nucleic acids. The **RAIDS** package implements a +data synthesis method that, for any given molecular profile, enables, on the one hand, profile-specific inference parameter optimization and, on the other hand, a profile-specific inference -accuracy estimate. +accuracy estimate.

@@ -365,7 +366,7 @@ A profile GDS file is created in the *pathProfileGDS* directory while all the ancestry and optimal parameters information are integrated in the output object. -Finally, all temporary files created in this example should be deleted. +The temporary files created in this example are deleted as follows. ```{r removeTmp, echo=TRUE, eval=TRUE, collapse=TRUE, warning=FALSE, message=FALSE} From 6fbfb87988826795e40ef152ed06419542e6ec72 Mon Sep 17 00:00:00 2001 From: krasnitz Date: Tue, 15 Apr 2025 17:34:48 -0400 Subject: [PATCH 352/385] Update RAIDS.Rmd --- vignettes/RAIDS.Rmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index c849c3d44..01c906839 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -404,13 +404,13 @@ names(resOut) ### 3.1 Inspect the inference and the optimal parameters -Global ancestry is inferred inference using principal-component decomposition +Global ancestry is inferred using principal-component decomposition followed by nearest neighbor classification. Two parameters are defined and optimized: *D*, the number of the top principal directions retained and *k*, the number of nearest neighbors. -The information is stored in the *Ancestry* entry as a *data.frame* object. -It contains the following columns: +The results of the inference are provided, as the *Ancestry* item in the *resOut* list. +It is a *data.frame* with the following columns: * _sample.id_: The unique identifier of the sample * _D_: The optimal PCA dimension value used to infer the ancestry From 575bee9fa0545ee128f5387f26e9b6c07cc0e1e9 Mon Sep 17 00:00:00 2001 From: krasnitz Date: Tue, 15 Apr 2025 18:27:53 -0400 Subject: [PATCH 353/385] Update RAIDS.Rmd --- vignettes/RAIDS.Rmd | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 01c906839..6b78f5c1a 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -68,9 +68,11 @@ sequences of: including those from cancer-derived nucleic acids. The **RAIDS** package implements a data synthesis method that, for any given -molecular profile, enables, on the one hand, profile-specific inference +molecular profile of an idividual, enables, on the one hand, profile-specific inference parameter optimization and, on the other hand, a profile-specific inference -accuracy estimate. +accuracy estimate. By the molecular profile we mean a table of the individual's +germline genotypes at genome positions with sufficient read coverage in the +individual's input data, where sequence variants are frequent in the population reference data.

@@ -302,14 +304,12 @@ According to the type of input data (RNA or DNA sequence), a specific function should be called. The *inferAncestry()* function is used for DNA profiles while the *inferAncestryGeneAware()* function is RNA specific. -The *inferAncestry()* function requires a specific input format for individual -genotyping profiles. The format is set by the *genoSource* parameter. +The *inferAncestry()* function requires a specific input format for the individual's +genotyping profile as explained in the Introduction. The format is set by the *genoSource* parameter. One of the allowed formats is VCF (*genoSource=c("VCF")*), with the following mandatory fields: _GT_, _AD_ and _DP_. -The SNVs must be germline variants and should include the genotype of the -wild-type homozygous at the selected positions in the reference. The VCF file -must be gzipped. +The VCF file must be gzipped. Also allowed is a "generic" file format (*genoSource=c("generic")*), specified as a comma-separated table The following columns are mandatory: @@ -362,9 +362,6 @@ if (requireNamespace("GenomeInfoDb", quietly=TRUE) && ``` -A profile GDS file is created in the *pathProfileGDS* directory while all the -ancestry and optimal parameters information are integrated in the output -object. The temporary files created in this example are deleted as follows. @@ -409,12 +406,12 @@ followed by nearest neighbor classification. Two parameters are defined and opti *D*, the number of the top principal directions retained and *k*, the number of nearest neighbors. -The results of the inference are provided, as the *Ancestry* item in the *resOut* list. +The results of the inference are provided as the *Ancestry* item in the *resOut* list. It is a *data.frame* with the following columns: * _sample.id_: The unique identifier of the sample -* _D_: The optimal PCA dimension value used to infer the ancestry -* _k_: The optimal number of neighbors value used to infer the ancestry +* _D_: The optimal *D* inference parameter +* _k_: The optimal *k* inference parameter * _SuperPop_: The inferred ancestry From b4f6d1fd04adacd9f960d564449969c327dff298 Mon Sep 17 00:00:00 2001 From: Pascal Belleau Date: Tue, 15 Apr 2025 21:45:50 -0400 Subject: [PATCH 354/385] Update RAIDS.Rmd --- vignettes/RAIDS.Rmd | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index 6b78f5c1a..235aca641 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -301,11 +301,13 @@ data are used to optimize the inference parameters and, with these, the ancestry is inferred from the input sequence profile. According to the type of input data (RNA or DNA sequence), a specific function -should be called. The *inferAncestry()* function is used for DNA profiles while +should be called. The *inferAncestry()* function (*inferAncestryDNA()* is +the same as *inferAncestry()* ) is used for DNA profiles while the *inferAncestryGeneAware()* function is RNA specific. The *inferAncestry()* function requires a specific input format for the individual's -genotyping profile as explained in the Introduction. The format is set by the *genoSource* parameter. +genotyping profile as explained in the Introduction. The format is set by +the *genoSource* parameter. One of the allowed formats is VCF (*genoSource=c("VCF")*), with the following mandatory fields: _GT_, _AD_ and _DP_. @@ -314,15 +316,15 @@ The VCF file must be gzipped. Also allowed is a "generic" file format (*genoSource=c("generic")*), specified as a comma-separated table The following columns are mandatory: -* _Chromosome_: The name of the chromosome +* _Chromosome_: The name of the chromosome can be formatted as chr1 or 1 * _Position_: The position on the chromosome * _Ref_: The reference nucleotide -* _Alt_: The aternative nucleotide +* _Alt_: The alternative nucleotide * _Count_: The total read count * _File1R_: Read count for the reference nucleotide * _File1A_: Read count for the alternative nucleotide - -Note that the start position in each chromosome is 0. + +Note: a header with identical column names is required. In this example, the profile is from DNA source and requires the use of the *inferAncestry()* function. From 3ab308bd0b7cfa86a764841572d6926a8456300a Mon Sep 17 00:00:00 2001 From: belleau Date: Tue, 15 Apr 2025 21:55:15 -0400 Subject: [PATCH 355/385] Tuning the functions for Rsamtools part 3 --- NAMESPACE | 1 + R/allelicFraction.R | 5 +- R/gdsWrapper_internal.R | 2 +- R/processStudy.R | 277 +++++++++++++++++++++++++++++++++++++ R/processStudy_internal.R | 43 ++++-- R/tools_internal.R | 28 ++-- inst/NEWS.md | 2 +- man/inferAncestryDNA.Rd | 281 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 612 insertions(+), 27 deletions(-) create mode 100644 man/inferAncestryDNA.Rd diff --git a/NAMESPACE b/NAMESPACE index 6baaacb71..c062f7143 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -28,6 +28,7 @@ export(groupChr1KGSNV) export(identifyRelative) export(identifyRelativeRef) export(inferAncestry) +export(inferAncestryDNA) export(inferAncestryGeneAware) export(prepPed1KG) export(prepSynthetic) diff --git a/R/allelicFraction.R b/R/allelicFraction.R index e41b22ae0..a37e1647f 100644 --- a/R/allelicFraction.R +++ b/R/allelicFraction.R @@ -184,11 +184,12 @@ estimateAllelicFraction <- function(gdsReference, gdsProfile, # Find segment with same lap snpPos$seg <- rep(0, nrow(snpPos)) k <- 1 - for(chr in unique(snpPos$snp.chr)) { + for(i in seq_len(length(unique(snpPos$snp.chr)))) { ##snpChr <- snpPos[snpPos$snp.chr == chr, ] ##tmp <- c(0, abs(snpChr[2:nrow(snpChr), "lap"] - ## snpChr[seq_len(nrow(snpChr)- 1), "lap"]) > 1e-3) - snpPos$seg[snpPos$snp.chr == chr] <- cumSumResult[[chr]] + k + chr <- unique(snpPos$snp.chr)[i] + snpPos$seg[snpPos$snp.chr == chr] <- cumSumResult[[i]] + k k <- max(snpPos$seg[snpPos$snp.chr == chr]) + 1 } diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index e7503cb1c..8a3f4fcf9 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -716,7 +716,7 @@ generateProfileGDS <- function(profileFile, profileName, paramSNVBAM=paramProfileGDS, offset, verbose=verbose) - listPos <- do.call(rbind, listPos) + # listPos <- do.call(rbind, listPos) colnames(listPos)[1:2] <- c("snp.chromosome", "snp.position") } diff --git a/R/processStudy.R b/R/processStudy.R index bf877d47f..580ea09d8 100644 --- a/R/processStudy.R +++ b/R/processStudy.R @@ -2380,6 +2380,283 @@ inferAncestry <- function(profileFile, pathProfileGDS, return(r) } +#' @title Run most steps leading to the ancestry inference call on a specific +#' DNA profile (alias for inferAncestry ) +#' +#' @description This function runs most steps leading to the ancestry inference +#' call on a specific RNA profile. First, the function creates the +#' Profile GDS file for the specific profile using the information from a +#' RDS Sample description file and the Population Reference GDS file. +#' +#' @param profileFile a \code{character} string representing the path and the +#' file name of the genotype file or the bam if genoSource is snp-pileup the +#' fine extension must be .txt.gz, if VCF the extension must be .vcf.gz +#' +#' @param pathProfileGDS a \code{character} string representing the path to +#' the directory where the GDS Profile files will be created. +#' Default: \code{NULL}. +#' +#' @param fileReferenceGDS a \code{character} string representing the file +#' name of the Population Reference GDS file. The file must exist. +#' +#' @param fileReferenceAnnotGDS a \code{character} string representing the +#' file name of the Population Reference GDS Annotation file. The file +#' must exist. +#' +#' @param chrInfo a \code{vector} of positive \code{integer} values +#' representing the length of the chromosomes. See 'details' section. +#' +#' @param syntheticRefDF a \code{data.frame} containing a subset of +#' reference profiles for each sub-population present in the Reference GDS +#' file. The \code{data.frame} must have those columns: +#' \describe{ +#' \item{sample.id}{ a \code{character} string representing the sample +#' identifier. } +#' \item{pop.group}{ a \code{character} string representing the +#' subcontinental population assigned to the sample. } +#' \item{superPop}{ a \code{character} string representing the +#' super-population assigned to the sample. } +#' } +#' +#' @param genoSource a \code{character} string with four possible values: +#' 'snp-pileup', 'generic', 'VCF' or 'bam'. It specifies if the genotype files +#' are generated by snp-pileup (Facets) or are a generic format CSV file +#' with at least those columns: +#' 'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +#' The 'Count' is the depth at the specified position; +#' 'FileR' is the depth of the reference allele and +#' 'File1A' is the depth of the specific alternative allele. +#' Finally the file can be a VCF file with at least those genotype +#' fields: GT, AD, DP. +#' +#' @param np a single positive \code{integer} specifying the number of +#' threads to be used. Default: \code{1L}. +#' +#' @param verbose a \code{logical} indicating if messages should be printed +#' to show how the different steps in the function. Default: \code{FALSE}. +#' +#' @return a \code{list} containing 4 entries: +#' \describe{ +#' \item{\code{pcaSample}}{ a \code{list} containing the information related +#' to the eigenvectors. The \code{list} contains those 3 entries: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +#' the eigenvectors for the reference profiles.} +#' \item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +#' eigenvectors for the current profile projected on the PCA from the +#' reference profiles.} +#' } +#' } +#' \item{\code{paraSample}}{ a \code{list} containing the results with +#' different \code{D} and \code{K} values that lead to optimal parameter +#' selection. The \code{list} contains those entries: +#' \describe{ +#' \item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +#' on all combined synthetic results done with a fixed value of \code{D} (the +#' number of dimensions). The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{median}}{ a \code{numeric} representing the median of the +#' minimum AUROC obtained (within super populations) for all combination of +#' the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +#' AUROC obtained (within super populations) for all combination of the fixed +#' \code{D} value and all tested \code{K} values. } +#' \item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +#' of the minimum AUROC obtained (within super populations) for all +#' combination of the fixed \code{D} value and all tested \code{K} values. } +#' \item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for a fixed \code{D} value. } +#' } +#' } +#' \item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +#' all combined synthetic results done with different values of \code{D} (the +#' number of dimensions) and \code{K} (the number of neighbors). +#' The \code{data.frame} contains those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +#' obtained by grouping all the synthetic results by super-populations, for +#' the specified values of \code{D} and \code{K}.} +#' \item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +#' by grouping all the synthetic results for the specified values of \code{D} +#' and \code{K}.} +#' \item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +#' of the confusion matrix obtained by grouping all the synthetic results for +#' the specified values of \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +#' super-population. The \code{data.frame} contains +#' those columns: +#' \describe{ +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions).} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors).} +#' \item{\code{Call}}{ a \code{character} string representing the +#' super-population.} +#' \item{\code{L}}{ a \code{numeric} representing the lower value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' \item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for the +#' fixed values of super-population, \code{D} and \code{K}.} +#' \item{\code{H}}{ a \code{numeric} representing the higher value of the 95% +#' confidence interval for the AUROC obtained for the fixed values of +#' super-population, \code{D} and \code{K}.} +#' } +#' } +#' \item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +#' (the number of dimensions) for the specific profile.} +#' \item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +#' (the number of neighbors) for the specific profile.} +#' \item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +#' values (the number of dimensions) for the specific profile. More than one +#' \code{D} is possible.} +#' } +#' } +#' \item{\code{KNNSample}}{ a \code{data.frame} containing the inferred ancestry +#' for different values of \code{K} and \code{D}. The \code{data.frame} +#' contains those columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry. } +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry. } +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry for the specified \code{D} and \code{K} values.} +#' } +#' } +#' \item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred ancestry +#' for each synthetic data for different values of \code{K} and \code{D}. +#' The \code{data.frame} +#' contains those columns: "sample.id", "D", "K", "infer.superPop", "ref.superPop" +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current synthetic data.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry. } +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry. } +#' \item{\code{infer.superPop}}{ a \code{character} string representing the inferred +#' ancestry for the specified \code{D} and \code{K} values.} +#' \item{\code{ref.superPop}}{ a \code{character} string representing the known +#' ancestry from the reference} +#' } +#' } +#' \item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +#' ancestry for the current profile. The \code{data.frame} contains those +#' columns: +#' \describe{ +#' \item{\code{sample.id}}{ a \code{character} string representing the unique +#' identifier of the current profile.} +#' \item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +#' number of dimensions) used to infer the ancestry.} +#' \item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +#' number of neighbors) used to infer the ancestry.} +#' \item{\code{SuperPop}}{ a \code{character} string representing the inferred +#' ancestry.} +#' } +#' } +#' } +#' +#' @references +#' +#' Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +#' Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +#' of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +#' doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +#' +#' @examples +#' +#' ## Required library for GDS +#' library(SNPRelate) +#' +#' ## Path to the demo 1KG GDS file is located in this package +#' dataDir <- system.file("extdata", package="RAIDS") +#' +#' ################################################################# +#' ## The 1KG GDS file and the 1KG SNV Annotation GDS file +#' ## need to be located in the same directory +#' ## Note that the 1KG GDS file used for this example is a +#' ## simplified version and CANNOT be used for any real analysis +#' ################################################################# +#' path1KG <- file.path(dataDir, "tests") +#' +#' fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +#' fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") +#' +#' ################################################################# +#' ## The Sample SNP pileup files (one per sample) need +#' ## to be located in the same directory. +#' ################################################################# +#' demoProfileEx1 <- file.path(dataDir, "example", "snpPileup", "ex1.txt.gz") +#' +#' ################################################################# +#' ## The path where the Profile GDS Files (one per sample) +#' ## will be created need to be specified. +#' ################################################################# +#' pathProfileGDS <- file.path(tempdir(), "out.tmp") +#' +#' #################################################################### +#' ## Fix seed to ensure reproducible results +#' #################################################################### +#' set.seed(3043) +#' +#' gds1KG <- snpgdsOpen(fileReferenceGDS) +#' dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +#' closefn.gds(gds1KG) +#' +#' ## Required library for this example to run correctly +#' if (requireNamespace("GenomeInfoDb", quietly=TRUE) && +#' requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { +#' +#' ## Chromosome length information +#' ## chr23 is chrX, chr24 is chrY and chrM is 25 +#' chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] +#' +#' \donttest{ +#' +#' res <- inferAncestryDNA(profileFile=demoProfileEx1, +#' pathProfileGDS=pathProfileGDS, +#' fileReferenceGDS=fileReferenceGDS, +#' fileReferenceAnnotGDS=fileAnnotGDS, +#' chrInfo=chrInfo, +#' syntheticRefDF=dataRef, +#' genoSource="snp-pileup") +#' +#' unlink(pathProfileGDS, recursive=TRUE, force=TRUE) +#' +#' } +#' } +#' +#' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +#' @importFrom utils write.csv +#' @importFrom rlang arg_match +#' @encoding UTF-8 +#' @export +inferAncestryDNA <- function(profileFile, pathProfileGDS, + fileReferenceGDS, fileReferenceAnnotGDS, + chrInfo, syntheticRefDF, + genoSource=c("snp-pileup", "generic", "VCF", "bam"), + np=1L, verbose=FALSE) { + + return(inferAncestry(profileFile=profileFile, pathProfileGDS=pathProfileGDS, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileReferenceAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=syntheticRefDF, + genoSource=genoSource, + np=np, verbose=verbose)) +} #' @title Run most steps leading to the ancestry inference call on a specific diff --git a/R/processStudy_internal.R b/R/processStudy_internal.R index 897f7baf6..e9a2799b5 100644 --- a/R/processStudy_internal.R +++ b/R/processStudy_internal.R @@ -2673,16 +2673,22 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, np=1L, blockTypeID=NULL, verbose=FALSE) { # This part can be share with runProfileAncestry studyType <- arg_match(studyType) - + if(verbose){ + message("pruningSample start ", Sys.time()) + } pruningSample(gdsReference=gdsReference, currentProfile=currentProfile, studyID=studyDF$study.id, pathProfileGDS=pathProfileGDS, np=np) - + if(verbose){ + message("pruningSample end ", Sys.time()) + } fileGDSProfile <- file.path(pathProfileGDS, paste0(currentProfile, ".gds")) add1KG2SampleGDS(gdsReference=gdsReference, fileProfileGDS=fileGDSProfile, currentProfile=currentProfile, studyID=studyDF$study.id) - + if(verbose){ + message("add1KG start ", Sys.time()) + } addStudy1Kg(gdsReference, fileGDSProfile) gdsProfile <- openfn.gds(fileGDSProfile, readonly=FALSE) @@ -2698,7 +2704,9 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, prepSynthetic(fileProfileGDS=fileGDSProfile, listSampleRef=listProfileRef, profileID=currentProfile, studyDF=studyDFSyn, prefix="1", verbose=verbose) - + if(verbose){ + message("syntheticGeno start ", Sys.time()) + } resG <- syntheticGeno(gdsReference=gdsReference, gdsRefAnnot=gdsRefAnnot, fileProfileGDS=fileGDSProfile, profileID=currentProfile, listSampleRef=listProfileRef, prefix="1") @@ -2720,7 +2728,9 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, ## Open the Profile GDS file gdsProfile <- snpgdsOpen(fileGDSProfile) - + if(verbose){ + message("SyntheticAncestry start ", Sys.time()) + } ## This variable will contain the results from the PCA analyses ## For each row of the sampleRM matrix resSyn <- lapply(seq_len(nrow(sampleRM)), FUN=function(x, sampleRM, @@ -2737,6 +2747,9 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, }, sampleRM=sampleRM, gdsProfile=gdsProfile, studyDFSyn=studyDFSyn, spRef=spRef, currentProfile=currentProfile) + if(verbose){ + message("SyntheticAncestry end ", Sys.time()) + } resSyn <- do.call(rbind, resSyn) ## Extract the super-population information from the 1KG GDS file ## for profiles associated to the synthetic study @@ -2756,7 +2769,9 @@ profileAncestry <- function(gdsReference, gdsRefAnnot, studyDF, gdsProfile=gdsProfile, syntheticKNN=resSyn, pedSyn=pedSyn, currentProfile=currentProfile, spRef=spRef, studyIDSyn=studyDFSyn$study.id, np=np) - + if(verbose){ + message("Ancestry end ", Sys.time()) + } # saveRDS(resCall, file.path(pathOut, # paste0(currentProfile, ".infoCall", ".rds"))) # @@ -3541,15 +3556,15 @@ createProfile <- function(profileFile, profileName, ALT = alDf[2,], stringsAsFactors = FALSE ) - listChr <- unique(listPos$chr) + # listChr <- unique(listPos$chr) # We can optimize - listPos <- lapply(listChr, - FUN=function(x, varDf){ - return(varDf[which(varDf$chr == x),]) - }, - varDf=listPos) - names(listPos) <- paste0("chr", listChr) - rm(alDf,listChr) + # listPos <- lapply(listChr, + # FUN=function(x, varDf){ + # return(varDf[which(varDf$chr == x),]) + # }, + # varDf=listPos) + # names(listPos) <- paste0("chr", listChr) + rm(alDf) } else{ listPos <- data.frame(snp.chromosome=read.gdsn(index.gdsn(node=gdsReference, "snp.chromosome")), snp.position=read.gdsn(index.gdsn(node=gdsReference, "snp.position"))) diff --git a/R/tools_internal.R b/R/tools_internal.R index af8dde9fc..e128bbfba 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -678,14 +678,24 @@ readSNVBAM <- function(fileName, yieldSize=10000000), verbose=FALSE) { # Note the offset is apply to the ref not the sequemce (snp-pileup and vcf) - listChr <- names(varSelected) - varSelected <- lapply(seq_len(length(varSelected)), - FUN=function(x, varSelected){ - varSelected[[x]]$chr <- paste0("chr", varSelected[[x]]$chr) - varSelected[[x]]$start <- varSelected[[x]]$start - offset - return(varSelected[[x]]) - }, - varSelected=varSelected) + varSelected$chr <- paste0("chr", varSelected$chr) + varSelected$start <- varSelected$start - offset + listChr <- unique(varSelected$chr) + # listChr <- names(varSelected) + varSelected <- lapply(listChr, + FUN=function(x, varDf){ + return(varDf[which(varDf$chr == x),]) + }, + varDf=varSelected) + + # names(listPos) <- paste0("chr", listChr) + # varSelected <- lapply(seq_len(length(varSelected)), + # FUN=function(x, varSelected){ + # varSelected[[x]]$chr <- paste0("chr", varSelected[[x]]$chr) + # varSelected[[x]]$start <- varSelected[[x]]$start + offset + # return(varSelected[[x]]) + # }, + # varSelected=varSelected) names(varSelected) <- listChr #varSelected$chr <- paste0("chr", varSelected$chr) #varSelected$start <- varSelected$start - offset @@ -800,7 +810,7 @@ readSNVBAM <- function(fileName, } resSNP <- resSNP[, c("seqnames", "pos", "REF", "ALT", "File1R", "File1A", "count", "A", "C", "G", "T")] colnames(resSNP) <- c("Chromosome", "Position", "Ref", "Alt", "File1R", "File1A", "count", "A", "C", "G", "T") - + resSNP$Position <- resSNP$Position + offset if(verbose) {message("readSNVBAM pileup format Done ", Sys.time())} diff --git a/inst/NEWS.md b/inst/NEWS.md index 2b8284282..dfc113acf 100644 --- a/inst/NEWS.md +++ b/inst/NEWS.md @@ -3,7 +3,7 @@ CHANGES IN VERSION 1.5.1 SIGNIFICANT USER-VISIBLE CHANGES - o Intagration of Rsamtools + o Integration of Rsamtools CHANGES IN VERSION 1.3.3 ------------------------ diff --git a/man/inferAncestryDNA.Rd b/man/inferAncestryDNA.Rd new file mode 100644 index 000000000..e5aeb0ba5 --- /dev/null +++ b/man/inferAncestryDNA.Rd @@ -0,0 +1,281 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/processStudy.R +\encoding{UTF-8} +\name{inferAncestryDNA} +\alias{inferAncestryDNA} +\title{Run most steps leading to the ancestry inference call on a specific +DNA profile (alias for inferAncestry )} +\usage{ +inferAncestryDNA( + profileFile, + pathProfileGDS, + fileReferenceGDS, + fileReferenceAnnotGDS, + chrInfo, + syntheticRefDF, + genoSource = c("snp-pileup", "generic", "VCF", "bam"), + np = 1L, + verbose = FALSE +) +} +\arguments{ +\item{profileFile}{a \code{character} string representing the path and the +file name of the genotype file or the bam if genoSource is snp-pileup the +fine extension must be .txt.gz, if VCF the extension must be .vcf.gz} + +\item{pathProfileGDS}{a \code{character} string representing the path to +the directory where the GDS Profile files will be created. +Default: \code{NULL}.} + +\item{fileReferenceGDS}{a \code{character} string representing the file +name of the Population Reference GDS file. The file must exist.} + +\item{fileReferenceAnnotGDS}{a \code{character} string representing the +file name of the Population Reference GDS Annotation file. The file +must exist.} + +\item{chrInfo}{a \code{vector} of positive \code{integer} values +representing the length of the chromosomes. See 'details' section.} + +\item{syntheticRefDF}{a \code{data.frame} containing a subset of +reference profiles for each sub-population present in the Reference GDS +file. The \code{data.frame} must have those columns: +\describe{ +\item{sample.id}{ a \code{character} string representing the sample +identifier. } +\item{pop.group}{ a \code{character} string representing the +subcontinental population assigned to the sample. } +\item{superPop}{ a \code{character} string representing the +super-population assigned to the sample. } +}} + +\item{genoSource}{a \code{character} string with four possible values: +'snp-pileup', 'generic', 'VCF' or 'bam'. It specifies if the genotype files +are generated by snp-pileup (Facets) or are a generic format CSV file +with at least those columns: +'Chromosome', 'Position', 'Ref', 'Alt', 'Count', 'File1R' and 'File1A'. +The 'Count' is the depth at the specified position; +'FileR' is the depth of the reference allele and +'File1A' is the depth of the specific alternative allele. +Finally the file can be a VCF file with at least those genotype +fields: GT, AD, DP.} + +\item{np}{a single positive \code{integer} specifying the number of +threads to be used. Default: \code{1L}.} + +\item{verbose}{a \code{logical} indicating if messages should be printed +to show how the different steps in the function. Default: \code{FALSE}.} +} +\value{ +a \code{list} containing 4 entries: +\describe{ +\item{\code{pcaSample}}{ a \code{list} containing the information related +to the eigenvectors. The \code{list} contains those 3 entries: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{eigenvector.ref}}{ a \code{matrix} of \code{numeric} containing +the eigenvectors for the reference profiles.} +\item{\code{eigenvector}}{ a \code{matrix} of \code{numeric} containing the +eigenvectors for the current profile projected on the PCA from the +reference profiles.} +} +} +\item{\code{paraSample}}{ a \code{list} containing the results with +different \code{D} and \code{K} values that lead to optimal parameter +selection. The \code{list} contains those entries: +\describe{ +\item{\code{dfPCA}}{ a \code{data.frame} containing statistical results +on all combined synthetic results done with a fixed value of \code{D} (the +number of dimensions). The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{median}}{ a \code{numeric} representing the median of the +minimum AUROC obtained (within super populations) for all combination of +the fixed \code{D} value and all tested \code{K} values. } +\item{\code{mad}}{ a \code{numeric} representing the MAD of the minimum +AUROC obtained (within super populations) for all combination of the fixed +\code{D} value and all tested \code{K} values. } +\item{\code{upQuartile}}{ a \code{numeric} representing the upper quartile +of the minimum AUROC obtained (within super populations) for all +combination of the fixed \code{D} value and all tested \code{K} values. } +\item{\code{k}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for a fixed \code{D} value. } +} +} +\item{\code{dfPop}}{ a \code{data.frame} containing statistical results on +all combined synthetic results done with different values of \code{D} (the +number of dimensions) and \code{K} (the number of neighbors). +The \code{data.frame} contains those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{AUROC.min}}{ a \code{numeric} representing the minimum accuracy +obtained by grouping all the synthetic results by super-populations, for +the specified values of \code{D} and \code{K}.} +\item{\code{AUROC}}{ a \code{numeric} representing the accuracy obtained +by grouping all the synthetic results for the specified values of \code{D} +and \code{K}.} +\item{\code{Accu.CM}}{ a \code{numeric} representing the value of accuracy +of the confusion matrix obtained by grouping all the synthetic results for +the specified values of \code{D} and \code{K}.} +} +} +\item{\code{dfAUROC}}{ a \code{data.frame} the summary of the results by +super-population. The \code{data.frame} contains +those columns: +\describe{ +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions).} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors).} +\item{\code{Call}}{ a \code{character} string representing the +super-population.} +\item{\code{L}}{ a \code{numeric} representing the lower value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +\item{\code{AUROC}}{ a \code{numeric} representing the AUROC obtained for the +fixed values of super-population, \code{D} and \code{K}.} +\item{\code{H}}{ a \code{numeric} representing the higher value of the 95\% +confidence interval for the AUROC obtained for the fixed values of +super-population, \code{D} and \code{K}.} +} +} +\item{\code{D}}{ a \code{numeric} representing the optimal \code{D} value +(the number of dimensions) for the specific profile.} +\item{\code{K}}{ a \code{numeric} representing the optimal \code{K} value +(the number of neighbors) for the specific profile.} +\item{\code{listD}}{ a \code{numeric} representing the optimal \code{D} +values (the number of dimensions) for the specific profile. More than one +\code{D} is possible.} +} +} +\item{\code{KNNSample}}{ a \code{data.frame} containing the inferred ancestry +for different values of \code{K} and \code{D}. The \code{data.frame} +contains those columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry. } +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry. } +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry for the specified \code{D} and \code{K} values.} +} +} +\item{\code{KNNSynthetic}}{ a \code{data.frame} containing the inferred ancestry +for each synthetic data for different values of \code{K} and \code{D}. +The \code{data.frame} +contains those columns: "sample.id", "D", "K", "infer.superPop", "ref.superPop" +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current synthetic data.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry. } +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry. } +\item{\code{infer.superPop}}{ a \code{character} string representing the inferred +ancestry for the specified \code{D} and \code{K} values.} +\item{\code{ref.superPop}}{ a \code{character} string representing the known +ancestry from the reference} +} +} +\item{\code{Ancestry}}{ a \code{data.frame} containing the inferred +ancestry for the current profile. The \code{data.frame} contains those +columns: +\describe{ +\item{\code{sample.id}}{ a \code{character} string representing the unique +identifier of the current profile.} +\item{\code{D}}{ a \code{numeric} representing the value of \code{D} (the +number of dimensions) used to infer the ancestry.} +\item{\code{K}}{ a \code{numeric} representing the value of \code{K} (the +number of neighbors) used to infer the ancestry.} +\item{\code{SuperPop}}{ a \code{character} string representing the inferred +ancestry.} +} +} +} +} +\description{ +This function runs most steps leading to the ancestry inference +call on a specific RNA profile. First, the function creates the +Profile GDS file for the specific profile using the information from a +RDS Sample description file and the Population Reference GDS file. +} +\examples{ + +## Required library for GDS +library(SNPRelate) + +## Path to the demo 1KG GDS file is located in this package +dataDir <- system.file("extdata", package="RAIDS") + +################################################################# +## The 1KG GDS file and the 1KG SNV Annotation GDS file +## need to be located in the same directory +## Note that the 1KG GDS file used for this example is a +## simplified version and CANNOT be used for any real analysis +################################################################# +path1KG <- file.path(dataDir, "tests") + +fileReferenceGDS <- file.path(path1KG, "ex1_good_small_1KG.gds") +fileAnnotGDS <- file.path(path1KG, "ex1_good_small_1KG_Annot.gds") + +################################################################# +## The Sample SNP pileup files (one per sample) need +## to be located in the same directory. +################################################################# +demoProfileEx1 <- file.path(dataDir, "example", "snpPileup", "ex1.txt.gz") + +################################################################# +## The path where the Profile GDS Files (one per sample) +## will be created need to be specified. +################################################################# +pathProfileGDS <- file.path(tempdir(), "out.tmp") + +#################################################################### +## Fix seed to ensure reproducible results +#################################################################### +set.seed(3043) + +gds1KG <- snpgdsOpen(fileReferenceGDS) +dataRef <- select1KGPop(gds1KG, nbProfiles=2L) +closefn.gds(gds1KG) + +## Required library for this example to run correctly +if (requireNamespace("GenomeInfoDb", quietly=TRUE) && + requireNamespace("BSgenome.Hsapiens.UCSC.hg38", quietly=TRUE)) { + + ## Chromosome length information + ## chr23 is chrX, chr24 is chrY and chrM is 25 + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + \donttest{ + + res <- inferAncestryDNA(profileFile=demoProfileEx1, + pathProfileGDS=pathProfileGDS, + fileReferenceGDS=fileReferenceGDS, + fileReferenceAnnotGDS=fileAnnotGDS, + chrInfo=chrInfo, + syntheticRefDF=dataRef, + genoSource="snp-pileup") + + unlink(pathProfileGDS, recursive=TRUE, force=TRUE) + + } +} + +} +\references{ +Galinsky KJ, Bhatia G, Loh PR, Georgiev S, Mukherjee S, Patterson NJ, +Price AL. Fast Principal-Component Analysis Reveals Convergent Evolution +of ADH1B in Europe and East Asia. Am J Hum Genet. 2016 Mar 3;98(3):456-72. +doi: 10.1016/j.ajhg.2015.12.022. Epub 2016 Feb 25. +} +\author{ +Pascal Belleau, Astrid Deschênes and Alexander Krasnitz +} From 12305bb39d00fd8f3616c6946700d3c4513a6a91 Mon Sep 17 00:00:00 2001 From: belleau Date: Tue, 15 Apr 2025 22:42:57 -0400 Subject: [PATCH 356/385] Update version --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 6d591627e..969b5a478 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: This package implements specialized algorithms that enable following publication: Belleau, P et al. Genetic Ancestry Inference from Cancer-Derived Molecular Data across Genomic and Transcriptomic Platforms. Cancer Res 1 January 2023; 83 (1): 49–58. -Version: 1.7.0 +Version: 1.7.1 Authors@R: c(person("Pascal", "Belleau", email="pascal_belleau@hotmail.com", role=c("cre", "aut"), comment = c(ORCID = "0000-0002-0802-1071")), person("Astrid", "Deschênes", email="adeschen@hotmail.com", From a1c206beff044531961a18accb387a46952a0586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Thu, 1 May 2025 14:19:43 -0400 Subject: [PATCH 357/385] Update test-coverage.yaml --- .github/workflows/test-coverage.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index cecf6b749..1b374b251 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -2,9 +2,7 @@ # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: - branches: main pull_request: - branches: main name: test-coverage @@ -29,3 +27,5 @@ jobs: - name: Test coverage run: covr::codecov(quiet = FALSE) shell: Rscript {0} + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 64dfaffd31712655716dd747b631238568b8e0d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Fri, 2 May 2025 16:22:39 -0400 Subject: [PATCH 358/385] Update README.md Update badge codecov --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f5867a03e..9a3029e4f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![codecov](https://codecov.io/gh/krasnitzlab/RAIDS/branch/main/graph/badge.svg?token=LPFLOMUDVT)](https://codecov.io/gh/krasnitzlab/RAIDS) +[![codecov](https://codecov.io/gh/adeschen/RAIDS/graph/badge.svg?token=JTTO1CH8AZ)](https://codecov.io/gh/adeschen/RAIDS) [![R-CMD-check-bioc](https://github.com/krasnitzlab/RAIDS/actions/workflows/check-bioc.yaml/badge.svg)](https://github.com/krasnitzlab/RAIDS/actions/workflows/check-bioc.yaml) From e542059ec8fd2033bfc83b5bf94769acaa4446e8 Mon Sep 17 00:00:00 2001 From: adeschen Date: Tue, 6 May 2025 15:04:10 -0400 Subject: [PATCH 359/385] Update createAccuracyGraph() to follow changes in ggplot2 library and add unit tests --- R/visualization.R | 4 ++-- tests/testthat/helper_initGDS.R | 4 ++-- tests/testthat/test-visualization.R | 11 +++++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/R/visualization.R b/R/visualization.R index ab7499d9a..8678b10b0 100644 --- a/R/visualization.R +++ b/R/visualization.R @@ -80,8 +80,8 @@ createAccuracyGraph <- function(fileRDS, title="", color=.data$D, linetype=.data$D)) + ylab(label = "AUROC") + geom_ribbon(aes(ymin=.data$L, ymax=.data$H, group=.data$D), - linetype="dotted", cex=2, alpha=0.1) + - geom_line(cex=2) + facet_grid(. ~ Call) + + linetype="dotted", linewidth=2, alpha=0.1) + + geom_line(linewidth=2) + facet_grid(. ~ Call) + ylim(c(ymin, 1)) + ggtitle(title) + scale_colour_manual(aesthetics = c("colour", "fill"), breaks=selectD, values=selectColor) + diff --git a/tests/testthat/helper_initGDS.R b/tests/testthat/helper_initGDS.R index 7ada8b90e..cc77d58e6 100644 --- a/tests/testthat/helper_initGDS.R +++ b/tests/testthat/helper_initGDS.R @@ -8,7 +8,7 @@ library(gdsfmt) ## The file will be removed automatically local_GDS_Sample_file <- function(path, env = parent.frame()) { GDS_file_tmp <- createfn.gds(filename=path) - defer(unlink(x=path, force=TRUE), envir = env) + withr::defer(unlink(x=path, force=TRUE), envir = env) add.gdsn(GDS_file_tmp, "Ref.count", rep(10L, 12)) add.gdsn(GDS_file_tmp, "Alt.count", rep(12L, 12)) @@ -24,7 +24,7 @@ local_GDS_Sample_file <- function(path, env = parent.frame()) { ## The file will be removed automatically local_GDS_1KG_file <- function(path, env = parent.frame()) { GDS_file_tmp <- createfn.gds(filename=path) - defer(unlink(x=path, force=TRUE), envir = env) + withr::defer(unlink(x=path, force=TRUE), envir = env) ## Create sample information initial add.gdsn(GDS_file_tmp, "sample.id", c("HTT101", "HTT102", "HTT103")) diff --git a/tests/testthat/test-visualization.R b/tests/testthat/test-visualization.R index d32b5f218..2f63c979a 100644 --- a/tests/testthat/test-visualization.R +++ b/tests/testthat/test-visualization.R @@ -102,3 +102,14 @@ test_that("createAccuracyGraph() must return error when selectColor shorter than selectD=c(1,2,3,4), selectColor=c("#5e688a", "#cd5700", "#CC79A7")), error_message) }) + + +test_that("createAccuracyGraph() must return a gglot object when successful", { + + fileGDS <- test_path("fixtures", "TEST_01.infoCall.RDS") + + graphE <-createAccuracyGraph(fileRDS=fileGDS, title="", + selectD=c(7,8,9), selectColor=c("#5e688a", "#cd5700", "#CC79A7")) + + testthat::expect_is(graphE, "ggplot") +}) From bd6fd5aa72ef072ec61e6e94d8bd3d11c1166c49 Mon Sep 17 00:00:00 2001 From: adeschen Date: Tue, 6 May 2025 15:52:02 -0400 Subject: [PATCH 360/385] Adding unit test for createAccuracyGraph() function --- tests/testthat/test-visualization.R | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/testthat/test-visualization.R b/tests/testthat/test-visualization.R index 2f63c979a..ef7f9ab57 100644 --- a/tests/testthat/test-visualization.R +++ b/tests/testthat/test-visualization.R @@ -91,6 +91,18 @@ test_that("createAccuracyGraph() must return error when selectD has 6 elements", }) +test_that("createAccuracyGraph() must return error when selectD value not in the file", { + + fileGDS <- test_path("fixtures", "TEST_01.infoCall.RDS") + + error_message <- paste0("Not all values in \'selectD\' are present in the RDS file.") + + expect_error(createAccuracyGraph(fileRDS=fileGDS, title="", + selectD=c(32,32,34), selectColor=c("#5e688a", "#cd5700", "#CC79A7")), + error_message) +}) + + test_that("createAccuracyGraph() must return error when selectColor shorter than selectD", { fileGDS <- test_path("fixtures", "TEST_01.infoCall.RDS") From eacc7368f99440e3a74a219eed310b0255980297 Mon Sep 17 00:00:00 2001 From: adeschen Date: Tue, 6 May 2025 16:50:49 -0400 Subject: [PATCH 361/385] Update createAUROCGraph() function to follow changes in ggplot2 and add unit test --- R/visualization.R | 16 +++++++----- tests/testthat/test-visualization.R | 38 +++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/R/visualization.R b/R/visualization.R index 8678b10b0..ec38426de 100644 --- a/R/visualization.R +++ b/R/visualization.R @@ -112,7 +112,8 @@ createAccuracyGraph <- function(fileRDS, title="", #' all tested ancestries. #' #' @param dfAUROC a \code{data.frame} corresponding to res$paraSample$dfAUROC -#' where res is the result of inferAncestry or inferAncestryGeneAware. +#' where res is the result of inferAncestry() or inferAncestryGeneAware() +#' functions. #' #' @param title a \code{character} string representing the title of the graph. #' Default: \code{""}. @@ -143,11 +144,14 @@ createAccuracyGraph <- function(fileRDS, title="", #' fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") #' info <- readRDS(fileRDS) #' dfAUROC <- info$paraSample$dfAUROC +#' +#' ## Some of the column names must be updated to fit new standards #' colnames(dfAUROC) <- c("D", "K", "Call", "L", "AUROC", "H") +#' #' ## Create accuracy graph #' accuracyGraph <- createAUROCGraph(dfAUROC=dfAUROC, title="Test 01", -#' selectD=c(3,6,9,12,15), -#' selectColor=c("steelblue", "darkorange", "violet", "pink", "gray80")) +#' selectD=c(3, 6, 9, 12, 15), +#' selectColor=c("steelblue", "darkorange", "violet", "pink", "gray40")) #' #' accuracyGraph #' @@ -159,7 +163,7 @@ createAccuracyGraph <- function(fileRDS, title="", #' @encoding UTF-8 #' @export createAUROCGraph <- function(dfAUROC, title="", - selectD=c(3,7,11), selectColor=c("#5e688a", "#cd5700", "#CC79A7")) { + selectD=c(3,7,11), selectColor=c("#5e688a", "#cd5700", "#CC79A7")) { ## Validate parameters # validateCreateAccuracyGraph(fileRDS=fileRDS, title=title, selectD=selectD, @@ -187,8 +191,8 @@ createAUROCGraph <- function(dfAUROC, title="", color=.data$D, linetype=.data$D)) + ylab(label = "AUROC") + geom_ribbon(aes(ymin=.data$L, ymax=.data$H, group=.data$D), - linetype="dotted", cex=2, alpha=0.1) + - geom_line(cex=2) + facet_grid(. ~ Call) + + linetype="dotted", linewidth=2, alpha=0.1) + + geom_line(linewidth=2) + facet_grid(. ~ Call) + ylim(c(ymin, 1)) + ggtitle(title) + scale_colour_manual(aesthetics = c("colour", "fill"), breaks=selectD, values=selectColor) + diff --git a/tests/testthat/test-visualization.R b/tests/testthat/test-visualization.R index ef7f9ab57..6b3b84595 100644 --- a/tests/testthat/test-visualization.R +++ b/tests/testthat/test-visualization.R @@ -125,3 +125,41 @@ test_that("createAccuracyGraph() must return a gglot object when successful", { testthat::expect_is(graphE, "ggplot") }) + + +############################################################################# +### Tests createAUROCGraph() results +############################################################################# + +context("createAUROCGraph() results") + + +test_that("createAccuracyGraph() must return a gglot object when successful", { + + dfAuroc <- data.frame(D=c(rep(2, 15), rep(3, 15)), + K=c(rep(c(2, 3, 4), 10)), + Call=c("EUR", "EUR", "EUR", "AMR", "AMR", "AMR", + "EAS", "EAS", "EAS", "SAS", "SAS", "SAS", + "AFR", "AFR", "AFR", + "EUR", "EUR", "EUR", "AMR", "AMR", "AMR", + "EAS", "EAS", "EAS", "SAS", "SAS", "SAS", + "AFR", "AFR", "AFR"), + AUROC=c(0.95000, 0.9628737, 0.9701246, 0.8337130, + 0.8509514, 0.9800000, 0.9158718, 0.9267399, + 0.9386384, 0.7484138, 0.9000000, 0.9892067, + 0.88000, 0.8758737, 0.9021246, + 0.99000, 0.9888737, 0.9931246, 0.8837130, + 0.8959514, 1.0000000, 0.9788718, 0.9977399, + 0.9886384, 0.8244138, 1.0000000, 0.9982067, + 0.92000, 0.8998737, 0.9251246)) + dfAuroc$L <- dfAuroc$AUROC - 0.03 + dfAuroc$H <- dfAuroc$AUROC + 0.02 + dfAuroc$H[which(dfAuroc$H > 1.0000)] <- 1.0000000 + + + graphE <-createAUROCGraph(dfAUROC=dfAuroc, title="", + selectD=c(2,3), selectColor=c("#5e688a", "#cd5700", "#CC79A7")) + + testthat::expect_is(graphE, "ggplot") +}) + From c42b590bc5897125a306405aa01b42bf06dea427 Mon Sep 17 00:00:00 2001 From: adeschen Date: Tue, 6 May 2025 17:33:46 -0400 Subject: [PATCH 362/385] Adding internal function to validate createAUROCgraph() parameters and correcting unit tests --- R/visualization.R | 8 +- R/visualization_internal.R | 112 ++++++++++++++++++++++++++- man/createAUROCGraph.Rd | 10 ++- man/validateAccuracyGraphInternal.Rd | 43 ++++++++++ man/validatecreateAUROCGraph.Rd | 55 +++++++++++++ tests/testthat/test-visualization.R | 2 +- 6 files changed, 219 insertions(+), 11 deletions(-) create mode 100644 man/validateAccuracyGraphInternal.Rd create mode 100644 man/validatecreateAUROCGraph.Rd diff --git a/R/visualization.R b/R/visualization.R index ec38426de..3a0571e08 100644 --- a/R/visualization.R +++ b/R/visualization.R @@ -166,12 +166,8 @@ createAUROCGraph <- function(dfAUROC, title="", selectD=c(3,7,11), selectColor=c("#5e688a", "#cd5700", "#CC79A7")) { ## Validate parameters - # validateCreateAccuracyGraph(fileRDS=fileRDS, title=title, selectD=selectD, - # selectColor=selectColor) - # - ## Extract required information from RDS file - # info <- readRDS(fileRDS) - # dfAUROC <- info$paraSample$dfAUROC + validatecreateAUROCGraph(dfAUROC=dfAUROC, title=title, selectD=selectD, + selectColor=selectColor) if (!all(selectD %in% unique(dfAUROC$D))) { stop("Not all values in \'selectD\' are present in the RDS file.") diff --git a/R/visualization_internal.R b/R/visualization_internal.R index 598c935f7..894960a9a 100644 --- a/R/visualization_internal.R +++ b/R/visualization_internal.R @@ -1,3 +1,70 @@ +#' @title Validate input parameters for createAccuracyGraph +#' function +#' +#' @description This function validates the parameters for the +#' \code{\link{createAccuracyGraph}} function. +#' +#' @param dfAUROC a \code{data.frame} corresponding to res$paraSample$dfAUROC +#' where res is the result of inferAncestry() or inferAncestryGeneAware() +#' functions. +#' +#' @param title a \code{character} string representing the title of the graph. +#' +#' @param selectD a \code{array} of \code{integer} representing the selected +#' PCA dimensions to plot. The length of the \code{array} cannot be more than +#' 5 entries. The dimensions must tested by RAIDS (i.e. be present in the +#' RDS file). +#' +#' @param selectColor a \code{array} of \code{character} strings representing +#' the selected colors for the associated PCA dimensions to plot. The length +#' of the \code{array} must correspond to the length of the \code{selectD} +#' parameter. In addition, the length of the \code{array} cannot be more than +#' 5 entries. +#' +#' @return The function returns \code{0L} when successful. +#' +#' @examples +#' +#' ## Path to RDS file with ancestry information generated by RAIDS (demo file) +#' dataDir <- system.file("extdata", package="RAIDS") +#' fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") +#' info <- readRDS(fileRDS) +#' dfAUROC <- info$paraSample$dfAUROC +#' +#' ## Some of the column names must be updated to fit new standards +#' colnames(dfAUROC) <- c("D", "K", "Call", "L", "AUROC", "H") +#' +#' ## Validate parameters +#' RAIDS:::validatecreateAUROCGraph(dfAUROC=dfAUROC, title="Accuracy Graph", +#' selectD=c(6, 12), selectColor=c("blue","darkblue")) +#' +#' @author Astrid Deschênes and Pascal Belleau +#' @importFrom stringr str_detect +#' @encoding UTF-8 +#' @keywords internal +validatecreateAUROCGraph <- function(dfAUROC, title, selectD, selectColor) { + + ## Validate dfAUROC is a data frame + if(!is.data.frame(dfAUROC)) { + stop("The \'dfAUROC\' parameter must be a data frame.") + } + + ## Validate the file extension + colL <- c("D", "K", "Call", "L", "AUROC", "H") + if (!all(colL %in% colnames(dfAUROC))) { + stop("The \'dfAUROC\' must have all those columns: D, K, Call, ", + "L, AUROC, H.") + } + + ## Validate other parameters + res <- validateAccuracyGraphInternal(title=title, selectD=selectD, + selectColor=selectColor) + + ## Success + return(res) +} + + #' @title Validate input parameters for createAccuracyGraph #' function #' @@ -43,7 +110,7 @@ validateCreateAccuracyGraph <- function(fileRDS, title, selectD, selectColor) { if(!is.character(fileRDS)) { stop("The \'fileRDS\' parameter must be a character string.") } - + ## Validate fileRDS exist if(!file.exists(fileRDS)) { stop("The \'fileRDS\' file does not exist.") @@ -54,6 +121,49 @@ validateCreateAccuracyGraph <- function(fileRDS, title, selectD, selectColor) { stop("The \'fileRDS\' must have a RDS (or rds) extension.") } + ## Validate other parameters + res <- validateAccuracyGraphInternal(title=title, selectD=selectD, + selectColor=selectColor) + + ## Success + return(res) +} + + +#' @title Validate input parameters for createAccuracyGraph and +#' createAUROCGraph functions +#' +#' @description This function validates the parameters for the +#' \code{\link{createAccuracyGraph}} and \code{\link{createAUROCGraph}} +#' functions. +#' +#' @param title a \code{character} string representing the title of the graph. +#' +#' @param selectD a \code{array} of \code{integer} representing the selected +#' PCA dimensions to plot. The length of the \code{array} cannot be more than +#' 5 entries. The dimensions must tested by RAIDS (i.e. be present in the +#' RDS file). +#' +#' @param selectColor a \code{array} of \code{character} strings representing +#' the selected colors for the associated PCA dimensions to plot. The length +#' of the \code{array} must correspond to the length of the \code{selectD} +#' parameter. In addition, the length of the \code{array} cannot be more than +#' 5 entries. +#' +#' @return The function returns \code{0L} when successful. +#' +#' @examples +#' +#' ## Validate parameters +#' RAIDS:::validateAccuracyGraphInternal(title="Accuracy Graph", +#' selectD=c(5, 10), selectColor=c("blue","darkblue")) +#' +#' @author Astrid Deschênes and Pascal Belleau +#' @importFrom stringr str_detect +#' @encoding UTF-8 +#' @keywords internal +validateAccuracyGraphInternal <- function(title, selectD, selectColor) { + ## Validate the title is a string if (!is.character(title)) { stop("The \'title\' must be a character string.") diff --git a/man/createAUROCGraph.Rd b/man/createAUROCGraph.Rd index 857de7080..28efae9a5 100644 --- a/man/createAUROCGraph.Rd +++ b/man/createAUROCGraph.Rd @@ -14,7 +14,8 @@ createAUROCGraph( } \arguments{ \item{dfAUROC}{a \code{data.frame} corresponding to res$paraSample$dfAUROC -where res is the result of inferAncestry or inferAncestryGeneAware.} +where res is the result of inferAncestry() or inferAncestryGeneAware() +functions.} \item{title}{a \code{character} string representing the title of the graph. Default: \code{""}.} @@ -52,11 +53,14 @@ dataDir <- system.file("extdata", package="RAIDS") fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") info <- readRDS(fileRDS) dfAUROC <- info$paraSample$dfAUROC + +## Some of the column names must be updated to fit new standards colnames(dfAUROC) <- c("D", "K", "Call", "L", "AUROC", "H") + ## Create accuracy graph accuracyGraph <- createAUROCGraph(dfAUROC=dfAUROC, title="Test 01", - selectD=c(3,6,9,12,15), - selectColor=c("steelblue", "darkorange", "violet", "pink", "gray80")) + selectD=c(3, 6, 9, 12, 15), + selectColor=c("steelblue", "darkorange", "violet", "pink", "gray40")) accuracyGraph diff --git a/man/validateAccuracyGraphInternal.Rd b/man/validateAccuracyGraphInternal.Rd new file mode 100644 index 000000000..85a614df1 --- /dev/null +++ b/man/validateAccuracyGraphInternal.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/visualization_internal.R +\encoding{UTF-8} +\name{validateAccuracyGraphInternal} +\alias{validateAccuracyGraphInternal} +\title{Validate input parameters for createAccuracyGraph and +createAUROCGraph functions} +\usage{ +validateAccuracyGraphInternal(title, selectD, selectColor) +} +\arguments{ +\item{title}{a \code{character} string representing the title of the graph.} + +\item{selectD}{a \code{array} of \code{integer} representing the selected +PCA dimensions to plot. The length of the \code{array} cannot be more than +5 entries. The dimensions must tested by RAIDS (i.e. be present in the +RDS file).} + +\item{selectColor}{a \code{array} of \code{character} strings representing +the selected colors for the associated PCA dimensions to plot. The length +of the \code{array} must correspond to the length of the \code{selectD} +parameter. In addition, the length of the \code{array} cannot be more than +5 entries.} +} +\value{ +The function returns \code{0L} when successful. +} +\description{ +This function validates the parameters for the +\code{\link{createAccuracyGraph}} and \code{\link{createAUROCGraph}} +functions. +} +\examples{ + +## Validate parameters +RAIDS:::validateAccuracyGraphInternal(title="Accuracy Graph", + selectD=c(5, 10), selectColor=c("blue","darkblue")) + +} +\author{ +Astrid Deschênes and Pascal Belleau +} +\keyword{internal} diff --git a/man/validatecreateAUROCGraph.Rd b/man/validatecreateAUROCGraph.Rd new file mode 100644 index 000000000..e8c4f0f1d --- /dev/null +++ b/man/validatecreateAUROCGraph.Rd @@ -0,0 +1,55 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/visualization_internal.R +\encoding{UTF-8} +\name{validatecreateAUROCGraph} +\alias{validatecreateAUROCGraph} +\title{Validate input parameters for createAccuracyGraph +function} +\usage{ +validatecreateAUROCGraph(dfAUROC, title, selectD, selectColor) +} +\arguments{ +\item{dfAUROC}{a \code{data.frame} corresponding to res$paraSample$dfAUROC +where res is the result of inferAncestry() or inferAncestryGeneAware() +functions.} + +\item{title}{a \code{character} string representing the title of the graph.} + +\item{selectD}{a \code{array} of \code{integer} representing the selected +PCA dimensions to plot. The length of the \code{array} cannot be more than +5 entries. The dimensions must tested by RAIDS (i.e. be present in the +RDS file).} + +\item{selectColor}{a \code{array} of \code{character} strings representing +the selected colors for the associated PCA dimensions to plot. The length +of the \code{array} must correspond to the length of the \code{selectD} +parameter. In addition, the length of the \code{array} cannot be more than +5 entries.} +} +\value{ +The function returns \code{0L} when successful. +} +\description{ +This function validates the parameters for the +\code{\link{createAccuracyGraph}} function. +} +\examples{ + +## Path to RDS file with ancestry information generated by RAIDS (demo file) +dataDir <- system.file("extdata", package="RAIDS") +fileRDS <- file.path(dataDir, "TEST_01.infoCall.RDS") +info <- readRDS(fileRDS) +dfAUROC <- info$paraSample$dfAUROC + +## Some of the column names must be updated to fit new standards +colnames(dfAUROC) <- c("D", "K", "Call", "L", "AUROC", "H") + +## Validate parameters +RAIDS:::validatecreateAUROCGraph(dfAUROC=dfAUROC, title="Accuracy Graph", + selectD=c(6, 12), selectColor=c("blue","darkblue")) + +} +\author{ +Astrid Deschênes and Pascal Belleau +} +\keyword{internal} diff --git a/tests/testthat/test-visualization.R b/tests/testthat/test-visualization.R index 6b3b84595..2ebe63004 100644 --- a/tests/testthat/test-visualization.R +++ b/tests/testthat/test-visualization.R @@ -158,7 +158,7 @@ test_that("createAccuracyGraph() must return a gglot object when successful", { graphE <-createAUROCGraph(dfAUROC=dfAuroc, title="", - selectD=c(2,3), selectColor=c("#5e688a", "#cd5700", "#CC79A7")) + selectD=c(2,3), selectColor=c("#5e688a", "#CC79A7")) testthat::expect_is(graphE, "ggplot") }) From 2a9ecf876ed6b65da4ff942be3e3d77fe4fcc7bf Mon Sep 17 00:00:00 2001 From: adeschen Date: Wed, 7 May 2025 11:44:50 -0400 Subject: [PATCH 363/385] Update createAccuracGraph() code and add unit tests --- R/visualization.R | 7 ++--- tests/testthat/test-visualization.R | 48 +++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/R/visualization.R b/R/visualization.R index 3a0571e08..cdecc1f60 100644 --- a/R/visualization.R +++ b/R/visualization.R @@ -78,14 +78,13 @@ createAccuracyGraph <- function(fileRDS, title="", ## Generate graph accuracy <- ggplot(dfAUROC, aes(x=.data$K, y=.data$AUC, group=.data$D, color=.data$D, linetype=.data$D)) + - ylab(label = "AUROC") + geom_ribbon(aes(ymin=.data$L, ymax=.data$H, group=.data$D), linetype="dotted", linewidth=2, alpha=0.1) + geom_line(linewidth=2) + facet_grid(. ~ Call) + - ylim(c(ymin, 1)) + ggtitle(title) + + ylim(c(ymin, 1)) + ggtitle(title) + ylab(label = "AUROC") + scale_colour_manual(aesthetics = c("colour", "fill"), breaks=selectD, values=selectColor) + - theme_classic() + + theme_classic() + theme(axis.text=element_text(size=20, colour = "black"), panel.background = element_rect(color="black"), axis.text.x=element_text(size=20, angle=90, @@ -177,8 +176,6 @@ createAUROCGraph <- function(dfAUROC, title="", dfAUROC <- dfAUROC[which(dfAUROC$D %in% selectD), ] dfAUROC$D <- as.factor(dfAUROC$D) - colnames(dfAUROC)[colnames(dfAUROC) == "D"] <- "D" - ## Set y axis minimum value ymin <- min(c(dfAUROC$L)) - 0.008 diff --git a/tests/testthat/test-visualization.R b/tests/testthat/test-visualization.R index 2ebe63004..40ddac367 100644 --- a/tests/testthat/test-visualization.R +++ b/tests/testthat/test-visualization.R @@ -98,7 +98,7 @@ test_that("createAccuracyGraph() must return error when selectD value not in the error_message <- paste0("Not all values in \'selectD\' are present in the RDS file.") expect_error(createAccuracyGraph(fileRDS=fileGDS, title="", - selectD=c(32,32,34), selectColor=c("#5e688a", "#cd5700", "#CC79A7")), + selectD=c(32,32,34), selectColor=c("#5e688a", "#cd5700", "#CC79A7")), error_message) }) @@ -121,7 +121,7 @@ test_that("createAccuracyGraph() must return a gglot object when successful", { fileGDS <- test_path("fixtures", "TEST_01.infoCall.RDS") graphE <-createAccuracyGraph(fileRDS=fileGDS, title="", - selectD=c(7,8,9), selectColor=c("#5e688a", "#cd5700", "#CC79A7")) + selectD=c(7,8,9), selectColor=c("#5e688a", "#cd5700", "#CC79A7")) testthat::expect_is(graphE, "ggplot") }) @@ -134,7 +134,7 @@ test_that("createAccuracyGraph() must return a gglot object when successful", { context("createAUROCGraph() results") -test_that("createAccuracyGraph() must return a gglot object when successful", { +test_that("createAUROCGraph() must return a gglot object when successful", { dfAuroc <- data.frame(D=c(rep(2, 15), rep(3, 15)), K=c(rep(c(2, 3, 4), 10)), @@ -163,3 +163,45 @@ test_that("createAccuracyGraph() must return a gglot object when successful", { testthat::expect_is(graphE, "ggplot") }) + +test_that("createAccuracyGraph() must return error when dfAUROC is missing mandatory column", { + + dfAuroc <- data.frame(D=c(rep(2, 15), rep(3, 15)), + K=c(rep(c(2, 3, 4), 10)), + Call=c("EUR", "EUR", "EUR", "AMR", "AMR", "AMR", + "EAS", "EAS", "EAS", "SAS", "SAS", "SAS", + "AFR", "AFR", "AFR", + "EUR", "EUR", "EUR", "AMR", "AMR", "AMR", + "EAS", "EAS", "EAS", "SAS", "SAS", "SAS", + "AFR", "AFR", "AFR"), + AUROC=c(0.95000, 0.9628737, 0.9701246, 0.8337130, + 0.8509514, 0.9800000, 0.9158718, 0.9267399, + 0.9386384, 0.7484138, 0.9000000, 0.9892067, + 0.88000, 0.8758737, 0.9021246, + 0.99000, 0.9888737, 0.9931246, 0.8837130, + 0.8959514, 1.0000000, 0.9788718, 0.9977399, + 0.9886384, 0.8244138, 1.0000000, 0.9982067, + 0.92000, 0.8998737, 0.9251246)) + dfAuroc$Low <- dfAuroc$AUROC - 0.03 + dfAuroc$H <- dfAuroc$AUROC + 0.02 + dfAuroc$H[which(dfAuroc$H > 1.0000)] <- 1.0000000 + + error_message <- paste0("The \'dfAUROC\' must have all those columns: ", + "D, K, Call, L, AUROC, H.") + + expect_error(createAUROCGraph(dfAUROC=dfAuroc, title="", + selectD=c(2, 3), selectColor=c("#cd5700", "#CC79A7")), + error_message) +}) + + +test_that("createAccuracyGraph() must return error when dfAUROC is an integer", { + + dfAuroc <- 100L + + error_message <- paste0("The \'dfAUROC\' parameter must be a data frame.") + + expect_error(createAUROCGraph(dfAUROC=dfAuroc, title="", + selectD=c(2, 3), selectColor=c("#cd5700", "#CC79A7")), + error_message) +}) \ No newline at end of file From 6a6f5da4aa317b1c0722e02151fea5d4e1abfe5a Mon Sep 17 00:00:00 2001 From: adeschen Date: Wed, 7 May 2025 12:41:21 -0400 Subject: [PATCH 364/385] Simplifying graph functions and adding unit tests --- R/visualization.R | 32 +++++++++++++---------------- tests/testthat/test-visualization.R | 31 ++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/R/visualization.R b/R/visualization.R index cdecc1f60..2c7fea29d 100644 --- a/R/visualization.R +++ b/R/visualization.R @@ -91,10 +91,8 @@ createAccuracyGraph <- function(fileRDS, title="", vjust = 0.5, hjust=1, colour="black"), plot.title = element_text(size=22, face="bold", colour="gray20", hjust=0.5), - axis.title.x=element_text(size=30,face="bold.italic"), - axis.title.y=element_text(size=30,face="bold.italic"), - strip.text.x = element_text(size=20, face="bold"), - strip.text.y = element_text(size=20, face="bold"), + axis.title=element_text(size=30,face="bold.italic"), + strip.text = element_text(size=20, face="bold"), strip.background = element_rect(fill="gray90"), legend.text=element_text(size=19), legend.title=element_text(size=22, face="bold.italic")) @@ -169,7 +167,8 @@ createAUROCGraph <- function(dfAUROC, title="", selectColor=selectColor) if (!all(selectD %in% unique(dfAUROC$D))) { - stop("Not all values in \'selectD\' are present in the RDS file.") + stop("Not all values in \'selectD\' are present in the \'dfAUROC\' ", + "data frame.") } ## Retained selected dimensions @@ -182,27 +181,24 @@ createAUROCGraph <- function(dfAUROC, title="", ## Generate graph accuracy <- ggplot(dfAUROC, aes(x=.data$K, y=.data$AUROC, group=.data$D, color=.data$D, linetype=.data$D)) + - ylab(label = "AUROC") + geom_ribbon(aes(ymin=.data$L, ymax=.data$H, group=.data$D), linetype="dotted", linewidth=2, alpha=0.1) + geom_line(linewidth=2) + facet_grid(. ~ Call) + - ylim(c(ymin, 1)) + ggtitle(title) + scale_colour_manual(aesthetics = c("colour", "fill"), breaks=selectD, values=selectColor) + + ylim(c(ymin, 1)) + ggtitle(title) + ylab(label = "AUROC") + theme_classic() + - theme(axis.text=element_text(size=20, colour = "black"), - panel.background = element_rect(color="black"), - axis.text.x=element_text(size=20, angle=90, + theme(axis.text=element_text(size=20, colour="black"), + panel.background = element_rect(color="black"), + axis.text.x=element_text(size=20, angle=90, vjust = 0.5, hjust=1, colour="black"), - plot.title = element_text(size=22, face="bold", + plot.title=element_text(size=22, face="bold", colour="gray20", hjust=0.5), - axis.title.x=element_text(size=30,face="bold.italic"), - axis.title.y=element_text(size=30,face="bold.italic"), - strip.text.x = element_text(size=20, face="bold"), - strip.text.y = element_text(size=20, face="bold"), - strip.background = element_rect(fill="gray90"), - legend.text=element_text(size=19), - legend.title=element_text(size=22, face="bold.italic")) + axis.title=element_text(size=30, face="bold.italic"), + strip.text=element_text(size=20, face="bold"), + strip.background = element_rect(fill="gray90"), + legend.text=element_text(size=19), + legend.title=element_text(size=22, face="bold.italic")) ## Successful return(accuracy) diff --git a/tests/testthat/test-visualization.R b/tests/testthat/test-visualization.R index 40ddac367..c8af637a5 100644 --- a/tests/testthat/test-visualization.R +++ b/tests/testthat/test-visualization.R @@ -204,4 +204,35 @@ test_that("createAccuracyGraph() must return error when dfAUROC is an integer", expect_error(createAUROCGraph(dfAUROC=dfAuroc, title="", selectD=c(2, 3), selectColor=c("#cd5700", "#CC79A7")), error_message) +}) + + +test_that("createAccuracyGraph() must return error when selectD not in the data frame", { + + dfAuroc <- data.frame(D=c(rep(2, 15), rep(3, 15)), + K=c(rep(c(2, 3, 4), 10)), + Call=c("EUR", "EUR", "EUR", "AMR", "AMR", "AMR", + "EAS", "EAS", "EAS", "SAS", "SAS", "SAS", + "AFR", "AFR", "AFR", + "EUR", "EUR", "EUR", "AMR", "AMR", "AMR", + "EAS", "EAS", "EAS", "SAS", "SAS", "SAS", + "AFR", "AFR", "AFR"), + AUROC=c(0.95000, 0.9628737, 0.9701246, 0.8337130, + 0.8509514, 0.9800000, 0.9158718, 0.9267399, + 0.9386384, 0.7484138, 0.9000000, 0.9892067, + 0.88000, 0.8758737, 0.9021246, + 0.99000, 0.9888737, 0.9931246, 0.8837130, + 0.8959514, 1.0000000, 0.9788718, 0.9977399, + 0.9886384, 0.8244138, 1.0000000, 0.9982067, + 0.92000, 0.8998737, 0.9251246)) + dfAuroc$L <- dfAuroc$AUROC - 0.03 + dfAuroc$H <- dfAuroc$AUROC + 0.02 + dfAuroc$H[which(dfAuroc$H > 1.0000)] <- 1.0000000 + + error_message <- paste0("Not all values in \'selectD\' are present in ", + "the \'dfAUROC\' data frame.") + + expect_error(createAUROCGraph(dfAUROC=dfAuroc, title="", + selectD=c(2, 4), selectColor=c("#cd5700", "#CC79A7")), + error_message) }) \ No newline at end of file From 09b7924f622c1b12e6f1541584c2e775caa1a524 Mon Sep 17 00:00:00 2001 From: adeschen Date: Wed, 7 May 2025 17:10:47 -0400 Subject: [PATCH 365/385] Add unit tess for readSNVFileGeneric() function --- tests/testthat/test-tools_internal.R | 73 ++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tests/testthat/test-tools_internal.R b/tests/testthat/test-tools_internal.R index 02175fd92..93eb1d10f 100644 --- a/tests/testthat/test-tools_internal.R +++ b/tests/testthat/test-tools_internal.R @@ -186,4 +186,77 @@ test_that("processPileupChrBin() must return NULL when chromosome absent", { varDf=varDf, verbose=FALSE) expect_identical(result1, NULL) +}) + + +############################################################################# +### Tests readSNVPileupFile() results +############################################################################# + +context("readSNVPileupFile") + + +test_that("readSNVPileupFile() must return error when file does not content expected columns", { + + data.dir <- test_path("fixtures") + fileTxt <- file.path(data.dir, "ex1.txt.gz") + + result1 <- RAIDS:::readSNVPileupFile(fileName=fileTxt, offset=0L) + + tmpF <- tempfile("ex1_notGood", fileext = c(".txt")) + + withr::defer(if(file.exists(tmpF)) unlink(tmpF), envir=parent.frame()) + + write.table(result1[1:10, 1:3], file = tmpF) + + error_message <- paste0("The SNP-pileup file must contain all those ", + "columns: \'Chromosome\', \'Position\', \'Ref\', \'Alt\',", + " \'File1R\', \'File1A\', \'File1E\', \'File1D\'.") + + expect_error(RAIDS:::readSNVPileupFile(fileName=tmpF, offset=0L), + error_message) +}) + + +############################################################################# +### Tests readSNVFileGeneric() results +############################################################################# + +context("readSNVFileGeneric") + + +test_that("readSNVFileGeneric() must return error when file does not content expected columns", { + + data.dir <- test_path("fixtures") + fileTxt <- file.path(data.dir, "ex1.txt.gz") + + result1 <- RAIDS:::readSNVPileupFile(fileName=fileTxt, offset=0L) + + tmpF2 <- tempfile("ex1_notGood", fileext = c(".txt")) + + withr::defer(if(file.exists(tmpF2)) unlink(tmpF2), envir=parent.frame()) + + write.table(result1[1:10, 1:4], file = tmpF2) + + error_message <- paste0("The generic SNP pileup file must contain all ", + "those columns: \'Chromosome\', \'Position\', \'Ref\', \'Alt\', ", + "\'File1R\', \'File1A\', \'Count\'.") + + expect_error(RAIDS:::readSNVFileGeneric(fileName=tmpF2, offset=0L), + error_message) +}) + + +test_that("readSNVPileupFile() must return expected value when all parameters are valid", { + + data.dir <- test_path("fixtures") + fileTxt <- file.path(data.dir, "ex1.generic.txt.gz") + + result1 <- RAIDS:::readSNVFileGeneric(fileName=fileTxt, offset=0L) + + expect_equal(ncol(result1), 7) + expect_equal(nrow(result1), 50) + expect_equal(colnames(result1), c("Chromosome", "Position", "Ref", "Alt", + "File1R", "File1A", "count")) + }) \ No newline at end of file From 5ffb02cee0aa18fa6ca61ac5fc1c4c97ab2b9778 Mon Sep 17 00:00:00 2001 From: adeschen Date: Thu, 8 May 2025 12:26:11 -0400 Subject: [PATCH 366/385] Adding unit test for readSNVVCF() function --- tests/testthat/fixtures/ex1_small.vcf.gz | Bin 0 -> 5330 bytes tests/testthat/test-tools_internal.R | 26 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 tests/testthat/fixtures/ex1_small.vcf.gz diff --git a/tests/testthat/fixtures/ex1_small.vcf.gz b/tests/testthat/fixtures/ex1_small.vcf.gz new file mode 100644 index 0000000000000000000000000000000000000000..d8e97ee6245281fe65f47a41901e475fca62b11d GIT binary patch literal 5330 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 Date: Thu, 8 May 2025 14:22:19 -0400 Subject: [PATCH 367/385] Update doc for readSNVVCF() and unit test --- R/tools_internal.R | 44 +++++++++++----------------- man/readSNVVCF.Rd | 6 ++-- tests/testthat/test-tools_internal.R | 1 - 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/R/tools_internal.R b/R/tools_internal.R index e128bbfba..5953514a0 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -320,8 +320,7 @@ readSNVFileGeneric <- function(fileName, offset = 0L) { #' @title Read a VCF file with the genotypes use for the ancestry call #' -#' @description The function reads VCF file and -#' returns a data frame +#' @description The function reads VCF file and returns a data frame #' containing the information about the read counts for the SNVs present in #' the file. #' @@ -329,8 +328,8 @@ readSNVFileGeneric <- function(fileName, offset = 0L) { #' the path, of a VCF file containing the SNV read counts. #' The VCF must contain those genotype fields: GT, AD, DP. #' -#' -#' @param profileName a \code{character} with Name.ID for the genotype name +#' @param profileName a \code{character} with Name.ID for the genotype name. +#' Default: \code{NULL}. #' #' @param offset a \code{integer} representing the offset to be added to the #' position of the SNVs. The value of offset @@ -370,8 +369,7 @@ readSNVFileGeneric <- function(fileName, offset = 0L) { #' @importFrom GenomicRanges seqnames start width #' @encoding UTF-8 #' @keywords internal -readSNVVCF <- function(fileName, - profileName = NULL, offset = 0L) { +readSNVVCF <- function(fileName, profileName=NULL, offset=0L) { vcf <- readVcf(fileName) @@ -394,25 +392,20 @@ readSNVVCF <- function(fileName, countV <- as.integer(gtCur$DP) countA <- gtCur$AD - # Ok - idVCF <- row.names(gtCur$GT) - tmp <- matrix(unlist(strsplit(idVCF, ":")),nrow=2)[2,] - alleleChar <- matrix(unlist(strsplit(tmp, "_")),nrow=2)[2,] + tmp <- matrix(unlist(strsplit(idVCF, ":")), nrow=2)[2,] + alleleChar <- matrix(unlist(strsplit(tmp, "_")), nrow=2)[2,] rm(tmp) - - matCur <- lapply(listKeep, FUN=function(x, countA, alleleChar){ listAlt <- strsplit(alleleChar[x], "\\/")[[1]] - keep <- ifelse(listAlt[2] %in% c("A", "C", "G", "T"),TRUE,FALSE) + keep <- ifelse(listAlt[2] %in% c("A", "C", "G", "T"), TRUE, FALSE) - res <- data.frame( Alt = as.character(listAlt[2]), - File1R = countA[[x]][1], - File1A = countA[[x]][2], - keep = keep) + res <- data.frame(Alt=as.character(listAlt[2]), + File1R=countA[[x]][1], File1A=countA[[x]][2], + keep=keep) return(res) }, @@ -422,16 +415,13 @@ readSNVVCF <- function(fileName, matCur <- do.call(rbind, matCur) listTmp <- which(matCur$keep) listKeep <- listKeep[listTmp] - matSample <- data.frame(Chromosome = as.integer(gsub("chr", "", - colChr))[listKeep], - Position = start[listKeep] + offset, - Ref = refCur[listKeep], - Alt = matCur$Alt[listTmp], - File1R = matCur$File1R[listTmp], - File1A = matCur$File1A[listTmp], - count = gtCur$DP[,1], - stringsAsFactors = FALSE - ) + matSample <- data.frame(Chromosome=as.integer(gsub("chr", "", + colChr))[listKeep], + Position=start[listKeep] + offset, + Ref=refCur[listKeep], Alt=matCur$Alt[listTmp], + File1R=matCur$File1R[listTmp], + File1A=matCur$File1A[listTmp], + count=gtCur$DP[,1], stringsAsFactors=FALSE) return(matSample) } diff --git a/man/readSNVVCF.Rd b/man/readSNVVCF.Rd index 27e3d94c9..acc082117 100644 --- a/man/readSNVVCF.Rd +++ b/man/readSNVVCF.Rd @@ -12,7 +12,8 @@ readSNVVCF(fileName, profileName = NULL, offset = 0L) the path, of a VCF file containing the SNV read counts. The VCF must contain those genotype fields: GT, AD, DP.} -\item{profileName}{a \code{character} with Name.ID for the genotype name} +\item{profileName}{a \code{character} with Name.ID for the genotype name. +Default: \code{NULL}.} \item{offset}{a \code{integer} representing the offset to be added to the position of the SNVs. The value of offset @@ -36,8 +37,7 @@ alternative nucleotide} } } \description{ -The function reads VCF file and -returns a data frame +The function reads VCF file and returns a data frame containing the information about the read counts for the SNVs present in the file. } diff --git a/tests/testthat/test-tools_internal.R b/tests/testthat/test-tools_internal.R index a59862b51..4eb68da08 100644 --- a/tests/testthat/test-tools_internal.R +++ b/tests/testthat/test-tools_internal.R @@ -276,7 +276,6 @@ test_that("readSNVVCF() must return expected results", { result1 <- RAIDS:::readSNVVCF(fileName=fileTxt, profileName=NULL, offset=0L) - expect_equal(ncol(result1), 7) expect_equal(nrow(result1), 60) expect_equal(colnames(result1), c("Chromosome", "Position", "Ref", "Alt", From 87f971c5090dcd10f7eba3ddce9c69d4aa748242 Mon Sep 17 00:00:00 2001 From: adeschen Date: Thu, 8 May 2025 17:03:11 -0400 Subject: [PATCH 368/385] Add example to readSNVBAM() function --- R/tools.R | 8 ++--- R/tools_internal.R | 79 +++++++++++++++++++++++----------------------- man/readSNVBAM.Rd | 16 +++++++--- 3 files changed, 55 insertions(+), 48 deletions(-) diff --git a/R/tools.R b/R/tools.R index 3ed733651..2446b44dd 100644 --- a/R/tools.R +++ b/R/tools.R @@ -120,13 +120,13 @@ snvListVCF <- function(gdsReference, fileOut, offset=0L, freqCutoff=NULL) { ## in the range (0,1)"> #CHROM POS ID REF ALT QUAL FILTER INFO - cat(paste0('##fileformat=VCFv4.3', "\n"), file = fileOut) + cat(paste0('##fileformat=VCFv4.3', "\n"), file=fileOut) cat(paste0('##FILTER=', - "\n"), file = fileOut, append=TRUE) + "\n"), file=fileOut, append=TRUE) cat(paste0('##INFO=', - "\n"), file = fileOut, append=TRUE) - cat('#', file = fileOut, append=TRUE) + "\n"), file=fileOut, append=TRUE) + cat('#', file=fileOut, append=TRUE) write.table(df, file=fileOut, sep="\t", append=TRUE, row.names=FALSE, col.names=TRUE, quote=FALSE) diff --git a/R/tools_internal.R b/R/tools_internal.R index 5953514a0..37a9f8031 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -620,7 +620,9 @@ processPileupChrBin <- function(chr, resPileup, varDf, verbose) { #' the path, of a BAM file with the index file in the same directory #' #' -#' @param paramSNVBAM a \code{data.frame} representing +#' @param paramSNVBAM a \code{list} containing the parameters passed to the +#' BamFile() function. Default: \code{list(ScanBamParam=NULL, PileupParam=NULL, +#' yieldSize=10000000)}. #' #' @param varSelected a \code{data.frame} representing the position to keep #' @@ -650,23 +652,25 @@ processPileupChrBin <- function(chr, resPileup, varDf, verbose) { #' @examples #' #' -#' ## Directory where demo SNP-pileup file -#' dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") -#' -#' +#' ## Required library for this example to run correctly +#' if (requireNamespace("Rsamtools", quietly=TRUE)) { +#' ## Demo bam +#' fl <- system.file("extdata", "no_which_buffered_pileup.bam", +#' package="Rsamtools", mustWork=TRUE) +#' +#' RAIDS:::readSNVBAM(fl, varSelected=data.frame(chr=c(1,1), +#' start=c(3,5), REF=c("A", "A"), ALT=c("C", "C"))) +#' } +#' #' @author Pascal Belleau, Astrid Deschênes and Alexander Krasnitz #' @importFrom Rsamtools BamFile ScanBamParam PileupParam pileup #' @importFrom MatrixGenerics rowRanges #' @importFrom GenomicRanges seqnames start width #' @encoding UTF-8 #' @keywords internal -readSNVBAM <- function(fileName, - varSelected, - offset = 0L, - paramSNVBAM=list(ScanBamParam=NULL, - PileupParam=NULL, - yieldSize=10000000), - verbose=FALSE) { +readSNVBAM <- function(fileName, varSelected, offset=0L, + paramSNVBAM=list(ScanBamParam=NULL, PileupParam=NULL, + yieldSize=10000000), verbose=FALSE) { # Note the offset is apply to the ref not the sequemce (snp-pileup and vcf) varSelected$chr <- paste0("chr", varSelected$chr) varSelected$start <- varSelected$start - offset @@ -709,8 +713,6 @@ readSNVBAM <- function(fileName, include_insertions=FALSE) } - - i<-1 res <- list() vcfChr <- list() @@ -732,59 +734,55 @@ readSNVBAM <- function(fileName, #print(paste0("nb Chr ", length(listChr))) res[[i]] <- NULL - if(length(listChr) > 0 ){ + if(length(listChr) > 0 ) { tmpChr <- grep("chr", listChr) if(length(tmpChr) != length(listChr)){ listChg <- listChr[-1* tmpChr] for(i in seq_len(length(listChg))){ - resPileup$seqnames[resPileup$seqnames == listChg[i]] = paste0("chr", listChg[i]) + resPileup$seqnames[resPileup$seqnames == listChg[i]] <- + paste0("chr", listChg[i]) } listChr <- unique(as.character(resPileup$seqnames)) } - if(sum(!(listChr %in% names(varSelected))) == length(listChr)){ + if(sum(!(listChr %in% names(varSelected))) == length(listChr)) { # message("End chromosome") break } # print(paste0("Current chr ", listChr)) - if(verbose) {message("readSNVBAM processPileupChrBin start ", - Sys.time())} + if(verbose) { message("readSNVBAM processPileupChrBin start ", + Sys.time()) } tmp <- lapply(listChr, - FUN=function(x, res, varSelected){ - return(processPileupChrBin(chr=x, res, varDf=varSelected, verbose=verbose)) - }, - res=resPileup, + FUN=function(x, res, varSelected){ + return(processPileupChrBin(chr=x, res, + varDf=varSelected, verbose=verbose)) + }, res=resPileup, varSelected=varSelected) - if(verbose) {message("readSNVBAM processPileupChrBin end ", - Sys.time())} - # print("aye2") - if(length(tmp) > 0){ + if(verbose) { message("readSNVBAM processPileupChrBin end ", + Sys.time()) } + + if(length(tmp) > 0) { res[[i]] <- do.call(rbind, tmp) i <- i + 1 #message(nrow(res[[i]]), " rows in result data.frame") } - # print("aye3") } if(nrow(resPileup) == 0L){ k <- k + 1 - # print(paste0("Break ", k)) - if(k > 20){ + if(k > 20) { break } }else{ k <- 0 # i <- i + 1 } - if(verbose) {message("readSNVBAM pileup end repeat ", - Sys.time())} + if(verbose) { message("readSNVBAM pileup end repeat ", Sys.time()) } } - if(verbose) {message("readSNVBAM pileup Done ", - Sys.time())} + if(verbose) {message("readSNVBAM pileup Done ", Sys.time())} resSNP <- do.call(rbind,res) close(bf) - if(verbose) {message("readSNVBAM pileup user ", - k, " i ", i)} + if(verbose) {message("readSNVBAM pileup user ", k, " i ", i)} resSNP$File1R <- rep(0, nrow(resSNP)) resSNP$File1A <- rep(0, nrow(resSNP)) @@ -798,12 +796,13 @@ readSNVBAM <- function(fileName, resSNP$File1A[tmp] <- resSNP[tmp, nuc] } } - resSNP <- resSNP[, c("seqnames", "pos", "REF", "ALT", "File1R", "File1A", "count", "A", "C", "G", "T")] - colnames(resSNP) <- c("Chromosome", "Position", "Ref", "Alt", "File1R", "File1A", "count", "A", "C", "G", "T") + resSNP <- resSNP[, c("seqnames", "pos", "REF", "ALT", "File1R", "File1A", + "count", "A", "C", "G", "T")] + colnames(resSNP) <- c("Chromosome", "Position", "Ref", "Alt", "File1R", + "File1A", "count", "A", "C", "G", "T") resSNP$Position <- resSNP$Position + offset - if(verbose) {message("readSNVBAM pileup format Done ", - Sys.time())} + if(verbose) {message("readSNVBAM pileup format Done ", Sys.time())} return(resSNP) } diff --git a/man/readSNVBAM.Rd b/man/readSNVBAM.Rd index dbd4be2ee..7a2d7ed10 100644 --- a/man/readSNVBAM.Rd +++ b/man/readSNVBAM.Rd @@ -23,7 +23,9 @@ the path, of a BAM file with the index file in the same directory} position of the SNVs. The value of offset is added to the position present in the file. Default: \code{0L}.} -\item{paramSNVBAM}{a \code{data.frame} representing} +\item{paramSNVBAM}{a \code{list} containing the parameters passed to the +BamFile() function. Default: \code{list(ScanBamParam=NULL, PileupParam=NULL, +yieldSize=10000000)}.} \item{verbose}{a \code{logical} indicating if messages should be printed to show how the different steps in the function. Default: \code{FALSE}.} @@ -54,9 +56,15 @@ the file. \examples{ -## Directory where demo SNP-pileup file -dataDir <- system.file("extdata/example/snpPileup", package="RAIDS") - +## Required library for this example to run correctly +if (requireNamespace("Rsamtools", quietly=TRUE)) { + ## Demo bam + fl <- system.file("extdata", "no_which_buffered_pileup.bam", + package="Rsamtools", mustWork=TRUE) + + RAIDS:::readSNVBAM(fl, varSelected=data.frame(chr=c(1,1), + start=c(3,5), REF=c("A", "A"), ALT=c("C", "C"))) +} } \author{ From 8ce729c8f84958072db1c0f836110724f5b291fa Mon Sep 17 00:00:00 2001 From: adeschen Date: Thu, 8 May 2025 17:54:21 -0400 Subject: [PATCH 369/385] Add unit test for readSNVBAM() function --- tests/testthat/test-tools_internal.R | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test-tools_internal.R b/tests/testthat/test-tools_internal.R index 4eb68da08..a47224085 100644 --- a/tests/testthat/test-tools_internal.R +++ b/tests/testthat/test-tools_internal.R @@ -3,7 +3,7 @@ library(RAIDS) library(withr) library(gdsfmt) - +library(Rsamtools) ############################################################################# ### Tests validateGDSClass() results @@ -281,3 +281,25 @@ test_that("readSNVVCF() must return expected results", { expect_equal(colnames(result1), c("Chromosome", "Position", "Ref", "Alt", "File1R", "File1A", "count")) }) + + +############################################################################# +### Tests readSNVVCF() results +############################################################################# + +context("readSNVBAM") + + +test_that("readSNVBAM() must return expected results", { + + fileTxt <- system.file("extdata", "no_which_buffered_pileup.bam", + package="Rsamtools", mustWork=TRUE) + + result1 <- RAIDS:::readSNVBAM(fileTxt, varSelected=data.frame(chr=c(1,1), + start=c(3,5), REF=c("A", "A"), ALT=c("C", "C"))) + + expect_equal(ncol(result1), 11) + expect_equal(nrow(result1), 2) + expect_equal(colnames(result1), c("Chromosome", "Position", "Ref", "Alt", + "File1R", "File1A", "count", "A", "C", "G", "T")) +}) \ No newline at end of file From 5b319beb96ce491eda6bf041fdcf3272eb26a3b8 Mon Sep 17 00:00:00 2001 From: adeschen Date: Thu, 8 May 2025 19:53:58 -0400 Subject: [PATCH 370/385] Re-indent function in gdsWrapper_internal.R file --- R/gdsWrapper_internal.R | 83 ++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 46 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 8a3f4fcf9..0762720c0 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -676,10 +676,9 @@ generateGDS1KGgenotypeFromSNPPileup <- function(pathGeno, #' @importFrom utils read.csv #' @encoding UTF-8 #' @keywords internal -generateProfileGDS <- function(profileFile, profileName, - listPos, offset, minCov=10, minProb=0.999, - seqError=0.001, dfPedProfile, batch, studyDF, pathProfileGDS, - genoSource, paramProfileGDS, verbose) { +generateProfileGDS <- function(profileFile, profileName, listPos, offset, + minCov=10, minProb=0.999, seqError=0.001, dfPedProfile, batch, studyDF, + pathProfileGDS, genoSource, paramProfileGDS, verbose) { # File with the description of the SNP keep # if(genoSource == "VCF"){ @@ -712,12 +711,10 @@ generateProfileGDS <- function(profileFile, profileName, } else if(genoSource == "bam"){ matSample <- readSNVBAM(fileName=profileFile, - varSelected=listPos, - paramSNVBAM=paramProfileGDS, - offset, - verbose=verbose) + varSelected=listPos, paramSNVBAM=paramProfileGDS, + offset, verbose=verbose) # listPos <- do.call(rbind, listPos) - colnames(listPos)[1:2] <- c("snp.chromosome", "snp.position") + colnames(listPos)[seq_len(2)] <- c("snp.chromosome", "snp.position") } # matAll <- merge(matSample[,c( "Chromosome", "Position", @@ -731,7 +728,7 @@ generateProfileGDS <- function(profileFile, profileName, # # below same as the merge above but faster - if(verbose) {message("End read ", Sys.time())} + if(verbose) { message("End read ", Sys.time()) } g <- as.matrix(rep(-1, nrow(listPos))) z <- cbind(c(listPos$snp.chromosome, matSample$Chromosome, matSample$Chromosome), @@ -748,22 +745,20 @@ generateProfileGDS <- function(profileFile, profileName, rm(matSample) z <- z[order(z[,1], z[,2], z[,3]),] - matAll <- data.frame(Chromosome=z[z[, 3] == 1, 1], - Position=z[z[, 3] == 1, 2], File1R=cumsum(z[, 4])[z[, 3] == 1], - File1A=cumsum(z[,5])[z[, 3] == 1], - count=cumsum(z[, 6])[z[, 3] == 1]) + matAll <- data.frame(Chromosome=z[z[, 3] == 1, 1], + Position=z[z[, 3] == 1, 2], File1R=cumsum(z[, 4])[z[, 3] == 1], + File1A=cumsum(z[,5])[z[, 3] == 1], + count=cumsum(z[, 6])[z[, 3] == 1]) rm(z) if(is.null(pathProfileGDS)){ stop("pathProfileGDS is NULL in ", - "generateGDS1KGgenotypeFromSNPPileup\n") + "generateGDS1KGgenotypeFromSNPPileup\n") } else{ - if(! dir.exists(pathProfileGDS)) { - dir.create(pathProfileGDS) - } + if(!dir.exists(pathProfileGDS)) { dir.create(pathProfileGDS) } } - fileGDSSample <- file.path(pathProfileGDS, - paste0(profileName, ".gds")) + fileGDSSample <- file.path(pathProfileGDS, paste0(profileName, ".gds")) + if(file.exists(fileGDSSample)) { gdsSample <- openfn.gds(fileGDSSample, readonly=FALSE) } else{ @@ -772,38 +767,37 @@ generateProfileGDS <- function(profileFile, profileName, if (! "Ref.count" %in% ls.gdsn(gdsSample)) { var.Ref <- add.gdsn(gdsSample, "Ref.count", matAll$File1R, - valdim=c( nrow(listPos), 1), - storage="sp.int16") + valdim=c( nrow(listPos), 1), storage="sp.int16") var.Alt <- add.gdsn(gdsSample, "Alt.count", matAll$File1A, - valdim=c( nrow(listPos), 1), - storage="sp.int16") - var.Count <- add.gdsn(gdsSample, "Total.count", - matAll$count, valdim=c( nrow(listPos), 1), - storage="sp.int16") + valdim=c( nrow(listPos), 1), storage="sp.int16") + var.Count <- add.gdsn(gdsSample, "Total.count", matAll$count, + valdim=c( nrow(listPos), 1), storage="sp.int16") } else { # you must append var.Ref <- append.gdsn(index.gdsn(gdsSample, "Ref.count"), - matAll$File1R) + matAll$File1R) var.Alt <- append.gdsn(index.gdsn(gdsSample, "Alt.count"), - matAll$File1A) + matAll$File1A) var.Count <- append.gdsn(index.gdsn(gdsSample, "Total.count"), - matAll$count) + matAll$count) } - listSampleGDS <- addStudyGDSSample(gdsSample, - pedProfile=dfPedProfile, batch=batch, - listSamples=c(profileName), studyDF=studyDF, verbose=verbose) + listSampleGDS <- addStudyGDSSample(gdsSample, pedProfile=dfPedProfile, + batch=batch, listSamples=c(profileName), studyDF=studyDF, + verbose=verbose) listCount <- table(matAll$count[matAll$count >= minCov]) cutOffA <- data.frame(count=unlist(vapply(as.integer(names(listCount)), - FUN=function(x, minProb, eProb){ - return(max(2,qbinom(minProb, x, eProb))) }, - FUN.VALUE=numeric(1), minProb=minProb, eProb=2 * seqError)), - allele=unlist(vapply(as.integer(names(listCount)), - FUN=function(x, minProb, eProb){ - return(max(2,qbinom(minProb, x, eProb))) }, - FUN.VALUE=numeric(1), minProb=minProb, eProb=seqError))) + FUN=function(x, minProb, eProb){ + return(max(2,qbinom(minProb, x, eProb))) }, + FUN.VALUE=numeric(1), minProb=minProb, + eProb=2 * seqError)), + allele=unlist(vapply(as.integer(names(listCount)), + FUN=function(x, minProb, eProb){ + return(max(2,qbinom(minProb, x, eProb))) }, + FUN.VALUE=numeric(1), minProb=minProb, + eProb=seqError))) row.names(cutOffA) <- names(listCount) # Initialize the genotype array at -1 @@ -845,18 +839,15 @@ generateProfileGDS <- function(profileFile, profileName, readmode.gdsn(var.geno) }else{ - var.geno <- add.gdsn(gdsSample, "geno.ref", - valdim=c(length(g), 1), - g, storage="bit2", compress = "LZMA_RA.fast") + var.geno <- add.gdsn(gdsSample, "geno.ref", valdim=c(length(g), 1), + g, storage="bit2", compress = "LZMA_RA.fast") readmode.gdsn(var.geno) } rm(g) closefn.gds(gdsfile=gdsSample) - if (verbose) { - message("End ", profileName, " ", Sys.time()) - } + if (verbose) { message("End ", profileName, " ", Sys.time()) } ## Success return(0L) From 6991f937cd1cd19ca12a22ec45d7cbb9fdaec47a Mon Sep 17 00:00:00 2001 From: adeschen Date: Thu, 8 May 2025 20:17:34 -0400 Subject: [PATCH 371/385] Update indents in allelicFraction_internal.R file --- R/allelicFraction_internal.R | 347 ++++++++++++++++------------------- 1 file changed, 156 insertions(+), 191 deletions(-) diff --git a/R/allelicFraction_internal.R b/R/allelicFraction_internal.R index 2481cde94..5ccd480bb 100644 --- a/R/allelicFraction_internal.R +++ b/R/allelicFraction_internal.R @@ -438,13 +438,15 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, # Freq of the more likely geno tmp <- apply(matrix(afSNV, ncol=1), 1, - FUN=function(x){max(max(x, 1-x)^2, 2* x *(1-x)) }) - # log10 (prod(FreqAllele^2) / prod(freq of more likely genotype)) + FUN=function(x){max(max(x, 1-x)^2, + 2* x *(1-x)) }) + # log10 (prod(FreqAllele^2) / prod(freq of more + # likely genotype)) # snvR * 1 + (-1)^snvR * afSNV freq of the genotype # (snvR = 1 homo ref # and 0 if homo alt) - logLHR <- sum(2 * log10(snvR * 1 + (-1)^snvR * afSNV)) - - sum(log10(tmp)) + logLHR <- sum(2 * log10(snvR * 1 + + (-1)^snvR * afSNV)) - sum(log10(tmp)) } homoBlock$logLHR[i] <- max(logLHR, -100) @@ -453,8 +455,7 @@ computeLOHBlocksDNAChr <- function(gdsReference, chrInfo, snpPos, chr, homoBlock$homoScore[i] <- lH1 - lM1 return(homoBlock[i,]) }, homoBlock=homoBlock, - blcSNV=blcSNV, listAF=listAF, - snpPos=snpPos) + blcSNV=blcSNV, listAF=listAF, snpPos=snpPos) homoBlock <- do.call(rbind,homoBlock) return(homoBlock) @@ -532,100 +533,96 @@ computeAlleleFraction <- function(snpPos, w=10, cutOff=-3) { end=seq_len(nrow(snpPos))[which(z[,2] < 0)]) listBlockAR <- lapply(seq_len(nrow(segImb)), - FUN=function(i, segImb, snpPos, w, cutOff){ - listBlockAR <- list() - j<-1 - listSeg <- (segImb$start[i]):(segImb$end[i]) - # index hetero segment - listHetero <- listSeg[snpPos[listSeg,"hetero"] == TRUE] - # SNP hetero for the segment - snp.hetero <- snpPos[listHetero,] - - if(nrow(snp.hetero) >= 2 * w) { - lapCur <- median(apply(snp.hetero[seq_len(w), + FUN=function(i, segImb, snpPos, w, cutOff){ + listBlockAR <- list() + j <- 1 + listSeg <- (segImb$start[i]):(segImb$end[i]) + # index hetero segment + listHetero <- listSeg[snpPos[listSeg,"hetero"] == TRUE] + # SNP hetero for the segment + snp.hetero <- snpPos[listHetero,] + + if(nrow(snp.hetero) >= 2 * w) { + lapCur <- median(apply(snp.hetero[seq_len(w), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[seq_len(w), + c("cnt.ref", "cnt.alt")]))) + + start <- 1 + k <- w + 1 + while(k < nrow(snp.hetero)) { + # We have (k+w-1) <= nrow(snp.hetero) + # Case 1 true because (nrow(snp.hetero) >= 2 * w + # Other case nrow(snp.hetero) >= w+k - 1 + curWin <- testAlleleFractionChange(snp.hetero[k:(k+w-1), + c("cnt.ref", "cnt.alt")], cutOff, lapCur) + + if(curWin$pCut1 == 1){ # new Region the allelicFraction + # table of the index of the block with lapCur + listBlockAR[[j]] <- c(listHetero[start], + listHetero[k], lapCur) + + lapCur <- median(apply(snp.hetero[k:(k+w-1), c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[seq_len(w), + (rowSums(snp.hetero[k:(k+w-1), c("cnt.ref", "cnt.alt")]))) - start <- 1 - k <- w + 1 - while(k < nrow(snp.hetero)) { - # We have (k+w-1) <= nrow(snp.hetero) - # Case 1 true because (nrow(snp.hetero) >= 2 * w - # Other case nrow(snp.hetero) >= w+k - 1 - curWin <- testAlleleFractionChange(snp.hetero[k:(k+w-1), - c("cnt.ref", "cnt.alt")], cutOff, lapCur) - - if(curWin$pCut1 == 1){ # new Region the allelicFraction - # table of the index of the block with lapCur - listBlockAR[[j]] <- c(listHetero[start], - listHetero[k], lapCur) - - lapCur <- median(apply(snp.hetero[k:(k+w-1), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[k:(k+w-1), - c("cnt.ref", "cnt.alt")]))) - - start <- k - - if(nrow(snp.hetero) - start < w) { # Close the segment - lapCur <- - median(apply(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")]))) - - listBlockAR[[j]] <- c(listHetero[start], - segImb$end[i], lapCur) - - j <- j+1 - k <- nrow(snp.hetero) - }else{ # nrow(snp.hetero) >= w+k - k<- k + 1 - j <- j + 1 - - } - }else{ # keep the same region - if((nrow(snp.hetero) - k ) < w){ # close - lapCur <- - median(apply(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[start:nrow(snp.hetero), - c("cnt.ref", "cnt.alt")]))) - - listBlockAR[[j]] <- c(listHetero[start], - segImb$end[i], lapCur) - - j <- j + 1 - - k <- nrow(snp.hetero) - } else{ # continue nrow(snp.hetero) >= w+k - lapCur <- median(apply(snp.hetero[start:k, - c("cnt.ref", "cnt.alt")], 1, min) / - (rowSums(snp.hetero[start:k,c("cnt.ref", - "cnt.alt")]))) - - k <- k + 1 - } - } - }# End while - } else { - lapCur <- median(apply(snp.hetero[, c("cnt.ref", "cnt.alt")], - 1, min) / (rowSums(snp.hetero[,c("cnt.ref", - "cnt.alt")]))) - - listBlockAR[[j]] <- c(segImb$start[i], - segImb$end[i], - lapCur) - - j <- j + 1 - } - listBlockAR <- do.call(rbind, listBlockAR) - return(listBlockAR) - }, - segImb=segImb, snpPos=snpPos, w=w, cutOff=cutOff) - } + start <- k + + if(nrow(snp.hetero) - start < w) { # Close the segment + lapCur <- median(apply(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")]))) + + listBlockAR[[j]] <- c(listHetero[start], + segImb$end[i], lapCur) + + j <- j + 1 + k <- nrow(snp.hetero) + } else { # nrow(snp.hetero) >= w+k + k <- k + 1 + j <- j + 1 + } + } else { # keep the same region + if((nrow(snp.hetero) - k ) < w){ # close + lapCur <- median(apply(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[start:nrow(snp.hetero), + c("cnt.ref", "cnt.alt")]))) + + listBlockAR[[j]] <- c(listHetero[start], + segImb$end[i], lapCur) + + j <- j + 1 + + k <- nrow(snp.hetero) + } else { # continue nrow(snp.hetero) >= w+k + lapCur <- median(apply(snp.hetero[start:k, + c("cnt.ref", "cnt.alt")], 1, min) / + (rowSums(snp.hetero[start:k,c("cnt.ref", + "cnt.alt")]))) + + k <- k + 1 + } + } + }# End while + } else { + lapCur <- + median(apply(snp.hetero[, c("cnt.ref", "cnt.alt")], + 1, min) / (rowSums(snp.hetero[,c("cnt.ref", + "cnt.alt")]))) + listBlockAR[[j]] <- c(segImb$start[i], + segImb$end[i], lapCur) + + j <- j + 1 + } + listBlockAR <- do.call(rbind, listBlockAR) + return(listBlockAR) + }, segImb=segImb, snpPos=snpPos, w=w, cutOff=cutOff) + } + # note NULL if length(listBlockAR) == 0 listBlockAR <- do.call(rbind, listBlockAR) # print(all.equal(listBlockAR, listBlockAR1)) @@ -772,8 +769,6 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, snpPos$LOH <- rep(0, nrow(snpPos)) snpPos$imbAR <- rep(-1, nrow(snpPos)) - - snpPos <- lapply(unique(snpPos$snp.chr), FUN=function(chr,snpPos){ if (verbose) { @@ -784,15 +779,13 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, listChr <- which(snpPos$snp.chr == chr) ## Identify LOH regions homoBlock[[chr]] <- computeLOHBlocksDNAChr( - gdsReference=gdsReference, - chrInfo=chrInfo, - snpPos=snpPos[listChr,], - chr=chr) + gdsReference=gdsReference, chrInfo=chrInfo, + snpPos=snpPos[listChr,], chr=chr) if (verbose) { message("Step 2 ", Sys.time()) } homoBlock[[chr]]$LOH <- as.integer(homoBlock[[chr]]$logLHR <= - cutOffLOH & homoBlock[[chr]]$homoScore <= cutOffHomoScore) + cutOffLOH & homoBlock[[chr]]$homoScore <= cutOffHomoScore) z <- cbind(c(homoBlock[[chr]]$start, homoBlock[[chr]]$end, snpPos[listChr, "snp.pos"]), @@ -830,8 +823,7 @@ computeAllelicFractionDNA <- function(gdsReference, gdsSample, currentProfile, } } return(snpPos[listChr,]) - }, - snpPos=snpPos) + }, snpPos=snpPos) snpPos <- do.call(rbind, snpPos) snpPos[which(snpPos[, "lap"] == -1), "lap"] <- 0.5 @@ -1245,17 +1237,13 @@ testAlleleFractionChange <- function(matCov, pCutOff=-3, vMean) { matTmp <- apply(matCov[, c("cnt.alt", "cnt.ref")], 1, FUN=function(x, vMean){ - vCur <- ifelse(x[1] <= x[2], - x[1], x[2]) - - diff2Mean <- abs(vMean * (x[1] + - x[2]) - vCur) - pCur1 <- pbinom(round(vMean * (x[1] + - x[2]) - diff2Mean), - size=x[2] + x[1], vMean) + vCur <- ifelse(x[1] <= x[2], x[1], x[2]) + + diff2Mean <- abs(vMean * (x[1] + x[2]) - vCur) + pCur1 <- pbinom(round(vMean * (x[1] + x[2]) - + diff2Mean), size=x[2] + x[1], vMean) pCur2 <- 1 - pbinom(round(vMean * (x[1] + - x[2]) + diff2Mean), - size=x[2] + x[1], vMean) + x[2]) + diff2Mean), size=x[2] + x[1], vMean) pCur <- pCur1 + pCur2 @@ -1274,8 +1262,7 @@ testAlleleFractionChange <- function(matCov, pCutOff=-3, vMean) { (matCov$pWin[nrow(matCov)] < 0.5) & ((p-pO) <= pCutOff)) res <- list(pWin=matCov$pWin, p=p, - pCut=as.integer(sum(matCov$pWin < 0.5) == nrow(matCov)), - pCut1=pCut1) + pCut=as.integer(sum(matCov$pWin < 0.5) == nrow(matCov)), pCut1=pCut1) return(res) } @@ -1336,11 +1323,9 @@ testEmptyBox <- function(matCov, pCutOff=-3) { matTmp <- apply(matCov[, c("cnt.alt", "cnt.ref")], 1, FUN=function(x){ - vCur1 <- ifelse(x[1] <= x[2], - x[1], x[2]) + vCur1 <- ifelse(x[1] <= x[2], x[1], x[2]) - pCur <- pbinom(q=vCur1, size=x[2] + x[1], - prob=vMean) + pCur <- pbinom(q=vCur1, size=x[2] + x[1], prob=vMean) pCurO <- max(1 - max(2 * pCur, 0.01), 0.01) @@ -1351,7 +1336,6 @@ testEmptyBox <- function(matCov, pCutOff=-3) { p <- sum(log10(matTmp[2,tmp])) + (ncol(matTmp) - length(tmp)) * log10(0.01) p0 <- sum(log10(matTmp[3,])) - ## Calculate a global statistic using all SNVs ## The region is imbalance or not pCut1 <- as.integer((sum(matCov$pWin < 0.5) >= nrow(matCov)-1) & @@ -1360,8 +1344,7 @@ testEmptyBox <- function(matCov, pCutOff=-3) { ## Return a list res <- list(pWin=matCov$pWin, p=p, - pCut=as.integer(sum(matCov$pWin < 0.5) == nrow(matCov)), - pCut1=pCut1) + pCut=as.integer(sum(matCov$pWin < 0.5) == nrow(matCov)), pCut1=pCut1) return(res) } @@ -1426,7 +1409,7 @@ testEmptyBox <- function(matCov, pCutOff=-3) { calcAFMLRNA <- function(snpPosHetero) { listPhase <- which(snpPosHetero$phase < 2) - m <- data.frame(aL=rep(0, nrow(snpPosHetero)), + m <- data.frame(aL=rep(0, nrow(snpPosHetero)), aH=rep(0, nrow(snpPosHetero))) # For the vairants phase # sum the coverage for each haplotype @@ -1457,10 +1440,8 @@ calcAFMLRNA <- function(snpPosHetero) { listUnphase <- which(snpPosHetero$phase > 1) if(length(listUnphase) > 0){ - minUnphase <- apply(snpPosHetero[,c("cnt.ref", "cnt.alt")], 1, - FUN=min) - maxUnphase <- apply(snpPosHetero[,c("cnt.ref", "cnt.alt")], 1, - FUN=max) + minUnphase <- apply(snpPosHetero[,c("cnt.ref", "cnt.alt")], 1, FUN=min) + maxUnphase <- apply(snpPosHetero[,c("cnt.ref", "cnt.alt")], 1, FUN=max) m[listUnphase, "aL"] <- minUnphase m[listUnphase, "aH"] <- maxUnphase } @@ -1470,8 +1451,7 @@ calcAFMLRNA <- function(snpPosHetero) { lM <- log10(aF) * sum(m[,"aL"]) + log10(1- aF) * sum(m[,"aH"]) lR <- lM - log10(0.5) * d res <- list(lR = lR, aFraction=aF, nPhase = length(listPhase), - sumAlleleLow = sum(m[,"aL"]), - sumAlleleHigh = sum(m[,"aH"])) + sumAlleleLow = sum(m[,"aL"]), sumAlleleHigh = sum(m[,"aH"])) return(res) } @@ -1561,74 +1541,59 @@ tableBlockAF <- function(snpPos) { resBlock$nbHetero <- tmp[as.character(listBlocks), 2] resBlock <- apply(resBlock, 1, FUN=function(x, snpPos) { - resBlock <- data.frame(block=x[1], - nbHomo=x[2], - nbKeep=x[3], - nbHetero=x[4], - aRF=-1, - aFraction=-1, - lR=-1, - nPhase=-1, - sumAlleleLow=-1, - sumAlleleHigh=-1, - lH=-1, - lM=-1, - lRhomo=1) - - - lH <- 1 - lM <- 1 - if (resBlock[1, "nbKeep"] > 0 & + resBlock <- data.frame(block=x[1], nbHomo=x[2], nbKeep=x[3], + nbHetero=x[4], aRF=-1, aFraction=-1, + lR=-1, nPhase=-1, sumAlleleLow=-1, + sumAlleleHigh=-1, lH=-1, lM=-1, lRhomo=1) + lH <- 1 + lM <- 1 + if (resBlock[1, "nbKeep"] > 0 & (resBlock[1, "nbKeep"] == resBlock[1, "nbHomo"] | - (resBlock[1, "nbHomo"] > 0 & resBlock[1, "nbHetero"] == 1))) { + (resBlock[1, "nbHomo"] > 0 & resBlock[1, "nbHetero"] == 1))) { - # Check if 1 hetero with allelic fraction (<=0.05) - # it is considered as all homozygote - flag <- TRUE - if (resBlock[1, "nbHetero"] == 1) { - tmp <- min(snpPos[snpPos$block.id == resBlock$block[1] & + # Check if 1 hetero with allelic fraction (<=0.05) + # it is considered as all homozygote + flag <- TRUE + if (resBlock[1, "nbHetero"] == 1) { + tmp <- min(snpPos[snpPos$block.id == resBlock$block[1] & snpPos$hetero, c("cnt.ref" , "cnt.alt")])/ sum(snpPos[snpPos$block.id == resBlock$block[1] & snpPos$hetero, c("cnt.ref" , "cnt.alt")]) - # flag is true if allelic fraction <= 0.05 - flag <- ifelse(tmp > 0.05, FALSE, TRUE) - } + # flag is true if allelic fraction <= 0.05 + flag <- ifelse(tmp > 0.05, FALSE, TRUE) + } - if(flag) { - # List homozygote ref - listRef <- which(snpPos$block.id == resBlock$block[1] & - snpPos$homo & - snpPos$cnt.ref > snpPos$cnt.alt) - # list homozygote alt - listAlt <- which(snpPos$block.id == resBlock$block[1] & - snpPos$homo & - snpPos$cnt.ref < snpPos$cnt.alt) - # freq of the Ref allele in population of listRef - tmp <- snpPos$freq[listRef] - ## min freq is 0.01 - tmp[which(tmp < 0.01)] <- 0.01 - ## log10 of the product of the frequency of the alternative - ## allele in pop for listRef - lH <- ifelse(length(listRef) > 0, sum(log10(1-tmp)*2), 0) - ## freq of the Ref allele in population of listAlt - tmp <- snpPos$freq[listAlt] - tmp[which(tmp < 0.01)] <- 0.01 - ## log10 of the product of the frequency of the - ## alternative allele in pop for listRef - ## plus log10 of the product of the frequency of - ##the reference allele in pop for listAlt - lH <- lH + ifelse(length(listAlt) > 0, - sum(log10(tmp)*2), 0) - - lM <- sum(log10(apply(snpPos[which(snpPos$block.id == - resBlock$block[1] & snpPos$homo), - "freq", drop=FALSE], 1, - FUN=function(x) { - return(max(x^2, 2*(x * (1-x)), (1-x)^2)) - }))) + if(flag) { + # List homozygote ref + listRef <- which(snpPos$block.id == resBlock$block[1] & + snpPos$homo & snpPos$cnt.ref > snpPos$cnt.alt) + # list homozygote alt + listAlt <- which(snpPos$block.id == resBlock$block[1] & + snpPos$homo & snpPos$cnt.ref < snpPos$cnt.alt) + # freq of the Ref allele in population of listRef + tmp <- snpPos$freq[listRef] + ## min freq is 0.01 + tmp[which(tmp < 0.01)] <- 0.01 + ## log10 of the product of the frequency of the alternative + ## allele in pop for listRef + lH <- ifelse(length(listRef) > 0, sum(log10(1-tmp)*2), 0) + ## freq of the Ref allele in population of listAlt + tmp <- snpPos$freq[listAlt] + tmp[which(tmp < 0.01)] <- 0.01 + ## log10 of the product of the frequency of the + ## alternative allele in pop for listRef + ## plus log10 of the product of the frequency of + ##the reference allele in pop for listAlt + lH <- lH + ifelse(length(listAlt) > 0, sum(log10(tmp)*2), 0) + + lM <- sum(log10(apply(snpPos[which(snpPos$block.id == + resBlock$block[1] & snpPos$homo), "freq", drop=FALSE], + 1, FUN=function(x) { + return(max(x^2, 2*(x * (1-x)), (1-x)^2))}))) resBlock$sumAlleleLow[1] <- 0 - resBlock$sumAlleleHigh[1] <- sum(snpPos[listRef, "cnt.ref"]) + + resBlock$sumAlleleHigh[1] <- + sum(snpPos[listRef, "cnt.ref"]) + sum(snpPos[listAlt, "cnt.alt"]) } } From cb2bba51af5a1580a591595393dc733d13696aec Mon Sep 17 00:00:00 2001 From: adeschen Date: Fri, 9 May 2025 13:49:46 -0400 Subject: [PATCH 372/385] Correct length of lines in tools_internal.R --- R/tools_internal.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/tools_internal.R b/R/tools_internal.R index 37a9f8031..09e0b94ff 100644 --- a/R/tools_internal.R +++ b/R/tools_internal.R @@ -861,8 +861,8 @@ processBlockChr <- function(fileReferenceGDS, fileBlock) { "representing the Reference GDS file. The file must exist.") } if (!(is.character(fileBlock) && (file.exists(fileBlock)))) { - stop("The \'fileBlock\' must be a character string ", - "representing the file .det from plink block result. The file must exist.") + stop("The \'fileBlock\' must be a character string representing the", + " file .det from plink block result. The file must exist.") } gdsReference <- snpgdsOpen(filename=fileReferenceGDS) From a47ddbfd3d55bed6b14a4edbeeadf5630035591f Mon Sep 17 00:00:00 2001 From: adeschen Date: Fri, 9 May 2025 14:50:51 -0400 Subject: [PATCH 373/385] Add unit tests for processBlockChr() function --- tests/testthat/test-tools_internal.R | 56 ++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/tests/testthat/test-tools_internal.R b/tests/testthat/test-tools_internal.R index a47224085..78b190b68 100644 --- a/tests/testthat/test-tools_internal.R +++ b/tests/testthat/test-tools_internal.R @@ -222,7 +222,7 @@ test_that("readSNVPileupFile() must return error when file does not content expe ### Tests readSNVFileGeneric() results ############################################################################# -context("readSNVFileGeneric") +context("readSNVFileGeneric() results") test_that("readSNVFileGeneric() must return error when file does not content expected columns", { @@ -266,7 +266,7 @@ test_that("readSNVFileGeneric() must return expected value when all parameters a ### Tests readSNVVCF() results ############################################################################# -context("readSNVVCF") +context("readSNVVCF() results") test_that("readSNVVCF() must return expected results", { @@ -287,7 +287,7 @@ test_that("readSNVVCF() must return expected results", { ### Tests readSNVVCF() results ############################################################################# -context("readSNVBAM") +context("readSNVBAM() results") test_that("readSNVBAM() must return expected results", { @@ -302,4 +302,52 @@ test_that("readSNVBAM() must return expected results", { expect_equal(nrow(result1), 2) expect_equal(colnames(result1), c("Chromosome", "Position", "Ref", "Alt", "File1R", "File1A", "count", "A", "C", "G", "T")) -}) \ No newline at end of file +}) + + + +############################################################################# +### Tests processBlockChr() results +############################################################################# + +context("processBlockChr() results") + + +test_that("processBlockChr() must return expected results", { + + fileGDS <- test_path("fixtures", "1KG_Test.gds") + + fileLdBlock <- test_path("fixtures", "ThisFileDoesntExist.txt") + + error_message <- paste0("The \'fileBlock\' must be a character string ", + "representing the file .det from plink block result. ", + "The file must exist.") + + expect_error(RAIDS:::processBlockChr(fileReferenceGDS=fileGDS, + fileBlock=fileLdBlock), error_message) +}) + + +test_that("processBlockChr() must return expected results", { + + fileGDS <- test_path("fixtures", "1KG_Test.gds") + + blockChr <- data.frame(CHR=c(rep(1, 4)), BP1=c(51897, 54707, 55544, 61986), + BP2=c(51927, 54715, 59039, 66506), KB=c(0.031, 0.009, 3.496, 4.521), + NSNPS=c(2, 2, 2, 3), SNPS=c("s3|s4", "s6|s7", "s14|s15", + "s17|s18|s31"), stringsAsFactors=FALSE) + + + tmpF3 <- tempfile("block.DEMO", fileext = c(".det")) + + withr::defer(if(file.exists(tmpF3)) unlink(tmpF3), envir=parent.frame()) + + write.table(x=blockChr, file=tmpF3, sep=" ") + + results <- RAIDS:::processBlockChr(fileReferenceGDS=fileGDS, + fileBlock=tmpF3) + + expect_equal(length(results), 2) + expect_equal(results$chr, c(1)) + expect_equal(results$block.snp, c(-1, -2, 1, 1, -3, 2, 2)) +}) From 4ac7fac56b5b02a6df61700b9a1932580da1afca Mon Sep 17 00:00:00 2001 From: adeschen Date: Fri, 9 May 2025 18:58:01 -0400 Subject: [PATCH 374/385] Adding unit test from computeAllelicFractionRNA() function --- .../testthat/test-allelicFraction_internal.R | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test-allelicFraction_internal.R b/tests/testthat/test-allelicFraction_internal.R index 9ef01fb68..cd3077c25 100644 --- a/tests/testthat/test-allelicFraction_internal.R +++ b/tests/testthat/test-allelicFraction_internal.R @@ -3,7 +3,8 @@ library(RAIDS) library(withr) library(gdsfmt) - +library(GenomeInfoDb) +library(BSgenome.Hsapiens.UCSC.hg38) ############################################################################# ### Tests testEmptyBox() results @@ -91,3 +92,48 @@ test_that("computeLOHBlocksDNAChr() must return expected results", { expect_equal(result, expected) }) + + +############################################################################# +### Tests computeAllelicFractionRNA() results +############################################################################# + +context("computeAllelicFractionRNA() results") + + +test_that("computeAllelicFractionRNA() must return expected results", { + + dataDir <- testthat::test_path("fixtures") + fileGDS <- file.path(dataDir, "ex1_good_small_1KG_GDS.gds") + fileAnnotGDS <- file.path(dataDir, "ex1_good_small_1KG_Annot_GDS.gds") + + ## Open the reference GDS file + gds1KG <- snpgdsOpen(fileGDS) + withr::defer((gdsfmt::closefn.gds(gds1KG)), envir = parent.frame()) + + ## Open the reference GDS file + gds1_Annot_KG <- openfn.gds(fileAnnotGDS) + withr::defer((gdsfmt::closefn.gds(gds1_Annot_KG)), envir = parent.frame()) + + ## Open Profile GDS file for one profile + dataDir <- system.file("extdata/tests", package="RAIDS") + fileProfile <- file.path(tempdir(), "ex1.gds") + file.copy(file.path(dataDir, "ex1_demo_with_pruning_and_1KG_annot.gds"), + fileProfile) + profileGDS <- openfn.gds(fileProfile) + withr::defer((gdsfmt::closefn.gds(profileGDS)), envir = parent.frame()) + + chrInfo <- GenomeInfoDb::seqlengths(BSgenome.Hsapiens.UCSC.hg38::Hsapiens)[1:25] + + result <- RAIDS:::computeAllelicFractionRNA(gdsReference=gds1KG, + gdsSample=profileGDS, gdsRefAnnot=gds1_Annot_KG, currentProfile="ex1", + studyID="MYDATA", blockID="GeneS.Ensembl.Hsapiens.v86", + chrInfo=chrInfo, minCov=35L, minProb=0.999, eProb=0.001, + cutOffLOH=-5, cutOffAR=3, verbose=FALSE) + + expect_equal(nrow(result), 49) + expect_equal(ncol(result), 17) + expect_equal(colnames(result), c("cnt.tot", "cnt.ref", "cnt.alt", + "snp.pos", "snp.chr", "normal.geno", "pruned", "snp.index", "keep", + "hetero", "homo", "block.id", "phase", "lap", "LOH", "imbAR", "freq")) +}) From 626fae1eb15de72cd9fd2992dccf3d18d0dbd33b Mon Sep 17 00:00:00 2001 From: adeschen Date: Fri, 9 May 2025 19:32:44 -0400 Subject: [PATCH 375/385] Adding unit test for calcAFMLRNA() function --- .../testthat/test-allelicFraction_internal.R | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/testthat/test-allelicFraction_internal.R b/tests/testthat/test-allelicFraction_internal.R index cd3077c25..17ea49e65 100644 --- a/tests/testthat/test-allelicFraction_internal.R +++ b/tests/testthat/test-allelicFraction_internal.R @@ -137,3 +137,27 @@ test_that("computeAllelicFractionRNA() must return expected results", { "snp.pos", "snp.chr", "normal.geno", "pruned", "snp.index", "keep", "hetero", "homo", "block.id", "phase", "lap", "LOH", "imbAR", "freq")) }) + + +############################################################################# +### Tests calcAFMLRNA() results +############################################################################# + +context("calcAFMLRNA() results") + + +test_that("calcAFMLRNA() must return expected results", { + + subset <- data.frame(cnt.ref=c(31, 31, 28, 17), cnt.alt=c(16, 16, 11, 27), + phase=c(3, 3, 3, 3)) + + result <- RAIDS:::calcAFMLRNA(subset) + + expect_equal(length(result), 5) + expect_equal(result$lR, 4.057862, tolerance=1e-7) + expect_equal(result$aFraction, 0.3389831, tolerance=1e-7) + expect_equal(result$nPhase, 0) + expect_equal(result$sumAlleleLow, 60) + expect_equal(result$sumAlleleHigh, 117) + +}) \ No newline at end of file From e3f69f9665278edeb94cca989e94b5076cd41797 Mon Sep 17 00:00:00 2001 From: adeschen Date: Mon, 12 May 2025 17:55:47 -0400 Subject: [PATCH 376/385] Add unit test for pruning1KGbyChr() function --- tests/testthat/test-process1KG_internal.R | 34 +++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/testthat/test-process1KG_internal.R b/tests/testthat/test-process1KG_internal.R index 788f64a6a..8dd56f3d7 100644 --- a/tests/testthat/test-process1KG_internal.R +++ b/tests/testthat/test-process1KG_internal.R @@ -46,3 +46,37 @@ test_that("validateGenerateGDS1KG() must return expected results when all input expect_identical(result1, 0L) }) + + + + +############################################################################# +### Tests pruning1KGbyChr() results +############################################################################# + +context("pruning1KGbyChr() results") + + +test_that("pruning1KGbyChr() must return expected results when all input are valid", { + + set.seed(121) + + dataDir <- test_path("fixtures") + + gds1KG <- snpgdsOpen(file.path(dataDir, "1KG_Test.gds")) + withr::defer((snpgdsClose(gds1KG)), envir = parent.frame()) + + outPrefix <- file.path(tempdir(), "Pruned_Test") + result1 <- RAIDS:::pruning1KGbyChr(gdsReference=gds1KG, + outPrefix=outPrefix) + withr::defer(if(file.exists(paste0(outPrefix, ".rds"))) + {unlink(paste0(outPrefix, ".rds"), force=TRUE)}, + envir=parent.frame()) + + expect_identical(result1, 0L) + expect_true(file.exists(paste0(outPrefix, ".rds"))) + + test <- readRDS(paste0(outPrefix, ".rds")) + + expect_identical(test, c("s5", "s7")) +}) \ No newline at end of file From d12b60b44c361a26bfc596a06a362dc1538d59b9 Mon Sep 17 00:00:00 2001 From: adeschen Date: Mon, 12 May 2025 20:13:23 -0400 Subject: [PATCH 377/385] Update unit test annotation --- tests/testthat/test-gdsWrapper_internal.R | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-gdsWrapper_internal.R b/tests/testthat/test-gdsWrapper_internal.R index a40daeff6..4f4ccb694 100644 --- a/tests/testthat/test-gdsWrapper_internal.R +++ b/tests/testthat/test-gdsWrapper_internal.R @@ -582,6 +582,11 @@ test_that("addUpdateLap() must copy the expected entry in \"lap\" node of the GD }) +############################################################################# +### Tests getBlockIDs() results +############################################################################# + + context("getBlockIDs() results") @@ -731,5 +736,3 @@ test_that("appendGDSSampleOnly() must copy the expected entry in \"sample.id\" n expect_equal(results, expected) }) - - From 283fcdb51beef18f1f9e545a637948bc4dc1e442 Mon Sep 17 00:00:00 2001 From: adeschen Date: Wed, 10 Sep 2025 18:17:28 -0400 Subject: [PATCH 378/385] Update default parameter in snpgdsIBDKING() function and adjust unit tests --- R/gdsWrapper_internal.R | 2 +- tests/testthat/test-gdsWrapper_internal.R | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/R/gdsWrapper_internal.R b/R/gdsWrapper_internal.R index 0762720c0..57672c9c9 100644 --- a/R/gdsWrapper_internal.R +++ b/R/gdsWrapper_internal.R @@ -1095,7 +1095,7 @@ runIBDKING <- function(gds, profileID=NULL, snpID=NULL, maf=0.05, verbose) { ## Calculate IBD coefficients by KING method of moment ibd.robust <- snpgdsIBDKING(gdsobj=gds, sample.id=profileID, - snp.id=snpID, maf=maf, + snp.id=snpID, maf=maf, missing.rate=0.01, type="KING-robust", verbose=verbose) diff --git a/tests/testthat/test-gdsWrapper_internal.R b/tests/testthat/test-gdsWrapper_internal.R index 4f4ccb694..1450c3527 100644 --- a/tests/testthat/test-gdsWrapper_internal.R +++ b/tests/testthat/test-gdsWrapper_internal.R @@ -132,13 +132,13 @@ test_that("runIBDKING() must return expected results", { maf=0.05, verbose=FALSE) sampleIDs <- c("NA07034", "NA07055", "NA12814") - ibs0 <- matrix(c(0.000000000000000, 0.079705823891870, 0.088194306191519, - 0.079705823891870, 0.000000000000000, 0.094035785288270, - 0.088194306191519, 0.094035785288270, 0.000000000000000), nrow=3, + ibs0 <- matrix(c(0.000000000000000, 0.079928243970500, 0.088100458441300, + 0.079928243970500, 0.000000000000000, 0.093880805262109, + 0.088100458441300, 0.093880805262109, 0.000000000000000), nrow=3, byrow=TRUE) - kinship <- matrix(c(0.500000000000000, 0.017237640936687, 0.001294777729823, - 0.017237640936687, 0.500000000000000, -0.014341590612777, - 0.001294777729823, -0.014341590612777, 0.500000000000000), nrow=3, + kinship <- matrix(c(0.500000000000000, 0.015481901439163, 0.001080847384349, + 0.015481901439163, 0.500000000000000, -0.014173571740078, + 0.001080847384349, -0.014173571740078, 0.500000000000000), nrow=3, byrow=TRUE) expect_equal(result$sample.id, sampleIDs) From 6b31ab3f7ad692ca728765a2c06d4173f16af442 Mon Sep 17 00:00:00 2001 From: adeschen Date: Wed, 10 Sep 2025 18:24:19 -0400 Subject: [PATCH 379/385] Update default version for github action --- .github/workflows/check-bioc.yaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index 4ae3a6cdc..b68c52c0f 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -52,11 +52,12 @@ jobs: matrix: config: ##- { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - - { os: ubuntu-latest, r: '4.4.1', bioc: '3.20', cont: "bioconductor/bioconductor_docker:RELEASE_3_20", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} - - { os: macOS-latest, r: '4.4.1', bioc: '3.20'} + - { os: ubuntu-latest, r: '4.5.0', bioc: '3.21', cont: "bioconductor/bioconductor_docker:RELEASE_3_21", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + - { os: ubuntu-devel, r: '4.6.0', bioc: '3.22', cont: "bioconductor/bioconductor_docker:RELEASE_3_22", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} + - { os: macOS-latest, r: '4.5.0', bioc: '3.21'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} - - { os: windows-latest, r: '4.4.1', bioc: '3.20'} + - { os: windows-latest, r: '4.4.1', bioc: '3.21'} env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true From 60ce1ba43c8b5a127ac176cb9ac468ed0c2a44c6 Mon Sep 17 00:00:00 2001 From: adeschen Date: Wed, 10 Sep 2025 18:29:39 -0400 Subject: [PATCH 380/385] Update R version for github action --- .github/workflows/check-bioc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index b68c52c0f..334eb5024 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -57,7 +57,7 @@ jobs: ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} - { os: macOS-latest, r: '4.5.0', bioc: '3.21'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} - - { os: windows-latest, r: '4.4.1', bioc: '3.21'} + - { os: windows-latest, r: '4.5.0', bioc: '3.21'} env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true From dc4987d5c0244ab8d43847bd108d7644fc339948 Mon Sep 17 00:00:00 2001 From: adeschen Date: Thu, 11 Sep 2025 12:50:15 -0400 Subject: [PATCH 381/385] Update check-bioc actions --- .github/workflows/check-bioc.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index 334eb5024..d66b4b4c4 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -52,12 +52,12 @@ jobs: matrix: config: ##- { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - - { os: ubuntu-latest, r: '4.5.0', bioc: '3.21', cont: "bioconductor/bioconductor_docker:RELEASE_3_21", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + ##- { os: ubuntu-latest, r: '4.5.0', bioc: '3.21', cont: "bioconductor/bioconductor_docker:RELEASE_3_21", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - { os: ubuntu-devel, r: '4.6.0', bioc: '3.22', cont: "bioconductor/bioconductor_docker:RELEASE_3_22", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} - - { os: macOS-latest, r: '4.5.0', bioc: '3.21'} + - { os: macOS-latest, r: '4.5.1', bioc: '3.21'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} - - { os: windows-latest, r: '4.5.0', bioc: '3.21'} + - { os: windows-latest, r: '4.5.1', bioc: '3.21'} env: R_REMOTES_NO_ERRORS_FROM_WARNINGS: true From 08c7adf7527840e0102f6109c5b8921381695450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Mon, 15 Sep 2025 21:06:52 -0400 Subject: [PATCH 382/385] Update check-bioc.yaml --- .github/workflows/check-bioc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index d66b4b4c4..0cb0d167a 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -53,7 +53,7 @@ jobs: config: ##- { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } ##- { os: ubuntu-latest, r: '4.5.0', bioc: '3.21', cont: "bioconductor/bioconductor_docker:RELEASE_3_21", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - - { os: ubuntu-devel, r: '4.6.0', bioc: '3.22', cont: "bioconductor/bioconductor_docker:RELEASE_3_22", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + - { os: ubuntu-devel, r: 'devel', bioc: '3.22', cont: "bioconductor/bioconductor_docker:RELEASE_3_22", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} - { os: macOS-latest, r: '4.5.1', bioc: '3.21'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} From 3731d5a45e612f275717b80718ec79a8ca6adfa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Mon, 15 Sep 2025 23:57:13 -0400 Subject: [PATCH 383/385] Update check-bioc.yaml --- .github/workflows/check-bioc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index 0cb0d167a..655b0b7a6 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -53,7 +53,7 @@ jobs: config: ##- { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } ##- { os: ubuntu-latest, r: '4.5.0', bioc: '3.21', cont: "bioconductor/bioconductor_docker:RELEASE_3_21", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - - { os: ubuntu-devel, r: 'devel', bioc: '3.22', cont: "bioconductor/bioconductor_docker:RELEASE_3_22", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + - { os: ubuntu-latest, r: 'devel', bioc: 'devel', cont: "bioconductor/bioconductor_docker:RELEASE_3_22", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} - { os: macOS-latest, r: '4.5.1', bioc: '3.21'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} From 10df291231a418cf9a9404d8fb5d8427f819b4ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Tue, 16 Sep 2025 00:00:18 -0400 Subject: [PATCH 384/385] Update check-bioc.yaml --- .github/workflows/check-bioc.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index 655b0b7a6..df3370d74 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -51,9 +51,8 @@ jobs: fail-fast: false matrix: config: - ##- { os: ubuntu-latest, r: '4.4', bioc: '3.19', cont: "bioconductor/bioconductor_docker:RELEASE_3_19", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } ##- { os: ubuntu-latest, r: '4.5.0', bioc: '3.21', cont: "bioconductor/bioconductor_docker:RELEASE_3_21", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - - { os: ubuntu-latest, r: 'devel', bioc: 'devel', cont: "bioconductor/bioconductor_docker:RELEASE_3_22", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } + - { os: ubuntu-latest, r: 'devel', bioc: '3.22', cont: "bioconductor/bioconductor_docker:RELEASE_3_22", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} - { os: macOS-latest, r: '4.5.1', bioc: '3.21'} ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} From 0c0ccf41245ad3f0669bdd0b168fd642d6a957d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Astrid=20Desch=C3=AAnes?= Date: Tue, 16 Sep 2025 14:43:06 -0400 Subject: [PATCH 385/385] Update check-bioc.yaml --- .github/workflows/check-bioc.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/check-bioc.yaml b/.github/workflows/check-bioc.yaml index df3370d74..2439140e4 100644 --- a/.github/workflows/check-bioc.yaml +++ b/.github/workflows/check-bioc.yaml @@ -51,11 +51,9 @@ jobs: fail-fast: false matrix: config: - ##- { os: ubuntu-latest, r: '4.5.0', bioc: '3.21', cont: "bioconductor/bioconductor_docker:RELEASE_3_21", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - { os: ubuntu-latest, r: 'devel', bioc: '3.22', cont: "bioconductor/bioconductor_docker:RELEASE_3_22", rspm: "https://packagemanager.posit.co/cran/__linux__/jammy/latest" } - ## - { os: macOS-latest, r: '4.4', bioc: '3.19'} + - { os: ubuntu-latest, r: '4.5.1', bioc: '3.21'} - { os: macOS-latest, r: '4.5.1', bioc: '3.21'} - ## - { os: windows-latest, r: '4.2.2', bioc: '3.16'} - { os: windows-latest, r: '4.5.1', bioc: '3.21'} env:

BA<GgCMmts0!B=_R0Ca*jg=M9YF346nIo zzxV~-xdX5!7G@aP8fy;qTh@{R^F`<(rHQeZ<|EHMHw;C+QAPJ~GN$8N0MbYmtx6?G zzmLHED6bL>aHz+-zagwtaPri+8ZFtF3gm8=#a)rTMH}y;#;p&?{1e^Y4#P^Ou4r^m z4?wYA=WG?erne2ycA!F32m+V?ow^51u(f-jX;~T%Aol7GVG5|E5K!ZLbr>we_lzf~ z-!{S$o<69~726uV!aMFlu7+x{4VS;}ocD-L;)E4ca?L2M79@#|Zg1KMxmqs*I1$F% zV-UGpAYai0O}VtONXiQbp#S;NAN55h5B#?;YZDy;C6JripKP(zI}q-1=Pw8~4-`_N%I5cZcZlqqWd;l6w9kHe zIm?QLQZ~1k5s14VC)QNmgepsrLsupWQ}mc=s(6}P`iD=2oNq~7cz@dE9S@Ib z=;!nezTtI=YocU&iG-fvOCLpp)9G_JB8p?{=S@Ez8eb>ZsHj@OVEa%XuFzXh()OL# z6N{9^Toz3EduAv*7z>@uGX2$InYX^8AwZWdnM+wFE~tA8be8ae)e# zI3>hi05oh%x3-l)2qjLznwau`VGY8GN^iX?04U*KTmxW^NUIFEf-zf}uV*mihAu@U z;K#UTosO>kk>rhnT;Qi_7~O>KbOK=ugj6ELKRn38c%}M(ptsYh^mJULDwHlFXSadc z1tEBEZQZacP=^3`99AF>Y%u&c)w`Kns6ojI<z*=v4 zWp>y$UNj`}8q4OeGzv?i#nF`rzHrU$Vt7daYWdtpQSnp6T&2T|ExYIuL+Zs+mkaHg z!nbrT?*BLHR&#?Ec24EOVzj0Y9W0SyL1}*4mmaS^!6r+4pt8sVz(g%nAv)FoUd39W z%w(t6e8WnpH!E3}JwcfOs&wegl1Aqg2K%wYGV;^09TJ??ve(u zJxPG^`{MI7Ie-}kFs2?K?!|35V^y02sN6joXMaIZaPD(faV@07RHaUjiJ*ArcT(2g ztsSUXbI5|g!1cPEu;N>#gII!uh>Y0qfI)b|6VbD2 zb7OtVBkF78P8dmsHN`VST69nPT*8xLcNJ7jIOG^;UlJ*QRD$BsuMFmD3=V2Ys5v#C z34++;YFX${Qk)0CKnr(_{K;1Jq4iIkFu@8BNJp=BJ4N_3)z%r5k&w~dw3wStTn+r%qalcrMS0A0JHgCb#m8bnj;udfR9gZjN51F(w!+ zSZiNus#eRh9@Z(flsoxM^uXuzrtkiIjjR4(!O(hJat>4qrJ5-%4Y1F-IB^^rI_H$R z$_H+B@F7)K?0$$jAsgiehOvzIwb3A(2EA(TtkLPVD?vj9}<=K_i)Y4>lSCg0b-^Bs5d54+z)EVX(qT zDzZ3ytU$1y@OmD$jS@?Aj2$w~XcaE(*S?ime)C>HH^`3t_vIq!Cv^?$O^5WF z&Slei7_FS)kEQ+(q&RBQvtDo1@s_}&#=Nn`&FWsQ+ZrJp>q?Y|+N4k!^wL-u1A*Ui z6W68X3A!WN=;afDaRxzxG|<`S2YP(7!Q)B1mX$b^W?<<>gLmGS;l~2vIO@vE2FcnQ ztp}3dBu;&Wbo+{=dP}-ng0F^stfslKeWSI>KoO929^HTn2CbRT;vO z`E4pzxsM+IS8FWxUpbs65>3Qz8`fF{Ms-IJP2;ysxD03yJpP@NKA`WGYPknBeGi0z zu3WqiITm-nZc0WcyvWZGw{bHN#MirRCxy1-PR8=Z08C6qOakEG57fXp_~!m!x?Q(n ze?DZ0gC+7;3dm6Ywk&BrB1Ijvr+`#!L6Wm2}|`?yee`=+kwnAIVnUR zKmqNSfE2=A5(n=R*ljPD+521w6KlKdHsSc<> zC*SXi#E4xVfr|qEF9#buk(tMqpM;KBAa?$bijC-Rpc;_>ew5o3mcahz=M(_d@6E?$ zm`U(B02T7(@62Eu0kQ!`M~Vp~EZVhyxTS~2sML9Lu>Y{+d;9s)tyEEtmic7YY&qwt-3^&_uiD3nP#ITnsjsEaG&l4f* zfs}Ohobri;=!bw1!j*eltNp?nS`WB-yV()awaY^V`COqriW&k)Vfrb+0`qB{2@|;v z{WAPX4Gip$$h!)rwD|PTUc(7OhM09+e;Lf02&lW#iSdSFk7@3PCQ(4~Vv?j#Ppy7& zGS-MC&%pHLfYq=1?)h(JuQT{6`GVORAPp!c!6D@0 zjr|Y^&jr|GtdjSiRfb^5&PL5dfo+&i%X!#V-H`t?zx*pwElLqU6-g=-i4Y@t*{yrf z7~;O!R1Gu{j6^76%>Bk+03or;0h!3N0z!!EqGJOCISQ4XEKnb#zKN5xj zaka`9{TK)#XZ@8I_gjoWD*7H144n67z;`<=*bOR_Pmq}oh5E&Bmj(E2Pnw(Fk)`{| zV)_f9Z2vAhbb6RU3r<1R`&U<7FGtb5&^*UmrsMpuGJYfOU>fH=yZH$^{+y`^> zDYs%7EFxWfpS$~A6kDKGcX!6lWu)nYwr37bVY&BgZxL5@&Y9mJ76! zv%6iJ&+jfvfDt}fq$t6cAGMH0ZJM(HCp-gAbp$2*zrPA3cr~;XfSLaJ3Zcg^wls#) zdj7nI|A?d;+b{^=)^40RNk_blDpT!E+bUqze@(DD+QJEXH_1e);<~aj*Y-yOb_QAj zNJ!3Pgf+2MlS?FQNenDmKx$D|0s`H!WLzDvi_aP=TK}t~(0+v75EHV=TzcJT68b zD$I;$ogy;PpOkp*>s(_Rp|?TEr1+o5nlZok`P{b;kKFgR~MqqD}k62LkhGitA)^1@!4I##8im5aRtzi$fE+o zYVLM|1{Ih6O#m^s@?Y*h)JqiTx^CBDY3Eui55&utw^iym4Yi6vO~NXi6Gl%mh7L-} z^9oPSN#KW1(89L-UPRLX<`G7Yc*XS((enOfh51zs$lUZ8O&LQ@7#QK|>ig$FOIsZe z6!x%5+$5fhrMe!Lq&nD+pCMRm^m2%1-4h0cF;zBDceL4kYuj9)jpldMKm`Mm+Kx*E za^ockjFn43;K^u@_#!8O?Ex-*Uf(JoC~PR9T7J+ru&5v#Y^)6#Lh*C^Xhd`*zJFou zVj6FM`v@ookqPUf4$m-GdT2z(5z5*Q)#mHv5-ILU60N_majAWw{23n{z9CKmT|o8t zeJJpK!hq)Xi;{*LUEy)tUwS8ZL6ftOaOVS(LWvB|cD;5f=PH*Xy!sEIyw>0%0aV~l zpW3Lu|9@fJ$LL@t`jvox6Acmnp((zcmc4pT5INApW{I!iz4|S`zPhjICmQ$6Wlw5+ zoA+$eukQ5xh5SHQUxJ|*PF2H9SU2hOc+I*u%#Q&iF*#t%^2%YnkTdhyTCBthAu8d> z*>KEZec;|*S_wswgzMTes7)G1u0l*-TS6Nv2McG#-l5b3#)MDB1C{Nwr5EpvE;8FUZA2Jl3gn^Bx8& zbDJI;4qVeRGNP11A@8`Ibfc}p_0(-|aRI=r1UV}ZhyEyz87}9a;WEmiFzo#3`;ISz zIrn}J1SS+8O3%z?bK5^IJGSWa6VqbezCr8->bWxXdIg6eyFd1$w-(E(+SozkiM`7$ z58MW$qN|viT+IoiS*_W6@IADlXe%Ro;Xg?J5t<{Ra(4ES*N1jeSGS!s{_k5NT=B14 zLYQdxzvZj&_EtWhFFKBHmRCy_vY?Mg3R4JBW8%+%fK(8=jMz&5=7%ZaWb?I?{8pFr~tq69H zWzRlZ-fJOs-3td4H1qPFE(*vUGK-5xQ55f-fa_fc2dyCt6nKAe_G9798>M_P5XZ`I zmN^9PK8%J+BqpkEdwbF#8WvR)-%&?HJPjE}+4kcphTnC8+ZyPQ^vwocOGA}=>*a0T z-hJx1-vq=Y_0;HayjM+G|qpCrQm89)kYd`&-*pgg14gtn+; zhh4{ujG-K>kU^pO0Pz1quv-Uw1ZYYriwV<4cT=Y9mTgHT>k(pmZqgYw>Is9kQx!3s zd=-xzU@+%Grvn3KK;%{w36k^Q^w$nV|GRs$A0u{$l!L%U5Z;?+YnO=pI_dcV9w=cS zS%y?YLd}gy3~St(L%s;j8jj@M%kJA?7zQWIYyjz}AdMo`mS3f85#@_duk%hax2Urt zODp}sQ%*(PZJ;=eS3pd>ry2BHG9e1o7(8f$AC&uj%CM>gQpKiGFQbME4AmqWqYpAd z<|CHNcDKJ270aUzKMib)3v!2QI8dE6yHpNRA6bDG0yFbYkvo1P8> zb{FjMqQ*n~tEMgt>q0B45}Q=&yelZ0 z_fs=nKY0|HRx!(sY*#vdFXirxdILR00qL^$-`Q!I3URcgGu}V{x>~2Pak$MF+mMLx z^!JD6Dp)Txc{d-NGzr1{8V{xv2#EqDkAdC}YK$I+LO5e%M?vgBZjgU1Ii?~2Q}OIwVUxR#E|+@=S|{EcQIW!s?(90GFWY zTyakjP_H{Nvkb|M;o~wmnVw2{y3oUEb$pNC8fBu)`b84t`1FANrXd7hKvF13UV>&` zi-IKDeMAM(o|RHE9`vTsSKPSWCb(;3XE>LG-yHqMt&p-Oh7QKf6o(nIA~6_p?%m%* z1{wVzpcxd^9aDq@FG~reYxXc4ztGsB%pxT&^+Ac@aB7U|a)_i|*28 zoNr*vW1olK68|3cM$re^;r{iLM5kCv839t6mWjYuaHf-m;EaAJ6Zelkf zqxVDhZl#Fv5KY`~;X;wOt5!7+GHJ{lnuOH2UQu}ta+R;nL8bZ5o!{)c2D|kYsaKqZcW_0yBzY z7i_YA`C!d_+sd=wx2<`&XBc9&66RmZev!I0#w7NkJ5Yw^&PMUGvdKfIBbV0li|-f8 zKQdMB?pdsv3p}iF*LI>|xms~M_@2jkj|e)R%SmwtOC?3s~D zswdl{85JI0Y}JEOl7jKX5+fdtbU%aLMXivR=3yrW45>^qahp+F3eRC~R zKGiWX8tN%u(v_lvnMK2ZQUPTEP*9ZvsHS*sbPqW*rPNzua3`7JdE96DKwAq!PBASB8n~M%N=*oZRPoD7$w(HSSDt7-~D` zQ;3PJz{u2iR!E^cG2)gG7kPZJssri33Q;D5TjP<2(|*^0+S?gs>Q)X>Bni#G=YZMO z{n(N4?jUNAh3Ciu6!Gft&V~`c%SaqD|9m(`Wrvx?+HJdw|8Z|FO>}H!R@Y` zxt@|Zv^2Fdnf`d8WhG|$#fvi)KreT448Dm)^d9WpC-K<79|*KzVj)~s$LH_GHmHMp z+n}Z+cdVc(snOA!B*rEl^!eR{P?a0$8-(&GpLBYxmzS{l!S2=L0zz*0`*E;7#a8HW z*{kxqBnW*s#;g2DV zpeC}=%Ni`!uG%Q>m%%*`5GGA@IPf+hRTbR(E+blSs_U0AvS84PS5)BN5P2e;G-Q5o z%7n561r)N8oY$sxkeoktYnYkQD^YI6G17}7%kE%}?h56T?3tl*`CaOj~Vx3pW=}0Sd*DgjGHybUY^#ydWP`DfPd01Y06x}>c{NaE}=g& zA^{EcQlE7onY~Kd+&%Wfe!ruap(F~q<5?YcdoLQrYcFx6YBqfe^E|9>TA~U9S>a`z zER4ulD7di+Gp9f&!0<}1!`6n?6Tid?^V4>zrEl4>yN&43cDBvi_prPPsG=UB;txdx#tFMou{mSpCPfN9d1K| zXJT0GDOTNa%zpk_(ljk*94|2AVE_9)npd`P4^2@zLy_^#3|CI};>_x(l`Iu;R!ha1 zCp>84PIgXSqQf5G<4Dr(g6(L`CXaezkwJ_(7ieqY`!mCC<#ye4oy``P4$@w|jT&yW zo-bXGn<(9&o9XH$_(b7+1Dq&~;6$k&2m@YEmI3_dkmS>ORk`!@`iQQC#`bydFUN{N zd|VMGiAyDRp5IWuMqPKlO|YGMo_fWL{3ZTn9N8E!W{$NE1eYrR^Gk4fd~9Qs&hEtY zQQ@hVeHD6dg-+jOM6D^>^PVj}PT+;eS>5T;)EBL)lc-5AhmxBsE*6sXEUGxbismGk zg$_D7zh^=7%BMt#+qL#(_3q|oU!7^6gVKRa`-sXuTMh@5%)qJ93{3pO#LiBm^IfE! z)uz?$t{L+&Lt$&!v4F|!^Gn#YQAuEAg~GoV@@3#Aa9$&qDjvA(J8e(@(3tNC=|fla z^+lVdlN=s<7H4%|HBVHjuZk5cZeAE<#l^!S3JAc*>OkNt0>!DnKklUps)GeoSTEy9 ze$)joa!vmC8ZaJsD(0oPt(fTm5~i3fgn6iGUT%Wk0iOWh`JF5h4vZTt&?5Q&m}*yDHUnl7nG1x&FyRJ~Csez_ zdaf-zHkL(0Sx+ya$h&kZDJK=Na>@K+OQa$&*%m>UA17kmv0YgJk|9O@z6w;Txr1j4}=d0US;R(`7 zu2+A3qZwvIg9<1lWDW;M)(91JlY-u<=_to_c}Ph;RhS8ZK)_EAohd}0y>}+0^j89J zkHPNv@!R^h!9?$s%I<)zu?<(k0BT`_i~VZ}TLy)A*a%+1p$7 zXUOr{k8rXxQebr$^6fq#|7AiSSuoDDo9G@WBqBia@w{s4VM_?9)!y>3JXun+WY2~+ zy%O;BF#+xGem|83^Hk7l{QXoe*uw74)tI2rPw$WpJ{gKb7g|TT?!l^i+|ezFaZ{lm zxP3aNJ0=@G{y7B+NIxE~i2b=oq>mPBbPL#H{4(TexBEZ@jFc zuRXHOc{fNC@7|Uzp06R|_9$1)033Ir>AvV5l&;iW9DZgHJSPZfF|uKt?6uBFbHCGZ zZjcVqT`plLVJIyD;_y%v-L-x~>@cOwW3Pp|BY%&9r@X9Cm(7~3eg&(!%t+{ijH8@P zKX`N4ai>PI)6ch8oj(ss)$xzT9izQ8bh)+~(Q5}J@E~ONvQZ8V@ImGyVD`^i-#dT8 z8moP3p?rm6@2d=--KXbq`%1`7Rb45~bd!zz0;Z>I{y@&n_5st@_EiNiPm+HCBoin!UV3LFr{MpfX%i{$=U*#QA}fo~9Eg~;Clj-bQv z&PuY&pOq~6Q3g!;>rD#bui!0c&aYQhH~)U)VI(j~Gm=R2KCn-R;eGaaR?NYLaVa=A zFQYl{=hHt-$2<#?9?$sWm!|RW8>Am?u2H54hE*CL4 zz<;lId+_5$mH;dB$LazrcFHVSx}=4Gy5wxt8Sx=fQaGxr zs$P(Pbtmifh9ieopn;F>Np&KW z5B%+PBx(7;6nSVlD4>cSS(EWsBrWxU8^0I@1Ox`&$y}HDSYAhtmkO zPPGgS?s#j|P>8q}#l^=f0iW|z(2HEXJ!2y8d`~r{Dx93x#Rr&+yx#5*%Xty+rRJ|A z2$%*WZhppfv5O06&gr70h$8(`vvT;nvgg^}C_XWS$F1_lWU_#LnBdlVrOuK;&sow{ z$K|2?prW<$s_r`;Kfk_{_gEeI7R3&M^&snZ);_WRU5v6ITv|{sIAet^IGlmJ&<(Tt zQH4Paf1ey6Ns2K~S0)r1T2s_diAbx11G4eBMuPzfm+xak%h_YhQvLrjgLcYO&;d9I zHDnk#2pS$9ZgsaCa#(f5$rxWj@QJ|Nf@ph3uL55oV9r#DS&zRLEdf}u1phGg4@Cfp z%gth~$J5_r@MmI*cY7b@oP$Zy5vd+<68_;lziQLVmOt(-yH8aV%^<)szl(5Dio<_> z94Kj>qBoH3o3Oh!X12|}L7zHNvnONF^6#F&0lW2+Qb7V!qg3#C9>cU&`*)<~djO8Xl#GgejF>p~l~4`R&|SeOjmoFq7lvIw z9k@j)Ou3vny^qw`kPo8Nq(wU~y^#LBWj`wbFoU@|l)(e%@u~Yt;Blk`lx38l_FF13 zMXLvP^}3I_aO#Y*JYnWFpF}Ef_w%n2V#B2lZ7*FS>Q|DL(uo2+jgMKx zea$Y?1{z%=c(CYk4sd;*R_YbFQ=_LL2mKKG-#?Ew4*2AUIq|XZK*_eqM2CEsQYK!O zujos&@k2CW>5g;U%WHpa`4Frpsm@!@$KjG~Vd;(~>CkAJc|Vn~i7igkGxP1;$e?;L z&bfd6k2G+zII&%9b<*IBzglr|9f*6RGth(V3$s44UxDr7kYko#kkBhqfLU_W*GOQy zJw1ASK9VJ2RLGV3Z>K~6a`l??koFqTG*Y6){$pK5Fpg;^t&lO4Z#()purXUk-FO2_ z>HhZCxOTbKiFn=dK*aWx6izZ3DSV+mW{(+EChx9?{W)uJ7(gahUxebBVz!juJ;+Y7 zWmo=c=H-wmD(;r#@zzI}556$iQcDd)Q3ajbUi=>I%S13*HAe}F6Cp&6Poe6G!i7rT z8~+Jrjj1n9w|kJDF2#p_I_RDQHu^ulU-BQ!D6`m$;CjZ!99OSi)zZ}L$9dxHT-Jkt zwDWGNr3iLL(aA8fw3|ngS}ycBvw!gflLvH#^!|7h9`FTb4{zhvBk}JF76k_D>g%ic z`8D07dhjrT$K3I*my%M*lZk4zuCA^q$i$G%Pj>LbbSH2AnJ*jx@V_a$@@lAC^Icua z2!7j`Jc>%^xwbJZ8aC)e!9f9NB3o81J)r@Np0_dtsRD|A84SymHuYiVgP_wL8N)v@Efm2e7y zopiJFyq2Q(@4p`A{c*}m6E#kmRzeV99o27XV&0FzL5Ml|D1=?} zqH*>-ZEf@E9xaQl^dNNCjXs$0kr^HUMb4hD>oqmqe=B0RV_}`7=!q}QETzr+Z&t^T z5}X~o{mMp?dGj{GzP+=S0 z?_QjQJA3V}GBI_V-M8*aP6p^cgx^K`4o$3i0#{^j0hzb~V`lrb9dg3-peMXHD?iCY zN4E`ogi7P$@{25$n)QKv7kvs53$08;QKsf>4W2h;Dssem;z>{yGNt3c$1wP{IoF~p z4iBR8vm>o7Dk_Tl*`GLC4UvLaR}zu9We7u6CfU}N-7A!Z^@jGfp_K!*&m7La6qX(6 zq|7uopoo$q#ZNyHReZkw=BDAmS^nHm&uEj!0kg?Sp5>Cq{KuCn1jXHy#ao5WJ@A}1 zNPA}DEB4Ec2j}hKh7WdBQ-y0Loy@3G>Qr>!(ZcfSl_dU71lSNmm*D&H$fdE;f&z91 z3NKvC1_UIPYbQowZ@SWUkjjBS=1ozq9ExPhCC55u7cR*}*BaRq%R6^rXy(1=fp6X4 zbAV)v&Oh%y!GEmS%g@E;rpl?%4qe4JLiu+C7?rKNp<6cAX+X>(M!=(A*_f>mec7yF6K7oCKPX~>{Qb=+ID-3F0!1W zp`OrHUV9h$qu2B5BB@3-3^S`o>XN;gZYn1yK<3 zs`!O7`K#WV??J`LRe>WIn{iqU=H}+swm`SD&>On8pO;=ZQe{8-v!Nj(Yhc!hL`J~g_Hicw{9yVz0dTLjc(+h$HnDa#aMT`aID$ZEfztc z72JE;5K|hOvyN|3U%brY9lhsz=PV)e)=K3JLJJ586Kr9MU~fQHq??k|0q4=QRGDf0 z>NQaMRaABqS&_UWyMCJSNn&OmYn@#|K%{kZ&OrChGQLJBAZ_x;UA0s@+G zU+SVx)x@g$v%#Klz{#jC(*OLfIz`|AIB-bsas{_XrQ>G{zoe=`AQxNjv*Y`upfp-& z3iPwQT9O*I{ncrt9eiu6-{c?u@XV+=t#OPmwZ=2Q_`=~_GobHlWmOehZMa4$_HDeu z-qNl+pm{7=dcOnVu}VSl@7q8~`UaHmsP6zv+_?O|f1U=ZZ^QgX zN`EwDChNK6zec-+O|MKF2hT}|Soh}pttX|Lth`o;r1q~5qw)<+mBE_22E}td#<}kwPpDetc$Lx!S_s@*+3N=!Nk-MeZtLUU&t%_5Lu!uZwD15^&BbCc9#OGo$Gh_#SX#i`Fzr?&%{zt74KVNvp<`B&gLij zy1jjxj!DB!&mMlY3&`N}c7m(FIbYS;bGMmXi>W8bt`f z-zbWCwmF!l}SSbE+T$8Kl(*iEO$1nh_fhPvYd{pNJ(!3vZL;}#l zl9GheQy+woQ(D+vA@0qPo5e^n3DHtb_%2-bERdXY&uGd%$NiBGmOF4);l(?9UyAm= z6z=gU4x9bgjFT?IG~=$F8!h}h?EwK>M9c5NH9b7`VL~p}2^9?uq6ksXaue^hs`95l zq%}+T!p8qpH{@Tn7~jaZ{thk+w$p zzFe8k`0=N*p{d6`KBo>fQzMGgJ?$cmEP$W!qm>9<0stPc$Z!8T?vJ;zKXbyi5(JWW z?rofd%NyezOS6_f243OwKR;#OFs$HK;*ZQt6i=SuuR-@WnDCkP(!)$TK~FhM`oD?& z#1eoMn51HiMlNN)?(Ia_9rP>E2!L2mhiSpPuP7!bf>*_aUI~c3_~YlGZ-Uy|KUt*z zc~wx$Dtd=x0vx=ha@qLP1@|Z&U&o1Ru98hUSelvmIRzDTM}s>U`(IB~8FvXj@(=~; z3XlBsj2gVVz_sx>%k{`a6R} zN+9Jsg{3i7#5cJW`sf3>cRdnlmQRVJ=o4 z#rh|)1F05~50*t-#dlciImP4CXJZM+&r`0efV#ncWQJ894pQ7juglC&JMHv`+dE+% zbFM>-i z`26bkB+uH@k+JsIO^~V*RCoWuGWKZVNkus^Wxm$Da#@|>-QNV}Qs6^?y;HXBeE>gw z?7OwR_IaR?e^>`Q>02D+{_Yhh%aSu&H2csYYMxD#l z1C1))ohzeXsy7g{LhDerea;0U_(9A8Qr zlBVv;n9$m>&Hdkc3F&Ob{LsIC5;F;y&kp`5V2bdcbTI%zlgwf~%e2%y9nwS3qq~_i zb)?-_Ta=)OKb*%JH{P2J*4$O0kcrY)|DW@bRur4E6CqrcDUh3Gw?RDS@?Jh-2pI<| zKd%5QJG6EH literal 0 HcmV?d00001 From f0da5111d571bd39dd5e4368edb81e25ab3292a4 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Wed, 21 Jun 2023 20:05:32 -0400 Subject: [PATCH 029/385] Update figures in vignettes --- vignettes/Ancestry_Inference_Step_by_Step.Rmd | 4 ++-- vignettes/Create_1KG_GDS_File.Rmd | 8 ++++---- vignettes/MainSteps_Step1_v02.png | Bin 54308 -> 0 bytes vignettes/MainSteps_Step1_v03.png | Bin 0 -> 55569 bytes vignettes/MainSteps_Step2_v02.png | Bin 54686 -> 0 bytes vignettes/MainSteps_Step2_v03.png | Bin 0 -> 55449 bytes vignettes/RAIDS.Rmd | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 vignettes/MainSteps_Step1_v02.png create mode 100644 vignettes/MainSteps_Step1_v03.png delete mode 100644 vignettes/MainSteps_Step2_v02.png create mode 100644 vignettes/MainSteps_Step2_v03.png diff --git a/vignettes/Ancestry_Inference_Step_by_Step.Rmd b/vignettes/Ancestry_Inference_Step_by_Step.Rmd index 523bd20e2..3d70d3b20 100644 --- a/vignettes/Ancestry_Inference_Step_by_Step.Rmd +++ b/vignettes/Ancestry_Inference_Step_by_Step.Rmd @@ -67,7 +67,7 @@ Step 2, sub-step 4, to Step 4. ```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from the population reference dataset (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step1_v02.png") +knitr::include_graphics("MainSteps_Step1_v03.png") ``` @@ -87,7 +87,7 @@ Molecular profiles in a cancer-derived data set must be formatted following a series of sub-steps. ```{r graphStep2, echo=FALSE, fig.align="center", fig.cap="Step 2 - Formatting the information from an external study", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step2_v02.png") +knitr::include_graphics("MainSteps_Step2_v03.png") ```
diff --git a/vignettes/Create_1KG_GDS_File.Rmd b/vignettes/Create_1KG_GDS_File.Rmd index b26731a66..9eec0c050 100644 --- a/vignettes/Create_1KG_GDS_File.Rmd +++ b/vignettes/Create_1KG_GDS_File.Rmd @@ -1,5 +1,5 @@ --- -title: "Formatting the information from 1000 Genomes (optional)" +title: "Formatting the information from the population reference dataset (optional)" author: Pascal Belleau, Astrid Deschênes and Alexander Krasnitz output: BiocStyle::html_document: @@ -12,7 +12,7 @@ urlcolor: darkred linkcolor: darkred bibliography: aicsBiblio.bibtex vignette: > - %\VignetteIndexEntry{Formatting the information from 1000 Genomes (optional)} + %\VignetteIndexEntry{Formatting the information from the population reference dataset (optional)} %\VignettePackage{RAIDS} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} @@ -40,7 +40,7 @@ set.seed(121444)

-# Step 1 - Formatting the information from 1000 Genomes (optional) +# Step 1 - Formatting the information from the population reference dataset (optional) This is an overview of the main steps to infer the genetic ancestry @@ -53,7 +53,7 @@ from cancer-derived molecular data: ```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from 1000 Genomes (optional)", out.width = '120%', results='asis'} -knitr::include_graphics("MainSteps_Step1_v02.png") +knitr::include_graphics("MainSteps_Step1_v03.png") ``` diff --git a/vignettes/MainSteps_Step1_v02.png b/vignettes/MainSteps_Step1_v02.png deleted file mode 100644 index 0a479cd4b31341164b93f5eb37e758c761e074ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54308 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 diff --git a/vignettes/MainSteps_Step1_v03.png b/vignettes/MainSteps_Step1_v03.png new file mode 100644 index 0000000000000000000000000000000000000000..dbc1e24dcbe2b335d8e50e235755da0ec59d8288 GIT binary patch literal 55569 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 literal 0 HcmV?d00001 diff --git a/vignettes/MainSteps_Step2_v02.png b/vignettes/MainSteps_Step2_v02.png deleted file mode 100644 index 1b89ee0fe42128995ddc15411cdcf8edd467041d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54686 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 literal 0 HcmV?d00001 diff --git a/vignettes/RAIDS.Rmd b/vignettes/RAIDS.Rmd index a0f5622ab..15bcb3396 100644 --- a/vignettes/RAIDS.Rmd +++ b/vignettes/RAIDS.Rmd @@ -133,7 +133,7 @@ in one command with the [wrapper](#wrapper) function. ```{r graphStep1, echo=FALSE, fig.align="center", fig.cap="Step 1 - Formatting the information from the population reference dataset (optional)", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step1_v02.png") +knitr::include_graphics("MainSteps_Step1_v03.png") ``` @@ -172,7 +172,7 @@ Molecular profiles in a cancer-derived data set must be formatted following a series of sub-steps. ```{r graphStep2, echo=FALSE, fig.align="center", fig.cap="Step 2 - Formatting the information from an external study", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_Step2_v02.png") +knitr::include_graphics("MainSteps_Step2_v03.png") ```
From d9498b43a111b07de91ee9768f48adab2682e301 Mon Sep 17 00:00:00 2001 From: Astrid Deschenes Date: Thu, 22 Jun 2023 15:28:15 -0400 Subject: [PATCH 030/385] Update main steps figure in vignette --- vignettes/Ancestry_Inference_Step_by_Step.Rmd | 2 +- vignettes/MainSteps_v03.png | Bin 0 -> 52210 bytes vignettes/RAIDS.Rmd | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 vignettes/MainSteps_v03.png diff --git a/vignettes/Ancestry_Inference_Step_by_Step.Rmd b/vignettes/Ancestry_Inference_Step_by_Step.Rmd index 3d70d3b20..710a265c9 100644 --- a/vignettes/Ancestry_Inference_Step_by_Step.Rmd +++ b/vignettes/Ancestry_Inference_Step_by_Step.Rmd @@ -42,7 +42,7 @@ This is an overview of genetic ancestry inference from cancer-derived molecular data: ```{r graphMainSteps, echo=FALSE, fig.align="center", fig.cap="An overview of the genetic ancestry inference process.", out.width='120%', results='asis', warning=FALSE, message=FALSE} -knitr::include_graphics("MainSteps_v02.png") +knitr::include_graphics("MainSteps_v03.png") ``` The main steps are: diff --git a/vignettes/MainSteps_v03.png b/vignettes/MainSteps_v03.png new file mode 100644 index 0000000000000000000000000000000000000000..e27983fcfee931c91577b8f56be37cb1c3caa052 GIT binary patch literal 52210 zcmeEu2|ShE+CGvl*g0Wuk+F7hasWr<`S}HTK+_w2YMEJ?x!7!PLhb_m`!)P90Vt0U|K`Xo z-OS*dPid><&3(p68m4JxuV>?|o*k8T>pO4~Cs4H!o+)&7*K9 zC%8Qrh5!pxj)hMOoWuS=WpGmqzS!Uy94`cH=U4n+uk%xYjlgxj8x6yV*GJJZRzM=xAwyd*8Sg&0JitFL`75 zxI