diff --git a/..Rcheck/00check.log b/..Rcheck/00check.log index 7e5aa07..9fb1445 100644 --- a/..Rcheck/00check.log +++ b/..Rcheck/00check.log @@ -1,10 +1,10 @@ * using log directory ‘/home/veit/devel/Bioinformatics/DataAnalysis/ShinyApps/vsclust/..Rcheck’ -* using R version 4.4.2 (2024-10-31) +* using R version 4.5.0 (2025-04-11) * using platform: x86_64-pc-linux-gnu * R was compiled by - gcc (Ubuntu 13.2.0-23ubuntu4) 13.2.0 - GNU Fortran (Ubuntu 13.2.0-23ubuntu4) 13.2.0 -* running under: Ubuntu 24.04.1 LTS + gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 + GNU Fortran (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 +* running under: Ubuntu 24.04.2 LTS * using session charset: UTF-8 * checking for file ‘./DESCRIPTION’ ... ERROR Required fields missing or empty: diff --git a/DESCRIPTION b/DESCRIPTION index 721854a..24c511b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,7 +2,7 @@ Package: vsclust Encoding: UTF-8 Type: Package Title: Feature-based variance-sensitive quantitative clustering -Version: 1.11.2 +Version: 1.13.1 Date: 2022-03-23 Authors@R: person( @@ -45,4 +45,4 @@ VignetteBuilder: knitr Depends: R (>= 4.2.0) Config/testthat/edition: 3 LazyData: false -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.3 diff --git a/NAMESPACE b/NAMESPACE index 81e9180..96cdddf 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -40,6 +40,7 @@ importFrom(matrixStats,rowSds) importFrom(qvalue,qvalue) importFrom(shiny,getDefaultReactiveDomain) importFrom(shiny,incProgress) +importFrom(shiny,isRunning) importFrom(shiny,need) importFrom(shiny,validate) useDynLib(vsclust, .registration = TRUE) diff --git a/R/EvaluateClustering.R b/R/EvaluateClustering.R index 56cc8d4..ebab8a2 100644 --- a/R/EvaluateClustering.R +++ b/R/EvaluateClustering.R @@ -182,7 +182,8 @@ mfuzz.plot <- colorseq <- seq(0, 1, length = length(colo)) for (j in seq_len(max(clusterindex))) { if (sum(clusterindex == j) > 0) { - tmp <- dat[clusterindex == j,] + # keep matrices in place even if a cluster has just one member + tmp <- dat[clusterindex == j,, drop = FALSE] tmpmem <- memship[clusterindex == j, j] if (((j - 1) %% (mfrow[1] * mfrow[2])) == 0) { if (!is.na(filename)) { @@ -375,4 +376,3 @@ estimClust.plot <- function(ClustInd) { # finally plot p <- recordPlot() } - diff --git a/R/PrepareData.R b/R/PrepareData.R index c57a5f6..4fcc77e 100644 --- a/R/PrepareData.R +++ b/R/PrepareData.R @@ -39,49 +39,49 @@ #' PMID: 20880957. #' @export SignAnalysisPaired <- function(Data, NumCond, NumReps) { - ########################################################## - # significance analysis - MAData <- Data[, 2:(NumCond)] - Data[, 1] - for (i in seq_len(NumReps - 1)) - MAData <- - cbind(MAData, Data[, (i * NumCond + 1) + seq_len(NumCond - 1)] - - Data[, (i * NumCond + 1)]) - rownames(MAData) <- rownames(Data) - MAReps <- rep(seq_len(NumCond - 1), NumReps) - if (is.null(rownames(MAData))) - rownames(MAData) <- paste0("feature", seq_len(nrow(MAData))) - ##limma with ratios - design <- plvalues <- NULL - for (c in (seq_len(NumCond - 1))) { - design <- cbind(design, as.numeric(MAReps == c)) - } - lm.fittedMA <- lmFit(MAData, design) - lm.bayesMA <- eBayes(lm.fittedMA) - topTable(lm.bayesMA) - plvalues <- lm.bayesMA$p.value - qvalues <- - matrix( - NA, - nrow = nrow(plvalues), - ncol = ncol(plvalues), - dimnames = dimnames(plvalues) - ) - # qvalue correction - for (i in seq_len(ncol(plvalues))) { - tqs <- tryCatch( - qvalue(na.omit(plvalues[, i]))$qvalues, - error = function(e) - NULL - ) - if (length(tqs) > 0) { - qvalues[names(tqs), i] <- tqs + ########################################################## + # significance analysis + MAData <- Data[, 2:(NumCond)] - Data[, 1] + for (i in seq_len(NumReps - 1)) + MAData <- + cbind(MAData, Data[, (i * NumCond + 1) + seq_len(NumCond - 1)] - + Data[, (i * NumCond + 1)]) + rownames(MAData) <- rownames(Data) + MAReps <- rep(seq_len(NumCond - 1), NumReps) + if (is.null(rownames(MAData))) + rownames(MAData) <- paste0("feature", seq_len(nrow(MAData))) + ##limma with ratios + design <- plvalues <- NULL + for (c in (seq_len(NumCond - 1))) { + design <- cbind(design, as.numeric(MAReps == c)) } - else { - qvalues[names(tqs), i] <- NA + lm.fittedMA <- lmFit(MAData, design) + lm.bayesMA <- eBayes(lm.fittedMA) + topTable(lm.bayesMA) + plvalues <- lm.bayesMA$p.value + qvalues <- + matrix( + NA, + nrow = nrow(plvalues), + ncol = ncol(plvalues), + dimnames = dimnames(plvalues) + ) + # qvalue correction + for (i in seq_len(ncol(plvalues))) { + tqs <- tryCatch( + qvalue(na.omit(plvalues[, i]))$qvalues, + error = function(e) + NULL + ) + if (length(tqs) > 0) { + qvalues[names(tqs), i] <- tqs + } + else { + qvalues[names(tqs), i] <- NA + } } - } - - return(list(qvalues = qvalues, Sds = sqrt(lm.bayesMA$s2.post))) + + return(list(qvalues = qvalues, Sds = sqrt(lm.bayesMA$s2.post))) } #' Unpaired statistical testing @@ -126,52 +126,52 @@ SignAnalysisPaired <- function(Data, NumCond, NumReps) { #' Nov 15;26(22):2841-8. doi: 10.1093/bioinformatics/btq534. Epub 2010 Sep 29. #' PMID: 20880957. SignAnalysis <- function(Data, NumCond, NumReps) { - ########################################################## - if (is.null(rownames(Data))) - rownames(Data) <- paste0("feature", seq_len(nrow(Data))) - # significance analysis - Reps <- rep(seq_len(NumCond), NumReps) - design <- model.matrix( ~ 0 + factor(Reps - 1)) - colnames(design) <- paste("i", c(seq_len(NumCond)), sep = "") - contrasts <- NULL - First <- 1 - for (i in (seq_len(NumCond))[-First]) - contrasts <- append(contrasts, - paste(colnames(design)[i], "-", colnames(design)[First], - sep = "")) - contrast.matrix <- makeContrasts(contrasts = contrasts, levels = design) - lm.fitted <- lmFit(Data, design) - - lm.contr <- contrasts.fit(lm.fitted, contrast.matrix) - lm.bayes <- eBayes(lm.contr) - #topTable(lm.bayes) - plvalues <- lm.bayes$p.value - qvalues <- matrix( - NA, - nrow = nrow(plvalues), - ncol = ncol(plvalues), - dimnames = dimnames(plvalues) - ) - # qvalue correction - for (i in seq_len(ncol(plvalues))) { - tqs <- tryCatch( - qvalue(na.omit(plvalues[, i]))$qvalues, - error = function(e) - NULL + ########################################################## + if (is.null(rownames(Data))) + rownames(Data) <- paste0("feature", seq_len(nrow(Data))) + # significance analysis + Reps <- rep(seq_len(NumCond), NumReps) + design <- model.matrix( ~ 0 + factor(Reps - 1)) + colnames(design) <- paste("i", c(seq_len(NumCond)), sep = "") + contrasts <- NULL + First <- 1 + for (i in (seq_len(NumCond))[-First]) + contrasts <- append(contrasts, + paste(colnames(design)[i], "-", colnames(design)[First], + sep = "")) + contrast.matrix <- makeContrasts(contrasts = contrasts, levels = design) + lm.fitted <- lmFit(Data, design) + + lm.contr <- contrasts.fit(lm.fitted, contrast.matrix) + lm.bayes <- eBayes(lm.contr) + #topTable(lm.bayes) + plvalues <- lm.bayes$p.value + qvalues <- matrix( + NA, + nrow = nrow(plvalues), + ncol = ncol(plvalues), + dimnames = dimnames(plvalues) ) - # print(tqs) - if (length(tqs) > 0) { - qvalues[names(tqs), i] <- tqs - } - else { - qvalues[names(tqs), i] <- NA + # qvalue correction + for (i in seq_len(ncol(plvalues))) { + tqs <- tryCatch( + qvalue(na.omit(plvalues[, i]))$qvalues, + error = function(e) + NULL + ) + # print(tqs) + if (length(tqs) > 0) { + qvalues[names(tqs), i] <- tqs + } + else { + qvalues[names(tqs), i] <- NA + } } - } - return(list( - pvalues = plvalues, - qvalues = qvalues, - Sds = sqrt(lm.bayes$s2.post) - )) + return(list( + pvalues = plvalues, + qvalues = qvalues, + Sds = sqrt(lm.bayes$s2.post) + )) } #' Visualize using principal component analysis (both loadings and scoring) @@ -192,7 +192,7 @@ SignAnalysis <- function(Data, NumCond, NumReps) { #' pcaWithVar(data, NumCond=2, NumReps=5, Sds=1) #' @import stats #' @import graphics -#' @importFrom shiny need +#' @importFrom shiny need isRunning validate #' @importFrom grDevices rainbow #' @export #' @references @@ -206,54 +206,61 @@ SignAnalysis <- function(Data, NumCond, NumReps) { #' #' Schwaemmle V, Jensen ON. A simple and fast method to determine the parameters #' for fuzzy c-means cluster analysis. Bioinformatics. 2010 -#' Nov 15;26(22):2841-8. doi: 10.1093/bioinformatics/btq534. Epub 2010 Sep 29. +#' Nov 15;26(22):2841-8. doi: 10.1093/bioinformatics/btq534. Epub 2010 Sep 29. #' PMID: 20880957. pcaWithVar <- function(data, NumReps, NumCond, Sds = 1) { - # Remove columns with only 5% of the data - plab <- rep(seq_len(NumCond), NumReps) - plab <- plab[colSums(!is.na(data)) > 0.05 * nrow(data)] - pcaDat <- data - if (ncol(pcaDat) != NumCond * NumReps) - stop("Wrong number of conditions and/or replicates!") - pcaDat <- data[, colSums(!is.na(data)) > 0.05 * nrow(data)] - pcaDat <- (pcaDat[complete.cases(pcaDat), ]) - validate(need( - length(pcaDat) > 0, - "Principal component analysis not shown as too many missing values" - )) - validate(need( - nrow(pcaDat) > 10, - "Principal component analysis not shown as too many missing values" - )) - pca <- prcomp(pcaDat, scale = TRUE, retx = TRUE) - # scores <- pca$x - # loadings <- pca$rotation - scores <- pca$rotation - loadings <- pca$x - par(mfrow = c(1, 2)) - # Set missing values to maximum std. dev. - Sds[is.na(Sds)] <- max(Sds, na.rm = TRUE) - # Scaling suitable for visualization - Sds <- sqrt(Sds) - plot( - loadings, - cex = Sds, - pch = 16, - col = paste("#000000", sprintf("%02X", as.integer( - 255 / max(1 / Sds) / Sds - )), sep = "") - ) - title(main = "Principal component analysis of data set (loadings)", sub = - "The point size corresponds to the estimated standard deviation") - plot(scores, pch = 19, col = rainbow(NumCond)[plab]) - title(main = "Principal component analysis of data set (scores)", sub = - "Colors denote different conditions") - legend( - "topright", - paste("Condition", seq_len(NumCond)), - pch = rep(19, NumCond), - col = rainbow(NumCond)[seq_len(NumCond)] - ) + # Remove columns with only 5% of the data + plab <- rep(seq_len(NumCond), NumReps) + plab <- plab[colSums(!is.na(data)) > 0.05 * nrow(data)] + pcaDat <- data + if (ncol(pcaDat) != NumCond * NumReps) + stop("Wrong number of conditions and/or replicates!") + pcaDat <- data[, colSums(!is.na(data)) > 0.05 * nrow(data)] + pcaDat <- (pcaDat[complete.cases(pcaDat), ]) + if (shiny::isRunning()){ + validate(need( + length(pcaDat) > 0, + "Principal component analysis not shown as too many missing values" + )) + validate(need( + nrow(pcaDat) > 10, + "Principal component analysis not shown as too many missing values" + )) + } else { + if (length(pcaDat) == 0 || nrow(pcaDat) < 10){ + warning("Principal component analysis not possible due to too many missing values") + return(NULL) + } + } + pca <- prcomp(pcaDat, scale = TRUE, retx = TRUE) + # scores <- pca$x + # loadings <- pca$rotation + scores <- pca$rotation + loadings <- pca$x + par(mfrow = c(1, 2)) + # Set missing values to maximum std. dev. + Sds[is.na(Sds)] <- max(Sds, na.rm = TRUE) + # Scaling suitable for visualization + Sds <- sqrt(Sds) + plot( + loadings, + cex = Sds, + pch = 16, + col = paste("#000000", sprintf("%02X", as.integer( + 255 / max(1 / Sds) / Sds + )), sep = "") + ) + title(main = "Principal component analysis of data set (loadings)", sub = + "The point size corresponds to the estimated standard deviation") + plot(scores, pch = 19, col = rainbow(NumCond)[plab]) + title(main = "Principal component analysis of data set (scores)", sub = + "Colors denote different conditions") + legend( + "topright", + paste("Condition", seq_len(NumCond)), + pch = rep(19, NumCond), + col = rainbow(NumCond)[seq_len(NumCond)] + ) } #' Determine optimal cluster number from validity index @@ -288,34 +295,34 @@ pcaWithVar <- function(data, NumReps, NumCond, Sds = 1) { #' for fuzzy c-means cluster analysis. Bioinformatics. 2010 Nov 15;26(22):2841-8. #' doi: 10.1093/bioinformatics/btq534. Epub 2010 Sep 29. PMID: 20880957. optimalClustNum <- - function(ClustInd, - index = "MinCentroidDist", - method = "VSClust") { - allowedInd <- c("XieBeni", "MinCentroidDist") - allowedMethod <- c("FCM", "VSClust") - if (!any(index == allowedInd)) { - stop(paste("index needs to be one of", paste(allowedInd, collapse = " "))) - } - if (!any(method == allowedMethod)) { - stop(paste( - "method needs to be one of", - paste(allowedMethod, collapse = " ") - )) - } - - tClustInd <- ClustInd[, grep(index, colnames(ClustInd))] - tClustInd <- tClustInd[, grep(method, colnames(tClustInd))] - opt_val <- NULL - if (length(tClustInd) < 3) - stop("Minimal length of ClustInd vector is 3") - if (index == "MinCentroidDist") { - opt_val <- - which.max(tClustInd[seq_len(length(tClustInd) - 1)] - - tClustInd[2:length(tClustInd)]) - } else if (index == "XieBeni") { - opt_val <- which.min(tClustInd[seq_len(length(tClustInd))]) - + function(ClustInd, + index = "MinCentroidDist", + method = "VSClust") { + allowedInd <- c("XieBeni", "MinCentroidDist") + allowedMethod <- c("FCM", "VSClust") + if (!any(index == allowedInd)) { + stop(paste("index needs to be one of", paste(allowedInd, collapse = " "))) + } + if (!any(method == allowedMethod)) { + stop(paste( + "method needs to be one of", + paste(allowedMethod, collapse = " ") + )) + } + + tClustInd <- ClustInd[, grep(index, colnames(ClustInd))] + tClustInd <- tClustInd[, grep(method, colnames(tClustInd))] + opt_val <- NULL + if (length(tClustInd) < 3) + stop("Minimal length of ClustInd vector is 3") + if (index == "MinCentroidDist") { + opt_val <- + which.max(tClustInd[seq_len(length(tClustInd) - 1)] - + tClustInd[2:length(tClustInd)]) + } else if (index == "XieBeni") { + opt_val <- which.min(tClustInd[seq_len(length(tClustInd))]) + + } + return(as.numeric(opt_val + 2)) } - return(as.numeric(opt_val + 2)) - } diff --git a/R/artificial_clusters.R b/R/artificial_clusters.R index 97d5725..8d3003a 100644 --- a/R/artificial_clusters.R +++ b/R/artificial_clusters.R @@ -4,6 +4,8 @@ #' The first 250 features were modeled through normal distributions shifted in the 10-dimensional space to form 5 different clusters. #' The 2nd half of the features were modeled through a normal distribution around the origin and thus should be assigned to any cluster #' +#' @docType data +#' @usage data(artificial_clusters) #' @format A data frame consisting of 500 features distributed over 5 clusters and being replicated 5 times each #' @source Protein Research Group, University of Southern Denmark, Odense -"artificial_clusters" \ No newline at end of file +"artificial_clusters" diff --git a/R/protein_expression.R b/R/protein_expression.R index 0cf2baf..8b7c586 100644 --- a/R/protein_expression.R +++ b/R/protein_expression.R @@ -4,6 +4,8 @@ #' Relative protein abundances were obtained using iTRAQ labelling. The given numbers are log2-transformed. #' Protein names as UniProt accession numbers are given as rownames. #' +#' @docType data +#' @usage data(protein_expressions) #' @format A data frame consisting of 574 proteins measured in 12 samples: #' \describe{ #' \item{HF.Rep.1}{Mice fed with a high fat diet, replicate 1} @@ -20,4 +22,4 @@ #' \item{TTA.FO.Rep.3}{Mice fed with a diet containing fish oil and TTA, replicate 3} #' } #' @source Protein Research Group, University of Southern Denmark, Odense -"protein_expressions" \ No newline at end of file +"protein_expressions" diff --git a/inst/docker/Dockerfile b/inst/docker/Dockerfile index 710d2c6..247b454 100644 --- a/inst/docker/Dockerfile +++ b/inst/docker/Dockerfile @@ -14,8 +14,8 @@ RUN R -e "library(BiocManager); BiocManager::install(c('genefilter', 'Rcpp', 'c 'DT', 'RJDBC','dplyr','plotly','RPostgreSQL','lubridate'),ask=F, force=T)" RUN R -e "install.packages('rJava')" RUN R CMD javareconf -COPY inst/other/RDAVIDWebService_1.28.0.tar.gz . -RUN R CMD INSTALL RDAVIDWebService_1.28.0.tar.gz +#COPY inst/other/RDAVIDWebService_1.28.0.tar.gz . +#RUN R CMD INSTALL RDAVIDWebService_1.28.0.tar.gz RUN bash diff --git a/man/artificial_clusters.Rd b/man/artificial_clusters.Rd index 95d8436..abbea15 100644 --- a/man/artificial_clusters.Rd +++ b/man/artificial_clusters.Rd @@ -11,7 +11,7 @@ A data frame consisting of 500 features distributed over 5 clusters and being re Protein Research Group, University of Southern Denmark, Odense } \usage{ -artificial_clusters +data(artificial_clusters) } \description{ 10-dimensional data set with 500 simulating features measured over 5 replicates each, comprising a total of 50 samples. diff --git a/man/pcaWithVar.Rd b/man/pcaWithVar.Rd index dacc631..b41cb86 100644 --- a/man/pcaWithVar.Rd +++ b/man/pcaWithVar.Rd @@ -40,6 +40,7 @@ the Quantitative Analysis of Protein Complexes. Methods Mol Biol. Schwaemmle V, Jensen ON. A simple and fast method to determine the parameters for fuzzy c-means cluster analysis. Bioinformatics. 2010 -Nov 15;26(22):2841-8. doi: 10.1093/bioinformatics/btq534. Epub 2010 Sep 29. +Nov 15;26(22):2841-8. doi: 10.1093/bioinformatics/btq534 +Epub 2010 Sep 29. PMID: 20880957. } diff --git a/man/protein_expressions.Rd b/man/protein_expressions.Rd index 3c948fc..4d7bf52 100644 --- a/man/protein_expressions.Rd +++ b/man/protein_expressions.Rd @@ -25,7 +25,7 @@ A data frame consisting of 574 proteins measured in 12 samples: Protein Research Group, University of Southern Denmark, Odense } \usage{ -protein_expressions +data(protein_expressions) } \description{ There are 12 samples coming from mouse fed with the four different diets, measured in three replicates each.