Nothing
####################################
# MuPETFlow #
# An app to calculate peaks from #
# flow cytometer histograms #
####################################
# Warn about Bioconductor dependencies
if (!requireNamespace("flowCore", quietly = TRUE)) {
stop("The 'flowCore' package is required for this app to work. Please install it manually using:\n",
"BiocManager::install('flowCore')")
}
# Download example data function
download_example_data <- function(dest_dir) {
# URL to the example files
base_url <- "https://github.com/CintiaG/MuPET-Flow/raw/refs/heads/master/example_data/"
file_list <- c("AVQ.fcs", "BY4742_1n.fcs", "BY4743_2n.fcs", "CRE.fcs", "YPS128_3n.fcs", "YPS128_4n.fcs")
for (file in file_list){
file_url <- file.path(base_url, file)
dest_file <- file.path(dest_dir, file)
download.file(file_url, dest_file, mode = "wb")
}
}
# Load R packages
library(shiny)
library(shinythemes)
library(flowCore)
library(zoo)
library(ggplot2)
library(DT)
library(ggrepel)
library(gridExtra)
library(markdown)
library(tidyr)
library(dplyr)
# Define UI
ui <- fluidPage(theme = shinytheme("united"),
# App name
navbarPage("MuPETFlow",
# Panel 1
tabPanel("Peaks",
# Panel 1 inputs
sidebarPanel(
h3("Inputs"),
# Input files
uiOutput("UiFileUp"),
# HTML instructions to add action button title
tags$div(
style = "margin-bottom: 5px;",
HTML("<strong style='font-size: 14px; '>Or load example data</strong>"),
),
# Run example
uiOutput("UiExample"),
HTML("</br>"),
# Select channel
uiOutput("UiChannelSel"),
# Select sample
uiOutput("UiSampleSel"),
# Adjust smoothing
uiOutput("UiSmoothNum"),
# Adjust window
uiOutput("UiWindowNum"),
# Select minimum number of events
uiOutput("UiEveMin"),
# Select maximum number of peaks
uiOutput("UiPeaksNum"),
# Select calculated peaks to plot
uiOutput("UiPeaksBox"),
),
# Panel 1 outputs
mainPanel(
# Histogram plot
h3("Histogram"),
verbatimTextOutput("Warn1"),
verbatimTextOutput("Warn6"),
plotOutput("HisPlot"),
# Table results 1
h3("Estimated peaks and used parameters"),
DT::dataTableOutput("ResDf1"),
)
),
# Panel 2
tabPanel("Regression",
# Panel 2 inputs
sidebarPanel(
h3("Inputs"),
# Select type of analysis
# HTML instructions for proper display
div(
# Change variable name
uiOutput("UiType")
),
# Select standards
uiOutput("UiCtrlsNum"),
# Display boxes
div(style = "display: inline-block;vertical-align:top; width: 150px;",
# Change variable name
uiOutput("UiCtrlsSampleSel")
),
# Separator
div(style = "display: inline-block;vertical-align:top; width: 50px;", HTML("<br>")),
# Ploidy level box
div(style = "display: inline-block;vertical-align:top; width: 150px;",
uiOutput("UiCtrlsPloNum")
),
# Perform regression and prediction
HTML("</br>"),
actionButton(inputId = "InReg",
label = "Regression"),
# Regression summary
verbatimTextOutput("RegText"),
),
# Panel 2 outputs
mainPanel(
# Regression plot
h3("Regression"),
verbatimTextOutput("Warn2"),
verbatimTextOutput("Warn3"),
plotOutput("RegPlot"),
# Table results 2
h3("Estimated ploidy"),
DT::dataTableOutput("ResDf2"),
),
),
# Panel 3
tabPanel("Summary",
# Panel 3 inputs
fluidPage(
fluidRow(
# Obtain summary
actionButton(inputId = "InSum",
label = "Preview"),
# Histogram of all samples
verbatimTextOutput("Warn4"),
verbatimTextOutput("Warn5"),
plotOutput("HisPlotAll"),
),
HTML("</br>"),
fluidRow(
# Display plot parameters
uiOutput("UiPlotParam"),
# Download plot
downloadButton("downloadPlot", "Save Plot"),
),
HTML("</br>"),
fluidRow(
# Table results 3
DT::dataTableOutput("ResDf3"),
# Download data
downloadButton("DownloadData", "Save Table"),
),
)
),
# Panel 4
tabPanel("Help",
uiOutput('textWithHTML')
)
)
)
# ------------------------------------------------------------------------------------------------------------------- #
# Define server function
server <- function(input, output, session) {
# Session
session$onSessionEnded(function() {
stopApp()
})
# Inputs calculated in server
# Panel 1 inputs
# Input files
output$UiFileUp <- renderUI({
fileInput(inputId = "InFiles",
label = "Upload multiple FCS files",
multiple = TRUE,
accept = c(".FCS", ".fcs"))
})
# Run example
output$UiExample <- renderUI({
actionButton(inputId = "LoadEx",
label = "Example")
})
# Select channel
output$UiChannelSel <- renderUI({
selectInput(inputId = "InChan",
label = "Select a channel",
choices = ifelse(is.na(input$InFiles), "", names(InitDf()$Files[[1]])),
selected = ifelse(is.na(input$InFiles), "", names(InitDf()$Files[[1]])[1]))
})
# Select sample
output$UiSampleSel <- renderUI({
selectInput(inputId = "InSample",
label = "Select a sample",
choices = ifelse(is.na(input$InFiles), "", names(InitDf()$Files)))
})
# Adjust smoothing
output$UiSmoothNum <- renderUI({
numericInput(inputId = "InSmooth",
label = "Adjust smoothing",
value = 0.1,
min = 0.02,
max = 1,
step = 0.02)
})
# Adjust window
output$UiWindowNum <- renderUI({
numericInput(inputId = "InWindow",
label = "Adjust window width",
value = 50,
min = 0,
max = 1000,
step = 5)
})
# Select maximum number of peaks
output$UiPeaksNum <- renderUI({
numericInput(inputId = "InMaxPeaks",
label = "Select maximun number of peaks to plot",
value = 3,
min = 1,
step = 1)
})
# Select minimun number of events
output$UiEveMin <- renderUI({
numericInput(inputId = "InMinEve",
label = "Select minimun cell count to call a peak",
value = 5,
min = 0.5,
step = 0.5)
})
# Update UI when when files are uploaded
observeEvent(trigger(), {
req(InitDf())
# Display sample names
output$UiSampleSel <- renderUI({
selectInput(inputId = "InSample",
label = "Select a sample",
choices = names(InitDf()$Files))
})
# Display channel names
output$UiChannelSel <- renderUI({
selectInput(inputId = "InChan",
label = "Select a channel",
choices = names(InitDf()$Files[[1]]),
selected = names(InitDf()$Files[[1]])[ifelse(trigger() == "example", 20, 1)])
})
})
# Update UI peaks when new channel is selected
observeEvent(input$InChan, {
output$UiPeaksBox <- renderUI({
checkboxGroupInput(inputId = "InPeaksPlot",
label = "Select G1 and G2 peaks",
choices = PlotPoints()$MaxIndex,
selected = c(PlotPoints()$MaxIndex[1], PlotPoints()$MaxIndex[2]))
})
})
# Display the last used parameters when changing sample
# Last used channel
observeEvent(input$InSample, {
req(InitDf())
SampNum <- grep(input$InSample, names(InitDf()$Files))
output$UiChannelSel <- renderUI({
selectInput(inputId = "InChan",
label = "Select a channel",
choices = names(InitDf()$Files[[1]]),
selected = Df$DataPeaks$Channel[SampNum])
})
})
# Last used smoothing
observeEvent(input$InSample, {
req(InitDf())
SampNum <- grep(input$InSample, names(InitDf()$Files))
output$UiSmoothNum <- renderUI({
numericInput(inputId = "InSmooth",
label = "Adjust smoothing",
value = Df$DataPeaks$Smoothing[SampNum],
min = 0.02,
max = 1,
step = 0.02)
})
})
# Last used window
observeEvent(input$InSample, {
req(InitDf())
SampNum <- grep(input$InSample, names(InitDf()$Files))
output$UiWindowNum <- renderUI({
numericInput(inputId = "InWindow",
label = "Adjust window",
value = Df$DataPeaks$Window[SampNum],
min = 0,
max = 1000,
step = 5)
})
})
# Last selected peaks
observeEvent(input$InSample, {
req(InitDf())
SampNum <- grep(input$InSample, names(InitDf()$Files))
LabNum <- match(Df$DataPeaks[SampNum, c(5,6)], PlotPoints()$MaxIndex)
output$UiPeaksBox <- renderUI({
checkboxGroupInput(inputId = "InPeaksPlot",
label = "Select G1 and G2 peaks",
choices = PlotPoints()$MaxIndex,
selected = PlotPoints()$MaxIndex[LabNum])
})
})
# Panel 2 inputs
# Select number of standards
output$UiCtrlsNum <- renderUI({
numericInput(inputId = "InNumCtrl",
label = "Select number of standards",
value = ifelse(length(InitDf()) < 4, length(InitDf()), 4),
min = 1,
step = 1)
})
# Create ploidy or genome size type of analysis
observeEvent(trigger(), {
output$UiType <- renderUI({
req(input$InNumCtrl)
radioButtons(inputId = "InType",
label = "Select type of analysis",
choices = c("Ploidy", "Genome size"),
selected = "Ploidy",
inline = TRUE)
})
})
# Create select standards
observeEvent(trigger(), {
output$UiCtrlsSampleSel <- renderUI({
req(input$InNumCtrl)
StandardList <- paste("Standard", 1:input$InNumCtrl)
Ls <- list()
for (i in 1:length(StandardList)){
Ls[[i]] <- selectInput(inputId = paste0("InCtrlSample", i),
label = StandardList[i],
choices = c("", names(InitDf()$Files)),
selected = "")
}
Ls
})
})
# Create standards ploidy
observeEvent(trigger(), {
output$UiCtrlsPloNum <- renderUI({
req(input$InNumCtrl)
PloidyList <- paste(input$InType, 1:input$InNumCtrl)
Ls <- list()
for (i in 1:length(PloidyList)){
Ls[[i]] <- numericInput(inputId = paste0("InCtrlPlo", i),
label = PloidyList[i],
value = i,
min = 1,
step = 1)
}
Ls
})
})
# Panel 3 inputs
# Render compilation of all histograms
output$HisPlotAll <- renderPlot({
req(Df$Res)
# Compile and arrange plots
grid.arrange(grobs = AllPl(), ncol = input$InGrid)
})
# Create selection inputs for plot saving
output$UiPlotParam <- renderUI({
PlotParamType <- c("Sel", "Sel", "Num", "Num", "Num", "Num")
PlotParamList <- c("Device", "Units", "Grid", "Width", "Height", "Dpi")
PlotParamChoi <- list(c("tiff", "png"), c("in", "cm", "mm", "px"), NA, NA, NA, NA)
PlotParamVal <- c(NA, NA, 4, 300, 200, 300)
PlotParamStep <- c(NA, NA, 1, 50, 50, 50)
PlotParamSel <- c("tiff", "mm")
Ls <- list()
for (i in 1:length(PlotParamList)){
if (PlotParamType[i] == "Sel"){
Ls[[i]] <- div(
selectInput(inputId = paste0("In", PlotParamList[i]),
label = PlotParamList[i],
choices = PlotParamChoi[[i]],
selected = PlotParamSel[i]),
style = "display: inline-block;vertical-align:top; width: 150px;",
)
} else {
Ls[[i]] <- div(
numericInput(inputId = paste0("In", PlotParamList[i]),
label = PlotParamList[i],
value = PlotParamVal[i],
step = PlotParamStep[i]),
style = "display: inline-block;vertical-align:top; width: 150px;",
)
}
}
Ls
})
# Download figure
output$downloadPlot <- downloadHandler(
filename <- function() {
paste("all_histograms", input$InDevice, sep = ".")
},
content <- function(file) {
ggsave(file, plot = grid.arrange(grobs = AllPl(), ncol = input$InGrid), device = input$InDevice, width = input$InWidth, units = input$InUnits, height = input$InHeight, dpi = input$InDpi)
}
)
# Download data
output$DownloadData <- downloadHandler(
filename <- function() {
"peaks.csv"
},
content <- function(file) {
write.csv(Df$Sum, file, row.names = FALSE)
}
)
# Define specific functions for peaks calculation
# Peak calculations
GetInit <- function(AllFiles, AllNames){
# Code used to evaluate run time (START)
timing_result <- system.time({
FilesLs <- list()
Channels <- NULL
Smoothings <- NULL
Windows <- NULL
LineLs <- list()
PointLs <- list()
G1s <- NULL
G2s <- NULL
Names <- NULL
# Read FCS files and calculate initial information
for(i in 1:length(AllFiles)){
FilesLs[[i]] <- read.FCS(AllFiles[i], emptyValue = FALSE, alter.names = TRUE)
Name <- sub(" .*", "", sub(".FCS", "", sub(".fcs", "", AllNames[i])))
Names <- c(Names, Name)
Channels[i] <- names(FilesLs[[i]])[1]
Smoothings[i] <- 0.1
Windows[i] <- 50
LineLs[[i]] <- GetLine(File = FilesLs[[i]], ChanNum = 1, Span = 0.1)
PointLs[[i]] <- GetPoints(PlotLine = LineLs[[i]], Width = 50)
G1s[i] <- PointLs[[i]]$MaxIndex[1]
G2s[i] <- PointLs[[i]]$MaxIndex[2]
}
names(FilesLs) <- Names
})
# Code used to evaluate run time (END)
print("Upload time")
print(timing_result)
# Return a list with the information
list(Files = FilesLs, Channels = Channels, Smoothings = Smoothings, Windows = Windows, G1s = G1s, G2s = G2s)
}
# Lines
GetLine <- function(File, ChanNum, Span){
# Extract and filter expressions
Exp <- exprs(File[, ChanNum])
# Estimate the maximum number of bins from the data, and exclude negative values
MaxBreaks <- length(seq(0, range(File)[,ChanNum][2]))
# Assumes that lowest possible binning is 256, which allows to exclude low range channels
MaxBreaks <- ifelse(MaxBreaks < 256, 256, MaxBreaks)
# Filter low and high values to fit bins in histogram
Exp <- Exp[Exp >= 1]
Exp <- Exp[Exp <= MaxBreaks]
# Add pseudo count to superior and inferior limit to anchor histogram
Exp <- c(1, Exp, MaxBreaks)
# Calculate histogram
Hist <- hist(Exp, breaks = 1000, plot = FALSE)
# Counts is the y histogram variable
Counts <- Hist$counts
# Index is the x histogram variable
Index <- 1:length(Counts)
# Fit a line to the data
Fit <- loess(Counts ~ Index, span = Span)
# FitLine is the smoothed line
FitLine <- predict(Fit)
# Create plotting data frame
data.frame(Fluorescence = Index, Count = FitLine)
}
# Points
GetPoints <- function(PlotLine, Width){
# The window to calculate the maximum
Window <- 2 * Width + 1
# Do a sliding window of 2 * Width + 1, and step of 1, and calculate the maximum value of a given window
FlatLine <- rollapply(data = zoo(PlotLine$Count), width = Window, FUN = max, align = "center")
# Calculate the difference between flattened and fitted lines
Delta <- FlatLine - PlotLine$Count[-c(1:Width, length(PlotLine$Fluorescence) + 1 - 1:Width)]
# Obtain the indices in which the difference equals to zero, and adjust to the width because of the sliding window step
MaxIndex <- which(Delta <= 0) + Width
# Obtain intensity of the points (y axis)
Intensity <- PlotLine$Count[MaxIndex]
# Remove peaks with number of events lower than specified by user
MaxIndex <- MaxIndex[Intensity > input$InMinEve]
Intensity <- Intensity[Intensity > input$InMinEve]
# Create points data frame
data.frame(MaxIndex = MaxIndex, Intensity = Intensity)
}
# Get initial files and information
trigger <- reactiveVal(NULL)
observeEvent(input$InFiles, {
# Set trigger to "upload"
trigger("upload")
})
observeEvent(input$LoadEx, {
# Set trigger to "example", only if internet collection available
if(curl::has_internet()){
trigger("example")
}
})
InitDf <- eventReactive(trigger(), {
if (trigger() == "upload") {
req(input$InFiles)
file_list <- input$InFiles$datapath
file_name <- input$InFiles$name
} else if (trigger() == "example") {
# Define example data directory
ExDir <- tempdir()
# Download example data function
download_example_data(ExDir)
# List downloaded files
example_files <- list.files(ExDir, full.names = TRUE, pattern = "\\.fcs$")
new_files <- list(
datapath = example_files,
name = basename(example_files),
size = file.info(example_files)$size,
type = rep("fcs", length(example_files)))
file_list <- new_files$datapath
file_name <- new_files$name
}
GetInit(file_list, file_name)
})
# Create reactive values to modify initially calculated data (It had to be created as reactive value to be modified via proxy)
Df <- reactiveValues(DataPeaks = NULL)
# Copy information form initial data frame
observeEvent(trigger(), {
req(InitDf())
Df$DataPeaks <- data.frame(Sample = names(InitDf()$Files),
Channel = InitDf()$Channels,
Smoothing = InitDf()$Smoothings,
Window = InitDf()$Windows,
G1 = InitDf()$G1s,
G2 = InitDf()$G2s)
output$ResDf1 <- DT::renderDataTable(isolate(Df$DataPeaks),
editable = FALSE)
})
# Create plot line
PlotLine <- eventReactive(c(input$InSample, input$InSmooth, input$InWindow, input$InChan), {
req(InitDf())
# Get sample name
SampNum <- grep(input$InSample, names(InitDf()$Files))
# Get file information
File <- InitDf()$Files[[SampNum]]
# Get channels information
ChanNum <- grep(input$InChan, names(File))
# Return Line
GetLine(File = File, ChanNum = ChanNum, Span = Df$DataPeaks[SampNum, 3])
})
# Create plot points
PlotPoints <- eventReactive(c(input$InSample, input$InSmooth, input$InWindow, input$InChan, input$InMaxPeaks, input$InMinEve), {
req(InitDf())
# Get sample name
SampNum <- grep(input$InSample, names(InitDf()$Files))
# Get width
Width <- Df$DataPeaks[SampNum, 4]
# Return points
GetPoints(Width = Width, PlotLine = PlotLine())
})
# Warning to incorrect execution of regression
WarnHis1 <- reactive({
validate(
need(trigger() != "", "Please upload files to obtain histograms."),
)
})
WarnHis2 <- eventReactive(input$LoadEx, {
validate(
need(curl::has_internet(), "Running the example files requires internet connection."),
)
})
output$Warn1 <- renderPrint({
WarnHis1()
})
output$Warn6 <- renderPrint({
WarnHis2()
})
# Plot data
output$HisPlot <- renderPlot({
req(InitDf())
req(input$InSample)
req(PlotLine())
req(input$InMaxPeaks)
req(input$InMinEve)
SampNum <- grep(input$InSample, names(InitDf()$Files))
# Get name for plotting and table
Name <- names(InitDf()$Files)[SampNum]
# Number of labels
LabNum <- match(input$InPeaksPlot, PlotPoints()$MaxIndex)
# Labels
Labs <- paste0("G", 1:length(PlotPoints()$MaxIndex))
# Plot histogram with points
ggplot(PlotLine(), aes(x = Fluorescence, y = Count)) +
geom_line() +
annotate("point", x = PlotPoints()$MaxIndex[1:input$InMaxPeaks],
y = PlotPoints()$Intensity[1:input$InMaxPeaks],
col = "red") +
annotate("text", x = PlotPoints()$MaxIndex[LabNum],
y = PlotPoints()$Intensity[LabNum] + 10,
col = "black",
label = Labs[1:length(LabNum)]) +
labs(title = Name) +
theme(plot.title = element_text(hjust = 0.5)) +
ylab("Cell count") +
xlim(0, 1000)
})
# Proxys for data replacement
# Channel
observeEvent(input$InChan, {
req(InitDf())
SampNum <- grep(input$InSample, names(InitDf()$Files))
# Update channel for all samples
Df$DataPeaks[, 2] <- input$InChan
# Recalculate peaks for all samples
for (i in 1:length(InitDf()$Files)){
# Get file information
File <- InitDf()$Files[[i]]
# Get channels information
ChanNum <- grep(input$InChan, names(File))
# Return Line working data frame
LineWkDf <- GetLine(File = File, ChanNum = ChanNum, Span = Df$DataPeaks[i, 3])
# Get width
Width <- Df$DataPeaks[i, 4]
# Return points
PointsWkDf <- GetPoints(Width = Width, PlotLine = LineWkDf)
# Update peaks
Df$DataPeaks[i, 5] <- PointsWkDf$MaxIndex[1]
Df$DataPeaks[i, 6] <- PointsWkDf$MaxIndex[2]
}
# Replace data
Proxy <- DT::dataTableProxy('ResDf1')
DT::replaceData(Proxy, Df$DataPeaks)
})
# Smoothing
observeEvent(input$InSmooth, {
SampNum <- grep(input$InSample, names(InitDf()$Files))
# Update smooth
Df$DataPeaks[SampNum, 3] <- input$InSmooth
# Replace data
Proxy <- DT::dataTableProxy('ResDf1')
DT::replaceData(Proxy, Df$DataPeaks)
})
# Window
observeEvent(input$InWindow, {
SampNum <- grep(input$InSample, names(InitDf()$Files))
# Update window
Df$DataPeaks[SampNum, 4] <- input$InWindow
# Replace data
Proxy <- DT::dataTableProxy('ResDf1')
DT::replaceData(Proxy, Df$DataPeaks)
})
# Peaks
observeEvent(input$InPeaksPlot, {
SampNum <- grep(input$InSample, names(InitDf()$Files))
# Update G1 and G2 peaks
Df$DataPeaks[SampNum, 5] <- input$InPeaksPlot[1]
Df$DataPeaks[SampNum, 6] <- input$InPeaksPlot[2]
# Replace data
Proxy <- DT::dataTableProxy('ResDf1')
DT::replaceData(Proxy, Df$DataPeaks)
})
# Regression calculations
# Warning to incorrect execution of regression
WarnReg2 <- reactive({
validate(
need(trigger() != "", "Please upload files to perform regression."),
need(input$InCtrlSample2 != "", "Please provide at least two standards to perform regression."),
)
})
output$Warn2 <- renderPrint({
WarnReg2()
})
WarnReg3 <- eventReactive(input$InReg, {
validate(
need(input$InCtrlSample2 != "", "Please provide at least two standards to perform regression."),
need(length(input$InPeaksPlot) != 0, "No peaks detected."),
)
})
output$Warn3 <- renderPrint({
WarnReg3()
})
# Create linear regression model
observeEvent(input$InReg, {
# Code used to evaluate run time (START)
timing_result <- system.time({
req(input$InCtrlSample2)
req(input$InPeaksPlot)
# Select required information from DataPeaks
Df$DataReg <- Df$DataPeaks[,c(1,5,6)]
# Combine G1 and G2 fluorescent intensity
Df$DataReg <- gather(data = Df$DataReg,
key = "Phase",
value = "Intensity",
-Sample)
# Convert intensity to numeric
Df$DataReg$Intensity <- as.numeric(Df$DataReg$Intensity)
# Order alphabetically
Df$DataReg <- Df$DataReg[order(Df$DataReg$Sample),]
# Initialize variable
Pattern <- NULL
# Create control sample strings to evaluate
CtrlSamples <- paste0("input$InCtrlSample", 1:input$InNumCtrl)
# Loop over strings
for (Sample in CtrlSamples){
# Evaluate each string to obtain the input stored value
Pattern <- c(Pattern, eval(parse(text = Sample)))
}
# Create pattern to search samples
PatternSearch <- paste(Pattern, collapse = "|")
# Separate standards and test data frames
Df$Ctrls <- Df$DataReg[grep(PatternSearch, Df$DataReg$Sample),]
Df$Tests <- Df$DataReg[-grep(PatternSearch, Df$DataReg$Sample),]
# Add test and control type information
Df$Ctrls$Type <- "Standard"
# To control in case no standards are selected
if (nrow(Df$Tests) > 0){
Df$Tests$Type <- "Test"
}
# Create control ploidy strings to evaluate
CtrlPloidies <- paste0("input$InCtrlPlo", 1:input$InNumCtrl)
# Initialize variable
AllPloidies <- NULL
# Loop over strings
for (Ploidy in CtrlPloidies){
# Evaluate each string to obtain the input stored value
AllPloidies <- c(AllPloidies, eval(parse(text = Ploidy)))
}
# Change order of all ploidies to match the one in the data frame
AllPloidies <- AllPloidies[match(unique(Df$Ctrls$Sample), Pattern)]
# Multiply ploidy for G2 peaks
AllPloidies <- rep(AllPloidies, each = 2) * 1:2
# Add ploidy
Df$Ctrls$Ploidy <- AllPloidies
# Linear model
Mod <- lm(Ploidy ~ Intensity, data = Df$Ctrls)
# Extract adjusted R squared
Rsquared <- substr(as.character(summary(Mod)$adj.r.squared), 0, 5)
# Extract p value
Pval <- pf(summary(Mod)$fstatistic[1], summary(Mod)$fstatistic[2], summary(Mod)$fstatistic[3], lower.tail = FALSE)
Pval <- formatC(Pval, format = "e", digits = 2)
# Print summary
output$RegText <- renderPrint({
print(summary(Mod))
})
# Perform prediction
Df$Tests$Ploidy <- predict(Mod, Df$Tests) %>% round(2)
# Combine results
Df$Res <- rbind(Df$Ctrls, Df$Tests)
# Before rendering data frame, change row names and column order
rownames(Df$Res) <- 1:nrow(Df$Res)
Df$Res <- Df$Res[,c(1, 4, 2, 3, 5)]
Df$ResPrelim <- Df$Res
# Add size to ploidy column name
colnames(Df$ResPrelim)[5] <- input$InType
# Final output data frame
output$ResDf2 <- DT::renderDataTable(isolate(Df$ResPrelim),
editable = FALSE)
# Get Rsquared coordinates to plot
RsquaredXcoord <- Df$Res$Intensity
RsquaredXcoord <- RsquaredXcoord[!is.na(RsquaredXcoord)]
RsquaredXcoord <- min(RsquaredXcoord)
RsquaredYcoord <- Df$Res$Ploidy
RsquaredYcoord <- RsquaredYcoord[!is.na(RsquaredYcoord)]
RsquaredYcoord <- max(RsquaredYcoord)
# Plot regression
output$RegPlot <- renderPlot({
ggplot(data = Df$Res, mapping = aes(Intensity, Ploidy)) +
geom_point(color = "red") +
geom_smooth(method = "lm", se = FALSE, linetype = "dashed", color = "black") +
geom_text_repel(label = paste(Df$Res$Sample, Df$Res$Phase)) +
annotate("text", x = RsquaredXcoord + 50, y = RsquaredYcoord - 1, label = paste0("R\u00B2 = ", Rsquared, "\np = ", Pval), size = 5, parse = FALSE) +
labs(y = input$InType)
})
})
# Code used to evaluate run time (END)
print("Regression time")
print(timing_result)
})
# Warning to incorrect execution of summary
WarnSum4 <- reactive({
validate(
need(trigger() != "", "Please perform regression first."),
)
})
output$Warn4 <- renderPrint({
WarnSum4()
})
WarnSum5 <- eventReactive(input$InSum, {
validate(
need(Df$Res != "", "No regression found.")
)
})
output$Warn5 <- renderPrint({
WarnSum5()
})
# Summary
observeEvent(input$InSum, {
# Code used to evaluate run time (START)
timing_result <- system.time({
req(InitDf())
req(Df$Res)
# Copy regression results data frame
Df$Sum <-Df$Res
# Remove intensity to compare ploidies of different phases
Df$Sum <- Df$Sum[,-4]
# Spread data
Df$Sum <- spread(Df$Sum,
key = "Phase",
value = "Ploidy")
# Divide G2 by 2
Df$Sum$G2 <- round(Df$Sum$G2 / 2, 2)
# Obtain mean of G1 and G2
Df$Sum <- dplyr::mutate(Df$Sum, Mean = round(rowMeans(select(Df$Sum, G1, G2), na.rm = TRUE), 2))
# Obtain rounded ploidy
Df$Sum$Rounded <- round(Df$Sum$Mean, 0)
# Rename phase G1 and G2 in the second data frame
colnames(Df$Sum)[3] <- paste(input$InType, "G1")
colnames(Df$Sum)[4] <- paste(input$InType, "G2")
# Combine with histograms panel data frame
Df$Sum <- left_join(Df$DataPeaks, Df$Sum)
# Convert intensity to numeric
Df$Sum$G1 <- as.numeric(Df$Sum$G1)
Df$Sum$G2 <- as.numeric(Df$Sum$G2)
# Rename phase G1 and G2 in the summary data frame
colnames(Df$Sum)[5] <- "Intensity G1"
colnames(Df$Sum)[6] <- "Intensity G2"
colnames(Df$Sum)[10] <- paste(input$InType, "mean")
colnames(Df$Sum)[11] <- paste(input$InType, "rounded")
# Rearrange data frame order and remove ploidy inferred from G1 and G2 peaks (columns 8 and 9)
Df$Sum <- Df$Sum[,c(1,7,2:6,10,11)]
# Final output data frame
output$ResDf3 <- DT::renderDataTable(isolate(Df$Sum),
editable = FALSE)
})
# Code used to evaluate run time (END)
print("Peaks calculation time")
print(timing_result)
})
# Plot all histograms
AllPl <- eventReactive(input$InSum, {
# Code used to evaluate run time (START)
timing_result <- system.time({
# Create empty list to store plots
PlotLs <- list()
# Loop over the samples and create lines
for (i in 1:length(InitDf()$Files)){
# Create plot line
# Get file information
File <- InitDf()$Files[[i]]
# Get channels information
ChanNum <- grep(input$InChan, names(File))
# Return Line working data frame
LineWkDf <- GetLine(File = File, ChanNum = ChanNum, Span = Df$DataPeaks[i, 3])
# Create plot points
# Get width
Width <- Df$DataPeaks[i, 4]
# Return points
PointsWkDf <- GetPoints(Width = Width, PlotLine = LineWkDf)
# Get name for plotting and table
Name <- names(InitDf()$Files)[i]
# Number of labels but only the peaks selected in Panel 1
LabNum <- match(Df$DataPeaks[i, c(5,6)], PointsWkDf$MaxIndex)
# Labels
Labs <- paste0("G", 1:length(PointsWkDf$MaxIndex))
# Plot histogram with points
Pl <- ggplot(LineWkDf, aes(x = Fluorescence, y = Count)) +
geom_line() +
annotate("point", x = PointsWkDf$MaxIndex[LabNum],
y = PointsWkDf$Intensity[LabNum],
col = "red") +
annotate("text", x = PointsWkDf$MaxIndex[LabNum],
y = PointsWkDf$Intensity[LabNum] + 10,
col = "black",
label = Labs[1:length(LabNum)]) +
labs(title = Name) +
theme(plot.title = element_text(hjust = 0.5)) +
ylab("Cell count") +
xlim(0, 1000)
# Save plot in list
PlotLs[[i]] <- Pl
}
})
# Code used to evaluate run time (END)
print("Plots generation time")
print(timing_result)
# Return list of plots
PlotLs
})
# Panel 4 help
output$textWithHTML <- renderUI({
HTML(markdown::markdownToHTML('help/help.md', template = FALSE))
})
}
# Create Shiny object
shinyApp(ui = ui, server = server)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.