diff --git a/DESCRIPTION b/DESCRIPTION index a526973..ee088e0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,10 +1,10 @@ Package: premessa Type: Package Title: R package for pre-processing of flow and mass cytometry data -Version: 0.2.6 -Author: "Pier Federico Gherardini [aut, cre]" +Version: 0.3.0 +Author: "Pier Federico Gherardini [aut, cre]" Description: This package includes panel editing/renaming for FCS files, bead-based normalization and debarcoding. -Imports: shiny (>= 0.14), flowCore, reshape, ggplot2, hexbin, gridExtra, rhandsontable, jsonlite +Imports: shiny (>= 0.14), flowCore, reshape, ggplot2, hexbin, gridExtra, rhandsontable, jsonlite, data.table, shinyjqui License: GPL v3 LazyData: TRUE -RoxygenNote: 6.1.0 +RoxygenNote: 7.1.1 diff --git a/NAMESPACE b/NAMESPACE index f491181..b3b599b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -23,3 +23,4 @@ export(rename_fcs_parameters_desc) export(rename_fcs_parameters_name) export(rename_parameters_in_files) export(write_flowFrame) +import(data.table) diff --git a/R/debarcode_cytof.R b/R/debarcode_cytof.R index 6ac6d43..dc1e163 100644 --- a/R/debarcode_cytof.R +++ b/R/debarcode_cytof.R @@ -26,12 +26,12 @@ get_barcode_channels_names <- function(m, bc.key) { sort_rows <- function(m) { - x <- data.table::as.data.table(m) + x <- as.data.table(m) x$row.id <- 1:nrow(x) x <- dcast(melt(setDT(x), id.var='row.id')[order(-value), .SD, row.id][, N:=1:.N , .(row.id)], - row.id~N, value.var=c("value")) + row.id~N, value.var = c("value")) x$row.id <- NULL return(as.matrix(x)) @@ -58,7 +58,8 @@ sort_rows <- function(m) { #' @param expected.positive A single number. The expected number of positive barcode channels for each event calculate_bcs_separation <- function(m, bc.channels, expected.positive, cutoff) { m.bcs <- m[, bc.channels] - m.bcs <- t(apply(m.bcs, 1, sort, decreasing = T)) + #m.bcs <- t(apply(m.bcs, 1, sort, decreasing = T)) + m.bcs <- sort_rows(m.bcs) deltas <- m.bcs[, expected.positive] - m.bcs[, expected.positive + 1] lowest.bc <- m.bcs[, expected.positive] @@ -255,7 +256,8 @@ debarcode_data_matrix <- function(m, bc.channels, bc.key) { #' #' @param m The data matrix #' @param bc.key The barcode key, as returned by \code{read_barcode_key} -#' +#' @param downsample.to Optional. If provided the data will be downsampled to the +#' specified number of events before debarcoding #' @return Returns a list with the following components #' \itemize{ #' \item{\code{m.normed}}{ matrix with \code{nrow(m)} rows. The normalized barcode intensities} @@ -266,7 +268,11 @@ debarcode_data_matrix <- function(m, bc.channels, bc.key) { #' } #' #' @export -debarcode_data <- function(m, bc.key) { +debarcode_data <- function(m, bc.key, downsample.to = NULL) { + if(!is.null(downsample.to) && nrow(m) > downsample.to) { + message(sprintf("Downsampling data to %d", downsample.to)) + m <- m[sample(1:nrow(m), downsample.to), ] + } barcode.channels <- get_barcode_channels_names(m, bc.key) diff --git a/R/debarcoder_plotting.R b/R/debarcoder_plotting.R index 8aba42c..acc2b2a 100644 --- a/R/debarcoder_plotting.R +++ b/R/debarcoder_plotting.R @@ -90,6 +90,7 @@ plot_barcode_yields <- function(bc.results, sep.threshold, mahal.threshold = NUL + ggplot2::scale_y_continuous("Cell count") + ggplot2::scale_x_discrete("Sample") + ggplot2::labs(title = title.string) + #+ ggplot2::theme(axis.text.y = ggplot2::element_blank()) ) return(p) diff --git a/R/package.R b/R/package.R index a460064..7974e54 100644 --- a/R/package.R +++ b/R/package.R @@ -6,4 +6,6 @@ #' #' @docType package #' @name premessa +#' +#' @import data.table NULL diff --git a/README.md b/README.md index f690028..52aed4e 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,12 @@ Copyright 2016. Parker Institute for Cancer Immunotherapy -**Please contact us with bugs/feature requests** - **---> Make sure to have a backup copy of your data before you use the software! <---** +**New in version 0.3.0**: +- Added UI for file concatenation under the normalizer GUI +- Much faster debarcoding. Note that for the purpose of debarcoder plotting, data will now be downsampled to 100000 events. This means that absolute cell numbers in the plots will not reflect the absolute cell numbers in the final data (but the ratios and trends will be correct). The final debarcoded data will always include **all** events + # Installation diff --git a/inst/debarcoder_shinyGUI/server.R b/inst/debarcoder_shinyGUI/server.R index 433f25c..671bad5 100644 --- a/inst/debarcoder_shinyGUI/server.R +++ b/inst/debarcoder_shinyGUI/server.R @@ -78,6 +78,11 @@ shinyServer(function(input, output, session) { ret <- NULL if(!is.null(fcs)) { m <- flowCore::exprs(fcs) + downsample.to <- 100000 + if(nrow(m) > downsample.to) { + message(sprintf("Downsampling data to %d", downsample.to)) + m <- m[sample(1:nrow(m), downsample.to), ] + } ret <- asinh(m / 10) } diff --git a/inst/normalizer_shinyGUI/server.R b/inst/normalizer_shinyGUI/server.R index 9bebfee..c883f95 100644 --- a/inst/normalizer_shinyGUI/server.R +++ b/inst/normalizer_shinyGUI/server.R @@ -2,8 +2,26 @@ gatePlot <- function (outputId) { HTML(paste("
", sep="")) } +render_concatenate_ui <- function(working.directory, ...) {renderUI({ + fluidPage( + fluidRow( + column(12, + #selectizeInput("concatenateui_selected_files", multiple = T, width = "100%", choices = c()), + shinyjqui::orderInput("concatenateui_available_files", "Available files", connect = "concatenateui_files_order", + items = list.files(working.directory, pattern = "*.fcs$", ignore.case = TRUE), width = "100%"), + shinyjqui::orderInput("concatenateui_files_order", "File order", placeholder = "Drag files here", + items = NULL, connect = "concatenateui_available_files", width = "100%"), + actionButton("concatenateui_concatenate_files", "Concatenate files") + + ) + ) + ) + + +})} + render_beadremoval_ui <- function(working.directory, ...) {renderUI({ fluidPage( @@ -26,7 +44,6 @@ render_beadremoval_ui <- function(working.directory, ...) {renderUI({ render_normalizer_ui <- function(working.directory, ...){renderUI({ - #Remove this fluidpage? fluidPage( fluidRow( column(12, @@ -82,11 +99,35 @@ shinyServer(function(input, output, session) { beads.removed.dir <- file.path(normed.dir, "beads_removed") beadremovalui.plots.number <- 3 + output$concatenateUI <- render_concatenate_ui(working.directory) output$normalizerUI <- render_normalizer_ui(working.directory, input, output, session) output$normalizerUI_plot_outputs <- generate_normalizerui_plot_outputs(5) output$beadremovalUI <- render_beadremoval_ui(working.directory, input, output, session) output$beadremovalUI_plot_outputs <- generate_beadremovalui_plot_outputs(beadremovalui.plots.number) + #concatenateUI functions + + observe({ + if(!is.null(input$concatenateui_concatenate_files) && input$concatenateui_concatenate_files != 0) { + input.files <- file.path(working.directory, input$concatenateui_files_order) + out.file <- file.path(working.directory, gsub(".fcs$", "_concat.fcs", input$concatenateui_files_order[[1]], ignore.case = TRUE)) + showModal(modalDialog( + title = "Normalizer report", + "File concatenation started, please wait..." + )) + premessa::concatenate_fcs_files(input.files, out.file) + showModal(modalDialog( + title = "Normalizer report", + p("Files concatenated in this order:", br(), + lapply(input$concatenateui_files_order, function(x) list(x, br())), + br(), "Outuput file: ", basename(out.file) + ) + )) + updateSelectizeInput(session, "normalizerui_selected_fcs", + choices = c("", list.files(working.directory, pattern = "*.fcs$", ignore.case = T))) + } + }) + #beadremovalUI functions get_beadremovalui_fcs <- reactive({ diff --git a/inst/normalizer_shinyGUI/ui.R b/inst/normalizer_shinyGUI/ui.R index 7f047c4..b81f294 100644 --- a/inst/normalizer_shinyGUI/ui.R +++ b/inst/normalizer_shinyGUI/ui.R @@ -1,5 +1,11 @@ shinyUI( navbarPage("premessa", + tabPanel("Concatenate files", + fluidPage( + fluidRow( + uiOutput("concatenateUI") + ) + )), tabPanel("Normalize data", tags$head(tags$script(src = "gate-plot.js")), tags$head(tags$script(src = "d3.min.js")), diff --git a/man/calculate_baseline.Rd b/man/calculate_baseline.Rd index 8596c37..43e7871 100644 --- a/man/calculate_baseline.Rd +++ b/man/calculate_baseline.Rd @@ -4,8 +4,12 @@ \alias{calculate_baseline} \title{Calculate baseline for normalization} \usage{ -calculate_baseline(wd, beads.type, files.type = c("data", "beads"), - beads.gates = NULL) +calculate_baseline( + wd, + beads.type, + files.type = c("data", "beads"), + beads.gates = NULL +) } \arguments{ \item{wd}{Working directory (character)} diff --git a/man/correct_data_channels.Rd b/man/correct_data_channels.Rd index 8aef354..72092f0 100644 --- a/man/correct_data_channels.Rd +++ b/man/correct_data_channels.Rd @@ -4,8 +4,13 @@ \alias{correct_data_channels} \title{Normalize data} \usage{ -correct_data_channels(m, beads.data, baseline, beads.col.names, - time.col.name = "Time") +correct_data_channels( + m, + beads.data, + baseline, + beads.col.names, + time.col.name = "Time" +) } \arguments{ \item{m}{The data matrix} diff --git a/man/debarcode_data.Rd b/man/debarcode_data.Rd index 0388db8..ddd2cc9 100644 --- a/man/debarcode_data.Rd +++ b/man/debarcode_data.Rd @@ -4,7 +4,7 @@ \alias{debarcode_data} \title{Debarcodes data by doing normalization after preliminary barcode assignemnts} \usage{ -debarcode_data(m, bc.key) +debarcode_data(m, bc.key, downsample.to = NULL) } \arguments{ \item{m}{The data matrix} diff --git a/man/debarcode_fcs.Rd b/man/debarcode_fcs.Rd index 57247aa..0354410 100644 --- a/man/debarcode_fcs.Rd +++ b/man/debarcode_fcs.Rd @@ -4,8 +4,14 @@ \alias{debarcode_fcs} \title{Main wrapper for the debarcoder pipeline.} \usage{ -debarcode_fcs(fcs, bc.key, output.dir, output.basename, sep.threshold, - mahal.dist.threshold = 30) +debarcode_fcs( + fcs, + bc.key, + output.dir, + output.basename, + sep.threshold, + mahal.dist.threshold = 30 +) } \arguments{ \item{fcs}{The input \code{flowFrame}} diff --git a/man/get_assignments_at_threshold.Rd b/man/get_assignments_at_threshold.Rd index 098cb48..8653fc5 100644 --- a/man/get_assignments_at_threshold.Rd +++ b/man/get_assignments_at_threshold.Rd @@ -4,8 +4,12 @@ \alias{get_assignments_at_threshold} \title{Assign events to a specific sample} \usage{ -get_assignments_at_threshold(bc.results, sep.threshold, - mahal.threshold = NULL, mahal.dist = NULL) +get_assignments_at_threshold( + bc.results, + sep.threshold, + mahal.threshold = NULL, + mahal.dist = NULL +) } \arguments{ \item{bc.results}{The debarcoding results returned from \code{debarcode_data}} diff --git a/man/get_sample_idx.Rd b/man/get_sample_idx.Rd index 76f74db..48ab92d 100644 --- a/man/get_sample_idx.Rd +++ b/man/get_sample_idx.Rd @@ -4,8 +4,13 @@ \alias{get_sample_idx} \title{Returns the indices of the events corresponding to a given sample label} \usage{ -get_sample_idx(label, bc.results, sep.threshold, mahal.threshold = NULL, - mahal.dist = NULL) +get_sample_idx( + label, + bc.results, + sep.threshold, + mahal.threshold = NULL, + mahal.dist = NULL +) } \arguments{ \item{label}{Character string. The desired sample label} diff --git a/man/get_well_abundances.Rd b/man/get_well_abundances.Rd index 27e544e..0ed71d8 100644 --- a/man/get_well_abundances.Rd +++ b/man/get_well_abundances.Rd @@ -4,8 +4,12 @@ \alias{get_well_abundances} \title{Calculate number of events assigned to each sample} \usage{ -get_well_abundances(bc.results, sep.thresholds, mahal.threshold = NULL, - mahal.dist = NULL) +get_well_abundances( + bc.results, + sep.thresholds, + mahal.threshold = NULL, + mahal.dist = NULL +) } \arguments{ \item{bc.results}{The debarcoding results returned from \code{debarcode_data}} diff --git a/man/normalize_folder.Rd b/man/normalize_folder.Rd index a28addb..670f745 100644 --- a/man/normalize_folder.Rd +++ b/man/normalize_folder.Rd @@ -4,8 +4,7 @@ \alias{normalize_folder} \title{Normalize a folder of FCS files} \usage{ -normalize_folder(wd, output.dir.name, beads.gates, beads.type, - baseline = NULL) +normalize_folder(wd, output.dir.name, beads.gates, beads.type, baseline = NULL) } \arguments{ \item{wd}{Working directory (character)} diff --git a/man/plot_barcode_yields.Rd b/man/plot_barcode_yields.Rd index ed5ca9f..1c3f756 100644 --- a/man/plot_barcode_yields.Rd +++ b/man/plot_barcode_yields.Rd @@ -4,8 +4,12 @@ \alias{plot_barcode_yields} \title{Plotting sample yields after debarcoding} \usage{ -plot_barcode_yields(bc.results, sep.threshold, mahal.threshold = NULL, - mahal.dist = NULL) +plot_barcode_yields( + bc.results, + sep.threshold, + mahal.threshold = NULL, + mahal.dist = NULL +) } \arguments{ \item{bc.results}{The debarcoding results returned from \code{debarcode_data}} diff --git a/man/premessa.Rd b/man/premessa.Rd index 530c823..d9428f9 100644 --- a/man/premessa.Rd +++ b/man/premessa.Rd @@ -3,7 +3,6 @@ \docType{package} \name{premessa} \alias{premessa} -\alias{premessa-package} \title{premessa: A package for normalization and debarcoding of CyTOF data.} \description{ For the normalizer GUI refer to the documentation for the \code{normalizer_GUI} function