OSCR

HNRNPH1 drives glioblastoma progression by regulating the splicing of cell cycle genes.

Code ↔ Paper

2 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 2 matches
  1. [1] § Materials and Methods › Analysis of spatial transcriptomics data ↔ Module1_MP.R, lines 56 to 99 · score 0.91 · FindVariableFeatures, NormalizeData, ScaleData, RunPCA, Seurat, assignment · Report a mismatch
  2. [2] § Materials and Methods › Analysis of single-cell RNA sequencing data ↔ Module1_MP.R, lines 56 to 99 · score 0.76 · FindClusters, FindNeighbors, RunPCA, Seurat, variable, log · 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 · 650 lines · 32 KB · no license · 2 matches

  1. Sys.setenv(RETICULATE_PYTHON = "/.conda/envs/leiden/bin/python")
  2. Sys.setenv(RETICULATE_PYTHON = "/.conda/envs/leiden/bin/python")
  3. library(reticulate)
  4. library(Seurat)
  5. library(scalop)
  6. library(leiden)
  7. library(ggplot2)
  8. library(RColorBrewer)
  9. library(viridis)
  10. library(scales)
  11. library(reshape2)
  12. library(reshape2)
  13. library(scales)
  14. library(NMF)
  15. library(MetBrewer)
  16. library(colorspace)
  17. library(tibble)
  18. library(dplyr)
  19. library(data.table)
  20. library(stringr)
  21. library(readr)
  22. library(Matrix)
  23. library(bigmemory)
  24. library(doMC)
  25. library(patchwork)
  26. ###### Per sample Leiden clustering##############################
  27. samples_names <- (read.delim("general/GBM_samples.txt", header = FALSE, sep = "\t"))$V1
  28. # set parameters
  29. complexity_filter <- 1000
  30. mitochondrial_filter <- 20
  31. genes_filter <- 7000
  32. n_dim <- 20
  33. dim_filter <- 5^(-15)
  34. res_param <- 1
  35. sig_th <- .005
  36. mp_num <- 13
  37. distinct16_pal<-c("#11A579","#F2B701","#66C5CC","#80BA5A","#F6CF71","#7F3C8D","#CF1C90","#3969AC","#f97b72","#E73F74","#4b4b8f","#ACA4E2","#31C53F","#B95FBB","#D4D915","#28CECA")
  38. dim2use_list <- c(8,20,19,9,12,14,16,10,10,14,8,10,12,16,7,5,14,16,4,12,6,6,8,12,13,10) # set by jackstraw
  39. leiden_clustering <- sapply(c(1:length(samples_names)), function(i){
  40. print(samples_names[i])
  41. # load spatial data
  42. unfilt_obj<-Load10X_Spatial(data.dir = paste("general/GBM_data/",samples_names[i],"/outs", sep = ""),
  43. filename = "filtered_feature_bc_matrix.h5",
  44. assay = "Spatial",
  45. slice = "detected_tissue_image.jpg",
  46. filter.matrix = TRUE,
  47. to.upper = FALSE
  48. )
  49. # filtering
  50. exp_obj <- subset(unfilt_obj, subset = nCount_Spatial > complexity_filter) # filter out spots with less than #complexity_filter UMIs
  51. exp_obj[["percent.mt"]] <- PercentageFeatureSet(exp_obj, pattern = "^MT-") # filter spots with high percent (mitochondrial_filter) mitochondrial genes
  52. exp_obj <- subset(exp_obj, subset = percent.mt<mitochondrial_filter)
  53. # normalization and centering
  54. exp_obj <- NormalizeData(exp_obj, assay = "Spatial", normalization.method="LogNormalize", scale.factor=10000)
  55. exp_obj <- FindVariableFeatures(exp_obj, selection.method = "vst", nfeatures = genes_filter) # use only #genes_filter most variable genes
  56. exp_obj <- ScaleData(exp_obj)
  57. # PCA
  58. exp_obj <- RunPCA(exp_obj, features = VariableFeatures(object = exp_obj))
  59. #PCA dims to use determined by Jackstraw
  60. #exp_obj <- JackStraw(exp_obj, num.replicate = 100)
  61. #exp_obj <- ScoreJackStraw(exp_obj, dims = 1:n_dim)
  62. #js_scores <- exp_obj@reductions$pca@jackstraw$overall.p.values
  63. #dim2use <- max(js_scores[,"PC"][js_scores[,"Score"] < dim_filter])
  64. dim2use <- dim2use_list[i]
  65. # clustering
  66. exp_obj <- FindNeighbors(exp_obj, dims = 1:dim2use)
  67. exp_obj <- FindClusters(exp_obj, algorithm=4, resolution = res_param) # leiden based clustering
  68. spatial_sample_programs <- FindAllMarkers(exp_obj, only.pos = TRUE, return.thresh = sig_th)
  69. genes_num <- table(spatial_sample_programs$cluster)
  70. spots_clusters <- [email hidden][,"seurat_clusters"]
  71. names(spots_clusters) <- row.names([email hidden])
  72. cluster_num <- table([email hidden]$seurat_clusters)
  73. return(list(spatial_sample_programs,genes_num,spots_clusters,cluster_num)) # output: #genes per cluster, #spots per cluster, clusters genes sig, spots assignment to cluster
  74. })
  75. # clusters quality
  76. genes_num <- c()
  77. spots_num <- c()
  78. sapply(c(1:length(samples_names)), function(i){
  79. genes_num <<- c(genes_num,as.numeric(leiden_clustering[2,i][[1]]))
  80. spots_num <<- c(spots_num,as.numeric(leiden_clustering[4,i][[1]]))
  81. })
  82. hist(genes_num, breaks = 30)
  83. hist(spots_num, breaks = 30)
  84. # create genes sig table for save
  85. genes_sig <- leiden_clustering[1,1][[1]]
  86. genes_sig$sample <- rep(samples_names[1],dim(genes_sig)[1])
  87. sapply(c(2:length(samples_names)),function(i){
  88. genes_sig_temp <- leiden_clustering[1,i][[1]]
  89. genes_sig_temp$sample <- rep(samples_names[i],dim(genes_sig_temp)[1])
  90. genes_sig <<- rbind(genes_sig,genes_sig_temp)
  91. })
  92. # create clusters assignment table for save
  93. spots_assign <- as.data.frame(leiden_clustering[3,1][[1]])
  94. spots_assign$sample <- rep(samples_names[1],dim(spots_assign)[1])
  95. row.names(spots_assign) <- paste(row.names(spots_assign), "_", samples_names[1], sep = "")
  96. colnames(spots_assign) <- c("cluster","sample")
  97. sapply(c(2:length(samples_names)),function(i){
  98. spots_assign_temp <- as.data.frame(leiden_clustering[3,i][[1]])
  99. spots_assign_temp$sample <- rep(samples_names[i],dim(spots_assign_temp)[1])
  100. row.names(spots_assign_temp) <- paste(row.names(spots_assign_temp), "_", samples_names[i], sep = "")
  101. colnames(spots_assign_temp) <- c("cluster","sample")
  102. spots_assign <<- rbind(spots_assign,spots_assign_temp)
  103. })
  104. # set gene signatures list in the right format
  105. genes_list <- lapply(c(1:length(samples_names)), function(i){
  106. sample_table <- leiden_clustering[1,i][[1]]
  107. sample_genes <- lapply(c(1:length(unique(sample_table$cluster))),function(j){
  108. cluster_table <- sample_table[sample_table$cluster == j,]
  109. genes <- cluster_table$gene[order(cluster_table$avg_log2FC, decreasing = TRUE)][1:min(50,nrow(cluster_table))]
  110. return(genes)
  111. })
  112. return(sample_genes)
  113. })
  114. genes_list <- unlist(genes_list, recursive = FALSE)
  115. names(genes_list) <- unlist(sapply(c(1:length(samples_names)),function(i){
  116. paste(samples_names[i],c(1:length(leiden_clustering[4,i][[1]])), sep = "_")
  117. }))
  118. samples_list <- unlist(sapply(c(1:length(samples_names)),function(i){
  119. rep(samples_names[i],length(leiden_clustering[4,i][[1]]))
  120. }))
  121. #saveRDS(genes_list,"/home/labs/tirosh/spatial_glioma/results/leiden_MPs/all_leiden_programs_v2.rds")
  122. # generate an ordered jaccard matrix and clusters
  123. jac_mat = Jaccard(genes_list)
  124. jac_matord = scalop::hca_reorder(jac_mat)
  125. jac_plot <- melt(jac_matord)
  126. prog_ordered <- colnames(jac_matord)
  127. clusters <- scalop::hca_groups(jac_matord,
  128. cor.method="none",
  129. k=mp_num,
  130. min.size=4,
  131. max.size=0.5)
  132. clusterCut <- sapply(names(clusters), function(i){
  133. new_vec <- rep(i,length(clusters[[i]]))
  134. names(new_vec) <- clusters[[i]]
  135. return(new_vec)
  136. })
  137. names(clusterCut) <- NULL
  138. clusterCut <- unlist(clusterCut)
  139. # plot jaccard
  140. jac_plot$value[jac_plot$value >= 0.35] <- 0.35
  141. p1 <- ggplot(data = jac_plot, aes(x = Var1, y = Var2, fill = value)) + geom_raster() +
  142. scale_fill_gradientn(colours = colorspace::sequential_hcl(9, palette="YlOrRd", rev=T), limits = c(0,0.35), name = "Jaccard\nIndex") +
  143. theme(axis.ticks = element_blank(), panel.background = element_rect(fill = "white"), axis.line = element_blank(), legend.text.align = 0.5) +
  144. scale_x_discrete(name = "\nPrograms", labels = element_blank(), breaks = element_blank()) + scale_y_discrete(name = "\nPrograms", labels = element_blank(), breaks = element_blank())
  145. metaprog_df <- data.frame(row.names = prog_ordered,
  146. cluster = as.factor(clusterCut[prog_ordered]),
  147. samples = stringr::str_replace(prog_ordered, "_.*",""),
  148. cells = prog_ordered)
  149. samples_annotation_plot <- ggplot(metaprog_df, aes(x = factor(cells, levels = cells), y = 1)) +
  150. geom_raster(aes(fill = samples)) + theme(legend.position = "none",axis.ticks = element_blank(), panel.background = element_rect(fill = "white"), axis.text = element_blank(), axis.line = element_blank(), axis.text.x = element_blank()) +
  151. labs(x = "", y = "samples", fill = "")
  152. metaprog_annotation_plot <- ggplot(metaprog_df, aes(x = factor(cells, levels = cells), y = 1)) +
  153. geom_raster(aes(fill = cluster)) + theme(legend.position = "none", axis.ticks = element_blank(), panel.background = element_rect(fill = "white"), axis.text = element_blank(), axis.line = element_blank(), axis.text.x = element_blank()) +
  154. labs(x = "", y = "", fill = "")
  155. MP_plot <- egg::ggarrange(p1, metaprog_annotation_plot, samples_annotation_plot, ncol = 1, nrow = 3, heights = c(40, 2, 1))
  156. #Define meta-programs from program clusters, Sort by frequency across programs in cluster (>= 3)
  157. cut_off <- table(metaprog_df$cluster)*0.25
  158. cut_off[cut_off < 3] <- 3
  159. mp_freqs = sapply(clusters, function(k) sort(table(unlist(genes_list[k])),decreasing = T),simplify = F)
  160. metaprograms = sapply(names(mp_freqs), function(c) head(names(mp_freqs[[c]])[mp_freqs[[c]] >= as.numeric(cut_off[c])], 50), simplify = F)
  161. names(metaprograms)<-c("vascular","neuron","hypoxia","hypoxia.immune","oligo","AC.immune","low.quality","NPC2","macrophage","MES.stromal","OPC.AC","metabolism","MES1.RGL")
  162. metaprog_df$samp_cluster <- str_split(metaprog_df$cells, "_", simplify = T)[,2]
  163. metaprog_df$anno_cluster <- metaprog_df$cluster
  164. class(metaprog_df$anno_cluster)
  165. levels(metaprog_df$anno_cluster) <- c("vascular","MES.stromal","OPC.AC","metabolism","MES1.RGL","neuron","hypoxia","hypoxia.immune","oligo","AC.immune","low.quality","NPC2","macrophage")
  166. sapply(c(1:26), function(i){
  167. print(samples_names[i])
  168. spots_gen_assign <- as.data.frame(leiden_clustering[3,i][[1]])
  169. spots_gen_assign$generalized <- apply(spots_gen_assign,1,function(r){
  170. return(metaprog_df$anno_cluster[metaprog_df$samples == samples_names[i] & metaprog_df$samp_cluster == r])
  171. })
  172. spots_gen_assign$barcodes <- row.names(spots_gen_assign)
  173. spots_gen_assign <- spots_gen_assign[,c("barcodes", "generalized")]
  174. })
  175. ######generating input matrices for NMF
  176. # vector of file paths
  177. file_paths <- list.files(path ="/general/exp_mats_GBM/", pattern = "\\.rds", full.names = TRUE)#directory with counts mats
  178. sample_ls <- gsub(pattern = "\\.rds$", replacement = "", x = basename(file_paths))
  179. per_sample_mat <- lapply(file_paths, readRDS)
  180. for (i in seq_along(per_sample_mat)){
  181. m <- as.matrix(per_sample_mat[[i]])
  182. if(min(colSums(m)) == 0){m <- m[, colSums(m) != 0]}
  183. scaling_factor <- 1000000/colSums(m)
  184. m_CPM <- sweep(m, MARGIN = 2, STATS = scaling_factor, FUN = "*")
  185. m_loged <- log2(1 + (m_CPM/10))
  186. # removing genes with zero variance across all cells
  187. var_filter <- apply(m_loged, 1, var)
  188. m_proc <- m_loged[var_filter != 0, ]
  189. # filtering out lowly expressed genes
  190. exp_genes <- rownames(m_proc)[(rowMeans(m_proc) > 0.4)]
  191. m_proc <- m_proc[exp_genes, ]
  192. # centering data gene-wise
  193. count_mat_cent<- m_proc - rowMeans(m_proc)
  194. #nmf preprocessing
  195. count_mat_nmf<- count_mat_cent
  196. count_mat_nmf[count_mat_nmf<0] <- 0 # negative values should be set to 0 in initial matrix
  197. # output to a list of gene expression profiles (GEP)
  198. per_sample_mat[[i]] <- count_mat_nmf
  199. names(per_sample_mat)[i] <- sample_ls[[i]]
  200. rm(m,m_loged, var_filter, exp_genes, m_proc,count_mat_cent)
  201. #saveRDS(count_mat_nmf, paste("MP/NMF/NMF_mats_GBM/", samples_names[i], ".rds", sep =""))
  202. }
  203. ## Extract sample names for sample list file:
  204. #samples <- list.files("MP/NMF/NMF_mats_GBM/") %>% substri(., pos = 1) %>% str_c(., collapse = "\n")
  205. #write_lines(samples, ("/samples.txt"), sep = "\n")
  206. ###### NMF (Previously run by server. Possible to run per sample below)---------------------------------------------------------------------
  207. #!/usr/bin/env Rscript
  208. #args = commandArgs(trailingOnly = TRUE)
  209. sname <- "MGH258"# enter sample name here
  210. rank_lb <- 2
  211. rank_ub <- 11
  212. m <- readRDS(paste0("MP/NMF/NMF_mats_GBM/", sname, ".rds"))
  213. m <- as.matrix(m)
  214. res <- NMF::nmf(x = m, rank = rank_lb:rank_ub, nrun = 5, method = "snmf/r", .opt = list(debug=F, parallel=F, shared.memory=F, verbose=T))
  215. ###### Generation of NMF + Leiden GBM spatial metaprograms#########
  216. #
  217. #robust_nmf_programs function
  218. robust_nmf_programs <- function(nmf_programs, intra_min = 30, intra_max = 10, inter_filter=T, inter_min = 10) {
  219. # Select NMF programs based on the minimum overlap with other NMF programs from the same sample
  220. intra_intersect <- lapply(nmf_programs, function(z) apply(z, 2, function(x) apply(z, 2, function(y) length(intersect(x,y)))))
  221. intra_intersect_max <- lapply(intra_intersect, function(x) apply(x, 2, function(y) sort(y, decreasing = T)[2]))
  222. nmf_sel <- lapply(names(nmf_programs), function(x) nmf_programs[[x]][,intra_intersect_max[[x]]>=intra_min])
  223. names(nmf_sel) <- names(nmf_programs)
  224. # Select NMF programs based on i) the maximum overlap with other NMF programs from the same sample and
  225. # ii) the minimum overlap with programs from another sample
  226. nmf_sel_unlist <- do.call(cbind, nmf_sel)
  227. inter_intersect <- apply(nmf_sel_unlist , 2, function(x) apply(nmf_sel_unlist , 2, function(y) length(intersect(x,y)))) ## calculating intersection between all programs
  228. final_filter <- NULL
  229. for(i in names(nmf_sel)) {
  230. a <- inter_intersect[grep(i, colnames(inter_intersect), invert = T),grep(i, colnames(inter_intersect))]
  231. b <- sort(apply(a, 2, max), decreasing = T) # for each sample, ranks programs based on their maximum overlap with programs of other samples
  232. if(inter_filter==T) b <- b[b>=inter_min] # selects programs with a maximum intersection of at least 10
  233. if(length(b) > 1) {
  234. c <- names(b[1])
  235. for(y in 2:length(b)) {
  236. if(max(inter_intersect[c,names(b[y])]) <= intra_max) c <- c(c,names(b[y])) # selects programs iteratively from top-down. Only selects programs that have a intersection smaller than 10 with a previously selected programs
  237. }
  238. final_filter <- c(final_filter, c)
  239. } else {
  240. final_filter <- c(final_filter, names(b))
  241. }
  242. }
  243. return(final_filter)
  244. }
  245. # Custom color palette
  246. custom_magma <- c(colorRampPalette(c("white", rev(magma(323, begin = 0.15))[1]))(10), rev(magma(323, begin = 0.18)))
  247. ## Create list of NMF matrics where each sample is an entry
  248. path <- "MP/NMF/out_dir/"
  249. sample_ls <- list.files(path)
  250. ## Create list of NMF matrics where each sample is an entry
  251. prog_genes_ls <- list()
  252. for(i in seq_along(sample_ls)) {
  253. nmf_obj <- readRDS(paste(path, sample_ls[[i]], sep = "/"))
  254. samp_name <- stringr::str_split(sample_ls[[i]], pattern = "_")[[1]][[1]]
  255. nmf_mats <- c()
  256. for(j in names(nmf_obj$fit)) {
  257. get_basis <- basis(nmf_obj$fit[[j]])
  258. colnames(get_basis) <- paste0(samp_name, ".", j, ".", 1:j)
  259. nmf_mats <- cbind(nmf_mats, get_basis)
  260. }
  261. prog_genes_ls[[i]] <- nmf_mats
  262. names(prog_genes_ls)[i] <- paste0(samp_name)
  263. rm(nmf_obj, nmf_mats, get_basis)
  264. }
  265. Genes_nmf_w_basis <- do.call(c, list(prog_genes_ls))
  266. # Find robust NMFs
  267. # get gene programs (top 50 genes by NMF score)
  268. nmf_programs_sig <- lapply(prog_genes_ls, function(x) apply(x, 2, function(y) names(sort(y, decreasing = T))[1:50]))
  269. # for each sample, select robust NMF programs (i.e. observed using different ranks in the same sample), remove redundancy due to multiple ranks, and apply a filter based on the similarity to programs from other samples.
  270. nmf_filter_all <- robust_nmf_programs(nmf_programs_sig, intra_min = 35, intra_max = 10, inter_filter=T, inter_min = 10)
  271. nmf_programs_sig <- lapply(nmf_programs_sig, function(x) x[, is.element(colnames(x), nmf_filter_all),drop=F])
  272. nmf_programs_sig <- do.call(cbind, nmf_programs_sig)
  273. #leiden clusters
  274. all_leiden_programs<-readRDS("MP/all_leiden_programs_v2.rds")
  275. all_leiden_programs <- do.call(cbind, all_leiden_programs)
  276. nmf_programs_sig<-cbind(nmf_programs_sig,all_leiden_programs)
  277. # calculate similarity between programs
  278. nmf_intersect <- apply(nmf_programs_sig , 2, function(x) apply(nmf_programs_sig , 2, function(y) length(intersect(x,y))))
  279. # hierarchical clustering of the similarity matrix
  280. nmf_intersect_hc_all <- hclust(as.dist(50-nmf_intersect), method="average")
  281. nmf_intersect_hc_all <- reorder(as.dendrogram(nmf_intersect_hc_all), colMeans(nmf_intersect))
  282. nmf_intersect <- nmf_intersect[order.dendrogram(nmf_intersect_hc_all), order.dendrogram(nmf_intersect_hc_all)]
  283. nmf_intersect<-readRDS("MP/NMF/nmf_intersect_124.RDS")
  284. nmf_programs_sig<-readRDS("MP/NMF/nmf_programs_sig_124.RDS")
  285. ### use a clustering approach that updates MPs in each iteration
  286. nmf_intersect_KEEP <- nmf_intersect
  287. nmf_programs_sig_KEEP <- nmf_programs_sig
  288. ### Parameters (later change to function form)v1-keep!
  289. Min_intersect_initial <- 12 # the minimal intersection cutoff for defining the Founder NMF program of a cluster
  290. Min_intersect_cluster <- 12 # the minimal intersection cuttof for adding a new NMF to the forming cluster
  291. Min_group_size <- 4 # the minimal group size to consider for defining the Founder_NMF of a MP
  292. Sorted_intersection <- sort(apply(nmf_intersect , 2, function(x) (length(which(x>=Min_intersect_initial))-1) ) , decreasing = TRUE)
  293. Cluster_list <- list() ### Every entry contains the NMFs of a chosec cluster
  294. k <- 1
  295. Curr_cluster <- c()
  296. MP_list <- list()
  297. while (Sorted_intersection[1]>Min_group_size) {
  298. Curr_cluster <- c(Curr_cluster , names(Sorted_intersection[1]))
  299. ### intersection between all remaining NMFs and Genes in MP
  300. Genes_MP <- nmf_programs_sig[,names(Sorted_intersection[1])] # initial genes are those in the first NMF. Genes_MP always has only 50 genes consisting of the current MP
  301. nmf_programs_sig <- nmf_programs_sig[,-match(names(Sorted_intersection[1]) , colnames(nmf_programs_sig))] # remove selected NMF
  302. Intersection_with_Genes_MP <- sort(apply(nmf_programs_sig, 2, function(x) length(intersect(Genes_MP,x))) , decreasing = TRUE) # intersection between all other NMFs and Genes_MP
  303. NMF_history <- Genes_MP # has all genes in all NMFs in the current cluster, for newly defining Genes_MP after adding a new NMF
  304. ### Create gene list - composed of intersecting genes in descending order. Update Curr_cluster each time.
  305. while ( Intersection_with_Genes_MP[1] >= Min_intersect_cluster) { ### Define current cluster
  306. Curr_cluster <- c(Curr_cluster , names(Intersection_with_Genes_MP)[1])
  307. Genes_MP_temp <- sort(table(c(NMF_history , nmf_programs_sig[,names(Intersection_with_Genes_MP)[1]])), decreasing = TRUE) ## Genes_MP is newly defined each time according to all NMFs in the current cluster
  308. Genes_at_border <- Genes_MP_temp[which(Genes_MP_temp == Genes_MP_temp[50])] ### genes with overlap equal to the 50th gene
  309. if (length(Genes_at_border)>1){
  310. ### Sort last genes in Genes_at_border according to maximal NMF gene scores
  311. ### Run over all NMF programs in Curr_cluster and extract NMF scores for each gene
  312. Genes_curr_NMF_score <- c()
  313. for (i in Curr_cluster) {
  314. curr_study <- strsplit(i, "[.]")[[1]][[1]]
  315. Q <- Genes_nmf_w_basis[[curr_study]][ match(names(Genes_at_border),toupper(rownames(Genes_nmf_w_basis[[curr_study]])))[!is.na(match(names(Genes_at_border),toupper(rownames(Genes_nmf_w_basis[[curr_study]]))))] ,i]
  316. #names(Q) <- names(Genes_at_border[!is.na(match(names(Genes_at_border),toupper(rownames(Genes_nmf_w_basis[[curr_study]]))))]) ### sometimes when adding genes the names do not appear
  317. Genes_curr_NMF_score <- c(Genes_curr_NMF_score, Q )
  318. }
  319. Genes_curr_NMF_score_sort <- sort(Genes_curr_NMF_score , decreasing = TRUE)
  320. Genes_curr_NMF_score_sort <- Genes_curr_NMF_score_sort[unique(names(Genes_curr_NMF_score_sort))] ## take only the maximal score of each gene - which is the first entry after sorting
  321. Genes_MP_temp <- c(names(Genes_MP_temp[which(Genes_MP_temp > Genes_MP_temp[50])]) , names(Genes_curr_NMF_score_sort))
  322. } else {
  323. Genes_MP_temp <- names(Genes_MP_temp)[1:50]
  324. }
  325. NMF_history <- c(NMF_history , nmf_programs_sig[,names(Intersection_with_Genes_MP)[1]])
  326. Genes_MP <- Genes_MP_temp[1:50]
  327. nmf_programs_sig <- nmf_programs_sig[,-match(names(Intersection_with_Genes_MP)[1] , colnames(nmf_programs_sig))] # remove selected NMF
  328. Intersection_with_Genes_MP <- sort(apply(nmf_programs_sig, 2, function(x) length(intersect(Genes_MP,x))) , decreasing = TRUE) # intersection between all other NMFs and Genes_MP
  329. }
  330. Cluster_list[[paste0("Cluster_",k)]] <- Curr_cluster
  331. MP_list[[paste0("MP_",k)]] <- Genes_MP
  332. k <- k+1
  333. nmf_intersect <- nmf_intersect[-match(Curr_cluster,rownames(nmf_intersect) ) , -match(Curr_cluster,colnames(nmf_intersect) ) ] # remove current chosen cluster
  334. Sorted_intersection <- sort(apply(nmf_intersect , 2, function(x) (length(which(x>=Min_intersect_initial))-1) ) , decreasing = TRUE) ### Sort intersection of remaining NMFs not included in any of the previous clusters
  335. Curr_cluster <- c()
  336. print(dim(nmf_intersect)[2])
  337. }
  338. #### ***** Sort Jaccard similarity plot according to new clusters:
  339. inds_sorted <- c()
  340. for (j in 1:length(Cluster_list)){
  341. inds_sorted <- c(inds_sorted , match(Cluster_list[[j]] , colnames(nmf_intersect_KEEP)))
  342. }
  343. inds_new <- c(inds_sorted , which(is.na( match(1:dim(nmf_intersect_KEEP)[2],inds_sorted)))) ### combine inds in clusters with inds without clusters
  344. # plot re-ordered similarity matrix heatmap
  345. nmf_intersect_meltI_NEW <- reshape2::melt(nmf_intersect_KEEP[inds_new,inds_new])
  346. custom_magma <- c(colorRampPalette(c("white", rev(magma(323, begin = 0.15))[1]))(10), rev(magma(323, begin = 0.18)))
  347. ggplot(data = nmf_intersect_meltI_NEW, aes(x=Var1, y=Var2, fill=100*value/(100-value), color=100*value/(100-value))) +
  348. geom_tile() +
  349. scale_color_gradient2(limits=c(2,25), low=custom_magma[1:111], mid =custom_magma[112:222], high = custom_magma[223:333], midpoint = 13.5, oob=squish, name="Similarity\n(Jaccard index)") +
  350. scale_fill_gradient2(limits=c(2,25), low=custom_magma[1:111], mid =custom_magma[112:222], high = custom_magma[223:333], midpoint = 13.5, oob=squish, name="Similarity\n(Jaccard index)") +
  351. theme( axis.ticks = element_blank(), panel.border = element_rect(fill=F), panel.background = element_blank(), axis.line = element_blank(), axis.text = element_text(size = 11), axis.title = element_text(size = 12), legend.title = element_text(size=11), legend.text = element_text(size = 10), legend.text.align = 0.5, legend.justification = "bottom") +
  352. theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank()) +
  353. theme(axis.title.y=element_blank(), axis.text.y=element_blank(), axis.ticks.y=element_blank()) +
  354. guides(fill = guide_colourbar(barheight = 4, barwidth = 1))
  355. ggplot(data = nmf_intersect_meltI_NEW, aes(x=Var1, y=Var2, fill=100*value/(100-value), color=100*value/(100-value))) +
  356. geom_tile() +
  357. scale_color_gradient2(limits=c(2,30), low=custom_magma[1:111], mid =custom_magma[112:222], high = custom_magma[223:333], midpoint = 16, oob=squish, name="Similarity\n(Jaccard index)") +
  358. scale_fill_gradient2(limits=c(2,30), low=custom_magma[1:111], mid =custom_magma[112:222], high = custom_magma[223:333], midpoint = 16, oob=squish, name="Similarity\n(Jaccard index)") +
  359. theme( axis.ticks = element_blank(), panel.border = element_rect(fill=F), panel.background = element_blank(), axis.line = element_blank(), axis.text = element_text(size = 11), axis.title = element_text(size = 12), legend.title = element_text(size=11), legend.text = element_text(size = 10), legend.text.align = 0.5, legend.justification = "bottom") +
  360. theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank()) +
  361. theme(axis.title.y=element_blank(), axis.text.y=element_blank(), axis.ticks.y=element_blank()) +
  362. guides(fill = guide_colourbar(barheight = 4, barwidth = 1))
  363. MP <- do.call(cbind, MP_list)
  364. names(MP_list)=c("Neuron","Vasc","MES.Hyp","Mac","OPC.AC","Oligo","LQ.Chromatin.reg","MES","Prolif.Metab","MES.Ast","Reactive.Ast","NPC","Inflammatory.Mac")
  365. ###### RECLUSTERING/HEIRARCHICAL CLUSTERING, EXTENDED MPs, AND SUBCLUSTER PROGRAMS ################
  366. programs_ls<-readRDS("MP/NMF/programs_ls_124.rds") #this is "nmf_programs_sig"
  367. Cluster_list<-readRDS("MP/NMF/Cluster_list_124.rds")
  368. str(Cluster_list)
  369. MP_list<-readRDS("MP/NMF/combined_gbm_metaprograms_raw_124.rds")
  370. #reclustering OPC.AC into 2 clusters
  371. opc.ac <- Cluster_list[[5]]
  372. mat2list <- function(x) {
  373. stopifnot(is.matrix(x))
  374. lapply(seq_len(ncol(x)), function(i) x[, i])
  375. }
  376. program_ls<-mat2list(programs_ls)
  377. names(program_ls)<-colnames(programs_ls)
  378. opc.ac_mat <- program_ls[names(program_ls) %in% opc.ac]
  379. jac_mat <- scalop::jaccard(opc.ac_mat)
  380. hc <- hclust(dist(1 - jac_mat), method = "average")
  381. jac_plot <- melt(jac_mat[hc$order, hc$order])
  382. #summary(jac_plot$value)
  383. p1 <- ggplot(data = jac_plot, aes(x = Var1, y = Var2, fill = value)) + geom_raster() +
  384. scale_fill_gradient2(limits = c(0, 0.4), low = rev(magma(323, begin = 0.15)), mid = "antiquewhite", high = rev(magma(323, begin = 0.18)), midpoint = 0 , oob = squish, name = "Pearson\nCorrelation") +
  385. theme(axis.ticks = element_blank(), panel.background = element_rect(fill = "white"), axis.line = element_blank(),axis.title = element_text(size=24), legend.text.align = 0.5) +
  386. scale_x_discrete(name = "\nPrograms", breaks = colnames(jac_mat)[hc$order][seq(5, ncol(jac_mat), by = 5)], labels = seq(5, ncol(jac_mat), by = 5)) +
  387. scale_y_discrete(name = "\nPrograms", breaks = colnames(jac_mat)[hc$order][seq(5, ncol(jac_mat), by = 5)], labels = seq(5, ncol(jac_mat), by = 5))
  388. prog_ordered <- colnames(jac_mat[hc$order, hc$order])
  389. plot(hc)
  390. rect.hclust(hc , k = 2, border = 2:6)
  391. clusterCut <- stats::cutree(tree = hc, k = 2)
  392. metaprog_df <- data.frame(row.names = prog_ordered)
  393. metaprog_df$cluster <- (clusterCut[prog_ordered])
  394. metaprog_df$cells <- prog_ordered
  395. metaprog_df$cluster <- as.factor(metaprog_df$cluster)
  396. metaprog_annotation_plot <- ggplot(metaprog_df, aes(x = factor(cells, levels = cells), y = 1)) +
  397. geom_raster(aes(fill = cluster)) + theme(legend.position = "bottom", axis.ticks = element_blank(),axis.title = element_text(size=24), panel.background = element_rect(fill = "white"), axis.text = element_blank(), axis.line = element_blank(), axis.text.x = element_blank()) +
  398. labs(x = "", y = "", fill = "")
  399. egg::ggarrange(p1, metaprog_annotation_plot, ncol = 1, nrow = 2, heights = c(40, 2))
  400. clust_list_ac_opc <- list(names(clusterCut[clusterCut == 1]), names(clusterCut[clusterCut == 2])) # use this ordering to reorder cluster 5 in main MP heatmap
  401. mp_freqs <- sapply(clust_list_ac_opc, function(k) sort(table(unlist(opc.ac_mat[k])), decreasing = T), simplify = F)
  402. opc.ac_metaprograms <- sapply(mp_freqs, function(tab) head(names(tab)[tab >= 3], 50), simplify = F)
  403. names(opc.ac_metaprograms)<-c("AC","OPC")
  404. #dividing low quality from chromatin.reg cluster
  405. chromatin <- Cluster_list[[7]]
  406. mat2list <- function(x) {
  407. stopifnot(is.matrix(x))
  408. lapply(seq_len(ncol(x)), function(i) x[, i])
  409. }
  410. program_ls<-mat2list(programs_ls)
  411. names(program_ls)<-colnames(programs_ls)
  412. chromatin_mat <- program_ls[names(program_ls) %in% chromatin]
  413. jac_mat <- scalop::jaccard(chromatin_mat)
  414. hc <- hclust(dist(1 - jac_mat), method = "average")
  415. jac_plot <- melt(jac_mat[hc$order, hc$order])
  416. #summary(jac_plot$value)
  417. p1 <- ggplot(data = jac_plot, aes(x = Var1, y = Var2, fill = value)) + geom_raster() +
  418. scale_fill_gradient2(limits = c(0, 0.4), low = rev(magma(323, begin = 0.15)), mid = "antiquewhite", high = rev(magma(323, begin = 0.18)), midpoint = 0 , oob = squish, name = "Pearson\nCorrelation") +
  419. theme(axis.ticks = element_blank(), panel.background = element_rect(fill = "white"), axis.line = element_blank(),axis.title = element_text(size=24), legend.text.align = 0.5) +
  420. scale_x_discrete(name = "\nPrograms", breaks = colnames(jac_mat)[hc$order][seq(5, ncol(jac_mat), by = 5)], labels = seq(5, ncol(jac_mat), by = 5)) +
  421. scale_y_discrete(name = "\nPrograms", breaks = colnames(jac_mat)[hc$order][seq(5, ncol(jac_mat), by = 5)], labels = seq(5, ncol(jac_mat), by = 5))
  422. prog_ordered <- colnames(jac_mat[hc$order, hc$order])
  423. plot(hc)
  424. rect.hclust(hc , k = 3, border = 2:6)
  425. clusterCut <- stats::cutree(tree = hc, k = 3)
  426. metaprog_df <- data.frame(row.names = prog_ordered)
  427. metaprog_df$cluster <- (clusterCut[prog_ordered])
  428. metaprog_df$cells <- prog_ordered
  429. metaprog_df$cluster <- as.factor(metaprog_df$cluster)
  430. metaprog_annotation_plot <- ggplot(metaprog_df, aes(x = factor(cells, levels = cells), y = 1)) +
  431. geom_raster(aes(fill = cluster)) + theme(legend.position = "bottom", axis.ticks = element_blank(),panel.background = element_rect(fill = "white"), axis.text = element_blank(), axis.line = element_blank(), axis.text.x = element_blank(),axis.title = element_text(size=16)) +
  432. labs(x = "", y = "", fill = "")
  433. egg::ggarrange(p1, metaprog_annotation_plot, ncol = 1, nrow = 2, heights = c(40, 2))
  434. clust_list <- list(names(clusterCut[clusterCut == 1]), names(clusterCut[clusterCut == 2]),names(clusterCut[clusterCut == 3]))
  435. mp_freqs <- sapply(clust_list, function(k) sort(table(unlist(chromatin_mat[k])), decreasing = T), simplify = F)
  436. chromatin_metaprograms <- sapply(mp_freqs, function(tab) head(names(tab)[tab >= 3], 50), simplify = F)
  437. names(chromatin_metaprograms)<-c("LQ1","chromatin_clean","LQ2")
  438. chromatin_metaprogram_clean<-chromatin_metaprograms$chromatin_clean
  439. clust_list2 <- list(names(clusterCut[clusterCut == 1]), names(clusterCut[clusterCut == 3]),names(clusterCut[clusterCut == 2]))
  440. #this is the order to use for the final MP heatmap
  441. clust_list_chromatin <- c(names(clusterCut[clusterCut == 1]), names(clusterCut[clusterCut == 2]),names(clusterCut[clusterCut == 3]))
  442. ###### MPs after OP/AC split and LQ/chromatin.reg split#######
  443. MP_list2<-MP_list[-c(5,7)]
  444. MP_list2[["chromatin.reg"]] <- chromatin_metaprogram_clean
  445. MP_list2[["OPC"]] <- opc.ac_metaprograms$OPC
  446. MP_list2[["AC"]] <- opc.ac_metaprograms$AC
  447. ###### SPOT ASSIGNMENTS TO CLEANED METAPROGRAMS##########
  448. # generate normalized exp matrices
  449. file_paths <- list.files(path ="general/exp_mats_GBM", pattern = "\\.rds", full.names = TRUE)
  450. sample_ls <- gsub(pattern = "\\.rds$", replacement = "", x = basename(file_paths))
  451. sample_ls->samples_names
  452. sample_ls->samples
  453. per_sample_mat <- lapply(file_paths, readRDS)
  454. for (i in seq_along(per_sample_mat)){
  455. m <- as.matrix(per_sample_mat[[i]])
  456. m <- m[-grep("^MT-|^RPL|^RPS", rownames(m)), ]
  457. if(min(colSums(m)) == 0){m <- m[, colSums(m) != 0]}
  458. scaling_factor <- 1000000/colSums(m)
  459. m_CPM <- sweep(m, MARGIN = 2, STATS = scaling_factor, FUN = "*")
  460. m_loged <- log2(1 + (m_CPM/10))
  461. # removing genes with zero variance across all cells
  462. var_filter <- apply(m_loged, 1, var)
  463. m_proc <- m_loged[var_filter != 0, ]
  464. # filtering out lowly expressed genes
  465. exp_genes <- rownames(m_proc)[(rowMeans(m_proc) > 0.4)]
  466. m_proc <- m_proc[exp_genes, ]
  467. # output to a list of gene expression profiles (GEP)
  468. per_sample_mat[[i]] <- m_proc
  469. names(per_sample_mat)[i] <- sample_ls[[i]]
  470. rm(m,m_loged, var_filter, exp_genes, m_proc)
  471. }
  472. #generate a list with the filtered exp matrix for each sample, i.e. m_proc<-(per_sample_mat[[1]])
  473. score_mat <- lapply(c(1:length(per_sample_mat)), function(i){
  474. m_proc<-per_sample_mat[[i]]
  475. metaprograms_gene_list <- readRDS("MP/clean_spatial_gbm_metaprograms_124.rds")
  476. signatures <- scalop::sigScores(m_proc, metaprograms_gene_list, expr.center = TRUE, conserved.genes = 0.5)
  477. spot_scores <- data.frame(spot_names = rownames(signatures))
  478. spot_scores$Neuron <- signatures$Neuron
  479. spot_scores$Vasc<- signatures$Vasc
  480. spot_scores$MES.Hyp <- signatures$MES.Hyp
  481. spot_scores$Mac <- signatures$Mac
  482. spot_scores$Oligo <- signatures$Oligo
  483. spot_scores$MES <- signatures$MES
  484. spot_scores$Prolif.Metab <- signatures$Prolif.Metab
  485. spot_scores$MES.Ast <- signatures$MES.Ast
  486. spot_scores$Reactive.Ast <- signatures$Reactive.Ast
  487. spot_scores$NPC <- signatures$NPC
  488. spot_scores$Inflammatory.Mac <- signatures$Inflammatory.Mac
  489. spot_scores$chromatin.reg <- signatures$chromatin.reg
  490. spot_scores$OPC <- signatures$OPC
  491. spot_scores$AC <- signatures$AC
  492. return(spot_scores)
  493. })
  494. names(score_mat) <- sample_ls
  495. for (i in seq_along(score_mat)){
  496. score_df <- as.data.frame(score_mat[[i]])
  497. score_df <-column_to_rownames(score_df, 'spot_names')
  498. maxcol_meta<-maxcol_strict(score_df)
  499. maxcol_meta<-stack(maxcol_meta)
  500. setnames(maxcol_meta,2,"spot_type_meta_new")
  501. setnames(maxcol_meta,1,"SpotID")
  502. }

Module1_MP.R at commit f38f9b6, no license · at the source

Overview

Authors: Genaro R Villa1, Paolo Alimonti1, Joseph S Toker2, Raziye Piranlioglu1, Mikayla A Karkoski1, Debora Mazzetti1, Reda Ben Mrid3, Sara El Guendouzi3, Alexa Lauinger1,4, Andrew N Chiocca1, Rachid El Fatimy3, E Antonio Chiocca1, Marco Mineo1
  1. Harvey W. Cushing Neuro-oncology Laboratories, Department of Neurosurgery, Brigham and Women’s Hospital and Harvard Medical School, Boston, MA USA
  2. Harvard Medical School, Boston, MA USA
  3. Faculty of Medical Sciences, UM6P Hospitals, Mohammed VI Polytechnic University, Benguerir, Morocco
  4. Carle Illinois College of Medicine, Urbana, IL USA
Institutions: Brigham and Women's Hospital (United States); Harvard University (United States); Université Mohammed VI Polytechnique (Morocco)
Journal: Cell death & disease, volume 17, issue 1, article 352
Dates: received 17 June 2025; accepted 6 March 2026; published online 24 March 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1038/s41419-026-08576-6 · PMID 41872153 · PMCID PMC13039110 · OpenAlex W7140234994
Open access: gold, a free copy (OpenAlex)
Status: code verified (how the code is found and verified)
Categories: human (organism), mouse (organism), other condition (population), cellular / molecular (subfield)
Methods: Statistics, Smoothing, state filtering, decompositions, Evoked potentials, Connectivity
Keywords: CNS cancer, RNA splicing
MeSH: Brain Neoplasms*, Genes, cdc*, Glioblastoma*, Heterogeneous-Nuclear Ribonucleoprotein Group F-H*, RNA Splicing*, Animals, Cell Cycle, Cell Line, Tumor, Cell Proliferation, Disease Progression, G2 Phase Cell Cycle Checkpoints, Gene Expression Regulation, Neoplastic, Humans, Mice (* major topic)
Topic: RNA Research and Splicing (Molecular Biology, Biochemistry, Genetics and Molecular Biology), according to OpenAlex
Funding: Neurosurgery Research and Education Foundation; U.S. Department of Health &amp; Human Services | NIH | National Institute of General Medical Sciences (T32GM144273); NIGMS NIH HHS (T32 GM144273); U.S. Department of Health & Human Services | NIH | National Institute of General Medical Sciences (NIGMS) (T32GM144273)
Citations: cited by 1 paper (Europe PMC); 41 references in the paper

Abstract

Although glioblastoma (GBM) harbors multiple genetic abnormalities leading to cell cycle deregulation, a functional mitotic checkpoint is essential to prevent mitotic catastrophe and tumor cell death. Here, we identify the RNA-binding protein HNRNPH1 as a key post-transcriptional modulator of G2/M checkpoint-associated genes in GBM. HNRNPH1 is overexpressed in malignant cells, especially in the neural- and oligodendrocyte-progenitor-like state, and its expression levels are higher in non-hypoxic regions of the tumor. Knocking out HNRNPH1 causes aberrant splicing and downregulation of several genes involved in cell division. These molecular alterations are associated with G2/M cell cycle arrest, reduced cell proliferation, abnormal cell morphology, and increased nuclear fragmentation. Silencing HNRNPH1 in vivo inhibits the tumor growth of patient-derived GBM cell-originated intracranial xenografts and has significant survival benefits. Together, our results show the critical importance of HNRNPH1 in cell cycle progression and tumor growth, potentially impacting the development of novel strategies to treat GBM.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repository

Its files are read in the Code ↔ Paper reader above, with 2 matches between paragraphs and lines of code.

tiroshlab/Spatial_Glioma

License: none: the authors keep all their rights
State: the link answers, verified on 30 September 2026
Evidence: files inventoried
Commit: f38f9b60ddbeefd9739e1483cbc66b2650f931d3, 6 January 2025
Languages: R (6)
Size: 7 files, 6 scripts
Software Heritage: not archived
Found in: the text, “Analysis of spatial transcriptomics data”
Holds: README
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: tidyverse (4 files), patchwork (3 files), data.table (2 files), ggpubr (2 files), igraph (2 files), reshape2 (2 files), circlize (1 file), ComplexHeatmap (1 file), ggplot2 (1 file), reticulate (1 file), Seurat (1 file), SingleCellExperiment (1 file)
Availability: 1 check, the latest on 30 September 2026: the link answers
  • 30 September 2026: the link answers
7 files

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:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 6 scripts, each with its path and the digest of its content;
  • 2 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

Data availability

The datasets generated and/or analyzed during the current study are available in the Gene Expression Omnibus (GEO), GSE294242, GSE294345, and GSE137489 (https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE137489).

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, 30 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 13 authors, 2 keywords, 14 MeSH terms, 4 funders, 41 references.

Cite

This paper

Villa, G. R., Alimonti, P., Toker, J. S., Piranlioglu, R., Karkoski, M. A., Mazzetti, D., Ben Mrid, R., El Guendouzi, S., Lauinger, A., Chiocca, A. N., El Fatimy, R., Chiocca, E. A., & Mineo, M. (2026). HNRNPH1 drives glioblastoma progression by regulating the splicing of cell cycle genes. Cell death & disease, 17(1), 352. https://doi.org/10.1038/s41419-026-08576-6

BibTeX

@article{villa2026hnrnph1,
author = {Villa, Genaro R and Alimonti, Paolo and Toker, Joseph S and Piranlioglu, Raziye and Karkoski, Mikayla A and Mazzetti, Debora and Ben Mrid, Reda and El Guendouzi, Sara and Lauinger, Alexa and Chiocca, Andrew N and El Fatimy, Rachid and Chiocca, E Antonio and Mineo, Marco},
title = {{HNRNPH1 drives glioblastoma progression by regulating the splicing of cell cycle genes}},
journal = {Cell death \& disease},
year = {2026},
month = mar,
volume = {17},
number = {1},
pages = {352},
publisher = {Nature Publishing Group},
issn = {2041-4889},
doi = {10.1038/s41419-026-08576-6},
url = {https://doi.org/10.1038/s41419-026-08576-6},
pmid = {41872153},
pmcid = {PMC13039110}
}

RIS

TY - JOUR
AU - Villa, Genaro R
AU - Alimonti, Paolo
AU - Toker, Joseph S
AU - Piranlioglu, Raziye
AU - Karkoski, Mikayla A
AU - Mazzetti, Debora
AU - Ben Mrid, Reda
AU - El Guendouzi, Sara
AU - Lauinger, Alexa
AU - Chiocca, Andrew N
AU - El Fatimy, Rachid
AU - Chiocca, E Antonio
AU - Mineo, Marco
TI - HNRNPH1 drives glioblastoma progression by regulating the splicing of cell cycle genes
T2 - Cell death & disease
J2 - Cell Death Dis
PY - 2026
DA - 2026/03/24
VL - 17
IS - 1
SP - 352
SN - 2041-4889
PB - Nature Publishing Group
DO - 10.1038/s41419-026-08576-6
UR - https://doi.org/10.1038/s41419-026-08576-6
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41419-026-08576-6",
"type": "article-journal",
"title": "HNRNPH1 drives glioblastoma progression by regulating the splicing of cell cycle genes",
"container-title": "Cell death & disease",
"author": [
{
"family": "Villa",
"given": "Genaro R"
},
{
"family": "Alimonti",
"given": "Paolo"
},
{
"family": "Toker",
"given": "Joseph S"
},
{
"family": "Piranlioglu",
"given": "Raziye"
},
{
"family": "Karkoski",
"given": "Mikayla A"
},
{
"family": "Mazzetti",
"given": "Debora"
},
{
"family": "Ben Mrid",
"given": "Reda"
},
{
"family": "El Guendouzi",
"given": "Sara"
},
{
"family": "Lauinger",
"given": "Alexa"
},
{
"family": "Chiocca",
"given": "Andrew N"
},
{
"family": "El Fatimy",
"given": "Rachid"
},
{
"family": "Chiocca",
"given": "E Antonio"
},
{
"family": "Mineo",
"given": "Marco"
}
],
"container-title-short": "Cell Death Dis",
"volume": "17",
"issue": "1",
"page": "352",
"DOI": "10.1038/s41419-026-08576-6",
"PMID": "41872153",
"PMCID": "PMC13039110",
"ISSN": "2041-4889",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41419-026-08576-6",
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
24
]
]
}
}

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.1016/j.celrep.2024.115149 [code]
Single-nucleus and spatial landscape of the sub-ventricular zone in human glioblastoma.
Journal: Cell reports
In common: reticulate, SingleCellExperiment, circlize, 9 other tools, other condition, cellular / molecular, 3 references
[2] doi:10.1038/s41586-026-10214-2 [code]
Multidimensional profiling of heterogeneity in supratentorial ependymomas.
Journal: Nature
In common: reticulate, SingleCellExperiment, circlize, 9 other tools, other condition, mouse, 2 references
[3] doi:10.1038/s41586-023-06623-2 [code]
Clinical trial links oncolytic immunoactivation to survival in glioblastoma.
Journal: Nature
In common: circlize, ComplexHeatmap, ggpubr, 2 other tools, other condition, 2 authors
[4] doi:10.1016/j.xcrm.2026.102766 [code]
A longitudinal single-cell and spatial multiomic atlas of pediatric high-grade glioma.
Journal: Cell reports. Medicine
In common: SingleCellExperiment, circlize, ComplexHeatmap, 8 other tools, other condition, cellular / molecular, 2 references
[5] doi:10.1038/s41586-026-10612-6 [code]
Acquired genetic and cell-state changes in IDH-mutant glioma progression.
Journal: Nature
In common: SingleCellExperiment, ComplexHeatmap, igraph, 7 other tools, other condition, cellular / molecular, 3 references
[6] doi:10.1038/s41591-024-02969-w [code]
A prognostic neural epigenetic signature in high-grade glioma.
Journal: Nature medicine
In common: reticulate, SingleCellExperiment, igraph, 7 other tools, other condition, mouse, 3 references
[7] doi:10.1016/j.isci.2022.105276 [code]
Integrative genomic analysis facilitates precision strategies for glioblastoma treatment.
Journal: iScience
In common: reticulate, SingleCellExperiment, igraph, 7 other tools, other condition, 3 references
[8] doi:10.1172/jci.insight.179853 [code]
Spatial analysis of recurrent glioblastoma reveals perivascular niche organization.
Journal: JCI insight
In common: reticulate, SingleCellExperiment, ComplexHeatmap, 7 other tools, other condition, cellular / molecular, 2 references
[9] doi:10.1186/s13059-024-03407-3 [code]
Spatiotemporal modeling reveals high-resolution invasion states in glioblastoma.
Journal: Genome biology
In common: circlize, ComplexHeatmap, igraph, 6 other tools, other condition, mouse, 3 references
[10] doi:10.3390/biomedicines13061304 [code]
Multi-Transcriptomic Analysis Reveals GSC-Driven MES-Like Differentiation via EMT in GBM Cell-Cell Communication.
Journal: Biomedicines
In common: SingleCellExperiment, igraph, Seurat, 4 other tools, NCBI GEO GSE131928, other condition, cellular / molecular, 2 references

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.

Add the badge to the code's README

OSCR: the badge of this paper

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 -->
[![OSCR](https://openscicode.org/badge/doi/10.1038/s41419-026-08576-6.svg)](https://openscicode.org/badge/doi/10.1038/s41419-026-08576-6)
<!-- oscr-badge:end -->
reStructuredText
.. oscr-badge:start

.. image:: https://openscicode.org/badge/doi/10.1038/s41419-026-08576-6.svg
   :target: https://openscicode.org/badge/doi/10.1038/s41419-026-08576-6
   :alt: OSCR

.. oscr-badge:end
HTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1038/s41419-026-08576-6"><img src="https://openscicode.org/badge/doi/10.1038/s41419-026-08576-6.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.