#' Plot PCA
#'
#' Conduct principal components analysis and plot the results, using either
#' ggplot2 or plotly.
#'
#' @export
#'
#' @param ns Processed NanoString data
#' @param pc1 Principal component to plot on x-axis (default 1)
#' @param pc2 Principal component to plot on y-axis (default 2)
#' @param interactive.plot Plot using plotly? Default FALSE (in which case
#' ggplot2 is used)
#' @param exclude.zeros Exclude genes that are not detected in all samples
#' (default TRUE)
#' @param codeclass.retain The CodeClasses to retain for principal components
#' analysis.Generally we're interested in endogenous genes, so we keep
#' "endogenous" only by default. Others can be included by entering a character
#' vector for this option. Alternatively, all targets can be retained by
#' setting this option to ".".
#' @return A list containing:
#' \item{pca}{The PCA object}
#' \item{plt}{The PCA plot}
#'
#' @examples
#' example_data <- system.file("extdata", "GSE117751_RAW", package = "NanoTube")
#' sample_data <- system.file("extdata", "GSE117751_sample_data.csv",
#' package = "NanoTube")
#'
#' # Process and normalize data first
#' dat <- processNanostringData(example_data,
#' sampleTab = sample_data,
#' groupCol = "Sample_Diagnosis",
#' normalization = "nSolver",
#' bgType = "t.test", bgPVal = 0.01)
#'
#' # Interactive PCA using plotly
#' nanostringPCA(dat, interactive.plot = TRUE)$plt
#'
#' # Static plot using ggplot2, for the 3rd and 4th PC's.
#' nanostringPCA(dat, pc1 = 3, pc2 = 4, interactive.plot = FALSE)$plt
nanostringPCA <- function(ns, pc1 = 1, pc2 = 2,
interactive.plot = FALSE,
exclude.zeros = TRUE,
codeclass.retain = "endogenous") {
# Bind local variables
PC1 <- PC2 <- group <- NULL
# Convert codeclass.retain option to format that can be used by grep.
codeclass.grep <- paste(codeclass.retain, collapse = "|")
if (is(ns, "list")) {
pca.dat <- ns$exprs[grep(codeclass.grep, ns$dict$CodeClass, ignore.case = TRUE),]
} else {
pca.dat <- exprs(ns)[grep(codeclass.grep, fData(ns)$CodeClass, ignore.case = TRUE),]
}
if (exclude.zeros) pca.dat <- pca.dat[rowSums(pca.dat == 0) == 0,]
# If RUV normalization was used, data are already log-transformed.
# Otherwise, log-transform with a pseudocount of 0.5
if (ns$normalization[1] != "RUVIII") pca.dat <- log2(pca.dat + 0.5)
pca <- prcomp(t(pca.dat),
center = TRUE, scale = TRUE)
pca.ly <- as.data.frame(pca$x[,c(pc1, pc2)])
colnames(pca.ly) <- c("PC1", "PC2")
pca.ly$sample <- row.names(pca$x)
pca.ly$group <- ns$groups
# Percent of variation explained by each PC
perc.var <- pca$sdev^2 / sum(pca$sdev^2) * 100
if (interactive.plot) {
layout.x <- layout.y <- list(
showline = TRUE,
showticklabels = TRUE,
showgrid = FALSE,
zeroline = FALSE,
linecolor = plotly::toRGB("black"),
linewidth = 1
)
layout.x$title <- paste0("PC", pc1, " (",
signif(perc.var[pc1], 2), "% var)")
layout.y$title <- paste0("PC", pc2, " (",
signif(perc.var[pc2], 2), "% var)")
`%>%` <- plotly::`%>%`
plt <- plotly::plot_ly(data = pca.ly, x = ~PC1, y = ~PC2,
text = ~paste0("Sample: ", sample),
color = ~group,
type = "scatter", mode = "markers") %>%
plotly::layout(xaxis = layout.x, yaxis = layout.y)
} else {
plt <- ggplot(data = pca.ly,
aes(x = PC1, y = PC2, color = group)) +
geom_point() + theme_bw() +
xlab(paste0("PC", pc1, " (", signif(perc.var[pc1], 2), "% var)")) +
ylab(paste0("PC", pc2, " (", signif(perc.var[pc2], 2), "% var)"))
}
return(list(pca = pca,
plt = plt))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.