library(scales) library(viridis) library(Seurat) library(stringr) library(tibble) library(dplyr) library(patchwork) library(ggplot2) library(tidyr) library(RColorBrewer) library(openxlsx) library(cowplot) args <- commandArgs(trailingOnly = TRUE) ######################################################################################### # KEEP ONLY BARCODE USED IN EXPERIMENT FROM FILE, NORMALIZE HTO AND DEMUX ######################################################################################### filterbarcodes <- function(object_seurat,i,marg.norm) { cat('## FILTER BACRODES') counts <- GetAssayData(object_seurat, slot="counts", assay="HTO") cat('number of cells for each HTO ') cat(rowSums(data.frame(counts))) hto.filter <- str_split(hto_conditions[hto_conditions$sample == sampleid, 'HTO'], ',')[[1]] #hto_conditions[[sampleid]] counts.sub <- counts[hto.filter,] ##filter and update number of cells per sample hto.assay <- CreateSeuratObject(counts=counts.sub) object_seurat@assays$HTO <- NULL ### to use if you want to subset HTO object_seurat@assays$HTO <- CreateAssayObject(counts = counts.sub) ### ### to use if you want to subset HTO object_seurat@assays$HTO@key <- 'hto_' cat('Normalize HTO data') scrna.hashtag <- NormalizeData(object_seurat, assay = "HTO",normalization.method = "CLR", margin = marg.norm) scrna.hashtag <- HTODemux(scrna.hashtag, assay = "HTO", positive.quantile = i, seed = 42) ## rerturn list of barcodes and obj demultiplexed return(list(sampleid, obj_demux=scrna.hashtag, barcodes=rownames(scrna.hashtag@assays$HTO))) } ######################################################################################### # CHOOSE POSITIVE QUANTILE PARAMETER ######################################################################################### eval_pq <- function(out_dir, obj.combined, sampleid, library_id, min_feature, max_feature, mito.prefix, max_pc_mito, marg.norm) { eval_pq_out_list <- list() #cat(sampleid) eval_pq_out <- tibble() #obj.combined = readRDS(paste(folder,sampleid,paste0(sampleid,'_minimal.rds'), sep='/')) DefaultAssay(obj.combined) <- 'RNA' print(DefaultAssay(obj.combined)) cat('filter cells', mito.prefix) # Compute mito % obj.combined[["percent.mt"]] <- PercentageFeatureSet(obj.combined, assay = 'RNA', pattern = mito.prefix) obj <- obj.combined %>% subset( nFeature_RNA > min_feature & ### Remove cells with < 250 detected genes nFeature_RNA < max_feature & ### Remove cells with > 2500 detected genes (could be doublets) percent.mt < max_pc_mito ### Remove cells with > 0.15 mito/total reads ) # filtering object based on hto count to zero DefaultAssay(obj) <- 'HTO' print(DefaultAssay(obj)) obj <- subset(obj,subset = nCount_HTO != 0 ) cat('find pq') for (i in seq(from = 0.9, to = 0.999999999, by = 0.005)) { cat(' demultiplexing cells based on HTO') x <- filterbarcodes(obj, i, marg.norm) object <- x$obj_demux cat('save pq') HTO_classification <- as.data.frame.matrix(table( object@meta.data$HTO_maxID, object@meta.data$HTO_classification.global )) %>% summarise(max.singlet = sum(Singlet)) %>% mutate(threshold = i) eval_pq_out <- bind_rows(eval_pq_out, HTO_classification) %>% mutate(library = sampleid) } eval_pq_out_list <- rbind( eval_pq_out_list, eval_pq_out) result_list <- list( "eval_pq_out" = eval_pq_out_list ) return(result_list) } obj_minimal <- args[1] # Sample minimal object obj_combined <- readRDS(obj_minimal) out_dir <- args[2] # Path to output result folder (results) sampleid <- args[3] #Sample id #min_cells <- as.numeric(args[4]) min_feature <- as.numeric(args[4]) max_feature <- as.numeric(args[5]) mito.prefix = args[6] max_pc_mito <- as.numeric(args[7]) marg.norm <- as.numeric(args[8]) hto <- args[9] cat('########## mito prefix #######') cat(mito.prefix) hto_conditions <- read.table(hto, header = TRUE, stringsAsFactors = FALSE) # Table with HTO list per sample ## Evaluate positive quantile parameter eval_pq_lib1 <- eval_pq(out_dir, obj_combined, sampleid, hto_conditions, min_feature, max_feature, mito.prefix, max_pc_mito, marg.norm) ## Plot number of Singlet detected pq <- eval_pq_lib1$eval_pq_out %>% ggplot(aes(x = threshold, y = max.singlet, fill = library, color = library)) + geom_line() + geom_point() + scale_color_brewer(palette = "Set1", direction = -1) + labs(x = "Postive Quantile", y = "# Singlet cells", fill = "", color = "") + theme_bw() out_dir_sample <- paste(out_dir, sampleid, 'plots',sep = "/") dir.create(out_dir_sample, showWarnings = FALSE) png(filename = paste(out_dir_sample, paste0(sampleid,"_max_threshod_pq_margin_",as.character(marg.norm),'.png'), sep = '/'), width = 12, height = 9, units = "in", res = 96) print(pq) dev.off() ## save threshold dx <- data.frame(eval_pq_lib1$eval_pq_out) dx$library <- as.factor(dx$library) max_threshold <- merge(aggregate(max.singlet ~ library, data=dx, max), dx, all.x=T) write.table(max_threshold,paste(out_dir_sample, paste0(sampleid,"_max_threshod_pq_margin_",as.character(marg.norm),".txt"), sep = '/')) # ##################################################################################### # # After computing best pq with higher number of singlets perform demux with max value # ##################################################################################### cat(sampleid) maxi <- max_threshold[max_threshold$library == sampleid, 'threshold'] # sample minimal object obj <- readRDS(obj_minimal) ### Add mitochondrial percentage to meta.data table DefaultAssay(obj) <- 'RNA' print(DefaultAssay(obj)) # Compute mito % obj[["percent.mt"]] <- PercentageFeatureSet(obj, assay = 'RNA', pattern = mito.prefix) obj <- obj %>% subset( nFeature_RNA > min_feature & ### Remove cells with < 250 detected genes nFeature_RNA < max_feature & ### Remove cells with > 2500 detected genes (could be doublets) percent.mt < max_pc_mito ### Remove cells with > 0.15 mito/total reads ) # filtering object based on hto count to zero DefaultAssay(obj) <- 'HTO' print(DefaultAssay(obj)) obj <- subset(obj,subset = nCount_HTO != 0 ) table(obj$orig.ident) cat('Demultiplexing cells based on HTO') x <- filterbarcodes(obj, maxi, marg.norm) scrna.hashtag <- x$obj_demux rowSums(data.frame(scrna.hashtag@assays$HTO@counts)) # Save demux Seurat object #oiut_dir_sample <- paste(out_dir, sampleid, sep = "/") #dir.create(out_dir_sample, showWarnings = FALSE) DefaultAssay(scrna.hashtag) <- "RNA" out_dir <- paste(out_dir, sampleid, sep = '/') saveRDS(object = scrna.hashtag, file = paste(out_dir, paste(sampleid, "demux_minimal.rds", sep = "_"), sep = "/")) cat(x$barcodes) cat('visualize demultiplexing - Global classification results', sampleid) class_hto <- list() class_hto[[sampleid]] <- table(scrna.hashtag$HTO_classification) class_hto[[sampleid]] class_htoglobal <- list() class_htoglobal[[sampleid]] <- table(scrna.hashtag$HTO_classification.global) class_htoglobal[[sampleid]] cat('Group cells based on the max HTO signal') Idents(scrna.hashtag) <- "HTO_maxID" DefaultAssay(scrna.hashtag) <- "HTO" rdgplot <- scrna.hashtag %>% RidgePlot( assay = "HTO", features = rownames(scrna.hashtag), ncol = 2) png(filename = paste(out_dir_sample, paste0(sampleid,"_ridgeplot.png"), sep = '/'), width = 12, height = 9, units = "in", res = 96) print(rdgplot) dev.off() ### Calculate doublet rate scrna.hashtag@meta.data %>% group_by(hash.ID) %>% summarize(fract = n() / nrow(.)) ### Create bar graphs comparing cell count for each sample HTO_bars_1 <- scrna.hashtag@meta.data %>% rownames_to_column("cell_id") %>% ggplot(aes(hash.ID, fill = hash.ID)) + geom_bar() + labs(y = "Cell Count") + cowplot::theme_cowplot() + theme( legend.position = "none", axis.title.x = element_blank(), axis.text.x = element_text(hjust = 1, angle = 45) ) ### Create stacked bar graph showing fraction of cells HTO_bars_2 <- scrna.hashtag@meta.data %>% rownames_to_column("cell_id") %>% group_by(hash.ID) %>% summarize(hash_frac = n() / nrow(.)) %>% ggplot(aes("scRNA-seq", hash_frac, fill = hash.ID)) + geom_bar(stat = "identity", color = "white", size = 0.5) + labs(y = "Fraction of Cells", x= sampleid) + cowplot::theme_cowplot() + theme( legend.title = element_blank(), axis.title.x = element_blank(), axis.text.x = element_blank(), axis.ticks.x = element_blank() ) ### Combine plots ### now add the title # title <- ggdraw() + # draw_label( # sampleid, # fontface = 'bold', # x = 0, # hjust = 0 # ) + # theme( # ### add margin on the left of the drawing canvas, # ### so title is aligned with left edge of first plot # plot.margin = margin(0, 0, 0, 7) # ) x <- plot_grid(#title, HTO_bars_1, HTO_bars_2, nrow = 1, rel_widths = c(0.5, 0.5), rel_heights = c(1, 0.8) ) png(filename = paste(out_dir_sample, paste0(sampleid,"_HTO_bars.png"), sep = '/'), width = 12, height = 9, units = "in", res = 96) print(x) dev.off() # cell count by hto classification scrna.hashtag@meta.data %>% group_by(HTO_classification) %>% summarize(fract = n() / nrow(.)) ### Create bar graphs comparing cell count by HTO classification HTO_bars_3 <- scrna.hashtag@meta.data %>% rownames_to_column("cell_id") %>% ggplot(aes(HTO_classification, fill = HTO_classification)) + geom_bar() + labs(y = "Cell Count") + cowplot::theme_cowplot() + theme( legend.position = "none", axis.title.x = element_blank(), axis.text.x = element_text(hjust = 1, angle = 45) ) ### Create stacked bar graph showing fraction of cells HTO_bars_4 <- scrna.hashtag@meta.data %>% rownames_to_column("cell_id") %>% group_by(HTO_classification) %>% summarize(hash_frac = n() / nrow(.)) %>% ggplot(aes("scRNA-seq", hash_frac, fill = HTO_classification)) + geom_bar(stat = "identity", color = "white", size = 0.5) + labs(y = "Fraction of Cells", x= sampleid) + cowplot::theme_cowplot() + theme( legend.title = element_blank(), axis.title.x = element_blank(), axis.text.x = element_blank(), axis.ticks.x = element_blank() ) ### Combine plots x <- plot_grid(#title, HTO_bars_3, HTO_bars_4, nrow = 1, rel_widths = c(0.5, 0.5), rel_heights = c(1, 0.8) ) png(filename = paste(out_dir_sample, paste0(sampleid,"_HTO_bars_classification.png"), sep = '/'), width = 12, height = 9, units = "in", res = 96) print(x) dev.off() fs <- FeatureScatter(scrna.hashtag, feature1 = "hto_H1", feature2 = "hto_H2") png(filename = paste(out_dir_sample, paste0(sampleid,"_HTO_1_2_featurescatter.png"), sep = '/'), width = 12, height = 9, units = "in", res = 96) print(fs) dev.off() Idents(scrna.hashtag) <- "HTO_classification.global" vnlp <- VlnPlot(scrna.hashtag, features = "nCount_RNA", pt.size = 0.1, log = TRUE) png(filename = paste(out_dir_sample, paste0(sampleid,"_ncount_RNA.png"), sep = '/'), width = 12, height = 9, units = "in", res = 96) print(vnlp) dev.off() cat('remove negative cells from the object') scrna.hashtag.subset <- subset(scrna.hashtag, idents = "Negative", invert = TRUE) cat('Calculate a tSNE embedding of the HTO data') DefaultAssay(scrna.hashtag.subset) <- "HTO" scrna.hashtag.subset <- ScaleData(scrna.hashtag.subset, features = rownames(scrna.hashtag.subset), verbose = FALSE) scrna.hashtag.subset <- RunPCA(scrna.hashtag.subset, features = rownames(scrna.hashtag.subset), approx = FALSE) # Calculate a distance matrix using HTO hto.dist.mtx <- as.matrix(dist(t(GetAssayData(object = scrna.hashtag.subset, assay = "HTO")))) scrna.hashtag.subset <- RunTSNE(scrna.hashtag.subset, dims = 1:length( hto_conditions[[sampleid]]), perplexity = 100,distance.matrix = hto.dist.mtx, check_duplicates = FALSE) Idents(scrna.hashtag.subset) <- 'HTO_classification' pdim_hto <- DimPlot(scrna.hashtag.subset,label=TRUE) png(filename = paste(out_dir_sample, paste0(sampleid,"_HTO_classification_dimplot.png"), sep = '/'), width = 12, height = 9, units = "in", res = 96) print(pdim_hto) dev.off() Idents(scrna.hashtag.subset) <- 'HTO_classification.global' pdim_hto_cl <- DimPlot(scrna.hashtag.subset,label=TRUE) png(filename = paste(out_dir_sample, paste0(sampleid,"_HTO_classification_global_dimplot.png"), sep = '/'), width = 12, height = 9, units = "in", res = 96) print(pdim_hto_cl) dev.off() htohm <- HTOHeatmap(scrna.hashtag.subset, assay = "HTO", ncells = 5000) png(filename = paste(out_dir_sample, paste0(sampleid,"_HTO_heatmap.png"), sep = '/'), width = 12, height = 9, units = "in", res = 96) print(htohm) dev.off() ## count all barcodes cat('count HTO reads') count_HTO_reads <- list() count_HTO_reads[[sampleid]] <- rowSums(data.frame(obj@assays$HTO@counts)) count_HTO_reads[[sampleid]] ###cat('Extract the singlets') scrna.hashtag.singlet <- subset(scrna.hashtag.subset, idents = "Singlet") count_HTO_reads_singlet <- list() count_HTO_reads_singlet[[sampleid]] <- rowSums(data.frame(scrna.hashtag.singlet@assays$HTO@counts)) cat('count HTO singlet reads\n') count_HTO_reads_singlet[[sampleid]] Idents(scrna.hashtag.singlet) <- "HTO_classification" count_HTO_reads_singlet_HTO <- list() count_HTO_reads_singlet_HTO_mean <- list() for (n in rownames(scrna.hashtag.singlet@assays$HTO@counts)){ x <- subset(scrna.hashtag.singlet, idents = n ) cat('hto', n) print(rowSums(data.frame(x@assays$HTO@counts))) ## count of reads HTO in cell classified as specific HTO count_HTO_reads_singlet_HTO[[sampleid]][n] <- rowSums(data.frame(x@assays$HTO@counts))[n] ## MEAN read count per hashatg over cell classified as specific-HTO count_HTO_reads_singlet_HTO_mean[[sampleid]][n] <- unname(rowSums(data.frame(x@assays$HTO@counts))[n])/unname(class_hto[[sampleid]][n]) } cat('count HTO reads, only in cell classified as singlet for specific HTO\n') count_HTO_reads_singlet_HTO cat('mean HTO reads, only in cell classified as singlet for specific HTO\n') count_HTO_reads_singlet_HTO_mean Idents(scrna.hashtag.subset) <- 'HTO_classification.global' ### Projecting singlet identities on TSNE visualization dimpl_htocl <- DimPlot(scrna.hashtag.singlet, group.by = "HTO_classification",label=TRUE) png(filename = paste(out_dir_sample, paste0(sampleid,"_HTO_classification_singlets.png"), sep = '/'), width = 12, height = 9, units = "in", res = 96) dimpl_htocl dev.off() # dimpl_htoglobal <- DimPlot(scrna.hashtag.singlet, group.by = 'HTO_classification.global', label=TRUE) # png(filename = paste(out_dir_sample, paste0(sampleid,"_HTO_classification_global_singlets.png"), sep = '/'), # width = 12, height = 9, units = "in", res = 96) # print(dimpl_htoglobal) # dev.off() vnl_hto <- scrna.hashtag.singlet %>% VlnPlot( features = c( "nCount_HTO"), ncol = 1, pt.size = 0.0005, log = T ) png(filename = paste(out_dir_sample, paste0(sampleid,"_violin_hto_singlets.png"), sep = '/'), width = 12, height = 9, units = "in", res = 96) print(vnl_hto) dev.off() ## Save Singlets cell and HTO classification in meta data DefaultAssay(scrna.hashtag) <- "RNA" scrna.hashtag[['HTO']] <- NULL # eliminate HTO assay saveRDS(object = scrna.hashtag.singlet, file = paste(out_dir, paste(sampleid, "singlet_minimal.rds", sep = "_"), sep = "/"))