Traumatic brain injury induces cell-type-specific remodelling of the proteostasis network.
The 10 matches
- [1] § Methods › Data clustering ↔ Mouse Code.R, lines 291 to 380 · score 0.76 · MRtree, adjusted Rand, clustering tree, clustree, resolutions, Jaccard · Report a mismatch
- [2] § Methods › Data clustering ↔ Human Code.R, lines 172 to 216 · score 0.74 · MRtree, adjusted Rand, clustering tree, clustree, resolutions, human · Report a mismatch
- [3] § Methods › Transcriptomic data pre-processing ↔ Mouse Code.R, lines 62 to 97 · score 0.69 · biomaRt, gene mapping, human genes, fewer, filtered, mouse · Report a mismatch
- [4] § Results › Identifying preferential gene expression in specific cell types ↔ 1A basic_features.R, lines 110 to 156 · score 0.60 · GM2A, N4BP1, UCHL1, A2M, KLHL2, naive · Report a mismatch
- [5] § Results › A core sub-proteostasis network in traumatic brain injury ↔ 1A basic_features.R, lines 158 to 218 · score 0.56 · Core Naive Sub, Core CCI Sub, TRANSL, ALP, TBI, PN · Report a mismatch
- [6] § Methods › Transcriptomic data pre-processing ↔ Human Code.R, lines 119 to 170 · score 0.55 · NormalizeData, ScaleData, PN genes, pre, Seurat, PCA · Report a mismatch
- [7] § Results › A core sub-proteostasis network in traumatic brain injury ↔ Mouse Code.R, lines 1303 to 1366 · score 0.54 · Core Naive Sub, Core CCI Sub, TRANSL, ALP, mice, PN · Report a mismatch
- [8] § Methods › Gene set enrichment analysis ↔ Mouse Code.R, lines 769 to 810 · score 0.52 · log2FC, FindAllMarkers, fgsea, Seurat, mouse, clusters · Report a mismatch
- [9] § Methods › Gene set enrichment analysis ↔ Human Code.R, lines 706 to 789 · score 0.52 · log2FC, FindAllMarkers, fgsea, human, TBI, clusters · Report a mismatch
- [10] § Methods › Proteostasis network and Hallmark Pathway association ↔ Figure S1.R, lines 44 to 129 · score 0.50 · enrichment odds ratio, Fisher, PN · Report a mismatch
Paper
Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
R · 1,395 lines · 81 KB · no license · 4 matches
- suppressMessages(library(Seurat))
- suppressMessages(library(biomaRt))
- suppressMessages(library(presto))
- suppressMessages(library(ggplot2))
- suppressMessages(library(RColorBrewer))
- suppressMessages(library(clustree))
- suppressMessages(library(mclust))
- suppressMessages(library(mrtree))
- suppressMessages(library(igraph))
- suppressMessages(library(fgsea))
- suppressMessages(library(data.table))
- suppressMessages(library(ComplexHeatmap))
- suppressMessages(library(DESeq2))
- suppressMessages(library(ggVennDiagram))
- mem.maxVSize(vsize=Inf)
- options(future.globals.maxSize = 1000 * 1024^2)
- ####session information####
- # R version 4.4.1 (2024-06-14)
- # Platform: aarch64-apple-darwin20
- # Running under: macOS Sonoma 14.5
- #
- # Matrix products: default
- # BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
- # LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.0
- #
- # locale:
- # [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
- #
- # time zone: America/New_York
- # tzcode source: internal
- #
- # attached base packages:
- # [1] stats4 grid stats graphics grDevices utils datasets methods base
- #
- # other attached packages:
- # [1] DESeq2_1.44.0 SummarizedExperiment_1.34.0 Biobase_2.64.0 MatrixGenerics_1.16.0 matrixStats_1.5.0 GenomicRanges_1.56.2 GenomeInfoDb_1.40.1 IRanges_2.38.1 S4Vectors_0.42.1 BiocGenerics_0.50.0 ComplexHeatmap_2.20.0
- # [12] fgsea_1.30.0 igraph_2.2.2 mrtree_0.0.0.9000 mclust_6.1.2 clustree_0.5.1 ggraph_2.2.2 RColorBrewer_1.1-3 ggplot2_4.0.2 presto_1.0.0 data.table_1.18.2.1 Rcpp_1.1.1
- # [23] biomaRt_2.60.1 Seurat_5.4.0 SeuratObject_5.3.0 sp_2.2-1
- #
- # loaded via a namespace (and not attached):
- # [1] fs_1.6.6 spatstat.sparse_3.1-0 httr_1.4.8 doParallel_1.0.17 numDeriv_2016.8-1.1 tools_4.4.1 sctransform_0.4.3 backports_1.5.0 R6_2.6.1 lazyeval_0.2.2 uwot_0.2.4
- # [12] GetoptLong_1.1.0 withr_3.0.2 prettyunits_1.2.0 gridExtra_2.3 progressr_0.18.0 cli_3.6.5 spatstat.explore_3.7-0 fastDummies_1.7.5 S7_0.2.1 spatstat.data_3.1-9 ggridges_0.5.7
- # [23] pbapply_1.7-4 systemfonts_1.3.1 yulab.utils_0.2.4 DEoptim_2.2-8 parallelly_1.46.1 maps_3.4.3 rstudioapi_0.18.0 RSQLite_2.4.6 optimParallel_1.0-2 generics_0.1.4 gridGraphics_0.5-1
- # [34] shape_1.4.6.1 combinat_0.0-8 ica_1.0-3 spatstat.random_3.4-4 SymSim_0.0.0.9000 dendextend_1.19.1 dplyr_1.2.0 Matrix_1.7-4 abind_1.4-8 lifecycle_1.0.5 yaml_2.3.12
- # [45] scatterplot3d_0.3-45 clusterGeneration_1.3.8 SparseArray_1.4.8 BiocFileCache_2.12.0 Rtsne_0.17 blob_1.3.0 promises_1.5.0 crayon_1.5.3 miniUI_0.1.2 lattice_0.22-9 cowplot_1.2.0
- # [56] KEGGREST_1.44.1 magick_2.9.1 pillar_1.11.1 rjson_0.2.23 future.apply_1.20.2 codetools_0.2-20 fastmatch_1.1-8 glue_1.8.0 ggiraph_0.9.6 ggimage_0.3.5 ggfun_0.2.0
- # [67] spatstat.univar_3.1-6 fontLiberation_0.1.0 treeio_1.28.0 vctrs_0.7.1 png_0.1-8 spam_2.11-3 gtable_0.3.6 cachem_1.1.0 S4Arrays_1.4.1 mime_0.13 tidygraph_1.3.1
- # [78] coda_0.19-4.1 survival_3.8-6 SingleCellExperiment_1.26.0 iterators_1.0.14 fitdistrplus_1.2-6 ROCR_1.0-12 nlme_3.1-168 ggtree_3.12.0 bit64_4.6.0-1 fontquiver_0.2.1 progress_1.2.3
- # [89] filelock_1.0.3 RcppAnnoy_0.0.23 data.tree_1.2.0 irlba_2.3.7 KernSmooth_2.23-26 otel_0.2.0 colorspace_2.1-2 DBI_1.3.0 phangorn_2.12.1 mnormt_2.1.2 tidyselect_1.2.1
- # [100] bit_4.6.0 compiler_4.4.1 curl_7.0.0 httr2_1.2.2 expm_1.0-0 xml2_1.5.2 fontBitstreamVera_0.1.1 DelayedArray_0.30.1 plotly_4.12.0 checkmate_2.3.4 scales_1.4.0
- # [111] lmtest_0.9-40 quadprog_1.5-8 rappdirs_0.3.4 stringr_1.6.0 digest_0.6.39 goftest_1.2-3 spatstat.utils_3.2-1 XVector_0.44.0 htmltools_0.5.9 pkgconfig_2.0.3 dbplyr_2.5.1
- # [122] fastmap_1.2.0 rlang_1.1.7 GlobalOptions_0.1.3 htmlwidgets_1.6.4 UCSC.utils_1.0.0 shiny_1.13.0 farver_2.1.2 zoo_1.8-15 jsonlite_2.0.0 BiocParallel_1.38.0 magrittr_2.0.4
- # [133] GenomeInfoDbData_1.2.12 ggplotify_0.1.3 dotCall64_1.2 patchwork_1.3.2 ape_5.8-1 viridis_0.6.5 gdtools_0.5.0 reticulate_1.45.0 stringi_1.8.7 zlibbioc_1.50.0 MASS_7.3-65
- # [144] plyr_1.8.9 parallel_4.4.1 listenv_0.10.0 ggrepel_0.9.6 deldir_2.0-4 Biostrings_2.72.1 graphlayouts_1.2.3 splines_4.4.1 tensor_1.5.1 hms_1.1.4 circlize_0.4.17
- # [155] locfit_1.5-9.12 spatstat.geom_3.7-0 RcppHNSW_0.6.0 reshape2_1.4.5 foreach_1.5.2 tweenr_2.0.3 httpuv_1.6.16 RANN_2.6.2 tidyr_1.3.2 purrr_1.2.1 polyclip_1.10-7
- # [166] clue_0.3-67 future_1.69.0 scattermore_1.2 ggforce_0.5.0 xtable_1.8-8 tidytree_0.4.7 phytools_2.5-2 RSpectra_0.16-2 later_1.4.7 viridisLite_0.4.3 tibble_3.3.1
- # [177] aplot_0.2.9 memoise_2.0.1 AnnotationDbi_1.66.0 cluster_2.1.8.2 globals_0.19.0
- #####PREPARE OBJECT#####
- #For gene ID mapping
- mousegenes <- useEnsembl(biomart = "ensembl", dataset = "mmusculus_gene_ensembl", version = 105)
- humangenes <- useEnsembl(biomart = "ensembl", dataset = "hsapiens_gene_ensembl", version = 105)
- load('all_SeuratObjects.RData') #this has the data
- expression_matrix <- Int_all_4C.combined[['RNA']]$counts #extract the counts for all conditions. At this stage we have 19558 genes.
- #Do gene mapping
- gene_name_map <- unique(getLDS(attributes = c("external_gene_name"),
- filters = "external_gene_name",
- values = rownames(expression_matrix),
- mart = mousegenes,
- attributesL = c("hgnc_symbol"),
- martL = humangenes, uniqueRows=T)) #make mapping table from biomaRt
- mouse_count <- as.data.frame(table(gene_name_map$Gene.name)) #counting frequency to identify duplicates in mouse names (one to many mapping)
- human_count <- as.data.frame(table(gene_name_map$HGNC.symbol)) #counting frequency to identify duplicates in mouse names (many to one mapping)
- gene_name_map$mouse_counts <- mouse_count$Freq[match(unlist(gene_name_map$Gene.name), mouse_count$Var1)] #mouse name frequencies added to data frame
- gene_name_map$human_counts <- human_count$Freq[match(unlist(gene_name_map$HGNC.symbol), human_count$Var1)] #human name frequencies added to data frame
- equals_one <- gene_name_map$mouse_counts == 1 & gene_name_map$human_counts == 1 #create boolean for one-to-one mapping
- gene_name_map <- gene_name_map[equals_one,] #filter to keep only one-to-one mapping
- in_map <- rownames(expression_matrix) %in% gene_name_map$Gene.name #which gene names in the expression matrix are mappable?
- expression_matrix <- expression_matrix[in_map,] #use only mappable genes. At this stage we have 14348 genes.
- rownames(expression_matrix) <- gene_name_map$HGNC.symbol[match(unlist(rownames(expression_matrix)), gene_name_map$Gene.name)] #convert from mouse to human gene names
- #But we only want to include two conditions, Naive and CCI
- conditions_of_interest <- c('CCI','Naive')
- metadata_of_interest <- subset([email hidden],condition %in% conditions_of_interest)
- expression_matrix <- expression_matrix[,rownames(metadata_of_interest)] #at this stage we have 14348 genes
- #Now we want to get rid of any genes that have fewer than 10 cells with at least count 1 in each sample.
- origidents <- unique(metadata_of_interest$orig.ident)
- #read_count_function returns the number of values in a supplied row or column that have a non-zero account. If you provide a row from the expression matrix, it's the number of cells that have a count of at least 1 for the gene. If you provide a column from the expression matrix, it's the number of genes that have a non-zero count for the cell. But I don't use the latter because I use the built-in feature of CreateSeuratObject below.
- read_count_function <- function(row_or_column) {
- the_table <- table(row_or_column)
- zero_count <- as.numeric(the_table[names(the_table)==0])
- non_zero_count <- length(row_or_column)-zero_count
- return(non_zero_count)
- }
- #Get rid of genes that are expressed in fewer than 10 cells per sample.
- too_sparse_genes_list = c()
- for (origident in origidents) { #for each of the idents that we are including (each naive and cci replicate)
- print(origident)
- temp_meta <- subset([email hidden], orig.ident %in% origident) #identify the subset of cells that match that particular replicate
- exp_temp <- expression_matrix[,rownames(temp_meta)] #subset the expression matrix for only those cells
- non_zero_count_list <- apply(exp_temp, 1, read_count_function) #use the count_function to get the # of cells that have a non-zero value for each gene. Supplying a row.
- too_sparse <- names(subset(non_zero_count_list, non_zero_count_list < 10)) #get the names of the genes that have fewer than 5 cells with non-zero values
- too_sparse_genes_list <- union(too_sparse_genes_list, too_sparse) #add that to a list of genes that are too sparsley expressed to be handled by default SCTransform settings
- }
- keep_genes <- subset(rownames(expression_matrix), !(rownames(expression_matrix) %in% too_sparse_genes_list))
- expression_matrix <- expression_matrix[keep_genes,] #11371 genes, 52384 cells
- ##Now we want to get rid of any cell that has fewer than 200 features. We set min.cells to 0 because we've already done this filtration on a sample by sample basis.
- cci_seurat_pre <- CreateSeuratObject(counts=expression_matrix, min.cells=0, min.features=200, meta.data=metadata_of_interest) #11371 genes, 52368 cells
- #Now I want to create a separate expression_matrix only for PN genes
- PN = read.table('proteostasis_list.txt',header=FALSE,sep='\n')$V1 #PN gene list
- in_PN <- rownames(cci_seurat_pre[['RNA']]$counts) %in% PN #list of genes in the expression_matrix that are in the PN
- expression_matrix_PN <- cci_seurat_pre[['RNA']]$counts[in_PN,] #include only PN genes #this is 2420 genes
- ##We set min.cells to 0 because we've already done this filtration on a sample by sample basis. We don't get rid of additional features here. This could potentially create the issue of cells that have a very low number of PN only features.
- ##You can test this out.
- cci_seurat_pre_PN <- CreateSeuratObject(counts=expression_matrix_PN, min.cells=0, min.features=0, meta.data=[email hidden])
- #2420 genes, 52368 cells. By empirically testing, we found that every cell expresses at least 48 PN genes.
- #now we prep the cci_seurat_pre object
- #Add meta data with the full cell type names
- lookup <- c("0" = "Microglia_1", "1" = "Microglia_2", "2" = "Ependymal_1", "3" = "Microglia_3",
- "4" = "Ependymal_2", "5" = "BCells", "6" = "Endothelial_1", "7" = "Neutrophils_1",
- "8" = "Microglia_4", "9" = "Microglia_5", "10" = "Ependymal_3", "11" = "Microglia_6",
- "12" = "Endothelial_2", "13" = "Astrocytes", "14" = "NKcells", "15" = "Neurons",
- "16" = "Neutrophils_2", "17" = "Ependymal_4", "18" = "Microglia_7", "19" = "Oligodendrocytes",
- "20" = "TmemoryCells", "21" = "Microglia_8", "22" = "Ependymal_5") #From Jha group, these are the cell types from their clusters
- celltype_col <- data.frame(celltype_col=lookup[as.character([email hidden]$celltype)]) #make a data frame converting the celltype clusters to the celltype names
- rownames(celltype_col) <- rownames([email hidden]) #add the cell row names there
- cci_seurat_pre <- AddMetaData(cci_seurat_pre, celltype_col) #add this to the meta data
- #Add meta data with abbreviated cell type names
- lookup <- c("0" = "M1", "1" = "M2", "2" = "Ep1", "3" = "M3",
- "4" = "Ep2", "5" = "B", "6" = "En1", "7" = "Nt1",
- "8" = "M4", "9" = "M5", "10" = "Ep3", "11" = "M6",
- "12" = "En2", "13" = "As", "14" = "NK", "15" = "Nr",
- "16" = "Nt2", "17" = "Ep4", "18" = "M7", "19" = "Olg",
- "20" = "Tmem", "21" = "M8", "22" = "Ep5") #From Jha group, these are the cell types from their clusters
- celltype_lab <- data.frame(celltype_lab=lookup[as.character([email hidden]$celltype)]) #make a data frame converting the celltype clusters to the celltype names
- rownames(celltype_lab) <- rownames([email hidden]) #add the cell row names there
- cci_seurat_pre <- AddMetaData(cci_seurat_pre, celltype_lab) #add this to the meta data
- #Add meta data with larger cell type categories, as defined in Jha Neuron 1B
- lookup <- c("0" = "M", "1" = "M", "2" = "Ep", "3" = "M",
- "4" = "Ep", "5" = "L", "6" = "En", "7" = "Nt",
- "8" = "M", "9" = "M", "10" = "Ep", "11" = "M",
- "12" = "En", "13" = "NG", "14" = "L", "15" = "NG",
- "16" = "Nt", "17" = "Ep", "18" = "M", "19" = "NG",
- "20" = "L", "21" = "M", "22" = "Ep") #From Jha group, these are the cell types from their clusters
- celltype_cat <- data.frame(celltype_cat=lookup[as.character([email hidden]$celltype)]) #make a data frame converting the celltype clusters to the celltype names
- rownames(celltype_cat) <- rownames([email hidden]) #add the cell row names there
- cci_seurat_pre <- AddMetaData(cci_seurat_pre, celltype_cat) #add this to the meta data
- saveRDS(cci_seurat_pre, file="cci_seurat_pre.rds")
- #now we prep the cci_seurat_pre_PN object
- #Add meta data with the full cell type names
- lookup <- c("0" = "Microglia_1", "1" = "Microglia_2", "2" = "Ependymal_1", "3" = "Microglia_3",
- "4" = "Ependymal_2", "5" = "BCells", "6" = "Endothelial_1", "7" = "Neutrophils_1",
- "8" = "Microglia_4", "9" = "Microglia_5", "10" = "Ependymal_3", "11" = "Microglia_6",
- "12" = "Endothelial_2", "13" = "Astrocytes", "14" = "NKcells", "15" = "Neurons",
- "16" = "Neutrophils_2", "17" = "Ependymal_4", "18" = "Microglia_7", "19" = "Oligodendrocytes",
- "20" = "TmemoryCells", "21" = "Microglia_8", "22" = "Ependymal_5") #From Jha group, these are the cell types from their clusters
- celltype_col <- data.frame(celltype_col=lookup[as.character([email hidden]$celltype)]) #make a data frame converting the celltype clusters to the celltype names
- rownames(celltype_col) <- rownames([email hidden]) #add the cell row names there
- cci_seurat_pre_PN <- AddMetaData(cci_seurat_pre_PN, celltype_col) #add this to the meta data
- #Add meta data with abbreviated cell type names
- lookup <- c("0" = "M1", "1" = "M2", "2" = "Ep1", "3" = "M3",
- "4" = "Ep2", "5" = "B", "6" = "En1", "7" = "Nt1",
- "8" = "M4", "9" = "M5", "10" = "Ep3", "11" = "M6",
- "12" = "En2", "13" = "As", "14" = "NK", "15" = "Nr",
- "16" = "Nt2", "17" = "Ep4", "18" = "M7", "19" = "Olg",
- "20" = "Tmem", "21" = "M8", "22" = "Ep5") #From Jha group, these are the cell types from their clusters
- celltype_lab <- data.frame(celltype_lab=lookup[as.character([email hidden]$celltype)]) #make a data frame converting the celltype clusters to the celltype names
- rownames(celltype_lab) <- rownames([email hidden]) #add the cell row names there
- cci_seurat_pre_PN <- AddMetaData(cci_seurat_pre_PN, celltype_lab) #add this to the meta data
- #Add meta data with larger cell type categories, as defined in Jha Neuron 1B
- lookup <- c("0" = "M", "1" = "M", "2" = "Ep", "3" = "M",
- "4" = "Ep", "5" = "L", "6" = "En", "7" = "Nt",
- "8" = "M", "9" = "M", "10" = "Ep", "11" = "M",
- "12" = "En", "13" = "NG", "14" = "L", "15" = "NG",
- "16" = "Nt", "17" = "Ep", "18" = "M", "19" = "NG",
- "20" = "L", "21" = "M", "22" = "Ep") #From Jha group, these are the cell types from their clusters
- celltype_cat <- data.frame(celltype_cat=lookup[as.character([email hidden]$celltype)]) #make a data frame converting the celltype clusters to the celltype names
- rownames(celltype_cat) <- rownames([email hidden]) #add the cell row names there
- cci_seurat_pre_PN <- AddMetaData(cci_seurat_pre_PN, celltype_cat) #add this to the meta data
- #Add meta data with larger cell type categories, but this time break out the neuroglial into their individual cell types because these are interesting
- lookup <- c("0" = "M", "1" = "M", "2" = "Ep", "3" = "M",
- "4" = "Ep", "5" = "L", "6" = "En", "7" = "Nt",
- "8" = "M", "9" = "M", "10" = "Ep", "11" = "M",
- "12" = "En", "13" = "As", "14" = "L", "15" = "Nr",
- "16" = "Nt", "17" = "Ep", "18" = "M", "19" = "Olg",
- "20" = "L", "21" = "M", "22" = "Ep") #From Jha group, these are the cell types from their clusters
- celltype_altcat <- data.frame(celltype_altcat=lookup[as.character([email hidden]$celltype)]) #make a data frame converting the celltype clusters to the celltype names
- rownames(celltype_altcat) <- rownames([email hidden]) #add the cell row names there
- cci_seurat_pre_PN <- AddMetaData(cci_seurat_pre_PN, celltype_altcat) #add this to the meta data
- condition_ctat <- data.frame(condition_ctat=paste0([email hidden]$condition,"_",[email hidden]$celltype_altcat))
- rownames(condition_ctat) <- rownames([email hidden])
- cci_seurat_pre_PN <- AddMetaData(cci_seurat_pre_PN, condition_ctat) #add this to the meta data
- saveRDS(cci_seurat_pre_PN, file="cci_seurat_pre_PN.rds")
- #####NORMALIZATION#####
- umap_theme <- theme(plot.title=element_blank(),
- panel.background=element_blank(),
- axis.line=element_line(colour='black',linewidth=0.3),
- axis.ticks=element_line(color='black',linewidth=0.3),
- axis.text=element_text(size=6,colour='black'),
- legend.title=element_blank(),legend.text=element_text(size=6, colour='black'),
- legend.position='none',title=element_blank(),
- axis.title=element_text(size=6,colour='black'))
- #Now we will identify PN genes that are in our data set --> these will be used for the PCA
- #log transform
- #First we normalize on all genes
- #I've decided to use this pipeline instead of the sctransform pipeline mostly because of the desire to use only the proteostasis genes as the loadings for the PCs.
- #The problem with using sctransform is the following. sctransform recommends splitting and re-integrated the data. The standard reintegration with CCA is very slow and may introduce some biases.
- #Doing RPCA is much faster, but requires doing the PCA first. But what that means is that I would either need to do the PCA on all the genes (defeating my purpose) or on the proteostasis genes alone,
- #which would mean that the reintegration would be limited to this smaller subset of genes, which I also think is not the ideal situation.
- #for this reason, I am just going to use the old pipeline.
- #I will continue to select genes that make some appearance in all the samples, as would be the default requirement in sctransform, because I think that's probably a reasonable thing anyway.
- # The other thing I note here is that I start by doing all the analysis only on PN genes. This is because even when you do the PCA with only the PN genes, when you try to find markers you find that the markers
- # of the clusters are largely not the PN genes, making it a bit harder to find the PN genes that drive the clustering. I guess I could look in the loadings as well.
- #Check the PCA explanatory power using all PN genes on the PN only seurat object.
- cci_seurat_pre_PN <- readRDS('cci_seurat_pre_PN.rds')
- cci_seurat_pre_PN <- NormalizeData(cci_seurat_pre_PN)
- all.genes <- rownames(cci_seurat_pre_PN) #all the genes in the seurat object
- cci_seurat_pre_PN <- ScaleData(cci_seurat_pre_PN, features=all.genes)
- cci_seurat_pre_PN <- RunPCA(cci_seurat_pre_PN, npcs=100, features=all.genes) #this does PCA using the PN_genes as features
- p<-ElbowPlot(cci_seurat_pre_PN, ndims=100, reduction='pca')+umap_theme
- p$layers[[1]]$aes_params$size <- 0.5
- pdf(paste0('elbow.pdf'), width=3/cm(1), height=3/cm(1))
- p
- dev.off()
- percent_var_pn <- 100*(cci_seurat_pre_PN[["pca"]]@stdev^2) / cci_seurat_pre_PN@reductions[["pca"]]@misc$total.variance
- cumulative_var_pn <- cumsum(percent_var_pn)
- saveRDS(cci_seurat_pre_PN, 'cci_seurat_pre_PN_PCA.rds')
- ##16.2% explained by 100 PCs
- ####FIND CLUSTERS####
- cci_seurat_lt_pca <- readRDS('cci_seurat_pre_PN_PCA.rds')
- #Now I cluster at various PC numbers and dimensions.
- for (dim in c(20,30,50)) {
- set.seed(42)
- cci_seurat <- FindNeighbors(cci_seurat_lt_pca, dims = 1:dim)
- for (i in seq(0.1,2,0.1)) {
- cci_seurat <- FindClusters(cci_seurat, resolution=i, cluster.name=paste0('res_',as.character(i)))
- }
- saveRDS(cci_seurat, paste0('cci_seurat_lt_pca_',as.character(dim),'.rds'))
- gc()
- }
- #####EVALUATE THE CLUSTERS#####
- if (!dir.exists('mouse_initial_cluster_tests')) {
- dir.create('mouse_initial_cluster_tests')
- }
- for (dim in c(20,30,50)) {
- cci_seurat <- readRDS(paste0('cci_seurat_lt_pca_',as.character(dim),'.rds'))
- rand_frame_lt_pca <- data.frame(resolution=c(), rand=c())
- for (i in seq(0.1,2,0.1)) {
- ari <- adjustedRandIndex([email hidden][[paste0('res_',as.character(i))]],[email hidden]$celltype)
- temp_frame <- data.frame(resolution=i,rand=ari)
- rand_frame_lt_pca <- rbind(rand_frame_lt_pca, temp_frame)
- }
- ari_plot <- ggplot(rand_frame_lt_pca, aes(x=resolution,y=rand))+geom_point(stat='identity', colour='black',size=1,alpha=1)+scale_x_continuous('Resolution')+scale_y_continuous('Adjusted Rand Index')+umap_theme
- ggsave(paste0('mouse_initial_cluster_tests/mouse_ari',as.character(dim),'.pdf'), plot=ari_plot, width=3, height=3, units='cm', dpi=600)
- cluster_tree<-clustree(cci_seurat,prefix='res_')
- ggsave(paste0('mouse_initial_cluster_tests/mouse_clustree_',as.character(dim),'.pdf'),plot=cluster_tree, width=40, height=30, units='cm', dpi=600)
- set.seed(42)
- out <- mrtree([email hidden], prefix='res_', n.cores = 12, consensus=FALSE, augment.path=FALSE)
- saveRDS(out, paste0('mouse_initial_cluster_tests/out_',as.character(dim),'.rds'))
- ks.flat = apply(out$labelmat.flat, 2, FUN=function(x) length(unique(x)))
- ks.mrtree = apply(out$labelmat.mrtree, 2, FUN=function(x) length(unique(x)))
- amri.flat = sapply(1:ncol(out$labelmat.flat), function(i) AMRI(out$labelmat.flat[,i], [email hidden]$celltype_lab)$amri)
- amri.flat = aggregate(amri.flat, by=list(k=ks.flat), FUN=mean)
- amri.recon = sapply(1:ncol(out$labelmat.mrtree), function(i) AMRI(out$labelmat.mrtree[,i], [email hidden]$celltype_lab)$amri)
- df = rbind(data.frame(k=amri.flat$k, amri=amri.flat$x, method='Seurat flat'),
- data.frame(k=ks.mrtree, amri=amri.recon, method='MRtree'))
- amri_plot <- ggplot(data=df, aes(x=k, y=amri, color=method)) + geom_line() + theme_bw()
- ggsave(paste0('mouse_initial_cluster_tests/mouse_amri_',as.character(dim),'.pdf'), plot=amri_plot, width=8, height=3, units='cm', dpi=600)
- stab.out = stability_plot(out)
- ggsave(paste0('mouse_initial_cluster_tests/mouse_stab_',as.character(dim),'.pdf'), plot=stab.out$plot, width=6, height=9, units='cm', dpi=600)
- cluster_numbers <- apply(out$labelmat.flat, 2, max)+1
- print(cluster_numbers)
- gc()
- }
- #20
- #res_0.1 res_0.2 res_0.3 res_0.4 res_0.5 res_0.6 res_0.7 res_0.8 res_0.9 res_1 res_1.1 res_1.2 res_1.3 res_1.4 res_1.5 res_1.6 res_1.7 res_1.8 res_1.9 res_2
- #10 14 16 17 17 19 19 21 24 25 27 27 29 30 31 31 33 35 36 37
- #30
- #res_0.1 res_0.2 res_0.3 res_0.4 res_0.5 res_0.6 res_0.7 res_0.8 res_0.9 res_1 res_1.1 res_1.2 res_1.3 res_1.4 res_1.6 res_1.5 res_1.7 res_1.8 res_1.9 res_2
- #12 14 16 17 17 19 21 24 25 26 27 29 30 31 33 34 35 36 37 39
- #50
- # res_0.1 res_0.2 res_0.3 res_0.4 res_0.5 res_0.6 res_0.7 res_0.8 res_0.9 res_1 res_1.2 res_1.1 res_1.3 res_1.4 res_1.6 res_1.5 res_1.7 res_1.8 res_1.9 res_2
- # 12 13 15 17 17 18 19 21 23 25 27 28 30 31 32 33 34 34 36 37
- #####MAKE UMAPs FOR THE SUBSET OF CLUSTERS THAT PERFORM REASONABLY WELL#####
- if (!dir.exists('mouse_initial_UMAPs')) {
- dir.create('mouse_initial_UMAPs')
- }
- iter_frame <- data.frame(dim_options = c("20","30","30","50","50","50","50","50","50","50","50"),
- res_options=c("0.9","1","1.1","0.4","0.5","0.6","0.7","0.8","1.1","1.2","1.3"))
- for (dim in c(20,30,50)) {
- cci_seurat <- readRDS(paste0('cci_seurat_lt_pca_',dim,'.rds'))
- cci_seurat <- RunUMAP(cci_seurat, dims=1:dim)
- dimplot_by_celltype <- DimPlot(cci_seurat,reduction='umap', group.by="celltype_lab", label=TRUE, label.size=2,label.box=TRUE, repel=TRUE, pt.size=1,raster=TRUE)+umap_theme+labs(x='UMAP 1',y='UMAP 2') #plot by cell type
- ggsave(paste0('mouse_initial_UMAPs/mouse_UMAP_',as.character(dim),'celltype_lab.pdf'), plot=dimplot_by_celltype, width=7, height=7, units='cm', dpi=600)
- saveRDS(cci_seurat, paste0('cci_seurat_lt_pca_',as.character(dim),'_UMAP.rds'))
- for (i in 1:nrow(iter_frame)) {
- dim_option <- iter_frame[i,]$dim_options
- res_option <- iter_frame[i,]$res_options
- if (dim==dim_option) {
- dimplot_by_res <- DimPlot(cci_seurat,reduction='umap', group.by=paste0('res_',res_option), label=TRUE, label.size=2,label.box=TRUE, repel=TRUE, pt.size=1,raster=TRUE)+umap_theme+labs(x='UMAP 1',y='UMAP 2') #plot by cell type
- ggsave(paste0('mouse_initial_UMAPs/mouse_UMAP_',as.character(dim_option),'_',as.character(res_option),'.pdf'), plot=dimplot_by_res, width=7, height=7, units='cm', dpi=600)
- }
- }
- }
- #####IDENTIFY CLUSTERS FOR MERGER BASED ON MARKER JACCARD SIMILARITY#####
- ###This function generates the markers to be used in the jaccard function
- if (!dir.exists('mouse_clustering_evaluation')) {
- dir.create('mouse_clustering_evaluation')
- }
- markers_function <- function(pca_dims, res) {
- prefix <- paste0('mouse_clustering_evaluation/cci_seurat_lt_pca_',pca_dims,'_res_',res)
- seurat_object <- readRDS(paste0('mouse_initial_UMAPs/cci_seurat_lt_pca_',pca_dims,'_UMAP.rds'))
- Idents(object = seurat_object) <- paste0('res_',res)
- the_markers_wilcox <- FindAllMarkers(seurat_object, logfc.threshold=-Inf, min.pct=-Inf, genes.use=row.names(seurat_object)) #first calculate all the wilcox scores. Note that we use the library presto to speed up computation as suggested by Seurat.
- write.table(the_markers_wilcox, file=paste0(prefix,'_wilcox_markers.txt'), quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- the_markers_wilcox_subset <- subset(the_markers_wilcox, the_markers_wilcox$p_val_adj < 0.05 & the_markers_wilcox$avg_log2FC >= 0.585 & the_markers_wilcox$pct.1 >= 0.5) #we then subset for those that are significant, with at least 1.5 fold change, and that are present in at least 50% of cells in the cluster.
- write.table(the_markers_wilcox_subset, file=paste0(prefix,'_wilcox_markers_significant.txt'), quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- return (list(all_markers = the_markers_wilcox, subset_markers = the_markers_wilcox_subset))
- }
- ###The jaccard function looks for similar clusters and returns the jaccard values and a reclustering in graph form
- jaccard_function <- function(wilcox_markers, pca_dims, res, percentage_threshold = 33.3) {
- prefix <- paste0('mouse_clustering_evaluation/cci_seurat_lt_pca_',pca_dims,'_res_',res)
- the_clusters <- unique(wilcox_markers$cluster)
- jaccard_matrix <- matrix(nrow=length(the_clusters), ncol=length(the_clusters))
- colnames(jaccard_matrix) <- the_clusters
- rownames(jaccard_matrix) <- the_clusters
- jaccard_threshold <- matrix(nrow=length(the_clusters), ncol=length(the_clusters))
- colnames(jaccard_threshold) <- the_clusters
- rownames(jaccard_threshold) <- the_clusters
- for (cluster1 in the_clusters) {
- for (cluster2 in the_clusters) {
- if (cluster1 != cluster2 & is.na(jaccard_matrix[cluster2,cluster1])) {
- subset1 <- unique(subset(wilcox_markers, wilcox_markers$cluster == cluster1)$gene)
- subset2 <- unique(subset(wilcox_markers, wilcox_markers$cluster == cluster2)$gene)
- the_intersection <- intersect(subset1, subset2)
- the_union <- union(subset1, subset2)
- jaccard <- 100*length(the_intersection)/length(the_union)
- jaccard_matrix[cluster1,cluster2] = jaccard
- if (jaccard >= 33.3) {
- jaccard_threshold[cluster1, cluster2] = 1
- }
- else {
- jaccard_threshold[cluster1, cluster2] = 0
- }
- }
- }
- }
- jaccard_adjacency <- matrix(nrow=length(the_clusters), ncol=length(the_clusters))
- colnames(jaccard_adjacency) <- the_clusters
- rownames(jaccard_adjacency) <- the_clusters
- for (cluster1 in the_clusters) {
- for (cluster2 in the_clusters) {
- subset1 <- unique(subset(wilcox_markers, wilcox_markers$cluster == cluster1)$gene)
- subset2 <- unique(subset(wilcox_markers, wilcox_markers$cluster == cluster2)$gene)
- the_intersection <- intersect(subset1, subset2)
- the_union <- union(subset1, subset2)
- jaccard <- 100*length(the_intersection)/length(the_union)
- if (cluster1 == cluster2) {
- jaccard_adjacency[cluster1, cluster2] = 0
- }
- else if (jaccard >= percentage_threshold) {
- jaccard_adjacency[cluster1, cluster2] = 1
- }
- else {
- jaccard_adjacency[cluster1, cluster2] = 0
- }
- }
- }
- set.seed(123)
- tg <- graph_from_adjacency_matrix(jaccard_adjacency, mode='undirected')
- saveRDS(tg, paste0(prefix,'_test_graph.rds'))
- saveRDS(jaccard_matrix, paste0(prefix,'_jaccard_matrix.rds'))
- write.table(jaccard_matrix, file=paste0(prefix,'_jaccard_wilcox_matrix.txt'), quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- write.table(jaccard_threshold, file=paste0(prefix,'_jaccard_wilcox_threshold.txt'), quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- pdf(paste0('mouse_clustering_evaluation/cci_seurat_lt_pca_',pca_dims,'_res_',res,'_test_graph.pdf'), width=4.5, height=4.5)
- plot.igraph(tg,vertex.color = "orange",vertex.size=15,vertex.frame.color = "black",vertex.label.cex=0.75, layout=layout_with_fr(tg, niter=10000))
- dev.off()
- return(list(mat = jaccard_matrix, adj = jaccard_adjacency, test_graph = tg))
- }
- iter_frame <- data.frame(dim_options = c("20","30","30","50","50","50","50","50","50","50","50"),
- res_options=c("0.9","1","1.1","0.4","0.5","0.6","0.7","0.8","1.1","1.2","1.3"))
- for (i in 1:nrow(iter_frame)) {
- dim_option <- iter_frame[i,]$dim_options
- res_option <- iter_frame[i,]$res_options
- the_markers <- markers_function(dim_option,res_option)
- jaccard <- jaccard_function(the_markers$subset_markers,dim_option,res_option)
- }
- ####MERGE CLUSTERS BASED ON ABOVE#####
- if (!dir.exists('mouse_merged_cluster_compare_fraction')) {
- dir.create('mouse_merged_cluster_compare_fraction')
- }
- if (!dir.exists('mouse_merged_clusters')) {
- dir.create('mouse_merged_clusters')
- }
- iter_frame <- data.frame(dim_options = c("20","30","30","50","50","50","50","50","50","50","50"),
- res_options=c("0.9","1","1.1","0.4","0.5","0.6","0.7","0.8","1.1","1.2","1.3"))
- for (i in 1:nrow(iter_frame)) {
- dim_option <- iter_frame[i,]$dim_options
- res_option <- iter_frame[i,]$res_options
- lookup_1 <- clusters(readRDS(paste0('mouse_clustering_evaluation/cci_seurat_lt_pca_',dim_option,'_res_',res_option,'_test_graph.rds')))$membership
- #now if we are on a new dimension seurat object, we open that file
- if(i==1) {
- cci_seurat <- readRDS(paste0('mouse_initial_UMAPs/cci_seurat_lt_pca_',dim_option,'_UMAP.rds'))
- }
- else if(!(iter_frame[i,]$dim_options == iter_frame[i-1,]$dim_options)) {
- cci_seurat <- readRDS(paste0('mouse_initial_UMAPs/cci_seurat_lt_pca_',dim_option,'_UMAP.rds'))
- }
- merged_clusters <- data.frame(x=lookup_1[as.character([email hidden][[paste0('res_',res_option)]])]) #make a data frame converting the celltype clusters to the celltype names
- rownames(merged_clusters) <- rownames([email hidden])#add the cell row names there
- column_name <- paste0("merged_clusters_",res_option)
- colnames(merged_clusters) <- column_name #rename column
- cci_seurat <- AddMetaData(cci_seurat, merged_clusters) #add this to the meta data
- dimplot_by_column_name <- DimPlot(cci_seurat,reduction='umap', group.by=column_name, label=TRUE, label.size=3,label.box=TRUE, repel=TRUE, pt.size=1,raster=TRUE)+umap_theme+labs(x='UMAP 1',y='UMAP 2') #plot by cluster
- ggsave(paste0('mouse_merged_clusters/mouse_merged_clusters_',dim_option,'_',res_option,'.pdf'), plot=dimplot_by_column_name, width=7, height=7, units='cm', dpi=600)
- merged_cluster_compare <- table(data.frame(clusters=[email hidden][[column_name]], celltypes=[email hidden]$celltype_lab))
- merged_cluster_compare_fraction <- sweep(merged_cluster_compare, 2, colSums(merged_cluster_compare), FUN='/')
- write.table(merged_cluster_compare_fraction, paste0('mouse_merged_cluster_compare_fraction/cci_seurat_lt_pca_',dim_option,'_merged_cluster_compare_fraction_',res_option,'.txt'),quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- #if we have finished that dimension seurat object, we can finally save that file
- if(i==nrow(iter_frame)) {
- saveRDS(cci_seurat, paste0('mouse_merged_clusters/cci_seurat_lt_pca_',dim_option,'_mergedclusters.rds'))
- }
- else if(!(iter_frame[i,]$dim_options == iter_frame[i+1,]$dim_options)) {
- saveRDS(cci_seurat, paste0('mouse_merged_clusters/cci_seurat_lt_pca_',dim_option,'_mergedclusters.rds'))
- }
- }
- #####SECOND MERGE: BASED ON MERGING IN LOW FIDELITY CLUSTERS#####
- ##One thing we notice after the new clusters are made is that some of them are low fidelity.
- #That is, their maximum value in any given cell type cluster is quite low.
- #We arbitrarily set the cutoff that if the maximum a given cluster contributes to the assignment of a cell type is < 20%, it should be merged with its closest cluster based on jaccard.
- #This tells us which clusters will need to be recast in this way.
- if (!dir.exists('mouse_merged_cluster_compare_fraction/cluster_assignment_scores')) {
- dir.create('mouse_merged_cluster_compare_fraction/cluster_assignment_scores')
- }
- umap_theme <- theme(plot.title=element_blank(),
- panel.background=element_blank(),
- axis.line=element_line(colour='black',linewidth=0.3),
- axis.ticks=element_line(color='black',linewidth=0.3),
- axis.text=element_text(size=6,colour='black'),
- legend.title=element_blank(),legend.text=element_text(size=6, colour='black'),
- legend.position='none',title=element_blank(),
- axis.title=element_text(size=6,colour='black'))
- merged_cluster_compare_files <- list.files('mouse_merged_cluster_compare_fraction')
- for (the_file in merged_cluster_compare_files) {
- if (!the_file=='cluster_assignment_scores') {
- temp_table <- read.table(paste0('mouse_merged_cluster_compare_fraction/',the_file), header=TRUE)
- temp_table_t <- as.data.frame(t(temp_table))
- the_scores <- data.frame(cluster=c(), scores=c())
- for (the_col in colnames(temp_table_t)) {
- temp_frame <- data.frame(cluster=c(the_col), scores=c(max(temp_table_t[[the_col]])))
- the_scores <- rbind(the_scores, temp_frame)
- }
- write.table(the_scores, paste0('mouse_merged_cluster_compare_fraction/cluster_assignment_scores/cluster_assignment_scores_',the_file), quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- }
- }
- #The algorithm for evaluating this first we identify what original cluster the merged cluster maps from.
- #Then we find near neighbors of that cluster based on jaccard, and consider as potential candidates those clusters that have a jaccard >= 0.2.
- #Then we find the average jaccard for the clusters to which that cluster belongs, and we select the one for which this cluster has the highest average jaccard.
- cluster_assignment_score_files <- list.files('mouse_merged_cluster_compare_fraction/cluster_assignment_scores')
- reassignment_function <- function(the_dim, the_res, lookup) {
- cluster_scores <- as.data.frame(read.table(paste0("mouse_merged_cluster_compare_fraction/cluster_assignment_scores/cluster_assignment_scores_cci_seurat_lt_pca_",the_dim,'_merged_cluster_compare_fraction_',the_res,'.txt'), header=TRUE))
- poor_clusters <- subset(cluster_scores, scores < 0.2) #find the clusters with poor scores
- jaccard_matrix <- read.table(paste0('mouse_clustering_evaluation/cci_seurat_lt_pca_',the_dim,'_res_',the_res,'_jaccard_wilcox_matrix.txt'),header=TRUE) #we will use the original jaccard matrix below
- jaccard_matrix_t <- as.data.frame(t(jaccard_matrix)) #the transposed matrix is also useful
- message("These are the poor clusters:")
- print(poor_clusters)
- cluster_assignments <- c()
- for (the_cluster in poor_clusters$cluster) { #for every poor scoring cluster
- original_cluster <- names(which(lookup == as.character(the_cluster))) #first find out what the original cluster is that it is associated with. This is not designed to work on clusters that are associated with more than one original cluster
- message(paste0("For the cluster ",the_cluster," the original cluster is ",original_cluster))
- if (length(original_cluster) > 1) {
- stop("This merged cluster arises from more than one original cluster. Cannot be handled by current algorithm.")
- }
- #now we reassemble the set of jaccard scores for the original cluster
- beginning <- na.omit(jaccard_matrix[[paste0('X',original_cluster)]])
- end <- na.omit(jaccard_matrix_t[[original_cluster]])
- jaccard_scores <- c(beginning,NA,end)
- print(jaccard_scores)
- #we only want to look at the jaccard scores >= 20 as being good potential merge candidates
- jaccard_scores_select <- jaccard_scores[jaccard_scores >=20 & !(jaccard_scores %in% NA)]
- select_clusters <- as.character(which(jaccard_scores %in% jaccard_scores_select)-1) #Find the indices associated with the high scoring jaccards and then subtract one to get the corresponding cluster
- if (length(select_clusters) > 0) {
- message(paste0("These original clusters have high associated scores with original cluster ",original_cluster))
- print(select_clusters)
- merged_cluster_candidates <- c()
- for (select_cluster in select_clusters) {
- merged_cluster_candidates <- c(merged_cluster_candidates, lookup[[select_cluster]])
- }
- merged_cluster_candidates <- unique(merged_cluster_candidates)
- message("These merged clusters are associated with those original clusters, and may be candidates to merge into:")
- print(merged_cluster_candidates)
- candidate_scores = c()
- for (merged_candidate in merged_cluster_candidates) {
- candidate_clusters <- as.numeric(names(which(lookup==merged_candidate)))
- candidate_scores[[as.character(merged_candidate)]] <- mean(jaccard_scores[candidate_clusters+1])
- }
- candidate_scores <- as.data.frame(candidate_scores)
- winning_merge_candidate <- merged_cluster_candidates[which(candidate_scores == max(candidate_scores))]
- message(paste0("Merge original cluster ", original_cluster," into merged cluster ", winning_merge_candidate))
- cluster_assignments[[original_cluster]] <- winning_merge_candidate
- }
- else {message('There are not other original clusters highly associated with ',original_cluster)}
- }
- lookup_2 <- lookup
- for (original_cluster in names(cluster_assignments)) {
- lookup_2[[original_cluster]] <- cluster_assignments[[original_cluster]]
- }
- print(lookup_2)
- lookup_lookup <- seq(1, length(unique(lookup_2)), 1)
- names(lookup_lookup) <- sort(unique(lookup_2))
- lookup_3 <- lookup_lookup[as.character(lookup_2)]
- names(lookup_3) <- names(lookup_2)
- return(lookup_3)
- }
- ##Now I re-do the assignments
- if (!dir.exists('mouse_recluster')) {
- dir.create('mouse_recluster')
- }
- iter_frame <- data.frame(dim_options = c("20","30","30","50","50","50","50","50","50","50","50"),
- res_options=c("0.9","1","1.1","0.4","0.5","0.6","0.7","0.8","1.1","1.2","1.3"))
- iter_frame <- data.frame(dim_options = c("50"),
- res_options=c("0.5"))
- for (i in 1:nrow(iter_frame)) {
- dim_option <- iter_frame[i,]$dim_options
- res_option <- iter_frame[i,]$res_options
- if(i==1) {
- cci_seurat <- readRDS(paste0('mouse_merged_clusters/cci_seurat_lt_pca_',dim_option,'_mergedclusters.rds'))
- }
- else if(!(iter_frame[i,]$dim_options == iter_frame[i-1,]$dim_options)) {
- cci_seurat <- readRDS(paste0('mouse_merged_clusters/cci_seurat_lt_pca_',dim_option,'_mergedclusters.rds'))
- }
- lookup_1 <- clusters(readRDS(paste0('mouse_clustering_evaluation/cci_seurat_lt_pca_',dim_option,'_res_',res_option,'_test_graph.rds')))$membership
- new_lookup <- reassignment_function(dim_option, res_option, lookup_1)
- merged_clusters <- data.frame(x=new_lookup[as.character([email hidden][[paste0('res_',res_option)]])])#make a data frame converting the celltype clusters to the celltype names
- rownames(merged_clusters) <- rownames([email hidden])#add the cell row names there
- column_name <- paste0("recluster_merged_clusters_",res_option)
- colnames(merged_clusters) <- column_name #rename column
- cci_seurat <- AddMetaData(cci_seurat, merged_clusters) #add this to the meta data
- dimplot_by_column_name <- DimPlot(cci_seurat,reduction='umap', group.by=column_name, label=TRUE, label.size=3,label.box=TRUE, repel=TRUE, pt.size=1,raster=TRUE)+umap_theme+labs(x='UMAP 1',y='UMAP 2') #plot by cluster
- ggsave(paste0('mouse_recluster/test_mouse_recluster_merged_clusters_',dim_option,'_',res_option,'_UMAP.pdf'), plot=dimplot_by_column_name, width=7, height=7, units='cm', dpi=600)
- merged_cluster_compare <- table(data.frame(clusters=[email hidden][[column_name]], celltypes=[email hidden]$celltype_lab))
- merged_cluster_compare_fraction <- sweep(merged_cluster_compare, 2, colSums(merged_cluster_compare), FUN='/')
- write.table(merged_cluster_compare_fraction, paste0('mouse_recluster/test_recluster_cci_seurat_lt_pca_',dim_option,'_merged_cluster_compare_fraction_',res_option,'.txt'),quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- if(i==nrow(iter_frame)) {
- saveRDS(cci_seurat, paste0('mouse_recluster/test_cci_seurat_lt_pca_',dim_option,'_recluster.rds'))
- }
- else if(!(iter_frame[i,]$dim_options == iter_frame[i+1,]$dim_options)) {
- saveRDS(cci_seurat, paste0('mouse_recluster/test_cci_seurat_lt_pca_',dim_option,'_recluster.rds'))
- }
- }
- #####FIND MARKERS ON THE NEW CLUSTERS#####
- cci_seurat_lt_pca_50_merged <- readRDS('mouse_recluster/cci_seurat_lt_pca_50_recluster.rds')
- Idents(cci_seurat_lt_pca_50_merged) <- 'recluster_merged_clusters_0.5'
- Idents(cci_seurat_lt_pca_50_merged) <- factor(Idents(cci_seurat_lt_pca_50_merged), levels=order(unique(Idents(cci_seurat_lt_pca_50_merged))))
- the_markers_wilcox <- FindAllMarkers(cci_seurat_lt_pca_50_merged, logfc.threshold=-Inf, min.pct=-Inf, genes.use=row.names(cci_seurat_lt_pca_50_merged)) #first calculate all the wilcox scores. Note that we use the library presto to speed up computation as suggested by Seurat.
- write.table(the_markers_wilcox, file='cci_seurat_lt_pca_50_merged_wilcox_markers.txt', quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- the_markers_wilcox_subset <- subset(the_markers_wilcox, the_markers_wilcox$p_val_adj < 0.05 & the_markers_wilcox$avg_log2FC >= 0.585 & the_markers_wilcox$pct.1 >= 0.5) #we then subset for those that are significant, with at least 1.5 fold change, and that are present in at least 50% of cells in the cluster.
- write.table(the_markers_wilcox_subset, file='cci_seurat_lt_pca_50_merged_wilcox_markers_significant.txt', quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- test_markers_wilcox_subset <- subset(the_markers_wilcox, the_markers_wilcox$p_val_adj < 0.05 & the_markers_wilcox$avg_log2FC >= 0.585 & the_markers_wilcox$pct.1 >= 0.5 & the_markers_wilcox$pct.1/the_markers_wilcox$pct.2 > 1) #we then subset for those that are significant, with at least 1.5 fold change, and that are present in at least 50% of cells in the cluster.
- table(test_markers_wilcox_subset$cluster)
- write.table(test_markers_wilcox_subset, file='test_cci_seurat_lt_pca_50_merged_wilcox_markers_significant.txt', quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- test_markers_wilcox_subset <- cbind(test_markers_wilcox_subset, data.frame(ratio=test_markers_wilcox_subset$pct.1/test_markers_wilcox_subset$pct.2))
- ##now we select the test_features to put in the dot plot. This is based on the top features for each cluster, ranked by the ratio of pct.1 to everything else (pct.2)
- the_clusters <- order(unique(test_markers_wilcox_subset$cluster))
- test_features <- c()
- for (the_cluster in the_clusters) {
- temp_subset <- subset(test_markers_wilcox_subset, cluster %in% the_cluster)
- temp_subset <- temp_subset[order(temp_subset$avg_log2FC, decreasing=TRUE),]
- test_features <- c(test_features,temp_subset[1:2,]$gene)
- }
- dotplot_legend_theme <- theme(plot.title=element_blank(),
- panel.background=element_blank(),
- axis.line=element_line(colour='black',linewidth=0.3),
- axis.ticks=element_line(color='black',linewidth=0.3),
- axis.text=element_text(size=6,colour='black'),
- title=element_blank(),
- axis.title=element_text(size=6,colour='black'), legend.text = element_text(size=6, colour='black'))
- dotplot <- DotPlot(cci_seurat_lt_pca_50_merged, features = test_features, dot.scale=3) + RotatedAxis()+dotplot_legend_theme
- ggsave('mouse_dotplot.pdf', plot=dotplot, width=9, height=7, units='cm', dpi=600)
- #Cluster Fraction Per Cell Type
- recluster_compare_0.5 <- table(data.frame(clusters=[email hidden]$recluster_merged_clusters_0.5, celltypes=[email hidden]$celltype_lab))
- recluster_compare_fraction_0.5 <- sweep(recluster_compare_0.5, 2, colSums(recluster_compare_0.5), FUN='/')
- pdf('mouse_cluster_fraction_per_celltype.pdf', width=3.9839, height=2.0617)
- Heatmap(recluster_compare_fraction_0.5,
- circlize::colorRamp2(seq(0,1,.01), colorRampPalette(rev(brewer.pal(n=7, name='RdYlBu')))(101)), na_col='#EEEEEE',
- column_names_gp=gpar(fontsize=6), row_names_gp = gpar(fontsize = 6),
- cluster_rows=TRUE, cluster_columns=TRUE,
- heatmap_legend_param = list(
- title = "Cluster Fraction Per Cell Type", at = c(0,0.5,1),
- title_position='leftcenter-rot',
- title_gp=gpar(fontsize=6, fontface='plain'),
- labels_gp=gpar(fontsize=6)))
- dev.off()
- #Cluster Fraction Per Condition
- recluster_compare_0.5_condition <- table(data.frame(clusters=[email hidden]$recluster_merged_clusters_0.5, celltypes=[email hidden]$orig.ident))
- recluster_compare_fraction_0.5_condition <- sweep(recluster_compare_0.5_condition, 2, colSums(recluster_compare_0.5_condition), FUN='/')
- pdf('mouse_cluster_fraction_per_condition.pdf', width=2.094, height=2.13)
- Heatmap(recluster_compare_fraction_0.5_condition,
- circlize::colorRamp2(seq(0,1,.01), colorRampPalette(rev(brewer.pal(n=7, name='RdYlBu')))(101)), na_col='#EEEEEE',
- column_names_gp=gpar(fontsize=6), row_names_gp = gpar(fontsize = 6),
- cluster_rows=TRUE, cluster_columns=TRUE,
- heatmap_legend_param = list(
- title = "Cluster Fraction Per Condition", at = c(0,0.5,1),
- title_position='leftcenter-rot',
- title_gp=gpar(fontsize=6, fontface='plain'),
- labels_gp=gpar(fontsize=6)))
- dev.off()
- umap_theme <- theme(plot.title=element_blank(),
- panel.background=element_blank(),
- axis.line=element_line(colour='black',linewidth=0.3),
- axis.ticks=element_line(color='black',linewidth=0.3),
- axis.text=element_text(size=6,colour='black'),
- legend.title=element_blank(),legend.text=element_text(size=6, colour='black'),
- legend.position='none',title=element_blank(),
- axis.title=element_text(size=6,colour='black'))
- dimplot_by_recluster_merged_clusters <- DimPlot(cci_seurat_lt_pca_50_merged,reduction='umap', group.by="recluster_merged_clusters_0.5", label=TRUE, label.size=2,label.box=TRUE, repel=TRUE, pt.size=1,raster=TRUE)+umap_theme+labs(x='UMAP 1',y='UMAP 2') #plot by cluster
- ggsave('test_mouse_recluster_merged_clusters_0.5_UMAP.pdf', plot=dimplot_by_recluster_merged_clusters, width=7, height=7, units='cm', dpi=600)
- dimplot_by_recluster_merged_clusters <- DimPlot(cci_seurat_lt_pca_50_merged,reduction='umap', group.by="celltype_lab", label=TRUE, label.size=2,label.box=TRUE, repel=TRUE, pt.size=1,raster=TRUE)+umap_theme+labs(x='UMAP 1',y='UMAP 2') #plot by cluster
- ggsave('mouse_recluster_merged_clusters_0.5_UMAP_by_celltype_lab.pdf', plot=dimplot_by_recluster_merged_clusters, width=7, height=7, units='cm', dpi=600)
- dimplot_by_recluster_merged_clusters <- DimPlot(cci_seurat_lt_pca_50_merged,reduction='umap', group.by="condition", label=TRUE, label.size=2,label.box=TRUE, repel=TRUE, pt.size=1,raster=TRUE)+umap_theme+labs(x='UMAP 1',y='UMAP 2') #plot by cluster
- ggsave('mouse_recluster_merged_clusters_0.5_UMAP_by_condition.pdf', plot=dimplot_by_recluster_merged_clusters, width=7, height=7, units='cm', dpi=600)
- #####PREP OBJECTS FOR GSEA#####
- #I now prep seurat objects that can be used for GSEA (they contain the new clustering, but on objects that have all the genes)
- #First I apply the new clusters onto a seurat object that hs all the genes
- cci_recluster <- readRDS('mouse_recluster/cci_seurat_lt_pca_50_recluster.rds')
- cci_pre <- readRDS('cci_seurat_pre.rds')
- recluster <- data.frame(recluster=[email hidden]$recluster_merged_clusters_0.5) #make a data frame converting the celltype clusters to the celltype names
- rownames(recluster) <- rownames([email hidden]) #add the cell row names there
- cci_pre <- AddMetaData(cci_pre, recluster)
- #now I normalize that seurat object
- cci_pre <- NormalizeData(cci_pre)
- all.genes <- rownames(cci_pre) #all the genes in the seurat object
- cci_pre <- ScaleData(cci_pre, features=all.genes)
- cci_pre <- FindVariableFeatures(cci_pre, selection.method = "vst") #I just want to check how much variance the PCA explains if you use the most variable genes
- cci_pre <- RunPCA(cci_pre, npcs=100) #this does PCA on variable genes only
- saveRDS(cci_pre, 'cci_pre_scaled.rds')
- #####FGSEA WITHIN CELL TYPES/CLUSTERS USING FINDALLMARKERS#####
- if (!dir.exists('gsea_results')) {
- dir.create('gsea_results')
- }
- fgsea_pathways <- gmtPathways("PN_limited_branchclass.gmt") #this is the file that will be used as gsea pathways
- #First use FindAllMarkers so I can have a log2FC for all the genes
- the_idents <- c('celltype_col', 'recluster') #I will do GSEA on groups of cell subtypes and each of the clusters
- for (the_ident in the_idents) {
- Idents(object = cci_pre) <- the_ident
- the_markers_wilcox <- FindAllMarkers(cci_pre, logfc.threshold=-Inf, min.pct=-Inf, genes.use=row.names(cci_pre))
- write.table(the_markers_wilcox, file=paste0('cci_pre_',the_ident,'_merged_wilcox_markers.txt'), quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- }
- #Now I loop through the files and run them through fgsea
- for (the_ident in the_idents) {
- groups <- unique([email hidden][[the_ident]])
- the_markers <- as.data.frame(read.table(paste0('cci_pre_',the_ident,'_merged_wilcox_markers.txt'), sep='\t',header=TRUE,row.names=1))
- for (group in groups) {
- key <- paste0(the_ident,"_",group)
- print(group)
- markers_subset <- subset(the_markers, cluster == group)
- rank_stat_matrix <- matrix(markers_subset$avg_log2FC)
- rownames(rank_stat_matrix) <- markers_subset$gene
- fgsea_stat_ranks <- setNames(markers_subset$avg_log2FC, markers_subset$gene)
- fgseaRes_stat <- fgsea(fgsea_pathways, fgsea_stat_ranks, minSize=10, maxSize=10000, nPermSimple=50000, scoreType="pos") #I use scoretype=pos here because I am really trying to find pathways that define these clusters, so the ones that are enriched, as opposed to ones that are downregulated.
- fwrite(fgseaRes_stat, file=paste0('branchclass_',key,'_stat_fgsea.tsv'), sep='\t', sep2=c(""," ",""))
- write.table(rank_stat_matrix,file=paste0('branchclass_rank_stat_matrix_',key,'.rnk'),sep='\t',col.names=FALSE,quote=FALSE)
- }
- }
- #Now this is the plotting
- the_idents <- c('recluster','celltype_col')
- size_frame <- data.frame(recluster=c(4.383,5.175),
- celltype_col=c(5.565,6.14))
- for (the_ident in the_idents) {
- groups <- unique([email hidden][[the_ident]])
- the_pathways <- c()
- exclude_list <- c()
- for (group in groups) {
- key <- paste0(the_ident,"_",group)
- gsea_table <- read.table(paste0('gsea_results/branchclass_',key,'_stat_fgsea.tsv'), sep='\t', header=TRUE)
- gsea_table <- subset(gsea_table, padj < 0.05) #I take the subset of significant pathways for each of the files
- if (length(rownames(gsea_table)) == 0) {
- exclude_list <- c(exclude_list, key) #if a file has no significant pathways, it will not be plotted later
- }
- the_pathways <- c(the_pathways, gsea_table$pathway)
- }
- the_pathways <- unique(the_pathways)
- NES_subset <- list()
- for (group in groups) {
- key <- paste0(the_ident,"_",group)
- if (!(key %in% exclude_list)) {
- gsea_table <- read.table(paste0('gsea_results/branchclass_',key,'_stat_fgsea.tsv'), sep='\t', row.names=1, header=TRUE)
- gsea_table <- gsea_table[the_pathways,]
- p_filter <- gsea_table$padj < 0.1
- NES_temp <- gsea_table$NES
- NES_temp[!p_filter] <- 0 #I am basically going to plot the NES as 0 if the padj ≥ 0.1
- NES_subset[[key]] <- NES_temp
- }
- }
- NES_subset <- as.data.frame(NES_subset)
- row.names(NES_subset) <- the_pathways
- NES_subset <- NES_subset[order(row.names(NES_subset)), ]
- write.table(NES_subset, paste0('mouse_',the_ident,'_NES_subset.txt'), sep='\t', quote=FALSE)
- pdf(paste0('mouse_',the_ident,'_GSEA_heatmap.pdf'), width=size_frame[[the_ident]][1], height=size_frame[[the_ident]][2])
- draw(pheatmap(as.matrix(NES_subset), fontsize=6, treeheight_row=10, treeheight_col=10, border_color=NA))
- dev.off()
- }
- #Here I plot the analysis just for microglia
- groups <- c('Microglia_1', 'Microglia_2', 'Microglia_3', 'Microglia_4', 'Microglia_5', 'Microglia_6', 'Microglia_7', 'Microglia_8')
- the_pathways <- c()
- the_ident <- 'celltype_col'
- for (group in groups) {
- key <- paste0(the_ident,"_",group)
- gsea_table <- read.table(paste0('gsea_results/branchclass_',key,'_stat_fgsea.tsv'), sep='\t', header=TRUE)
- gsea_table <- subset(gsea_table, padj < 0.05)
- # gsea_table <- subset(gsea_table, !(grepl('Translation_*', pathway)))
- the_pathways <- c(the_pathways, gsea_table$pathway)
- }
- the_pathways <- unique(the_pathways)
- NES_subset <- list()
- for (group in groups) {
- key <- paste0(the_ident,"_",group)
- gsea_table <- read.table(paste0('gsea_results/branchclass_',key,'_stat_fgsea.tsv'), sep='\t', row.names=1, header=TRUE)
- gsea_table <- gsea_table[the_pathways,]
- p_filter <- gsea_table$padj < 0.1
- NES_temp <- gsea_table$NES
- NES_temp[!p_filter] <- 0
- NES_subset[[key]] <- NES_temp
- }
- NES_subset <- as.data.frame(NES_subset)
- row.names(NES_subset) <- the_pathways
- NES_subset <- NES_subset[order(row.names(NES_subset)), ]
- write.table(NES_subset, 'NES_subset.txt', sep='\t', quote=FALSE)
- pdf(paste0('microglia_GSEA_heatmap.pdf'), width=4.501, height=4.96)
- draw(pheatmap(as.matrix(NES_subset), fontsize=6, treeheight_row=10, treeheight_col=10, border_color=NA))
- dev.off()
- #####FGSEA BETWEEN NAIVE AND CCI USING PSEUDOBULK#####
- if (!dir.exists('pseudobulk')) {
- dir.create('pseudobulk')
- }
- cci_seurat <- readRDS('cci_pre_scaled.rds')
- pseudobulk_process <- function(seurat_object, group_by, condition_start_string, condition_end_string) {
- pseudo_seurat <- AggregateExpression(seurat_object, assays="RNA", return.seurat=T, group.by = c('orig.ident', group_by))
- pseudo_seurat$condition <- substr(pseudo_seurat$orig.ident, condition_start_string, condition_end_string)
- return(pseudo_seurat)
- }
- results_output <- function(pseudobulk_object, group_by, pathways_file, p_threshold, lfc_threshold, contrast1, contrast2, select_split, split_index) {
- cell_type_list <- unique([email hidden][[group_by]])
- counts_object <- pseudobulk_object[['RNA']]$counts #we are using the raw counts matrix after pseudobulk for our analysis
- print(colnames(counts_object))
- resAsh_list <- list()
- for (cell_type in cell_type_list) {#loop on cell type
- #set up the DESeq2 sample table
- select_list = grep(glob2rx(paste0('*',cell_type)), colnames(counts_object), value=TRUE)
- print(select_list)
- countData <- counts_object[, select_list]
- cond_list = c()
- for (select in select_list) {
- cond_list = c(cond_list, strsplit(select, select_split)[[1]][split_index])
- }
- sample_table <- data.frame(Condition=factor(cond_list))
- row.names(sample_table) <- colnames(countData)
- print(sample_table)
- #DESeq2
- dds <- DESeqDataSetFromMatrix(countData=countData, colData=sample_table, design=~Condition) #DeSeq design matrix, we only use condition as a variable, and then we do the analysis on each gene separately
- ##filter out some genes
- keep <- rowSums(counts(dds) >=10) >= 3 #selected based on it being the smallest group size in any given sample
- dds <- dds[keep]
- dds1 <- DESeq(dds)
- ##generate results table
- resAsh <- lfcShrink(dds1, contrast=c('Condition',contrast1,contrast2), type='ashr', alpha=p_threshold, lfcThreshold=lfc_threshold) #perform lfcShrink, I prefer ashr because of the format of the comparisons
- print(length(rownames(resAsh)))
- resAsh_list[[cell_type]] <- resAsh #assign this to a list where we store all the differential expression data
- #GSEA
- ##based on various suggestions, including this one from Anthony Castanza at GSEA (https://groups.google.com/g/gsea-help/c/UUNzkRPbvz4), we use stat as the metric.
- fgsea_pathways <- gmtPathways(pathways_file) #this is the file that will be used as gsea pathways
- rank_stat_matrix <- matrix(resAsh$stat)
- rownames(rank_stat_matrix) <- row.names(resAsh)
- fgsea_stat_ranks <- setNames(resAsh$stat, row.names(resAsh))
- fgseaRes_stat <- fgsea(fgsea_pathways, fgsea_stat_ranks, minSize=10, maxSize=10000, nPermSimple=50000) #number of permutations based on recommendations from the package GOAT
- fwrite(fgseaRes_stat, file=paste0('pseudobulk/',cell_type,'_stat_fgsea.tsv'),sep='\t',sep2=c(""," ",""))
- #output files
- write.table(rank_stat_matrix,file=paste0('pseudobulk/branchclass_rank_stat_matrix_',cell_type,'.rnk'),sep='\t',col.names=FALSE,quote=FALSE)
- write.table(resAsh, file=paste0('pseudobulk/branchclass_',cell_type,'_resAsh.tsv'),sep='\t',row.names=TRUE, col.names=NA, quote=FALSE)
- }
- return(resAsh_list)
- }
- the_groups <- c('recluster','celltype_col')
- for (group_by_cat in the_groups) {
- pseudo_seurat <- pseudobulk_process(cci_seurat, group_by_cat, 1, 3)
- resAsh_list <- results_output(pseudobulk_object=pseudo_seurat, group_by=group_by_cat, pathways_file='PN_limited_branchclass.gmt',p_threshold=0.01, lfc_threshold=0.585, contrast1='CCI', contrast2='Naive', select_split='-',split_index=1)
- }
- size_frame <- data.frame(recluster=c(6,6),
- celltype_col=c(6,6))
- for (group_by_cat in the_groups) {
- exclude_list <- c()
- for (group in unique([email hidden][[group_by_cat]])) {
- temp_subset <- subset([email hidden], [email hidden][[group_by_cat]]==group)
- print(group)
- print(table(temp_subset$orig.ident))
- if (min(table(temp_subset$orig.ident)) < 10) {
- exclude_list <- c(exclude_list, group)
- }
- }
- print(exclude_list)
- if (group_by_cat == 'celltype_col') {
- celltypes <- c('Microglia-1','Microglia-2','Microglia-3','Microglia-4','Microglia-5','Microglia-6','Microglia-7','Microglia-8',
- 'Astrocytes','Neurons','Ependymal-1','Ependymal-2','Ependymal-3','Ependymal-4','Ependymal-5',
- 'Endothelial-1','Endothelial-2','Neutrophils-1','Neutrophils-2','BCells','TmemoryCells','NKcells')
- }
- else {
- celltypes = c('1','2','3','4','5','6','7','8','9','10')
- }
- the_pathways <- c()
- for (celltype in celltypes) {
- gsea_table <- read.table(paste0('pseudobulk/',celltype,'_stat_fgsea.tsv'), sep='\t', header=TRUE)
- gsea_table <- subset(gsea_table, padj < 0.05)
- if (length(rownames(gsea_table)) == 0) {
- exclude_list <- c(exclude_list, celltype)
- }
- the_pathways <- c(the_pathways, gsea_table$pathway)
- }
- exclude_list <- unique(exclude_list)
- the_pathways <- unique(the_pathways)
- NES_subset <- list()
- for (celltype in celltypes) {
- if (!(celltype %in% exclude_list)) {
- gsea_table <- read.table(paste0('pseudobulk/',celltype,'_stat_fgsea.tsv'), sep='\t', row.names=1, header=TRUE)
- gsea_table <- gsea_table[the_pathways,]
- p_filter <- gsea_table$padj < 0.1
- NES_temp <- gsea_table$NES
- NES_temp[!p_filter] <- 0
- NES_subset[[celltype]] <- NES_temp
- }
- }
- NES_subset <- as.data.frame(NES_subset)
- row.names(NES_subset) <- the_pathways
- NES_subset <- NES_subset[order(row.names(NES_subset)), ]
- write.table(NES_subset, paste0('pseudobulk/mouse_pseudobulk_',group_by_cat,'_NES_subset.txt'), sep='\t', quote=FALSE)
- pdf(paste0('pseudobulk/mouse_pseudobulk_',group_by_cat,'_NES_heatmap.pdf'),width=6, height=6)
- draw(pheatmap(as.matrix(NES_subset),fontsize=6, treeheight_row=10, treeheight_col=10, border_color=NA,cellwidth=8.54,cellheight=8.54))
- dev.off()
- }
- #####BASIC FEATURES#####
- if (!dir.exists('mouse_basic_features')) {
- dir.create('mouse_basic_features')
- }
- cci_seurat_pre_PN <- readRDS("cci_seurat_pre_PN.rds")
- read_count_function_1 <- function(row) {
- the_table <- table(row)
- low_count <- sum(as.numeric(the_table[names(the_table) ==0]))
- non_low_count <- length(row)-low_count
- fraction_non_low <- non_low_count/length(row)
- return(fraction_non_low)
- }
- #What is the common PN in naive
- naive_only <- subset(cci_seurat_pre_PN,[email hidden]$condition=='Naive')
- naive_common_list <- c()
- for (ct in unique([email hidden]$celltype_altcat)) {
- subset_seurat <- subset(naive_only, [email hidden]$celltype_altcat==ct)
- print(ct)
- print(length(colnames(subset_seurat)))
- expression_matrix <- subset_seurat[['RNA']]$counts
- fraction_high <- apply(expression_matrix, 1, read_count_function_1)
- subset_high <- subset(fraction_high, fraction_high > 0.5)
- if (length(naive_common_list) == 0) {
- naive_common_list <- names(subset_high)
- }
- else {
- naive_common_list <- intersect(naive_common_list, names(subset_high))
- }
- write.table(fraction_high,paste0('mouse_basic_features/naive_fraction_',ct,'.txt'), sep='\t', quote=FALSE)
- write.table(subset_high,paste0('mouse_basic_features/naive_fraction>=0.5_',ct,'.txt'), sep='\t', quote=FALSE)
- }
- write.table(naive_common_list, 'mouse_basic_features/coreNaive_subPN.txt',sep='\t',quote=FALSE)
- #What is the common PN in CCI
- cci_only <- subset(cci_seurat_pre_PN,[email hidden]$condition=='CCI')
- cci_common_list <- c()
- for (ct in unique([email hidden]$celltype_altcat)) {
- subset_seurat <- subset(cci_only, [email hidden]$celltype_altcat==ct)
- print(ct)
- print(length(colnames(subset_seurat)))
- expression_matrix <- subset_seurat[['RNA']]$counts
- fraction_high <- apply(expression_matrix, 1, read_count_function_1)
- subset_high <- subset(fraction_high, fraction_high > 0.5)
- if (length(cci_common_list) == 0) {
- cci_common_list <- names(subset_high)
- }
- else {
- cci_common_list <- intersect(cci_common_list, names(subset_high))
- }
- write.table(fraction_high,paste0('mouse_basic_features/cci_fraction_',ct,'.txt'), sep='\t', quote=FALSE)
- write.table(subset_high,paste0('mouse_basic_features/cci_fraction>=0.5_',ct,'.txt'), sep='\t', quote=FALSE)
- }
- write.table(cci_common_list, 'mouse_basic_features/coreCCI_subPN.txt',sep='\t',quote=FALSE)
- #Unique in naive
- select_markers <- function(seurat_object, name_column, greater_than, less_than, the_folder, read_file) {
- unique_list <- c()
- for (ct1 in unique([email hidden][[name_column]])) {
- list_1 <- read.table(paste0(the_folder,'/',read_file,'_',ct1,'.txt'),sep='\t')
- list_1 <- row.names(subset(list_1, list_1$x >= greater_than))
- print(list_1)
- common_list = c()
- for (ct2 in unique([email hidden][[name_column]])) {
- if (!(ct1 == ct2)) {
- list_2 <- read.table(paste0(the_folder,'/',read_file,'_',ct2,'.txt'),sep='\t')
- list_2 <- row.names(subset(list_2, list_2$x <= less_than))
- if (length(common_list)==0) {
- common_list <- list_2
- }
- else {
- common_list <- intersect(common_list, list_2)
- }
- }
- }
- unique_list[[ct1]] <- list_1[(list_1 %in% common_list)]
- }
- return(unique_list)
- }
- cci_seurat_lt_pca_50_merged <- readRDS('mouse_recluster/cci_seurat_lt_pca_50_recluster.rds')
- Idents(cci_seurat_lt_pca_50_merged) <- 'condition'
- #Unique in naive
- ##Here we need to pull something in from later analysis to be able to sense check that these genes are actually up in naive
- naive_unique_list <- select_markers(naive_only, "celltype_altcat", 0.6, 0.4,'mouse_basic_features', 'naive_fraction')
- flat_naive_unique_list <- as.character(unlist(naive_unique_list))
- naive_markers <- FindMarkers(cci_seurat_lt_pca_50_merged, ident.1='Naive', ident.2='CCI', thresh.use=-Inf, min.pct=0, features=flat_naive_unique_list) #first calculate all the wilcox scores. Note that we use the library presto to speed up computation as suggested by Seurat.
- write.table(naive_markers, file='mouse_basic_features/naive_markers6040.txt', quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- exclude_naive_markers_1 <- row.names(subset(naive_markers, naive_markers$avg_log2FC <= 0))
- exclude_naive_markers_2 <- flat_naive_unique_list[!(flat_naive_unique_list %in% row.names(naive_markers))]
- exclude_naive_markers <- c(exclude_naive_markers_1,exclude_naive_markers_2)
- new_flat_naive_unique_list <- flat_naive_unique_list[!(flat_naive_unique_list %in% exclude_naive_markers)]
- naive_unique_list_6040 = c()
- for (ct1 in names(naive_unique_list)) {
- temp <- naive_unique_list[[ct1]]
- print(temp)
- naive_unique_list_6040[[ct1]] <- temp[!(temp %in% exclude_naive_markers)]
- }
- ##Now I am doing 50/50 so I can get my freqspec for naive
- naive_unique_list <- select_markers(naive_only, "celltype_altcat", 0.5, 0.5,'mouse_basic_features', 'naive_fraction')
- flat_naive_unique_list <- as.character(unlist(naive_unique_list))
- naive_markers <- FindMarkers(cci_seurat_lt_pca_50_merged, ident.1='Naive', ident.2='CCI', thresh.use=-Inf, min.pct=0, features=flat_naive_unique_list) #first calculate all the wilcox scores. Note that we use the library presto to speed up computation as suggested by Seurat.
- write.table(naive_markers, file='mouse_basic_features/naive_markers5050.txt', quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- exclude_naive_markers_1 <- row.names(subset(naive_markers, naive_markers$avg_log2FC <= 0))
- exclude_naive_markers_2 <- flat_naive_unique_list[!(flat_naive_unique_list %in% row.names(naive_markers))]
- exclude_naive_markers <- c(exclude_naive_markers_1,exclude_naive_markers_2)
- new_flat_naive_unique_list <- flat_naive_unique_list[!(flat_naive_unique_list %in% exclude_naive_markers)]
- naive_unique_list_5050 = c()
- for (ct1 in names(naive_unique_list)) {
- temp <- naive_unique_list[[ct1]]
- print(temp)
- naive_unique_list_5050[[ct1]] <- temp[!(temp %in% exclude_naive_markers)]
- }
- out_data <- data.frame(freq=c(), spec=c(), celltype=c())
- for (ct1 in names(naive_unique_list_5050)) {
- list_1 <- read.table(paste0('mouse_basic_features/naive_fraction_',ct1,'.txt'),sep='\t')
- list_1 <- subset(list_1, row.names(list_1) %in% naive_unique_list_5050[[ct1]])
- check = 0
- for (ct2 in unique([email hidden]$celltype_altcat)) {
- if (!ct2==ct1) {
- list_2 <- read.table(paste0('mouse_basic_features/naive_fraction_',ct2,'.txt'),sep='\t')
- list_2 <- subset(list_2, row.names(list_2) %in% naive_unique_list_5050[[ct1]])
- names(list_2) <- ct2
- if (check == 0) {
- running_list <- data.frame(list_2)
- }
- else {
- running_list <- cbind(running_list, list_2)
- }
- check = 1
- }
- }
- print(running_list)
- max_list <- apply(running_list, 1, max)
- out_data <- rbind(out_data, data.frame(freq=list_1$x, spec=max_list, celltype=rep(ct1, length(max_list))))
- }
- write.table(out_data, file='freqspec_naive.txt', sep='\t',quote=FALSE, col.names=NA)
- fs <- read.table("mouse_basic_features/freqspec_naive_unique_table.txt", header=TRUE, sep='\t')
- color_table <- c('En'="#E41A1CFF",
- "Ep"="#377EB8FF",
- "Nr"="#4DAF4AFF",
- "OPC"="#984EA3FF",
- "M"="#FECEA8FF",
- "Olg"="#F781BFFF",
- "As"="#A65628FF",
- "L"=,"#FF7F00FF",
- "Nt"="#321701")
- the_theme <- theme(plot.title=element_blank(),
- panel.background=element_blank(),
- panel.border = element_blank(),
- panel.grid=element_blank(),
- axis.line=element_line(linewidth=0.3),
- axis.ticks=element_line(linewidth=0.3),
- axis.text=element_text(size=6),
- legend.position='none',
- title=element_blank(),
- axis.title=element_blank())
- fs_plot <- ggplot(fs, aes(x=spec, y=freq, label=label, colour=celltype_label))+geom_point(size=0.5)+geom_vline(xintercept=0.4, linetype=2, linewidth=0.3)+geom_hline(yintercept=0.6, linetype=2, linewidth=0.3)+
- geom_text(size=2)+scale_x_continuous(breaks=c(0.1,0.2,0.3,0.4,0.5), limits=c(0.05,0.55))+scale_colour_manual(values=color_table, na.value='#CCCCCC')+
- the_theme
- ggsave('fs_plot_naive.pdf', fs_plot, width=6, height=6, units='cm', dpi=600)
- ####################
- cci_naive <- subset(cci_seurat_lt_pca_50_merged, [email hidden]$condition=='Naive')
- Idents(cci_naive) <- "celltype_altcat"
- feature_list <- c('EPN2','GJA1','HEMK1','FNBP1L') #highest log2FC for marker for each cell type that has a marker#
- dev.new(width=8, height=6, noRStudioGD = TRUE, units = "cm")
- RidgePlot(cci_naive, features=feature_list)
- ####################
- ###########Unique in cci
- ##Here we need to pull something in from later analysis to be able to sense check that these genes are actually up in cci
- cci_unique_list <- select_markers(cci_only, "celltype_altcat", 0.6, 0.4,'mouse_basic_features', 'cci_fraction')
- flat_cci_unique_list <- as.character(unlist(cci_unique_list))
- cci_markers <- FindMarkers(cci_seurat_lt_pca_50_merged, ident.1='CCI', ident.2='Naive', thresh.use=-Inf, min.pct=0, features=flat_cci_unique_list) #first calculate all the wilcox scores. Note that we use the library presto to speed up computation as suggested by Seurat.
- write.table(cci_markers, file='mouse_basic_features/cci_markers6040.txt', quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- exclude_cci_markers_1 <- row.names(subset(cci_markers, cci_markers$avg_log2FC <= 0))
- exclude_cci_markers_2 <- flat_cci_unique_list[!(flat_cci_unique_list %in% row.names(cci_markers))]
- exclude_cci_markers <- c(exclude_cci_markers_1,exclude_cci_markers_2)
- new_flat_cci_unique_list <- flat_cci_unique_list[!(flat_cci_unique_list %in% exclude_cci_markers)]
- cci_unique_list_6040 = c()
- for (ct1 in names(cci_unique_list)) {
- temp <- cci_unique_list[[ct1]]
- cci_unique_list_6040[[ct1]] <- temp[!(temp %in% exclude_cci_markers)]
- }
- ##Now I am doing 50/50 so I can get my my freqspec
- cci_unique_list <- select_markers(cci_only, "celltype_altcat", 0.5, 0.5,'mouse_basic_features', 'cci_fraction')
- flat_cci_unique_list <- as.character(unlist(cci_unique_list))
- cci_markers <- FindMarkers(cci_seurat_lt_pca_50_merged, ident.1='CCI', ident.2='Naive', thresh.use=-Inf, min.pct=0, features=flat_cci_unique_list) #first calculate all the wilcox scores. Note that we use the library presto to speed up computation as suggested by Seurat.
- write.table(cci_markers, file='mouse_basic_features/cci_markers5050.txt', quote=FALSE, sep='\t', row.names=TRUE, col.names=NA)
- exclude_cci_markers_1 <- row.names(subset(cci_markers, cci_markers$avg_log2FC <= 0))
- exclude_cci_markers_2 <- flat_cci_unique_list[!(flat_cci_unique_list %in% row.names(cci_markers))]
- exclude_cci_markers <- c(exclude_cci_markers_1,exclude_cci_markers_2)
- new_flat_cci_unique_list <- flat_cci_unique_list[!(flat_cci_unique_list %in% exclude_cci_markers)]
- ###now 5050
- cci_unique_list_5050 = c()
- for (ct1 in names(cci_unique_list)) {
- temp <- cci_unique_list[[ct1]]
- cci_unique_list_5050[[ct1]] <- temp[!(temp %in% exclude_cci_markers)]
- }
- out_data <- data.frame(freq=c(), spec=c(), celltype=c())
- for (ct1 in names(cci_unique_list_5050)) {
- list_1 <- read.table(paste0('mouse_basic_features/cci_fraction_',ct1,'.txt'),sep='\t')
- list_1 <- subset(list_1, row.names(list_1) %in% cci_unique_list_5050[[ct1]])
- check = 0
- for (ct2 in unique([email hidden]$celltype_altcat)) {
- if (!ct2==ct1) {
- list_2 <- read.table(paste0('mouse_basic_features/cci_fraction_',ct2,'.txt'),sep='\t')
- list_2 <- subset(list_2, row.names(list_2) %in% cci_unique_list_5050[[ct1]])
- names(list_2) <- ct2
- if (check == 0) {
- running_list <- data.frame(list_2)
- }
- else {
- running_list <- cbind(running_list, list_2)
- }
- check = 1
- }
- }
- print(running_list)
- max_list <- apply(running_list, 1, max)
- out_data <- rbind(out_data, data.frame(freq=list_1$x, spec=max_list, celltype=rep(ct1, length(max_list))))
- }
- write.table(out_data, file='freqspec_cci.txt', sep='\t',quote=FALSE, col.names=NA)
- fs <- read.table("mouse_basic_features/freqspec_cci_unique_table.txt", header=TRUE, sep='\t')
- the_theme <- theme(plot.title=element_blank(),
- panel.background=element_blank(),
- panel.border = element_blank(),
- panel.grid=element_blank(),
- axis.line=element_line(linewidth=0.3),
- axis.ticks=element_line(linewidth=0.3),
- axis.text=element_text(size=6),
- legend.position='none',
- title=element_blank(),
- axis.title=element_blank())
- fs_plot <- ggplot(fs, aes(x=spec, y=freq, label=label, colour=celltype_label))+geom_point(size=0.5)+geom_vline(xintercept=0.4, linetype=2, linewidth=0.3)+geom_hline(yintercept=0.6, linetype=2, linewidth=0.3)+
- geom_text(size=2, position=position_nudge(x=0.02,y=0.02))+scale_x_continuous(breaks=c(0.1,0.2,0.3,0.4,0.5), limits=c(0.05,0.55))+scale_colour_manual(values=color_table, na.value='#cccccc')+
- the_theme
- ggsave('fs_plot_cci.pdf', fs_plot, width=6, height=6, units='cm', dpi=600)
- #############
- cci_cci <- subset(cci_seurat_lt_pca_50_merged, [email hidden]$condition=='CCI')
- Idents(cci_cci) <- "celltype_altcat"
- feature_list <- c('TRAF1','A2M','KLHL2','N4BP1','TTC9B','UCHL1') #*top for each cell type that has a marker, except I also added UCHL1*#
- dev.new(width=8, height=6, noRStudioGD = TRUE, units = "cm")
- RidgePlot(cci_cci, features=feature_list)
- #naive
- naive_subPN <- data.frame(
- group = factor(c("TRANSL","ALP", "EXTRA", "ER","UPS","CYTONUC",'CYTONUC/ALP','TRANSL/ALP','UPS/ALP','UPS/PNREG'), levels=c("TRANSL", "ALP", "EXTRA", "ER","UPS","CYTONUC",'CYTONUC/ALP','TRANSL/ALP','UPS/ALP','UPS/PNREG')),
- value = c(46,3,2,2,2,1,2,1,1,1),
- colors = c('#377eb8','#984ea3','#ffff33','#f781bf','#a65628','#ff7f00','#fdae61','#ece7f2','#cc9966','#ffcc99'))
- the_theme <- theme(plot.title=element_blank(),
- panel.background=element_blank(),
- panel.border = element_blank(),
- panel.grid=element_blank(),
- axis.line=element_blank(),
- axis.ticks=element_blank(),
- axis.text=element_blank(),
- legend.title=element_blank(),legend.text=element_text(size=7.5, colour='black'),
- legend.position='none',
- title=element_blank(),
- axis.title=element_blank())
- dev.new(width=1.5, height=1.5, noRStudioGD = TRUE, units = "cm")
- ggplot(naive_subPN, aes(x="",y=value,fill=group))+geom_bar(width=1, stat='identity')+coord_polar("y",start=0)+scale_fill_manual(values=naive_subPN$colors)+the_theme
- #coreCCI
- coreCCI_subPN <- data.frame(
- group = factor(c("TRANSL","ALP", "EXTRA", "ER","UPS","CYTONUC",'CYTONUC/ALP','TRANSL/ALP','UPS/ALP','UPS/PNREG'), levels=c("TRANSL","ALP", "EXTRA", "ER","UPS","CYTONUC",'CYTONUC/ALP','TRANSL/ALP','UPS/ALP','UPS/PNREG')),
- value = c(27,3,3,1,6,0,1,1,1,1),
- colors = c('#377eb8','#984ea3','#ffff33','#f781bf','#a65628','#ff7f00','#fdae61','#ece7f2','#cc9966','#ffcc99'))
- the_theme <- theme(plot.title=element_blank(),
- panel.background=element_blank(),
- panel.border = element_blank(),
- panel.grid=element_blank(),
- axis.line=element_blank(),
- axis.ticks=element_blank(),
- axis.text=element_blank(),
- legend.title=element_blank(),legend.text=element_text(size=7.5, colour='black'),
- legend.position='none',
- title=element_blank(),
- axis.title=element_blank())
- dev.new(width=1.5, height=1.5, noRStudioGD = TRUE, units = "cm")
- ggplot(coreCCI_subPN, aes(x="",y=value,fill=group))+geom_bar(width=1, stat='identity')+coord_polar("y",start=0)+scale_fill_manual(values=coreCCI_subPN$colors)+the_theme
- naive_common_list <- read.table('mouse_basic_features/coreNaive_subPN.txt',sep='\t')$x
- cci_common_list <- read.table('mouse_basic_features/coreCCI_subPN.txt',sep='\t')$x
- dev.new(width=2.1, height=1.6, noRStudioGD = TRUE, units = "cm")
- the_theme <- theme(plot.title=element_blank(),
- panel.background=element_blank(),
- panel.border = element_blank(),
- panel.grid=element_blank(),
- axis.line=element_blank(),
- axis.ticks=element_blank(),
- axis.text=element_blank(),
- legend.title=element_blank(),legend.text=element_text(size=7.5, colour='black'),
- legend.position='none',
- title=element_blank(),
- axis.title=element_blank())
- #values=c('Naive'='#67a9cf','CCI'='#ef8a62','Naive:CCI'='#caa099') just do this in illustrator
- ggVennDiagram(x=list('Naive'=naive_common_list, 'CCI'=cci_common_list),category.names=c('Naive','CCI'),fontfamily='Arial',label='count',label_size=5,label_alpha=0)+coord_flip()+the_theme
- #####FIGURE 3#####
- #CCI_1 CCI_2 CCI_3 Naive_1 Naive_2 Naive_3 Naive_4
- #Astrocytes 130 97 71 112 213 22 152
- #BCells 601 893 902 40 53 59 59
- #Endothelial_1 147 187 326 213 627 187 339
- #Endothelial_2 65 82 133 106 293 76 169
- #Ependymal_1 467 564 960 392 726 1204 2130
- #Ependymal_2 80 78 375 161 265 283 861
- #Ependymal_3 80 89 131 84 180 300 328
- #Ependymal_4 36 135 233 1 3 4 15
- #Ependymal_5 0 15 19 4 48 18 76
- #Microglia_1 1111 1638 2112 2186 2362 3494 1869
- #Microglia_2 606 1351 1214 741 1132 1127 973
- #Microglia_3 954 1261 1410 300 319 407 240
- #Microglia_4 217 887 640 32 36 50 29
- #Microglia_5 414 604 663 5 27 10 4
- #Microglia_6 64 69 81 73 329 183 174
- #Microglia_7 8 3 24 16 48 24 117
- #Microglia_8 9 21 39 22 48 27 37
- #Neurons 129 59 67 27 23 38 32
- #Neutrophils_1 317 1071 606 8 9 7 12
- #Neutrophils_2 28 135 60 7 11 11 12
- #NKcells 162 125 114 41 51 63 99
- #Oligodendrocytes 21 43 32 11 88 19 28
- #TmemoryCells 107 60 91 0 2 1 1
Mouse Code.R at commit ff25fc9, no license · at the source
Overview
- Department of Neurology, University of Maryland School of Medicine, Baltimore, MD, USA
- Departments of Neurology, Barrow Neurological Institute, Phoenix, AZ, USA
- Department of Neurological Surgery, Barrow Neurological Institute, Phoenix, AZ, USA
- Department of Translational Neuroscience, Barrow Neurological Institute, Phoenix, AZ, USA
- Safar Center for Resuscitation Research, UPMC Children's Hospital of Pittsburgh, School of Medicine, University of Pittsburgh, Pittsburgh, PA, USA
- Division of Health Informatics, Department of Pediatrics, UPMC Children's Hospital of Pittsburgh, School of Medicine, University of Pittsburgh, Pittsburgh, PA, USA
- Shock Trauma Neurocritical Care, Program in Trauma, R Adams Cowley Shock Trauma Center, University of Maryland Medical Center, Baltimore, MD, USA
Abstract
Traumatic brain injury (TBI) triggers competing damage and repair processes that can result in chronic neurodegenerative protein conformational disorders. Acute alterations in proteostasis have been reported after injury, but a comprehensive understanding of changes to the proteostasis network (PN) has been limited by the complex cellular pathology of TBI. The recent enumeration of the human PN and advances in single-cell transcriptomics make it possible to delineate PN dynamics in multifactorial diseases such as TBI. Here, we leverage archival mouse and human transcriptomic data to identify cell-type-specific Sub-PNs in the brain and their alteration by TBI. We find characteristic PN gene expression profiles in many cell types and subtypes, reflecting tremendous diversity in the enrichment of specific PN processes. TBI induces a broad transcriptional remodelling of translation, the ubiquitin–proteasome system and nuclear proteostasis machinery across cell types. In addition to this shared response, numerous cell-type-specific responses occur, some of which are conserved between mouse and human, despite differences in injury mechanism and timing. Our extensive characterization of the PN transcriptome across cell type and disease reveals potentially modifiable mechanisms of PN alteration in TBI. More broadly, our results provide a framework for elucidating changes to the PN in complex diseases.
This article is part of the Theo Murphy meeting issue ‘ProteostaSys: a systems view of proteostasis’.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above, with 10 matches between paragraphs and lines of code.
Ciryam-Lab/Lefkowitz-Proteostasis-2026
ff25fc9aa97e585cd71ea47710d7d811441b99bf, 5 August 2026Availability: 1 check, the latest on 3 October 2026: the link answers
- 3 October 2026: the link answers
5 files
- 1A basic_features.R, R, 388 lines, 2 matches
- Figure S1.R, R, 130 lines, 1 match
- Human Code.R, R, 1,238 lines, 3 matches
- Mouse Code.R, R, 1,395 lines, 4 matches
- gsea_test.py, Python, 17 lines
doi:10.6084/m9.figshare.c.8672767
Availability: 20 checks, the latest on 14 October 2026: unreachable at the last attempt (HTTP 202)
- 14 October 2026: unreachable at the last attempt (HTTP 202)
- 14 October 2026: unreachable at the last attempt (HTTP 202)
- 14 October 2026: unreachable at the last attempt (HTTP 202)
- 13 October 2026: unreachable at the last attempt (HTTP 202)
- 13 October 2026: unreachable at the last attempt (HTTP 202)
- 8 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
- 6 October 2026: unreachable at the last attempt (HTTP 202)
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 5 scripts, each with its path and the digest of its content;
- 10 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
Datasets cited
- figshare:33329113, at figshare; found in DataCite
Data accessibility
Code relevant to this manuscript is available at https://
Supplementary material is available online [50].
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 6 October 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 6 authors, 3 keywords, 7 MeSH terms, 9 funders, 50 references.
Cite
This paper
Lefkowitz, J., Taylor, M., Kumar, A., Jha, R. M., Rajasundaram, D., & Ciryam, P. (2026). Traumatic brain injury induces cell-type-specific remodelling of the proteostasis network. Philosophical transactions of the Royal Society of London. Series B, Biological sciences, 381(1960), 20250264. https://
BibTeX
@article{lefkowitz2026tr
author = {Lefkowitz, Jonathan and Taylor, Milo and Kumar, Aditya and Jha, Ruchira M and Rajasundaram, Dhivyaa and Ciryam, Prajwal},
title = {{Traumatic brain injury induces cell-type-specific remodelling of the proteostasis network}},
journal = {Philosophical transactions of the Royal Society of London. Series B, Biological sciences},
year = {2026},
month = oct,
volume = {381},
number = {1960},
pages = {20250264},
publisher = {The Royal Society},
issn = {0962-8436},
doi = {10.1098/
url = {https://
pmid = {42817638},
pmcid = {PMC13628056}
}
RIS
TY - JOUR
AU - Lefkowitz, Jonathan
AU - Taylor, Milo
AU - Kumar, Aditya
AU - Jha, Ruchira M
AU - Rajasundaram, Dhivyaa
AU - Ciryam, Prajwal
TI - Traumatic brain injury induces cell-type-specific remodelling of the proteostasis network
T2 - Philosophical transactions of the Royal Society of London. Series B, Biological sciences
J2 - Philos Trans R Soc Lond B Biol Sci
PY - 2026
DA - 2026/
VL - 381
IS - 1960
SP - 20250264
SN - 0962-8436
PB - The Royal Society
DO - 10.1098/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1098/
"type": "article-journal",
"title": "Traumatic brain injury induces cell-type-specific remodelling of the proteostasis network",
"container-title": "Philosophical transactions of the Royal Society of London. Series B, Biological sciences",
"author": [
{
"family": "Lefkowitz",
"given": "Jonathan"
},
{
"family": "Taylor",
"given": "Milo"
},
{
"family": "Kumar",
"given": "Aditya"
},
{
"family": "Jha",
"given": "Ruchira M"
},
{
"family": "Rajasundaram",
"given": "Dhivyaa"
},
{
"family": "Ciryam",
"given": "Prajwal"
}
],
"container-title-short":
"volume": "381",
"issue": "1960",
"page": "20250264",
"DOI": "10.1098/
"PMID": "42817638",
"PMCID": "PMC13628056",
"ISSN": "0962-8436",
"publisher": "The Royal Society",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
10,
1
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1002/ccs3.70006 [code]
- Evaluation of altered cell-cell communication between glia and neurons in the hippocampus of 3xTg-AD mice at two time points.Journal: Journal of cell communication and signalingIn common: circlize, ComplexHeatmap, DESeq2, 4 other tools, genetics / omics, mouse, cellular / molecular, 2 references
- [2] doi:10.1016/j.celrep.2023.113070 [code]
- TMEM127 suppresses tumor development by promoting RET ubiquitination, positioning, and degradation.Journal: Cell reportsIn common: igraph, Seurat, data.table, 1 other tool, genetics / omics, mouse, cellular / molecular, 1 reference, author Jonathan Lefkowitz
- [3] doi:10.1007/s00401-025-02913-3 [code]
- Single-cell transcriptomic landscape of the neuroimmune compartment in amyotrophic lateral sclerosis brain and spinal cord.Journal: Acta neuropathologicaIn common: circlize, ComplexHeatmap, DESeq2, 4 other tools, genetics / omics, cellular / molecular, 1 reference
- [4] doi:10.1084/jem.20232357 [code]
- Microglia and CD8+ T cell activation precede neuronal loss in a murine model of spastic paraplegia 15.Journal: The Journal of experimental medicineIn common: circlize, ComplexHeatmap, igraph, 3 other tools, mouse, cellular / molecular, 2 references
- [5] doi:10.1126/sciadv.adf6251 [code]
- Single-cell genomics reveals region-specific developmental trajectories underlying neuronal diversity in the human hypothalamus.Journal: Science advancesIn common: circlize, ComplexHeatmap, igraph, 3 other tools, genetics / omics, mouse, 1 reference
- [6] doi:10.1038/s41380-026-03585-5 [code]
- Multiomics analysis identifies VPA-induced changes in neural progenitor cells, ventricular-like regions, and cellular microenvironment in dorsal forebrain organoids.Journal: Molecular psychiatryIn common: ComplexHeatmap, igraph, Seurat, 2 other tools, genetics / omics, mouse, 2 references
- [7] doi:10.1016/j.ebiom.2026.106324 [code]
- Refined single-cell profiling captures a CCR5&
lt;sup& gt;high& lt;/ sup& gt; CD4& lt;sup& gt;+& lt;/ sup& gt; cytotoxic T-cell precursor in multiple sclerosis. Journal: EBioMedicineIn common: DESeq2, igraph, Seurat, 2 other tools, genetics / omics, cellular / molecular, 2 references - [8] doi:10.1016/j.neuron.2025.09.022 [code]
- Integrated omics reveals disease-associated radial glia-like cells with epigenetically dysregulated interferon response in multiple sclerosis.Journal: NeuronIn common: circlize, ComplexHeatmap, Seurat, 2 other tools, genetics / omics, cellular / molecular, 1 reference
- [9] doi:10.1093/molbev/msaf189 [code]
- A General Principle of Neuronal Evolution Reveals a Human-Accelerated Neuron Type Potentially Underlying the High Prevalence of Autism in Humans.Journal: Molecular biology and evolutionIn common: DESeq2, igraph, Seurat, 2 other tools, genetics / omics, cellular / molecular, 1 reference
- [10] doi:10.1038/s41559-023-02186-7 [code]
- Comparative single-cell transcriptomic analysis of primate brains highlights human-specific regulatory evolution.Journal: Nature ecology & evolutionIn common: DESeq2, igraph, Seurat, 2 other tools, genetics / omics, cellular / molecular, 1 reference
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 2 repositories of the authors' code, each at its verified commit and with its license, 5 scripts, and 10 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:7442104f645170aa…
Add the badge to the code's README
If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.
Markdown
<!-- oscr-badge:start -->
[](https://openscicode.org/badge/doi/10.1098/rstb.2025.0264)
<!-- oscr-badge:end -->reStructuredText
.. oscr-badge:start
.. image:: https://openscicode.org/badge/doi/10.1098/rstb.2025.0264.svg
:target: https://openscicode.org/badge/doi/10.1098/rstb.2025.0264
:alt: OSCR
.. oscr-badge:endHTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1098/rstb.2025.0264"><img src="https://openscicode.org/badge/doi/10.1098/rstb.2025.0264.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->On GitHub, open the README, choose Edit (the pencil), paste the snippet under the title, then "Commit changes".
If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge page.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.
Report a mismatch between the code and the paper · Report a code error (signed in)
Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.
Report a reproduction failure (signed in)
Versions of its code: the releases of its code tied to a version of this paper (the preprint, the accepted manuscript, the version of record…), each with the tracing map versioned with it.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
