OSCR

Long-term effects of adolescent risperidone treatment on the mouse cortex.

Code ↔ Paper

4 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 4 matches
  1. [1] § Materials and methods › SnRNA-seq statistics ↔ Antipsychotic_github.Rmd, lines 931–1055 · score 0.85 · FDR threshold, Cellular Component, EnrichGO, Biological Process, Molecular Function, CC
  2. [2] § Results › SnRNA-seq analysis shows transcriptional changes associated with synaptic function in risperidone-treated mouse cortex ↔ Antipsychotic_github.Rmd, lines 2263–2404 · score 0.72 · log2FC, Upregulated genes, downregulated genes, GO enrichment, log10 adjusted, MF
  3. [3] § Results › High-dimensional WGCNA identifies key gene modules associated with risperidone treatment ↔ Antipsychotic_github.Rmd, lines 3495–3592 · score 0.64 · co expression network, module assignment, hub gene, glutamatergic neurons, Dendogram, WGCNA
  4. [4] § Results › High-dimensional WGCNA identifies key gene modules associated with risperidone treatment ↔ Antipsychotic_github.Rmd, lines 3384–3493 · score 0.61 · M10, GO terms, hdWGCNA, M8, M9, M6

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

R Markdown · 5,888 lines · 195 KB · no license · 4 matches

  1. ---
  2. title: "Antipsychotic_manuscript"
  3. output: html_notebook
  4. ---
  5. Libraries
  6. ```{r}
  7. library(Seurat)
  8. library(DESeq2)
  9. library(clusterProfiler)
  10. library(enrichR)
  11. library(GeneOverlap)
  12. library(WGCNA)
  13. library(hdWGCNA)
  14. library(ensembldb)
  15. library(org.Mm.eg.db)
  16. library(ggplot2)
  17. library(ggrepel)
  18. library(dplyr)
  19. library(tidyr)
  20. library(Matrix)
  21. library(cowplot)
  22. library(patchwork)
  23. library(tidyverse)
  24. library(magrittr)
  25. library(igraph)
  26. library(pheatmap)
  27. library(RColorBrewer)
  28. library(openxlsx)
  29. library(writexl)
  30. ```
  31. Load h5 files
  32. ```{r}
  33. counts_r1 <- Read_CellBender_h5_Mat(file_name = "~/Risperidone_Proj/Hahn_AA01_1/Hahn_AA01/count/Hahn_AA01_Risperdal_1/outs/cellbender_output/cellbender_filtered_feature_bc_matrix_filtered.h5")
  34. counts_r2 <- Read_CellBender_h5_Mat(file_name = "~/Risperidone_Proj/Hahn_AA01_1/Hahn_AA01/count/Hahn_AA01_Risperdal_2/outs/cellbender_output/cellbender_filtered_feature_bc_matrix_filtered.h5")
  35. counts_s1 <- Read_CellBender_h5_Mat(file_name = "~/Risperidone_Proj/Hahn_AA01_1/Hahn_AA01/count/Hahn_AA01_Saline_1/outs/cellbender_output/cellbender_filtered_feature_bc_matrix_filtered.h5")
  36. counts_s2 <- Read_CellBender_h5_Mat(file_name = "~/Risperidone_Proj/Hahn_AA01_1/Hahn_AA01/count/Hahn_AA01_Saline_2/outs/cellbender_output/cellbender_filtered_feature_bc_matrix_filtered.h5")
  37. ```
  38. Create Seurat object
  39. ```{r}
  40. SO_r1 <- CreateSeuratObject(counts = counts_r1, project = "risperdal", min.cells = 3, min.features = 200)
  41. SO_r2 <- CreateSeuratObject(counts = counts_r2, project = "risperdal", min.cells = 3, min.features = 200)
  42. SO_s1 <- CreateSeuratObject(counts = counts_s1, project = "saline", min.cells = 3, min.features = 200)
  43. SO_s2 <- CreateSeuratObject(counts = counts_s2, project = "saline", min.cells = 3, min.features = 200)
  44. ```
  45. Merge Seurat objects
  46. ```{r}
  47. Mcortex <- merge(SO_r1, y = c(SO_r2, SO_s1, SO_s2), add.cell.ids = c("R1", "R2", "S1", "S2"), project = "Mcortex")
  48. # Create joint count matrix
  49. Mcortex <- JoinLayers(Mcortex)
  50. Layers(Mcortex[["RNA"]])
  51. ```
  52. Quality Control
  53. ```{r}
  54. # Add number of genes per UMI for each cell to metadata
  55. Mcortex$log10GenesPerUMI <- log10(Mcortex$nFeature_RNA) / log10(Mcortex$nCount_RNA)
  56. # Compute percent mito ratio
  57. Mcortex$mitoRatio <- PercentageFeatureSet(object = Mcortex, pattern = "^mt-")
  58. Mcortex$mitoRatio <- [email hidden]$mitoRatio / 100
  59. # Visualize mitoRatio as a violin plot
  60. VlnPlot(Mcortex, features = c("mitoRatio"), ncol = 3, raster=FALSE)
  61. # Visualize the number of cell counts per sample
  62. [email hidden] %>%
  63. mutate(orig.ident = factor(orig.ident, levels = c("saline", "risperdal"))) %>%
  64. ggplot(aes(x = orig.ident, fill = orig.ident)) +
  65. geom_bar() +
  66. geom_text(stat = "count", aes(label = after_stat(count)), vjust = -0.3, size = 3.5) +
  67. theme_classic() +
  68. theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
  69. theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
  70. ggtitle("NCells")
  71. # Visualize the number UMIs/transcripts per cell
  72. [email hidden] %>%
  73. ggplot(aes(color=orig.ident, x=nCount_RNA, fill= orig.ident)) +
  74. geom_density(alpha = 0.2) +
  75. scale_x_log10() +
  76. theme_classic() +
  77. ylab("Cell density") +
  78. geom_vline(xintercept = 500)
  79. # Visualize the distribution of genes detected per cell via histogram
  80. [email hidden] %>%
  81. ggplot(aes(color=orig.ident, x=nFeature_RNA, fill= orig.ident)) +
  82. geom_density(alpha = 0.2) +
  83. theme_classic() +
  84. scale_x_log10() +
  85. geom_vline(xintercept = 300)
  86. # Visualize the correlation between genes detected and number of UMIs and determine whether strong presence of cells with low numbers of genes/UMIs
  87. [email hidden] %>%
  88. ggplot(aes(x=nCount_RNA, y=nFeature_RNA, color=mitoRatio)) +
  89. geom_point() +
  90. scale_colour_gradient(low = "gray90", high = "black") +
  91. stat_smooth(method=lm, aes(color = mitoRatio)) +
  92. scale_x_log10() +
  93. scale_y_log10() +
  94. theme_classic() +
  95. geom_vline(xintercept = 500) +
  96. geom_hline(yintercept = 250) +
  97. facet_wrap(~orig.ident)
  98. # Visualize the distribution of mitochondrial gene expression detected per cell
  99. [email hidden] %>%
  100. ggplot(aes(color=orig.ident, x=mitoRatio, fill=orig.ident)) +
  101. geom_density(alpha = 0.2) +
  102. scale_x_log10() +
  103. theme_classic() +
  104. geom_vline(xintercept = 0.2)
  105. # Visualize the overall complexity of the gene expression by visualizing the genes detected per UMI
  106. [email hidden] %>%
  107. ggplot(aes(x=log10GenesPerUMI, color = orig.ident, fill=orig.ident)) +
  108. geom_density(alpha = 0.2) +
  109. theme_classic() +
  110. geom_vline(xintercept = 0.8)
  111. #Cell-Level Filtering
  112. # Filter out low quality reads using selected thresholds - these will change with experiment
  113. Mcortex_QC <- subset(x = Mcortex,
  114. subset= (nCount_RNA >= 500) &
  115. (nFeature_RNA >= 250) &
  116. (log10GenesPerUMI > 0.80) &
  117. (mitoRatio < 0.20))
  118. # Gene-Level Filtering
  119. # Extract counts
  120. counts_cell <- GetAssayData(object = Mcortex_QC, layer = "counts")
  121. # Output a logical vector for every gene on whether the more than zero counts per cell
  122. nonzero <- counts_cell > 0
  123. # Sums all TRUE values and returns TRUE if more than 10 TRUE values per gene
  124. keep_genes <- Matrix::rowSums(nonzero) >= 10
  125. # Only keeping those genes expressed in more than 10 cells
  126. filtered_counts <- counts_cell[keep_genes, ]
  127. # Reassign to filtered Seurat object
  128. Mcortex_QC <- CreateSeuratObject(filtered_counts, meta.data = [email hidden])
  129. # Visualize Cell counts after filtering
  130. [email hidden] %>%
  131. mutate(orig.ident = factor(orig.ident, levels = c("saline", "risperdal"))) %>%
  132. ggplot(aes(x = orig.ident, fill = orig.ident)) +
  133. geom_bar() +
  134. geom_text(stat = "count", aes(label = after_stat(count)), vjust = -0.3, size = 3.5) +
  135. theme_classic() +
  136. theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
  137. theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
  138. ggtitle("NCells post-filter")
  139. ```
  140. Dimensionality reduction and normalization
  141. ```{r}
  142. # Normalize and scale the data
  143. Mcortex_QC <- SCTransform(Mcortex_QC, verbose = FALSE)
  144. # Perform PCA
  145. Mcortex_QC <- RunPCA(Mcortex_QC, features = VariableFeatures(object = Mcortex_QC))
  146. ```
  147. Re-organize metadata
  148. ```{r}
  149. # Create new metadata called Tx, and change saline to Control
  150. Mcortex_QC$Tx <- ifelse(Mcortex_QC$orig.ident == "saline", "Control", "Risperidone")
  151. # Make it into a factor for consistent ordering in plot
  152. Mcortex_QC$Tx <- factor(Mcortex_QC$Tx, levels = c("Control", "Risperidone"))
  153. ```
  154. Add metadata for predicted sex
  155. ```{r}
  156. # read CSV file with predicted sex information
  157. sex_info <- read.csv("~/Risperidone_Proj/Hahn_AA01_1/Hahn_AA01/aggr/Hahn_AA01/outs/predicted_sex.csv")
  158. # Add prefix based on suffix
  159. sex_info <- sex_info %>%
  160. mutate(
  161. new_barcode = paste0(
  162. case_when(
  163. str_detect(X, "-1$") ~ "R1_",
  164. str_detect(X, "-2$") ~ "R2_",
  165. str_detect(X, "-3$") ~ "S1_",
  166. str_detect(X, "-4$") ~ "S2_",
  167. TRUE ~ NA_character_
  168. ),
  169. str_remove(X, "-[1-4]$"),
  170. "-1"
  171. )
  172. )
  173. # Check the new barcode
  174. View(sex_info)
  175. # Create a named vector for easy lookup
  176. barcode_to_sex <- setNames(sex_info$Predicted_Sex, sex_info$new_barcode)
  177. # Perform matching between Mcortex_QC and sex_info
  178. Predicted_Sex_vec <- barcode_to_sex[match(colnames(Mcortex_QC), names(barcode_to_sex))]
  179. # Find the barcodes from sex_info that are not found in Mcortex_QC
  180. unmatched_barcodes <- sex_info[is.na(match(sex_info$new_barcode, colnames(Mcortex_QC))), ]
  181. # Save the unmatched barcodes to a separate CSV file for record-keeping
  182. write.csv(unmatched_barcodes, "unmatched_barcodes_from_RisperdalProj4.csv", row.names = FALSE)
  183. # Find the shared barcodes between Mcortex_QC and sex_info
  184. shared_barcodes <- intersect(colnames(Mcortex_QC), sex_info$new_barcode)
  185. # Extract the Predicted_Sex values for the shared barcodes from sex_info
  186. Predicted_Sex_shared <- sex_info$Predicted_Sex[match(shared_barcodes, sex_info$new_barcode)]
  187. # Create a vector for Predicted_Sex with NA for unmatched barcodes
  188. Predicted_Sex_vec <- rep(NA, ncol(Mcortex_QC)) # Default to NA for all cells
  189. names(Predicted_Sex_vec) <- colnames(Mcortex_QC) # Ensure the names are the same as the column names of Mcortex_QC
  190. # Assign the Predicted_Sex values to the shared barcodes
  191. Predicted_Sex_vec[shared_barcodes] <- Predicted_Sex_shared
  192. # Add the Predicted_Sex metadata column to Mcortex_QC
  193. Mcortex_QC <- AddMetaData(Mcortex_QC, metadata = Predicted_Sex_vec, col.name = "Predicted_Sex")
  194. # Check new metadata
  195. View([email hidden])
  196. ```
  197. Clustering and UMAP visualization
  198. ```{r}
  199. # Determine the dimensionality of the dataset
  200. ElbowPlot(Mcortex_QC)
  201. Mcortex_QC <- FindNeighbors(Mcortex_QC, dims = 1:20)
  202. Mcortex_QC <- FindClusters(Mcortex_QC, resolution = 0.5)
  203. # Run non-linear dimensional reduction (UMAP)
  204. Mcortex_QC <- RunUMAP(Mcortex_QC, dims = 1:20)
  205. # visualize UMAP
  206. DimPlot(Mcortex_QC, reduction = "umap", label = TRUE, raster = FALSE, pt.size = 0.1, alpha = 0.5) + ggtitle("")
  207. ```
  208. Find cluster markers
  209. ```{r}
  210. # find markers for every cluster compared to all remaining cells, report only the positive ones
  211. cluster.markers <- FindAllMarkers(Mcortex_QC, only.pos = TRUE)
  212. cluster.markers <- cluster.markers %>%
  213. group_by(cluster) %>%
  214. dplyr::filter(avg_log2FC > 1) %>%
  215. arrange(desc(avg_log2FC))
  216. write.xlsx(cluster.markers, file = "cluster_markers_Proj4_all.xlsx")
  217. ```
  218. Assign cell type identity to clusters
  219. ```{r}
  220. # Define cluster ID's
  221. cluster.id2 <- c(
  222. "0" = "Glutamatergic L2/3 IT",
  223. "1" = "Astrocytes",
  224. "2" = "Glutamatergic L6 CT",
  225. "3" = "Glutamatergic L5 IT",
  226. "4" = "Glutamatergic (unspecified)",
  227. "5" = "GABAergic Vip",
  228. "6" = "Glutamatergic L5 IT",
  229. "7" = "Glutamatergic L2/3 IT",
  230. "8" = "Glutamatergic L6 IT",
  231. "9" = "GABAergic Pvalb",
  232. "10" = "Oligodendrocytes",
  233. "11" = "Astrocytes",
  234. "12" = "Glutamatergic L5/6 NP",
  235. "13" = "GABAergic Sst",
  236. "14" = "Glutamatergic L5 ET",
  237. "15" = "Undetermined",
  238. "16" = "Oligodendrocytes",
  239. "17" = "GABAergic Lamp5",
  240. "18" = "Glutamatergic (unspecified)",
  241. "19" = "Glutamatergic L6 CT",
  242. "20" = "Glutamatergic L5/6 NP",
  243. "21" = "Endothelial cells",
  244. "22" = "Oligodendrocytes",
  245. "23" = "Glutamatergic L6 IT Car3",
  246. "24" = "Glutamatergic (unspecified)",
  247. "25" = "Undetermined",
  248. "26" = "Oligodendrocytes"
  249. )
  250. Mcortex_QC$celltype2 <- unname(cluster.id2[clusters_char])
  251. # Visualize on UMAP
  252. DimPlot(Mcortex_QC, reduction = "umap", group.by = 'celltype2', label = TRUE, raster = FALSE, repel = TRUE, pt.size = 0.1, alpha = 0.5) + ggtitle("")
  253. ```
  254. Count the number of cells per cell type
  255. ```{r}
  256. # NCell by cell type
  257. [email hidden] %>%
  258. ggplot(aes(x = celltype1, fill = celltype1)) +
  259. geom_bar() +
  260. geom_text(stat = "count", aes(label = after_stat(count)), vjust = -0.3, size = 3) +
  261. theme_classic() +
  262. theme(
  263. axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1),
  264. plot.title = element_text(hjust = 0.5, face = "bold", margin = margin(b = 20)),
  265. legend.position = "none"
  266. ) +
  267. scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
  268. ggtitle("NCells by cell type")
  269. ```
  270. DE analysis (Pseudobulk) - Glut (all glutamatergic neurons)
  271. ```{r}
  272. # Get the expression matrix
  273. expr_mat <- GetAssayData(Mcortex_QC, assay = "SCT", layer = "data")
  274. Glut_cells <- colnames(Mcortex_QC)[Mcortex_QC$celltype1 == "Glutamatergic neurons"]
  275. # Subset Seurat object for all glutamatergic neurons
  276. Mcortex_QC_Glut <- subset(Mcortex_QC, cells = Glut_cells)
  277. # Filter out all genes with count sum <10
  278. Mcortex_QC_Glut <- subset(Mcortex_QC_Glut, features = rownames(Mcortex_QC_Glut)[Matrix::rowSums(GetAssayData(Mcortex_QC_Glut, assay = "RNA", layer = "counts")) >= 10])
  279. # Extract sample_id from barcode names
  280. Mcortex_QC_Glut$sample_id <- sapply(strsplit(Cells(Mcortex_QC_Glut), "_"), `[`, 1)
  281. # Aggregate counts
  282. expr_mat_Glut <- AggregateExpression(
  283. Mcortex_QC_Glut,
  284. group.by = c("Tx", "sample_id"),
  285. assays = "RNA"
  286. )$RNA
  287. # Create colData (metadata about your samples)
  288. sample_info_Glut <- data.frame(
  289. sample_id = colnames(expr_mat_Glut),
  290. condition = ifelse(grepl("Risperidone", colnames(expr_mat_Glut)), "Risperidone", "Control"),
  291. stringsAsFactors = FALSE
  292. )
  293. rownames(sample_info_Glut) <- sample_info_Glut$sample_id
  294. # Build DESeq2 object
  295. dds_Glut <- DESeqDataSetFromMatrix(
  296. countData = expr_mat_Glut,
  297. colData = sample_info_Glut,
  298. design = ~ condition
  299. )
  300. # Run DE analysis
  301. dds_Glut <- DESeq(dds_Glut)
  302. # Get results
  303. res_Glut <- results(dds_Glut, contrast = c("condition", "Risperidone", "Control"))
  304. # Save results
  305. write.csv(
  306. as.data.frame(res_Glut) %>%
  307. subset(!is.na(padj)) %>%
  308. arrange(padj, desc(abs(log2FoldChange))),
  309. file = paste0("~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_Glut.csv"),
  310. row.names = TRUE
  311. )
  312. ```
  313. Glut DEG - heatmap
  314. ```{r}
  315. # Count the number of DEGs with padj < 0.05
  316. sum(res_Glut$padj < 0.05, na.rm = TRUE) #9092
  317. # Select all DEGs with padj < 0.05 and remove NA
  318. res_Glut_filtered <- res_Glut[!is.na(res_Glut$padj) & res_Glut$padj < 0.05, ]
  319. # Then order and extract gene names
  320. top_genes_Glut <- rownames(res_Glut_filtered[order(res_Glut_filtered$padj), ])
  321. # Perform Variance-Stabilizing Transformation (VST)
  322. vst_data_Glut <- vst(dds_Glut, blind = TRUE)
  323. # Ensure genes exist in the dataset
  324. common_genes_Glut <- intersect(top_genes_Glut, rownames(assay(vst_data_Glut)))
  325. # Extract the VST-transformed expression values for these genes
  326. heatmap_matrix_Glut <- assay(vst_data_Glut)[common_genes_Glut, ]
  327. # Extract metadata for annotations
  328. annotation_Glut <- sample_info_Glut %>% select(condition)
  329. # Make sure your 'condition' column is a factor in desired order
  330. annotation_Glut$condition <- factor(annotation_Glut$condition, levels = c("Control", "Risperidone"))
  331. # Now reorder the columns of your heatmap matrix
  332. ordered_samples_Glut <- rownames(annotation_Glut)[order(annotation_Glut$condition)]
  333. heatmap_matrix_Glut <- heatmap_matrix_Glut[, ordered_samples_Glut]
  334. annotation_colors_Glut <- list(
  335. condition = c(
  336. "Control" = brewer.pal(8, "Set2")[1],
  337. "Risperidone" = brewer.pal(8, "Set2")[2]
  338. )
  339. )
  340. #Generate Heatmap
  341. pheatmap(heatmap_matrix_Glut,
  342. scale = "row", # Normalize each gene across samples
  343. cluster_rows = TRUE,
  344. cluster_cols = TRUE,
  345. show_rownames = FALSE,
  346. show_colnames = TRUE,
  347. annotation_col = annotation_Glut,
  348. annotation_colors = annotation_colors,
  349. border_color = NA,
  350. fontsize = 8,
  351. main = "",
  352. )
  353. ```
  354. Glut DEG - volcano
  355. ```{r}
  356. # Convert DESeq2 results to a data frame
  357. res_df_Glut <- as.data.frame(res_Glut)
  358. res_df_Glut$gene <- rownames(res_df_Glut)
  359. # Remove any NA values
  360. res_df_Glut <- na.omit(res_df_Glut)
  361. # Define significance threshold
  362. padj_threshold <- 0.05
  363. log2FoldChange_threshold <- 0.5
  364. # Add a new column to categorize genes for coloring
  365. res_df_Glut$Significance <- "Not Significant"
  366. res_df_Glut$Significance[res_df_Glut$padj < padj_threshold & abs(res_df_Glut$log2FoldChange) > log2FoldChange_threshold] <- "Significant"
  367. # Generate volcano plot with specific genes of interest labeled
  368. # Define genes of interest
  369. genes_of_interest_Glut <- c("Kcnh1", "Kcnq2", "Kcnq3", "Kcnq5", "Kcnd3", "Kcnj6", "Kcnj9", "Grin2a", "Grin2b", "Gabra5", "Gabrb1", "Gabrb3", "Gabrg3", "Gabrd", "Shank1", "Shank2", "Dlg1", "Dlg2", "Dlg4")
  370. # Generate Volcano plot
  371. volcano_plot_Glut <- ggplot(res_df_Glut, aes(x = log2FoldChange, y = -log10(padj))) +
  372. geom_point(data = res_df_Glut %>% dplyr::filter(Significance == "Not Significant"),
  373. aes(x = log2FoldChange, y = -log10(padj)),
  374. color = "gray", alpha = 0.5, size = 1) +
  375. geom_point(data = res_df_Glut %>% dplyr::filter(Significance == "Significant" & log2FoldChange > 0),
  376. aes(x = log2FoldChange, y = -log10(padj)),
  377. color = "red", alpha = 0.5, size = 1) +
  378. geom_point(data = res_df_Glut %>% dplyr::filter(Significance == "Significant" & log2FoldChange < 0),
  379. aes(x = log2FoldChange, y = -log10(padj)),
  380. color = "blue", alpha = 0.5, size = 1) +
  381. geom_label_repel(
  382. aes(label = ifelse(gene %in% genes_of_interest_Glut, gene, "")),
  383. size = 7,
  384. box.padding = 0.75,
  385. label.padding = 0.35,
  386. fill = alpha("white", 0),
  387. color = "black",
  388. segment.color = "black",
  389. segment.size = 0.8,
  390. segment.alpha = 0.8,
  391. min.segment.length = 0,
  392. force = 5,
  393. max.overlaps = Inf
  394. ) +
  395. geom_vline(xintercept = c(-0.5, 0.5), linetype = "dotted", color = "black") +
  396. geom_hline(yintercept = -log10(0.05), linetype = "dotted", color = "black") +
  397. theme_minimal() +
  398. labs(title = "Glut",
  399. x = "Log2 Fold Change",
  400. y = "-Log10 Adjusted P-Value") +
  401. theme(
  402. legend.position = "right",
  403. axis.title.x = element_text(size = 16), # X-axis label size
  404. axis.title.y = element_text(size = 16), # Y-axis label size
  405. axis.text.x = element_text(size = 14), # X-axis tick labels
  406. axis.text.y = element_text(size = 14), # Y-axis tick labels
  407. plot.title = element_text(size = 20, face = "bold", hjust = 0.5, margin = margin(b = 20)),
  408. plot.margin = margin(t = 10, r = 10, b = 10, l = 10) # adds space above the whole plot
  409. )
  410. # Print the plot
  411. print(volcano_plot_Glut)
  412. ```
  413. DE analysis (Pseudobulk) - PV-IN
  414. ```{r}
  415. # Subset cell type
  416. Mcortex_QC_Pvalb <- subset(Mcortex_QC, subset = celltype1 == "GABAergic Pvalb")
  417. # Filter out all genes with count sum <10
  418. Mcortex_QC_Pvalb <- subset(Mcortex_QC_Pvalb, features = rownames(Mcortex_QC_Pvalb)[Matrix::rowSums(GetAssayData(Mcortex_QC_Pvalb, assay = "RNA", layer = "counts")) >= 10])
  419. # Extract sample_id from barcode names
  420. Mcortex_QC_Pvalb$sample_id <- sapply(strsplit(Cells(Mcortex_QC_Pvalb), "_"), `[`, 1)
  421. # Aggregate counts
  422. expr_mat_Pvalb <- AggregateExpression(
  423. Mcortex_QC_Pvalb,
  424. group.by = c("Tx", "sample_id"),
  425. assays = "RNA"
  426. )$RNA
  427. # Create colData (metadata about your samples)
  428. sample_info_Pvalb <- data.frame(
  429. sample_id = colnames(expr_mat_Pvalb),
  430. condition = ifelse(grepl("Risperidone", colnames(expr_mat_Pvalb)), "Risperidone", "Control"),
  431. stringsAsFactors = FALSE
  432. )
  433. rownames(sample_info_Pvalb) <- sample_info_Pvalb$sample_id
  434. # Build DESeq2 object
  435. dds_Pvalb <- DESeqDataSetFromMatrix(
  436. countData = expr_mat_Pvalb,
  437. colData = sample_info_Pvalb,
  438. design = ~ condition
  439. )
  440. # Run DE analysis
  441. dds_Pvalb <- DESeq(dds_Pvalb)
  442. # Get results
  443. res_Pvalb <- results(dds_Pvalb, contrast = c("condition", "Risperidone", "Control"))
  444. # Save results
  445. write.csv(
  446. as.data.frame(res_Pvalb) %>%
  447. subset(!is.na(padj)) %>%
  448. arrange(padj, desc(abs(log2FoldChange))),
  449. file = paste0("~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_PV-IN.csv"),
  450. row.names = TRUE
  451. )
  452. ```
  453. PV-IN DEG - heatmap
  454. ```{r}
  455. # Count the number of DEGs with padj < 0.05
  456. sum(res_Pvalb$padj < 0.05, na.rm = TRUE) #2298
  457. # Select all DEGs with padj < 0.05 and remove NA
  458. res_Pvalb_filtered <- res_Pvalb[!is.na(res_Pvalb$padj) & res_Pvalb$padj < 0.05, ]
  459. # Then order and extract gene names
  460. top_genes_Pvalb <- rownames(res_Pvalb_filtered[order(res_Pvalb_filtered$padj), ])
  461. # Perform Variance-Stabilizing Transformation (VST)
  462. vst_data_Pvalb <- vst(dds_Pvalb, blind = TRUE)
  463. # Ensure genes exist in the dataset
  464. common_genes_Pvalb <- intersect(top_genes_Pvalb, rownames(assay(vst_data_Pvalb)))
  465. # Extract the VST-transformed expression values for these genes
  466. heatmap_matrix_Pvalb <- assay(vst_data_Pvalb)[common_genes_Pvalb, ]
  467. # Extract metadata for annotations
  468. annotation_Pvalb <- sample_info_Pvalb %>% select(condition)
  469. # Make sure your 'condition' column is a factor in desired order
  470. annotation_Pvalb$condition <- factor(annotation_Pvalb$condition, levels = c("Control", "Risperidone"))
  471. # Now reorder the columns of your heatmap matrix
  472. ordered_samples_Pvalb <- rownames(annotation_Pvalb)[order(annotation_Pvalb$condition)]
  473. heatmap_matrix_Pvalb <- heatmap_matrix_Pvalb[, ordered_samples_Pvalb]
  474. # Change the colors manually
  475. annotation_colors <- list(
  476. condition = c(
  477. "Control" = "#7ef29d",
  478. "Risperidone" = "#0f68a9"))
  479. annotation_colors_Pvalb <- list(
  480. condition = c(
  481. "Control" = brewer.pal(8, "Set2")[1],
  482. "Risperidone" = brewer.pal(8, "Set2")[2]
  483. )
  484. )
  485. #Generate Heatmap
  486. pheatmap(heatmap_matrix_Pvalb,
  487. scale = "row", # Normalize each gene across samples
  488. cluster_rows = TRUE,
  489. cluster_cols = TRUE,
  490. show_rownames = FALSE,
  491. show_colnames = TRUE,
  492. annotation_col = annotation_Pvalb,
  493. annotation_colors = annotation_colors,
  494. border_color = NA,
  495. fontsize = 8,
  496. main = "")
  497. ```
  498. PV-IN DEG - volcano
  499. ```{r}
  500. # Convert DESeq2 results to a data frame
  501. res_df_Pvalb <- as.data.frame(res_Pvalb)
  502. res_df_Pvalb$gene <- rownames(res_df_Pvalb)
  503. # Remove any NA values
  504. res_df_Pvalb <- na.omit(res_df_Pvalb)
  505. # Add a new column to categorize genes for coloring
  506. res_df_Pvalb$Significance <- "Not Significant"
  507. res_df_Pvalb$Significance[res_df_Pvalb$padj < padj_threshold & abs(res_df_Pvalb$log2FoldChange) > log2FoldChange_threshold] <- "Significant"
  508. # Generate volcano plot with specific genes of interest labeled
  509. # Define genes of interest
  510. genes_of_interest_Pvalb <- c("Kcna2", "Kcnc1", "Kcnc3", "Kcnd3", "Kcnq2", "Kcnq3", "Grin2a", "Grin2b", "Dlg1", "Shank1", "Shank2", "Gabrg3", "Gabra1", "Gabrb1")
  511. # Generate Volcano plot
  512. volcano_plot_Pvalb <- ggplot(res_df_Pvalb, aes(x = log2FoldChange, y = -log10(padj))) +
  513. geom_point(data = res_df_Pvalb %>% dplyr::filter(Significance == "Not Significant"),
  514. aes(x = log2FoldChange, y = -log10(padj)),
  515. color = "gray", alpha = 0.5, size = 1) +
  516. geom_point(data = res_df_Pvalb %>% dplyr::filter(Significance == "Significant" & log2FoldChange > 0),
  517. aes(x = log2FoldChange, y = -log10(padj)),
  518. color = "red", alpha = 0.5, size = 1) +
  519. geom_point(data = res_df_Pvalb %>% dplyr::filter(Significance == "Significant" & log2FoldChange < 0),
  520. aes(x = log2FoldChange, y = -log10(padj)),
  521. color = "blue", alpha = 0.5, size = 1) +
  522. geom_label_repel(
  523. aes(label = ifelse(gene %in% genes_of_interest_Pvalb, gene, "")),
  524. size = 7,
  525. box.padding = 0.75,
  526. label.padding = 0.35,
  527. fill = alpha("white", 0),
  528. color = "black",
  529. segment.color = "black",
  530. segment.size = 0.8,
  531. segment.alpha = 0.8,
  532. min.segment.length = 0,
  533. force = 15,
  534. max.overlaps = Inf
  535. ) +
  536. geom_vline(xintercept = c(-0.5, 0.5), linetype = "dotted", color = "black") +
  537. geom_hline(yintercept = -log10(0.05), linetype = "dotted", color = "black") +
  538. theme_minimal() +
  539. labs(title = "PV-IN",
  540. x = "Log2 Fold Change",
  541. y = "-Log10 Adjusted P-Value") +
  542. theme(
  543. legend.position = "right",
  544. axis.title.x = element_text(size = 16), # X-axis label size
  545. axis.title.y = element_text(size = 16), # Y-axis label size
  546. axis.text.x = element_text(size = 14), # X-axis tick labels
  547. axis.text.y = element_text(size = 14), # Y-axis tick labels
  548. plot.title = element_text(size = 20, face = "bold", hjust = 0.5, margin = margin(b = 10)),
  549. plot.margin = margin(t = 10, r = 10, b = 10, l = 10) # adds space above the whole plot
  550. )
  551. # Print the plot
  552. print(volcano_plot_Pvalb)
  553. ```
  554. DE analysis (Pseudobulk) - Sst-IN
  555. ```{r}
  556. # Subset cell type
  557. Mcortex_QC_Sst <- subset(Mcortex_QC, subset = celltype1 == "GABAergic Sst")
  558. # Filter out all genes with count sum <10
  559. Mcortex_QC_Sst <- subset(Mcortex_QC_Sst, features = rownames(Mcortex_QC_Sst)[Matrix::rowSums(GetAssayData(Mcortex_QC_Sst, assay = "RNA", layer = "counts")) >= 10])
  560. # Extract sample_id from barcode names
  561. Mcortex_QC_Sst$sample_id <- sapply(strsplit(Cells(Mcortex_QC_Sst), "_"), `[`, 1)
  562. # Aggregate counts
  563. expr_mat_Sst <- AggregateExpression(
  564. Mcortex_QC_Sst,
  565. group.by = c("Tx", "sample_id"),
  566. assays = "RNA"
  567. )$RNA
  568. # Create colData (metadata about your samples)
  569. sample_info_Sst <- data.frame(
  570. sample_id = colnames(expr_mat_Sst),
  571. condition = ifelse(grepl("Risperidone", colnames(expr_mat_Sst)), "Risperidone", "Control"),
  572. stringsAsFactors = FALSE
  573. )
  574. rownames(sample_info_Sst) <- sample_info_Sst$sample_id
  575. # Build DESeq2 object
  576. dds_Sst <- DESeqDataSetFromMatrix(
  577. countData = expr_mat_Sst,
  578. colData = sample_info_Sst,
  579. design = ~ condition
  580. )
  581. # Run DE analysis
  582. dds_Sst <- DESeq(dds_Sst)
  583. # Get results
  584. res_Sst <- results(dds_Sst, contrast = c("condition", "Risperidone", "Control"))
  585. # Save results
  586. write.csv(
  587. as.data.frame(res_Sst) %>%
  588. subset(!is.na(padj)) %>%
  589. arrange(padj, desc(abs(log2FoldChange))),
  590. file = paste0("~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_Sst-IN.csv"),
  591. row.names = TRUE
  592. )
  593. ```
  594. Sst-IN DEG - heatmap
  595. ```{r}
  596. # Count the number of DEGs with padj < 0.05
  597. sum(res_Sst$padj < 0.05, na.rm = TRUE) #1305
  598. # Select all DEGs with padj < 0.05 and remove NA
  599. res_Sst_filtered <- res_Sst[!is.na(res_Sst$padj) & res_Sst$padj < 0.05, ]
  600. # Then order and extract gene names
  601. top_genes_Sst <- rownames(res_Sst_filtered[order(res_Sst_filtered$padj), ])
  602. # Perform Variance-Stabilizing Transformation (VST)
  603. vst_data_Sst <- vst(dds_Sst, blind = TRUE)
  604. # Ensure genes exist in the dataset
  605. common_genes_Sst <- intersect(top_genes_Sst, rownames(assay(vst_data_Sst)))
  606. # Extract the VST-transformed expression values for these genes
  607. heatmap_matrix_Sst <- assay(vst_data_Sst)[common_genes_Sst, ]
  608. # Extract metadata for annotations
  609. annotation_Sst <- sample_info_Sst %>% select(condition)
  610. # Make sure your 'condition' column is a factor in desired order
  611. annotation_Sst$condition <- factor(annotation_Sst$condition, levels = c("Control", "Risperidone"))
  612. # Now reorder the columns of your heatmap matrix
  613. ordered_samples_Sst <- rownames(annotation_Sst)[order(annotation_Sst$condition)]
  614. heatmap_matrix_Sst <- heatmap_matrix_Sst[, ordered_samples_Sst]
  615. annotation_colors_Sst <- list(
  616. condition = c(
  617. "Control" = brewer.pal(8, "Set2")[1],
  618. "Risperidone" = brewer.pal(8, "Set2")[2]
  619. )
  620. )
  621. #Generate Heatmap
  622. pheatmap(heatmap_matrix_Sst,
  623. scale = "row", # Normalize each gene across samples
  624. cluster_rows = TRUE,
  625. cluster_cols = TRUE,
  626. show_rownames = FALSE,
  627. show_colnames = TRUE,
  628. annotation_col = annotation_PN,
  629. annotation_colors = annotation_colors,
  630. border_color = NA,
  631. fontsize = 8,
  632. main = "",
  633. )
  634. ```
  635. Sst-IN DEG - volcano
  636. ```{r}
  637. # Convert DESeq2 results to a data frame
  638. res_df_Sst <- as.data.frame(res_Sst)
  639. res_df_Sst$gene <- rownames(res_df_Sst)
  640. # Remove any NA values
  641. res_df_Sst <- na.omit(res_df_Sst)
  642. # Add a new column to categorize genes for coloring
  643. res_df_Sst$Significance <- "Not Significant"
  644. res_df_Sst$Significance[res_df_Sst$padj < padj_threshold & abs(res_df_Sst$log2FoldChange) > log2FoldChange_threshold] <- "Significant"
  645. # Generate volcano plot with specific genes of interest labeled
  646. # Define genes of interest
  647. genes_of_interest_Sst <- c("Kcnb1", "Kcnc1", "Kcnd3", "Kcnq3", "Kcnq2", "Kcnh7", "Grin2a", "Grin2b", "Dlg1", "Shank1", "Shank2", "Gabrg3")
  648. # Generate Zoomed-in Volcano plot
  649. volcano_plot_Sst_zoom <- ggplot(res_df_Sst, aes(x = log2FoldChange, y = -log10(padj))) +
  650. geom_point(data = res_df_Sst %>% dplyr::filter(Significance == "Not Significant"),
  651. aes(x = log2FoldChange, y = -log10(padj)),
  652. color = "gray", alpha = 0.5, size = 2) +
  653. geom_point(data = res_df_Sst %>% dplyr::filter(Significance == "Significant" & log2FoldChange > 0),
  654. aes(x = log2FoldChange, y = -log10(padj)),
  655. color = "red", alpha = 0.5, size = 2) +
  656. geom_point(data = res_df_Sst %>% dplyr::filter(Significance == "Significant" & log2FoldChange < 0),
  657. aes(x = log2FoldChange, y = -log10(padj)),
  658. color = "blue", alpha = 0.5, size = 2) +
  659. geom_label_repel(
  660. aes(label = ifelse(gene %in% genes_of_interest_Sst, gene, "")),
  661. size = 5,
  662. box.padding = 0.75,
  663. label.padding = 0.35,
  664. fill = alpha("white", 0),
  665. color = "black",
  666. segment.color = "black",
  667. segment.size = 0.8,
  668. segment.alpha = 0.8,
  669. min.segment.length = 0,
  670. force = 5,
  671. max.overlaps = Inf
  672. ) +
  673. geom_vline(xintercept = c(-0.5, 0.5), linetype = "dotted", color = "black") +
  674. geom_hline(yintercept = -log10(0.05), linetype = "dotted", color = "black") +
  675. coord_cartesian(xlim = c(-4, 4), ylim = c(0, 100)) + # 👈 Zoomed view
  676. theme_minimal() +
  677. labs(title = "",
  678. x = "Log2 Fold Change",
  679. y = "-Log10 Adjusted P-Value") +
  680. theme(legend.position = "right",
  681. axis.text = element_text(size = 14),
  682. axis.title = element_text(size = 16))
  683. # Print the plot
  684. print(volcano_plot_Sst_zoom)
  685. ```
  686. Graph specific DEG expression change by treatment
  687. ```{r}
  688. ## Glut
  689. # To plot log2FC in DEG results (not the raw count)
  690. genes_to_plot <- c("Drd2", "Drd3", "Ddc", "Domt", "Htr2a", "Htr1f", "Htr4", "Htr2c", "Htf5a", "Htr7", "Htr6", "Htr1d", "Htr2b", "Maoa")
  691. # Subset the gene of interest
  692. res_df_Glut_plot <- res_df_Glut[res_df_Glut$gene %in% genes_to_plot, c("gene", "log2FoldChange", "padj")]
  693. # Create 2-line p-value label column
  694. res_df_Glut_plot$label <- sprintf("p =\n%.2g", res_df_Glut_plot$padj)
  695. # Create the bar plot for log2FC
  696. ggplot(res_df_Glut_plot, aes(x = gene, y = log2FoldChange, fill = log2FoldChange > 0)) +
  697. geom_col() +
  698. scale_fill_manual(values = c("steelblue", "firebrick")) +
  699. geom_hline(yintercept = 0, linetype = "dashed") +
  700. geom_text_repel(
  701. aes(label = label),
  702. size = 4,
  703. nudge_y = 0.5, # pushes labels slightly above/below bars
  704. direction = "y", # keeps labels aligned vertically
  705. segment.color = "grey50",
  706. box.padding = 0.3,
  707. point.padding = 0.2
  708. ) +
  709. labs(
  710. title = "Glutamatergic neurons saline vs. risperidone",
  711. x = NULL,
  712. y = "Log2 Fold Change"
  713. ) +
  714. theme_minimal() +
  715. theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 14))
  716. ## PV-IN
  717. # To plot log2FC in DEG results (not the raw count)
  718. genes_to_plot <- c("Drd2", "Htr2a")
  719. # Subset the gene of interest
  720. res_df_Pvalb_plot <- res_df_Pvalb[res_df_Pvalb$gene %in% genes_to_plot, c("gene", "log2FoldChange", "padj")]
  721. # Create 2-line p-value label column
  722. res_df_Pvalb_plot$label <- sprintf("p =\n%.2g", res_df_Pvalb_plot$padj)
  723. # Create the bar plot for log2FC
  724. ggplot(res_df_Pvalb_plot, aes(x = gene, y = log2FoldChange, fill = log2FoldChange > 0)) +
  725. geom_col() +
  726. scale_fill_manual(values = c("steelblue", "firebrick")) +
  727. geom_hline(yintercept = 0, linetype = "dashed") +
  728. geom_text_repel(
  729. aes(label = label),
  730. size = 4,
  731. nudge_y = 0.5, # pushes labels slightly above/below bars
  732. direction = "y", # keeps labels aligned vertically
  733. segment.color = "grey50",
  734. box.padding = 0.3,
  735. point.padding = 0.2
  736. ) +
  737. labs(
  738. title = "PV-IN saline vs. risperidone",
  739. x = NULL,
  740. y = "Log2 Fold Change"
  741. ) +
  742. theme_minimal() +
  743. theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 14))
  744. ## Sst-IN
  745. # To plot log2FC in DEG results (not the raw count)
  746. genes_to_plot <- c("Drd2")
  747. # Subset the gene of interest
  748. res_df_Sst_plot <- res_df_Sst[res_df_Sst$gene %in% genes_to_plot, c("gene", "log2FoldChange", "padj")]
  749. # Create 2-line p-value label column
  750. res_df_Sst_plot$label <- sprintf("p =\n%.2g", res_df_Sst_plot$padj)
  751. # Create the bar plot for log2FC
  752. ggplot(res_df_Sst_plot, aes(x = gene, y = log2FoldChange, fill = log2FoldChange > 0)) +
  753. geom_col() +
  754. scale_fill_manual(values = c("steelblue", "firebrick")) +
  755. geom_hline(yintercept = 0, linetype = "dashed") +
  756. geom_text_repel(
  757. aes(label = label),
  758. size = 4,
  759. nudge_y = 0.5, # pushes labels slightly above/below bars
  760. direction = "y", # keeps labels aligned vertically
  761. segment.color = "grey50",
  762. box.padding = 0.3,
  763. point.padding = 0.2
  764. ) +
  765. labs(
  766. title = "Sst-IN saline vs. risperidone",
  767. x = NULL,
  768. y = "Log2 Fold Change"
  769. ) +
  770. theme_minimal() +
  771. theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 14))
  772. ```
  773. Venn Diagram for DEGs
  774. ```{r}
  775. library(VennDiagram)
  776. library(grid)
  777. # Set adjusted FDR threshold
  778. padj_cutoff <- 0.05
  779. # Get significant gene names from the DEG lists from 3 cell types
  780. sig_genes_Glut <- rownames(res_Glut[which(res_Glut$padj < padj_cutoff), ])
  781. sig_genes_Pvalb <- rownames(res_Pvalb[which(res_Pvalb$padj < padj_cutoff), ])
  782. sig_genes_Sst <- rownames(res_Sst[which(res_Sst$padj < padj_cutoff), ])
  783. # Create and draw the Venn diagram
  784. venn_plot <- venn.diagram(
  785. x = list(
  786. Glut = sig_genes_Glut,
  787. PV = sig_genes_Pvalb,
  788. Sst = sig_genes_Sst
  789. ),
  790. filename = NULL, # Don't save to file
  791. fill = c("skyblue", "pink", "yellow"),
  792. alpha = 0.5,
  793. cex = 1.5,
  794. cat.cex = 0,
  795. cat.pos = 0,
  796. cat.dist = 0.05,
  797. scaled = FALSE,
  798. main = "Overlap of DEGs in 3 cell types"
  799. )
  800. grid.draw(venn_plot)
  801. # Prepare a named list of vectors (each becomes a sheet)
  802. DEG_threecell <- list(
  803. DEGs_Glut = data.frame(Gene = sig_genes_Glut),
  804. DEGs_PV = data.frame(Gene = sig_genes_Pvalb),
  805. DEGs_Sst = data.frame(Gene = sig_genes_Sst),
  806. Shared_Glut_PV = data.frame(Gene = intersect(sig_genes_Glut, sig_genes_Pvalb)),
  807. Shared_Glut_Sst = data.frame(Gene = intersect(sig_genes_Glut, sig_genes_Sst)),
  808. Shared_Sst_PV = data.frame(Gene = intersect(sig_genes_Sst, sig_genes_Pvalb)),
  809. Shared_all = data.frame(
  810. Gene = Reduce(intersect, list(
  811. sig_genes_Glut,
  812. sig_genes_Sst,
  813. sig_genes_Pvalb
  814. ))
  815. )
  816. )
  817. # Save to Excel file
  818. write_xlsx(DEG_threecell, path = "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/DE_modified/Proj4_threecell_overlap.xlsx")
  819. ## EnrichGO for DEGs that are shared by all 3 cell types
  820. # Run EnrichGO - BP
  821. BP_GO_shared <- enrichGO(
  822. gene = DEG_threecell$Shared_all$Gene,
  823. OrgDb = org.Mm.eg.db,
  824. keyType = "SYMBOL",
  825. ont = "BP",
  826. pAdjustMethod = "BH",
  827. pvalueCutoff = 0.05,
  828. qvalueCutoff = 0.05
  829. )
  830. # Run EnrichGO - MF
  831. MF_GO_shared <- enrichGO(
  832. gene = DEG_threecell$Shared_all$Gene,
  833. OrgDb = org.Mm.eg.db,
  834. keyType = "SYMBOL",
  835. ont = "MF",
  836. pAdjustMethod = "BH",
  837. pvalueCutoff = 0.05,
  838. qvalueCutoff = 0.05
  839. )
  840. # Run EnrichGO - CC
  841. CC_GO_shared <- enrichGO(
  842. gene = DEG_threecell$Shared_all$Gene,
  843. OrgDb = org.Mm.eg.db,
  844. keyType = "SYMBOL",
  845. ont = "CC",
  846. pAdjustMethod = "BH",
  847. pvalueCutoff = 0.05,
  848. qvalueCutoff = 0.05
  849. )
  850. # Save as Excel file
  851. write.xlsx(
  852. list(
  853. BP = as.data.frame(BP_GO_shared),
  854. MF = as.data.frame(MF_GO_shared),
  855. CC = as.data.frame(CC_GO_shared)
  856. ),
  857. file = "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/EnrichGO/Proj4/Proj4_threecelltype_overlap.xlsx"
  858. )
  859. # Plot dotplot
  860. dotplot(BP_GO_shared, showCategory = 10, title = "GO Enrichment (Biological Process)") +
  861. theme(
  862. text = element_text(size = 14), # Adjust global text size
  863. axis.text.x = element_text(size = 12), # Adjust x-axis font size
  864. axis.text.y = element_text(size = 14), # Adjust y-axis font size
  865. plot.title = element_text(size = 12) # Adjust title font size
  866. )
  867. dotplot(MF_GO_shared, showCategory = 10, title = "GO Enrichment (Molecular Function)") +
  868. theme(
  869. text = element_text(size = 14), # Adjust global text size
  870. axis.text.x = element_text(size = 12), # Adjust x-axis font size
  871. axis.text.y = element_text(size = 14), # Adjust y-axis font size
  872. plot.title = element_text(size = 12) # Adjust title font size
  873. )
  874. dotplot(CC_GO_shared, showCategory = 10, title = "GO Enrichment (Cellular Component)") +
  875. theme(
  876. text = element_text(size = 14), # Adjust global text size
  877. axis.text.x = element_text(size = 12), # Adjust x-axis font size
  878. axis.text.y = element_text(size = 14), # Adjust y-axis font size
  879. plot.title = element_text(size = 12) # Adjust title font size
  880. )
  881. ```
  882. DE analysis (Pseudobulk) - PV-IN - F vs. M
  883. ```{r}
  884. # Subset male and female separately
  885. Mcortex_QC_Pvalb_F <- subset(Mcortex_QC_Pvalb, Predicted_Sex %in% "Female")
  886. Mcortex_QC_Pvalb_M <- subset(Mcortex_QC_Pvalb, Predicted_Sex %in% "Male")
  887. ## Female
  888. # Filter out all genes with count sum less than 10
  889. Mcortex_QC_Pvalb_F <- subset(Mcortex_QC_Pvalb_F, features = rownames(Mcortex_QC_Pvalb_F)[Matrix::rowSums(GetAssayData(Mcortex_QC_Pvalb_F, assay = "RNA", layer = "counts")) >= 10])
  890. # Aggregate counts
  891. expr_mat_Pvalb_F <- AggregateExpression(
  892. Mcortex_QC_Pvalb_F,
  893. group.by = c("Tx", "sample_id"),
  894. assays = "RNA"
  895. )$RNA
  896. # Create colData (metadata about your samples)
  897. sample_info_Pvalb_F <- data.frame(
  898. sample_id = colnames(expr_mat_Pvalb_F),
  899. condition = ifelse(grepl("Risperidone", colnames(expr_mat_Pvalb_F)), "Risperidone", "Control"),
  900. stringsAsFactors = FALSE
  901. )
  902. rownames(sample_info_Pvalb_F) <- sample_info_Pvalb_F$sample_id
  903. # Build DESeq2 object
  904. dds_Pvalb_F <- DESeqDataSetFromMatrix(
  905. countData = expr_mat_Pvalb_F,
  906. colData = sample_info_Pvalb_F,
  907. design = ~ condition
  908. )
  909. # Run DE analysis
  910. dds_Pvalb_F <- DESeq(dds_Pvalb_F)
  911. # Get results
  912. res_Pvalb_F <- results(dds_Pvalb_F, contrast = c("condition", "Risperidone", "Control"))
  913. # Save results
  914. write.csv(
  915. as.data.frame(res_Pvalb_F) %>%
  916. subset(!is.na(padj)) %>%
  917. arrange(padj, desc(abs(log2FoldChange))),
  918. file = paste0("~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_PV-IN_F.csv"),
  919. row.names = TRUE
  920. )
  921. ## Male
  922. # Filter out all genes with count sum less than 10
  923. Mcortex_QC_Pvalb_M <- subset(Mcortex_QC_Pvalb_M, features = rownames(Mcortex_QC_Pvalb_M)[Matrix::rowSums(GetAssayData(Mcortex_QC_Pvalb_M, assay = "RNA", layer = "counts")) >= 10])
  924. # Aggregate counts
  925. expr_mat_Pvalb_M <- AggregateExpression(
  926. Mcortex_QC_Pvalb_M,
  927. group.by = c("Tx", "sample_id"),
  928. assays = "RNA"
  929. )$RNA
  930. # Create colData (metadata about your samples)
  931. sample_info_Pvalb_M <- data.frame(
  932. sample_id = colnames(expr_mat_Pvalb_M),
  933. condition = ifelse(grepl("Risperidone", colnames(expr_mat_Pvalb_M)), "Risperidone", "Control"),
  934. stringsAsFactors = FALSE
  935. )
  936. rownames(sample_info_Pvalb_M) <- sample_info_Pvalb_M$sample_id
  937. # Build DESeq2 object
  938. dds_Pvalb_M <- DESeqDataSetFromMatrix(
  939. countData = expr_mat_Pvalb_M,
  940. colData = sample_info_Pvalb_M,
  941. design = ~ condition
  942. )
  943. # Run DE analysis
  944. dds_Pvalb_M <- DESeq(dds_Pvalb_M)
  945. # Get results
  946. res_Pvalb_M <- results(dds_Pvalb_M, contrast = c("condition", "Risperidone", "Control"))
  947. # Save results
  948. write.csv(
  949. as.data.frame(res_Pvalb_M) %>%
  950. subset(!is.na(padj)) %>%
  951. arrange(padj, desc(abs(log2FoldChange))),
  952. file = paste0("~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_PV-IN_M.csv"),
  953. row.names = TRUE
  954. )
  955. ```
  956. PV-IN - F vs. M DEG Heatmap
  957. ```{r}
  958. ## Female
  959. # Count the number of DEGs with padj < 0.05
  960. sum(res_Pvalb_F$padj < 0.05, na.rm = TRUE) #701
  961. # Select all DEGs with adjusted p-value < 0.05
  962. sig_Pvalb_F <- res_Pvalb_F[!is.na(res_Pvalb_F$padj) & res_Pvalb_F$padj < 0.05, ]
  963. # Then order and extract gene names
  964. top_genes_Pvalb_F <- rownames(sig_Pvalb_F[order(sig_Pvalb_F$padj), ])
  965. # Perform VST
  966. vst_data_Pvalb_F <- vst(dds_Pvalb_F, blind = TRUE)
  967. # Keep only genes that are present in the VST-transformed data
  968. common_genes_Pvalb_F <- intersect(top_genes_Pvalb_F, rownames(assay(vst_data_Pvalb_F)))
  969. # Extract VST expression matrix
  970. heatmap_matrix_Pvalb_F <- assay(vst_data_Pvalb_F)[common_genes_Pvalb_F, ]
  971. # Extract metadata for annotations
  972. annotation_Pvalb_F <- sample_info_Pvalb_F %>% select(condition)
  973. # Make sure your 'condition' column is a factor in desired order
  974. annotation_Pvalb_F$condition <- factor(annotation_Pvalb_F$condition, levels = c("Control", "Risperidone"))
  975. # Now reorder the columns of your heatmap matrix
  976. ordered_samples_Pvalb_F <- rownames(annotation_Pvalb_F)[order(annotation_Pvalb_F$condition)]
  977. heatmap_matrix_Pvalb_F <- heatmap_matrix_Pvalb_F[, ordered_samples_Pvalb_F]
  978. annotation_colors_Pvalb_F <- list(
  979. condition = c(
  980. "Control" = brewer.pal(8, "Set2")[1],
  981. "Risperidone" = brewer.pal(8, "Set2")[2]
  982. )
  983. )
  984. # Generate heatmap
  985. pheatmap(heatmap_matrix_Pvalb_F,
  986. scale = "row",
  987. cluster_rows = TRUE,
  988. cluster_cols = TRUE,
  989. show_rownames = FALSE,
  990. show_colnames = TRUE,
  991. annotation_col = annotation_Pvalb_F,
  992. annotation_colors = annotation_colors,
  993. border_color = NA,
  994. fontsize = 8,
  995. main = "")
  996. ## Male
  997. # Count the number of DEGs with padj < 0.05
  998. sum(res_Pvalb_M$padj < 0.05, na.rm = TRUE) #528
  999. # Select all DEGs with adjusted p-value < 0.05
  1000. sig_Pvalb_M <- res_Pvalb_M[!is.na(res_Pvalb_M$padj) & res_Pvalb_M$padj < 0.05, ]
  1001. # Then order and extract gene names
  1002. top_genes_Pvalb_M <- rownames(sig_Pvalb_M[order(sig_Pvalb_M$padj), ])
  1003. # Perform VST
  1004. vst_data_Pvalb_M <- vst(dds_Pvalb_M, blind = TRUE)
  1005. # Keep only genes that are present in the VST-transformed data
  1006. common_genes_Pvalb_M <- intersect(top_genes_Pvalb_M, rownames(assay(vst_data_Pvalb_M)))
  1007. # Extract VST expression matrix
  1008. heatmap_matrix_Pvalb_M <- assay(vst_data_Pvalb_M)[common_genes_Pvalb_M, ]
  1009. # Extract metadata for annotations
  1010. annotation_Pvalb_M <- sample_info_Pvalb_M %>% select(condition)
  1011. # Make sure your 'condition' column is a factor in desired order
  1012. annotation_Pvalb_M$condition <- factor(annotation_Pvalb_M$condition, levels = c("Control", "Risperidone"))
  1013. # Now reorder the columns of your heatmap matrix
  1014. ordered_samples_Pvalb_M <- rownames(annotation_Pvalb_M)[order(annotation_Pvalb_M$condition)]
  1015. heatmap_matrix_Pvalb_M <- heatmap_matrix_Pvalb_M[, ordered_samples_Pvalb_M]
  1016. annotation_colors_Pvalb_M <- list(
  1017. condition = c(
  1018. "Control" = brewer.pal(8, "Set2")[1],
  1019. "Risperidone" = brewer.pal(8, "Set2")[2]
  1020. )
  1021. )
  1022. # Generate heatmap
  1023. pheatmap(heatmap_matrix_Pvalb_M,
  1024. scale = "row",
  1025. cluster_rows = TRUE,
  1026. cluster_cols = TRUE,
  1027. show_rownames = FALSE,
  1028. show_colnames = TRUE,
  1029. annotation_col = annotation_Pvalb_M,
  1030. annotation_colors = annotation_colors,
  1031. border_color = NA,
  1032. fontsize = 8,
  1033. main = "")
  1034. ```
  1035. PV-IN - F vs. M DEG volcano
  1036. ```{r}
  1037. # Convert DESeq2 results to a data frame
  1038. res_Pvalb_F_df <- as.data.frame(res_Pvalb_F)
  1039. res_Pvalb_F_df$gene <- rownames(res_Pvalb_F_df)
  1040. res_Pvalb_M_df <- as.data.frame(res_Pvalb_M)
  1041. res_Pvalb_M_df$gene <- rownames(res_Pvalb_M_df)
  1042. # Remove any NA values
  1043. res_Pvalb_F_df <- na.omit(res_Pvalb_F_df)
  1044. res_Pvalb_M_df <- na.omit(res_Pvalb_M_df)
  1045. # Add a new column to categorize genes for coloring
  1046. res_Pvalb_F_df$Significance <- "Not Significant"
  1047. res_Pvalb_F_df$Significance[res_Pvalb_F_df$padj < padj_threshold & abs(res_Pvalb_F_df$log2FoldChange) > log2FoldChange_threshold] <- "Significant"
  1048. res_Pvalb_M_df$Significance <- "Not Significant"
  1049. res_Pvalb_M_df$Significance[res_Pvalb_M_df$padj < padj_threshold & abs(res_Pvalb_M_df$log2FoldChange) > log2FoldChange_threshold] <- "Significant"
  1050. # Generate volcano plot with specific genes of interest labeled
  1051. # Define genes of interest
  1052. genes_of_interest_PV_F <- c("Kcnd3", "Kcnt2", "Shank1", "Shank2", "Dlg1", "Gria1", "Grid1", "Grik3", "Gabrg3")
  1053. genes_of_interest_PV_M <- c("Kcnd3", "Kcnh1", "Nrg1", "Shank1", "Shank2", "Grid1", "Grik3", "Grm8")
  1054. # Generate Volcano plot
  1055. volcano_plot_PV_F <- ggplot(res_Pvalb_F_df, aes(x = log2FoldChange, y = -log10(padj))) +
  1056. geom_point(data = res_Pvalb_F_df %>% dplyr::filter(Significance == "Not Significant"),
  1057. aes(x = log2FoldChange, y = -log10(padj)),
  1058. color = "gray", alpha = 0.5, size = 1) +
  1059. geom_point(data = res_Pvalb_F_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange > 0),
  1060. aes(x = log2FoldChange, y = -log10(padj)),
  1061. color = "red", alpha = 0.5, size = 1) +
  1062. geom_point(data = res_Pvalb_F_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange < 0),
  1063. aes(x = log2FoldChange, y = -log10(padj)),
  1064. color = "blue", alpha = 0.5, size = 1) +
  1065. geom_label_repel(
  1066. aes(label = ifelse(gene %in% genes_of_interest_PV_F, gene, "")),
  1067. size = 7,
  1068. box.padding = 0.75,
  1069. label.padding = 0.35,
  1070. fill = alpha("white", 0),
  1071. color = "black",
  1072. segment.color = "black",
  1073. segment.size = 0.8,
  1074. segment.alpha = 0.8,
  1075. min.segment.length = 0,
  1076. force = 5,
  1077. max.overlaps = Inf
  1078. ) +
  1079. geom_vline(xintercept = c(-0.5, 0.5), linetype = "dotted", color = "black") +
  1080. geom_hline(yintercept = -log10(0.05), linetype = "dotted", color = "black") +
  1081. theme_minimal() +
  1082. labs(title = "PV-IN F",
  1083. x = "Log2 Fold Change",
  1084. y = "-Log10 Adjusted P-Value") +
  1085. theme(
  1086. legend.position = "right",
  1087. axis.title.x = element_text(size = 16), # X-axis label size
  1088. axis.title.y = element_text(size = 16), # Y-axis label size
  1089. axis.text.x = element_text(size = 14), # X-axis tick labels
  1090. axis.text.y = element_text(size = 14), # Y-axis tick labels
  1091. plot.title = element_text(size = 20, face = "bold", hjust = 0.5, margin = margin(b = 10)),
  1092. plot.margin = margin(t = 10, r = 10, b = 10, l = 10) # adds space above the whole plot
  1093. )
  1094. volcano_plot_PV_M <- ggplot(res_Pvalb_M_df, aes(x = log2FoldChange, y = -log10(padj))) +
  1095. geom_point(data = res_Pvalb_M_df %>% dplyr::filter(Significance == "Not Significant"),
  1096. aes(x = log2FoldChange, y = -log10(padj)),
  1097. color = "gray", alpha = 0.5, size = 1) +
  1098. geom_point(data = res_Pvalb_M_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange > 0),
  1099. aes(x = log2FoldChange, y = -log10(padj)),
  1100. color = "red", alpha = 0.5, size = 1) +
  1101. geom_point(data = res_Pvalb_M_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange < 0),
  1102. aes(x = log2FoldChange, y = -log10(padj)),
  1103. color = "blue", alpha = 0.5, size = 1) +
  1104. geom_label_repel(
  1105. aes(label = ifelse(gene %in% genes_of_interest_PV_M, gene, "")),
  1106. size = 7,
  1107. box.padding = 0.75,
  1108. label.padding = 0.35,
  1109. fill = alpha("white", 0),
  1110. color = "black",
  1111. segment.color = "black",
  1112. segment.size = 0.8,
  1113. segment.alpha = 0.8,
  1114. min.segment.length = 0,
  1115. force = 5,
  1116. max.overlaps = Inf
  1117. ) +
  1118. geom_vline(xintercept = c(-0.5, 0.5), linetype = "dotted", color = "black") +
  1119. geom_hline(yintercept = -log10(0.05), linetype = "dotted", color = "black") +
  1120. theme_minimal() +
  1121. labs(title = "PV-IN M",
  1122. x = "Log2 Fold Change",
  1123. y = "-Log10 Adjusted P-Value") +
  1124. theme(
  1125. legend.position = "right",
  1126. axis.title.x = element_text(size = 16), # X-axis label size
  1127. axis.title.y = element_text(size = 16), # Y-axis label size
  1128. axis.text.x = element_text(size = 14), # X-axis tick labels
  1129. axis.text.y = element_text(size = 14), # Y-axis tick labels
  1130. plot.title = element_text(size = 20, face = "bold", hjust = 0.5, margin = margin(b = 10)),
  1131. plot.margin = margin(t = 10, r = 10, b = 10, l = 10) # adds space above the whole plot
  1132. )
  1133. # Print the plot
  1134. print(volcano_plot_PV_F)
  1135. print(volcano_plot_PV_M)
  1136. ```
  1137. PV-IN DEG - F vs. M list comparison - Venn Diagram
  1138. ```{r}
  1139. # Set adjusted p-value threshold
  1140. padj_cutoff <- 0.05
  1141. # Get significant gene names
  1142. sig_genes_Pvalb_F <- rownames(res_Pvalb_F[which(res_Pvalb_F$padj < padj_cutoff), ])
  1143. sig_genes_Pvalb_M <- rownames(res_Pvalb_M[which(res_Pvalb_M$padj < padj_cutoff), ])
  1144. # Prepare a named list of vectors (each becomes a sheet)
  1145. deg_lists <- list(
  1146. DEGs_Male = data.frame(Gene = sig_genes_Pvalb_M),
  1147. DEGs_Female = data.frame(Gene = sig_genes_Pvalb_F),
  1148. Shared_DEGs = data.frame(Gene = intersect(sig_genes_Pvalb_M, sig_genes_Pvalb_F)),
  1149. Male_only = data.frame(Gene = setdiff(sig_genes_Pvalb_M, sig_genes_Pvalb_F)),
  1150. Female_only = data.frame(Gene = setdiff(sig_genes_Pvalb_F, sig_genes_Pvalb_M))
  1151. )
  1152. # Save to Excel file
  1153. write_xlsx(deg_lists, path = "~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_PV-IN_FvM.xlsx")
  1154. ```
  1155. DE analysis (Pseudobulk) - Glut - F vs. M
  1156. ```{r}
  1157. # Subset male and female separately
  1158. Mcortex_QC_Glut_F <- subset(Mcortex_QC_Glut, Predicted_Sex %in% "Female")
  1159. Mcortex_QC_Glut_M <- subset(Mcortex_QC_Glut, Predicted_Sex %in% "Male")
  1160. ## Female
  1161. # Filter out all genes with count sum less than 10
  1162. Mcortex_QC_Glut_F <- subset(Mcortex_QC_Glut_F, features = rownames(Mcortex_QC_Glut_F)[Matrix::rowSums(GetAssayData(Mcortex_QC_Glut_F, assay = "RNA", layer = "counts")) >= 10])
  1163. # Aggregate counts
  1164. expr_mat_Glut_F <- AggregateExpression(
  1165. Mcortex_QC_Glut_F,
  1166. group.by = c("Tx", "sample_id"),
  1167. assays = "RNA"
  1168. )$RNA
  1169. # Create colData (metadata about your samples)
  1170. sample_info_Glut_F <- data.frame(
  1171. sample_id = colnames(expr_mat_Glut_F),
  1172. condition = ifelse(grepl("Risperidone", colnames(expr_mat_Glut_F)), "Risperidone", "Control"),
  1173. stringsAsFactors = FALSE
  1174. )
  1175. rownames(sample_info_Glut_F) <- sample_info_Glut_F$sample_id
  1176. # Build DESeq2 object
  1177. dds_Glut_F <- DESeqDataSetFromMatrix(
  1178. countData = expr_mat_Glut_F,
  1179. colData = sample_info_Glut_F,
  1180. design = ~ condition
  1181. )
  1182. # Run DE analysis
  1183. dds_Glut_F <- DESeq(dds_Glut_F)
  1184. # Get results
  1185. res_Glut_F <- results(dds_Glut_F, contrast = c("condition", "Risperidone", "Control"))
  1186. # Save results
  1187. write.csv(
  1188. as.data.frame(res_Glut_F) %>%
  1189. subset(!is.na(padj)) %>%
  1190. arrange(padj, desc(abs(log2FoldChange))),
  1191. file = paste0("~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_Glut_F.csv"),
  1192. row.names = TRUE
  1193. )
  1194. ## Male
  1195. # Filter out all genes with count sum less than 10
  1196. Mcortex_QC_Glut_M <- subset(Mcortex_QC_Glut_M, features = rownames(Mcortex_QC_Glut_M)[Matrix::rowSums(GetAssayData(Mcortex_QC_Glut_M, assay = "RNA", layer = "counts")) >= 10])
  1197. # Aggregate counts
  1198. expr_mat_Glut_M <- AggregateExpression(
  1199. Mcortex_QC_Glut_M,
  1200. group.by = c("Tx", "sample_id"),
  1201. assays = "RNA"
  1202. )$RNA
  1203. # Create colData (metadata about your samples)
  1204. sample_info_Glut_M <- data.frame(
  1205. sample_id = colnames(expr_mat_Glut_M),
  1206. condition = ifelse(grepl("Risperidone", colnames(expr_mat_Glut_M)), "Risperidone", "Control"),
  1207. stringsAsFactors = FALSE
  1208. )
  1209. rownames(sample_info_Glut_M) <- sample_info_Glut_M$sample_id
  1210. # Build DESeq2 object
  1211. dds_Glut_M <- DESeqDataSetFromMatrix(
  1212. countData = expr_mat_Glut_M,
  1213. colData = sample_info_Glut_M,
  1214. design = ~ condition
  1215. )
  1216. # Run DE analysis
  1217. dds_Glut_M <- DESeq(dds_Glut_M)
  1218. # Get results
  1219. res_Glut_M <- results(dds_Glut_M, contrast = c("condition", "Risperidone", "Control"))
  1220. # Save results
  1221. write.csv(
  1222. as.data.frame(res_Glut_M) %>%
  1223. subset(!is.na(padj)) %>%
  1224. arrange(padj, desc(abs(log2FoldChange))),
  1225. file = paste0("~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_Glut_M.csv"),
  1226. row.names = TRUE
  1227. )
  1228. ```
  1229. Glut - F vs. M DEG Heatmap
  1230. ```{r}
  1231. ## Female
  1232. # Count the number of DEGs with padj < 0.05
  1233. sum(res_Glut_F$padj < 0.05, na.rm = TRUE) #5534
  1234. # Select all DEGs with adjusted p-value < 0.05
  1235. sig_Glut_F <- res_Glut_F[!is.na(res_Glut_F$padj) & res_Glut_F$padj < 0.05, ]
  1236. # Then order and extract gene names
  1237. top_genes_Glut_F <- rownames(sig_Glut_F[order(sig_Glut_F$padj), ])
  1238. # Perform VST
  1239. vst_data_Glut_F <- vst(dds_Glut_F, blind = TRUE)
  1240. # Keep only genes that are present in the VST-transformed data
  1241. common_genes_Glut_F <- intersect(top_genes_Glut_F, rownames(assay(vst_data_Glut_F)))
  1242. # Extract VST expression matrix
  1243. heatmap_matrix_Glut_F <- assay(vst_data_Glut_F)[common_genes_Glut_F, ]
  1244. # Extract metadata for annotations
  1245. annotation_Glut_F <- sample_info_Glut_F %>% select(condition)
  1246. # Make sure your 'condition' column is a factor in desired order
  1247. annotation_Glut_F$condition <- factor(annotation_Glut_F$condition, levels = c("Control", "Risperidone"))
  1248. # Now reorder the columns of your heatmap matrix
  1249. ordered_samples_Glut_F <- rownames(annotation_Glut_F)[order(annotation_Glut_F$condition)]
  1250. heatmap_matrix_Glut_F <- heatmap_matrix_Glut_F[, ordered_samples_Glut_F]
  1251. annotation_colors_Glut_F <- list(
  1252. condition = c(
  1253. "Control" = brewer.pal(8, "Set2")[1],
  1254. "Risperidone" = brewer.pal(8, "Set2")[2]
  1255. )
  1256. )
  1257. # Generate heatmap
  1258. pheatmap(heatmap_matrix_Glut_F,
  1259. scale = "row",
  1260. cluster_rows = TRUE,
  1261. cluster_cols = TRUE,
  1262. show_rownames = FALSE,
  1263. show_colnames = TRUE,
  1264. annotation_col = annotation_Glut_F,
  1265. annotation_colors = annotation_colors,
  1266. border_color = NA,
  1267. fontsize = 8,
  1268. main = "")
  1269. ## Male
  1270. # Count the number of DEGs with padj < 0.05
  1271. sum(res_Glut_M$padj < 0.05, na.rm = TRUE) #5643
  1272. # Select all DEGs with adjusted p-value < 0.05
  1273. sig_Glut_M <- res_Glut_M[!is.na(res_Glut_M$padj) & res_Glut_M$padj < 0.05, ]
  1274. # Then order and extract gene names
  1275. top_genes_Glut_M <- rownames(sig_Glut_M[order(sig_Glut_M$padj), ])
  1276. # Perform VST
  1277. vst_data_Glut_M <- vst(dds_Glut_M, blind = TRUE)
  1278. # Keep only genes that are present in the VST-transformed data
  1279. common_genes_Glut_M <- intersect(top_genes_Glut_M, rownames(assay(vst_data_Glut_M)))
  1280. # Extract VST expression matrix
  1281. heatmap_matrix_Glut_M <- assay(vst_data_Glut_M)[common_genes_Glut_M, ]
  1282. # Extract metadata for annotations
  1283. annotation_Glut_M <- sample_info_Glut_M %>% select(condition)
  1284. # Make sure your 'condition' column is a factor in desired order
  1285. annotation_Glut_M$condition <- factor(annotation_Glut_M$condition, levels = c("Control", "Risperidone"))
  1286. # Now reorder the columns of your heatmap matrix
  1287. ordered_samples_Glut_M <- rownames(annotation_Glut_M)[order(annotation_Glut_M$condition)]
  1288. heatmap_matrix_Glut_M <- heatmap_matrix_Glut_M[, ordered_samples_Glut_M]
  1289. annotation_colors_Glut_M <- list(
  1290. condition = c(
  1291. "Control" = brewer.pal(8, "Set2")[1],
  1292. "Risperidone" = brewer.pal(8, "Set2")[2]
  1293. )
  1294. )
  1295. # Generate heatmap
  1296. pheatmap(heatmap_matrix_Glut_M,
  1297. scale = "row",
  1298. cluster_rows = TRUE,
  1299. cluster_cols = TRUE,
  1300. show_rownames = FALSE,
  1301. show_colnames = TRUE,
  1302. annotation_col = annotation_Glut_M,
  1303. annotation_colors = annotation_colors,
  1304. border_color = NA,
  1305. fontsize = 8,
  1306. main = "")
  1307. ```
  1308. Glut - F vs. M DEG volcano
  1309. ```{r}
  1310. # Convert DESeq2 results to a data frame
  1311. res_Glut_F_df <- as.data.frame(res_Glut_F)
  1312. res_Glut_F_df$gene <- rownames(res_Glut_F_df)
  1313. res_Glut_M_df <- as.data.frame(res_Glut_M)
  1314. res_Glut_M_df$gene <- rownames(res_Glut_M_df)
  1315. # Remove any NA values
  1316. res_Glut_F_df <- na.omit(res_Glut_F_df)
  1317. res_Glut_M_df <- na.omit(res_Glut_M_df)
  1318. # Add a new column to categorize genes for coloring
  1319. res_Glut_F_df$Significance <- "Not Significant"
  1320. res_Glut_F_df$Significance[res_Glut_F_df$padj < padj_threshold & abs(res_Glut_F_df$log2FoldChange) > log2FoldChange_threshold] <- "Significant"
  1321. res_Glut_M_df$Significance <- "Not Significant"
  1322. res_Glut_M_df$Significance[res_Glut_M_df$padj < padj_threshold & abs(res_Glut_M_df$log2FoldChange) > log2FoldChange_threshold] <- "Significant"
  1323. # Generate volcano plot with specific genes of interest labeled
  1324. # Define genes of interest
  1325. genes_of_interest_Glut_F <- c("Kcnd3", "Kcnq3", "Kcnt2", "Kcnb1", "Shank1", "Shank2", "Grin2a", "Grin2b", "Dlg1", "Gria1", "Grid1", "Grik3", "Nrg1", "Erbb4", "Gabrb1", "Gabra5")
  1326. genes_of_interest_Glut_M <- c("Kcnd3", "Kcnq3", "Kcnt2", "Nrg1", "Erbb4", "Shank1", "Shank2", "Gria1", "Grid1", "Grik3", "Grin2a")
  1327. # Generate Volcano plot
  1328. volcano_plot_Glut_F <- ggplot(res_Glut_F_df, aes(x = log2FoldChange, y = -log10(padj))) +
  1329. geom_point(data = res_Glut_F_df %>% dplyr::filter(Significance == "Not Significant"),
  1330. aes(x = log2FoldChange, y = -log10(padj)),
  1331. color = "gray", alpha = 0.5, size = 1) +
  1332. geom_point(data = res_Glut_F_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange > 0),
  1333. aes(x = log2FoldChange, y = -log10(padj)),
  1334. color = "red", alpha = 0.5, size = 1) +
  1335. geom_point(data = res_Glut_F_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange < 0),
  1336. aes(x = log2FoldChange, y = -log10(padj)),
  1337. color = "blue", alpha = 0.5, size = 1) +
  1338. geom_label_repel(
  1339. aes(label = ifelse(gene %in% genes_of_interest_Glut_F, gene, "")),
  1340. size = 7,
  1341. box.padding = 0.75,
  1342. label.padding = 0.35,
  1343. fill = alpha("white", 0),
  1344. color = "black",
  1345. segment.color = "black",
  1346. segment.size = 0.8,
  1347. segment.alpha = 0.8,
  1348. min.segment.length = 0,
  1349. force = 25,
  1350. max.overlaps = Inf
  1351. ) +
  1352. geom_vline(xintercept = c(-0.5, 0.5), linetype = "dotted", color = "black") +
  1353. geom_hline(yintercept = -log10(0.05), linetype = "dotted", color = "black") +
  1354. theme_minimal() +
  1355. labs(title = "Glut F",
  1356. x = "Log2 Fold Change",
  1357. y = "-Log10 Adjusted P-Value") +
  1358. theme(
  1359. legend.position = "right",
  1360. axis.title.x = element_text(size = 16), # X-axis label size
  1361. axis.title.y = element_text(size = 16), # Y-axis label size
  1362. axis.text.x = element_text(size = 14), # X-axis tick labels
  1363. axis.text.y = element_text(size = 14), # Y-axis tick labels
  1364. plot.title = element_text(size = 20, face = "bold", hjust = 0.5, margin = margin(b = 10)),
  1365. plot.margin = margin(t = 10, r = 10, b = 10, l = 10) # adds space above the whole plot
  1366. )
  1367. volcano_plot_Glut_M <- ggplot(res_Glut_M_df, aes(x = log2FoldChange, y = -log10(padj))) +
  1368. geom_point(data = res_Glut_M_df %>% dplyr::filter(Significance == "Not Significant"),
  1369. aes(x = log2FoldChange, y = -log10(padj)),
  1370. color = "gray", alpha = 0.5, size = 1) +
  1371. geom_point(data = res_Glut_M_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange > 0),
  1372. aes(x = log2FoldChange, y = -log10(padj)),
  1373. color = "red", alpha = 0.5, size = 1) +
  1374. geom_point(data = res_Glut_M_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange < 0),
  1375. aes(x = log2FoldChange, y = -log10(padj)),
  1376. color = "blue", alpha = 0.5, size = 1) +
  1377. geom_label_repel(
  1378. aes(label = ifelse(gene %in% genes_of_interest_Glut_M, gene, "")),
  1379. size = 7,
  1380. box.padding = 0.75,
  1381. label.padding = 0.35,
  1382. fill = alpha("white", 0),
  1383. color = "black",
  1384. segment.color = "black",
  1385. segment.size = 0.8,
  1386. segment.alpha = 0.8,
  1387. min.segment.length = 0,
  1388. force = 5,
  1389. max.overlaps = Inf
  1390. ) +
  1391. geom_vline(xintercept = c(-0.5, 0.5), linetype = "dotted", color = "black") +
  1392. geom_hline(yintercept = -log10(0.05), linetype = "dotted", color = "black") +
  1393. theme_minimal() +
  1394. labs(title = "Glut M",
  1395. x = "Log2 Fold Change",
  1396. y = "-Log10 Adjusted P-Value") +
  1397. theme(
  1398. legend.position = "right",
  1399. axis.title.x = element_text(size = 16), # X-axis label size
  1400. axis.title.y = element_text(size = 16), # Y-axis label size
  1401. axis.text.x = element_text(size = 14), # X-axis tick labels
  1402. axis.text.y = element_text(size = 14), # Y-axis tick labels
  1403. plot.title = element_text(size = 20, face = "bold", hjust = 0.5, margin = margin(b = 10)),
  1404. plot.margin = margin(t = 10, r = 10, b = 10, l = 10) # adds space above the whole plot
  1405. )
  1406. # Print the plot
  1407. print(volcano_plot_Glut_F)
  1408. print(volcano_plot_Glut_M)
  1409. ```
  1410. Glut DEG - F vs. M list comparison
  1411. ```{r}
  1412. # Get significant gene names
  1413. sig_genes_Glut_F <- rownames(res_Glut_F[which(res_Glut_F$padj < padj_cutoff), ])
  1414. sig_genes_Glut_M <- rownames(res_Glut_M[which(res_Glut_M$padj < padj_cutoff), ])
  1415. # Prepare a named list of vectors (each becomes a sheet)
  1416. deg_lists <- list(
  1417. DEGs_Male = data.frame(Gene = sig_genes_Glut_M),
  1418. DEGs_Female = data.frame(Gene = sig_genes_Glut_F),
  1419. Shared_DEGs = data.frame(Gene = intersect(sig_genes_Glut_M, sig_genes_Glut_F)),
  1420. Male_only = data.frame(Gene = setdiff(sig_genes_Glut_M, sig_genes_Glut_F)),
  1421. Female_only = data.frame(Gene = setdiff(sig_genes_Glut_F, sig_genes_Glut_M))
  1422. )
  1423. # Save to Excel file
  1424. write_xlsx(deg_lists, path = "~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_Glut_FvM.xlsx")
  1425. ```
  1426. DE analysis (Pseudobulk) - Sst-IN - F vs. M
  1427. ```{r}
  1428. # Subset male and female separately
  1429. Mcortex_QC_Sst_F <- subset(Mcortex_QC_Sst, Predicted_Sex %in% "Female")
  1430. Mcortex_QC_Sst_M <- subset(Mcortex_QC_Sst, Predicted_Sex %in% "Male")
  1431. ## Female
  1432. # Filter out all genes with count sum less than 10
  1433. Mcortex_QC_Sst_F <- subset(Mcortex_QC_Sst_F, features = rownames(Mcortex_QC_Sst_F)[Matrix::rowSums(GetAssayData(Mcortex_QC_Sst_F, assay = "RNA", layer = "counts")) >= 10])
  1434. # Aggregate counts
  1435. expr_mat_Sst_F <- AggregateExpression(
  1436. Mcortex_QC_Sst_F,
  1437. group.by = c("Tx", "sample_id"),
  1438. assays = "RNA"
  1439. )$RNA
  1440. # Create colData (metadata about your samples)
  1441. sample_info_Sst_F <- data.frame(
  1442. sample_id = colnames(expr_mat_Sst_F),
  1443. condition = ifelse(grepl("Risperidone", colnames(expr_mat_Sst_F)), "Risperidone", "Control"),
  1444. stringsAsFactors = FALSE
  1445. )
  1446. rownames(sample_info_Sst_F) <- sample_info_Sst_F$sample_id
  1447. # Build DESeq2 object
  1448. dds_Sst_F <- DESeqDataSetFromMatrix(
  1449. countData = expr_mat_Sst_F,
  1450. colData = sample_info_Sst_F,
  1451. design = ~ condition
  1452. )
  1453. # Run DE analysis
  1454. dds_Sst_F <- DESeq(dds_Sst_F)
  1455. # Get results
  1456. res_Sst_F <- results(dds_Sst_F, contrast = c("condition", "Risperidone", "Control"))
  1457. # Save results
  1458. write.csv(
  1459. as.data.frame(res_Sst_F) %>%
  1460. subset(!is.na(padj)) %>%
  1461. arrange(padj, desc(abs(log2FoldChange))),
  1462. file = paste0("~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_Sst_F.csv"),
  1463. row.names = TRUE
  1464. )
  1465. ## Male
  1466. # Filter out all genes with count sum less than 10
  1467. Mcortex_QC_Sst_M <- subset(Mcortex_QC_Sst_M, features = rownames(Mcortex_QC_Sst_M)[Matrix::rowSums(GetAssayData(Mcortex_QC_Sst_M, assay = "RNA", layer = "counts")) >= 10])
  1468. # Aggregate counts
  1469. expr_mat_Sst_M <- AggregateExpression(
  1470. Mcortex_QC_Sst_M,
  1471. group.by = c("Tx", "sample_id"),
  1472. assays = "RNA"
  1473. )$RNA
  1474. # Create colData (metadata about your samples)
  1475. sample_info_Sst_M <- data.frame(
  1476. sample_id = colnames(expr_mat_Sst_M),
  1477. condition = ifelse(grepl("Risperidone", colnames(expr_mat_Sst_M)), "Risperidone", "Control"),
  1478. stringsAsFactors = FALSE
  1479. )
  1480. rownames(sample_info_Sst_M) <- sample_info_Sst_M$sample_id
  1481. # Build DESeq2 object
  1482. dds_Sst_M <- DESeqDataSetFromMatrix(
  1483. countData = expr_mat_Sst_M,
  1484. colData = sample_info_Sst_M,
  1485. design = ~ condition
  1486. )
  1487. # Run DE analysis
  1488. dds_Sst_M <- DESeq(dds_Sst_M)
  1489. # Get results
  1490. res_Sst_M <- results(dds_Sst_M, contrast = c("condition", "Risperidone", "Control"))
  1491. # Save results
  1492. write.csv(
  1493. as.data.frame(res_Sst_M) %>%
  1494. subset(!is.na(padj)) %>%
  1495. arrange(padj, desc(abs(log2FoldChange))),
  1496. file = paste0("~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_Sst_M.csv"),
  1497. row.names = TRUE
  1498. )
  1499. ```
  1500. Sst-IN - F vs. M DEG Heatmap
  1501. ```{r}
  1502. ## Female
  1503. # Count the number of DEGs with padj < 0.05
  1504. sum(res_Sst_F$padj < 0.05, na.rm = TRUE) #339
  1505. # Select all DEGs with adjusted p-value < 0.05
  1506. sig_Sst_F <- res_Sst_F[!is.na(res_Sst_F$padj) & res_Sst_F$padj < 0.05, ]
  1507. # Then order and extract gene names
  1508. top_genes_Sst_F <- rownames(sig_Sst_F[order(sig_Sst_F$padj), ])
  1509. # Perform VST
  1510. vst_data_Sst_F <- vst(dds_Sst_F, blind = TRUE)
  1511. # Keep only genes that are present in the VST-transformed data
  1512. common_genes_Sst_F <- intersect(top_genes_Sst_F, rownames(assay(vst_data_Sst_F)))
  1513. # Extract VST expression matrix
  1514. heatmap_matrix_Sst_F <- assay(vst_data_Sst_F)[common_genes_Sst_F, ]
  1515. # Extract metadata for annotations
  1516. annotation_Sst_F <- sample_info_Sst_F %>% select(condition)
  1517. # Make sure your 'condition' column is a factor in desired order
  1518. annotation_Sst_F$condition <- factor(annotation_Sst_F$condition, levels = c("Control", "Risperidone"))
  1519. # Now reorder the columns of your heatmap matrix
  1520. ordered_samples_Sst_F <- rownames(annotation_Sst_F)[order(annotation_Sst_F$condition)]
  1521. heatmap_matrix_Sst_F <- heatmap_matrix_Sst_F[, ordered_samples_Sst_F]
  1522. annotation_colors_Sst_F <- list(
  1523. condition = c(
  1524. "Control" = brewer.pal(8, "Set2")[1],
  1525. "Risperidone" = brewer.pal(8, "Set2")[2]
  1526. )
  1527. )
  1528. # Generate heatmap
  1529. pheatmap(heatmap_matrix_Sst_F,
  1530. scale = "row",
  1531. cluster_rows = TRUE,
  1532. cluster_cols = TRUE,
  1533. show_rownames = FALSE,
  1534. show_colnames = TRUE,
  1535. annotation_col = annotation_Sst_F,
  1536. annotation_colors = annotation_colors,
  1537. border_color = NA,
  1538. fontsize = 8,
  1539. main = "")
  1540. ## Male
  1541. # Count the number of DEGs with padj < 0.05
  1542. sum(res_Sst_M$padj < 0.05, na.rm = TRUE) #269
  1543. # Select all DEGs with adjusted p-value < 0.05
  1544. sig_Sst_M <- res_Sst_M[!is.na(res_Sst_M$padj) & res_Sst_M$padj < 0.05, ]
  1545. # Then order and extract gene names
  1546. top_genes_Sst_M <- rownames(sig_Sst_M[order(sig_Sst_M$padj), ])
  1547. # Perform VST
  1548. vst_data_Sst_M <- vst(dds_Sst_M, blind = TRUE)
  1549. # Keep only genes that are present in the VST-transformed data
  1550. common_genes_Sst_M <- intersect(top_genes_Sst_M, rownames(assay(vst_data_Sst_M)))
  1551. # Extract VST expression matrix
  1552. heatmap_matrix_Sst_M <- assay(vst_data_Sst_M)[common_genes_Sst_M, ]
  1553. # Extract metadata for annotations
  1554. annotation_Sst_M <- sample_info_Sst_M %>% select(condition)
  1555. # Make sure your 'condition' column is a factor in desired order
  1556. annotation_Sst_M$condition <- factor(annotation_Sst_M$condition, levels = c("Control", "Risperidone"))
  1557. # Now reorder the columns of your heatmap matrix
  1558. ordered_samples_Sst_M <- rownames(annotation_Sst_M)[order(annotation_Sst_M$condition)]
  1559. heatmap_matrix_Sst_M <- heatmap_matrix_Sst_M[, ordered_samples_Sst_M]
  1560. annotation_colors_Sst_M <- list(
  1561. condition = c(
  1562. "Control" = brewer.pal(8, "Set2")[1],
  1563. "Risperidone" = brewer.pal(8, "Set2")[2]
  1564. )
  1565. )
  1566. # Generate heatmap
  1567. pheatmap(heatmap_matrix_Sst_M,
  1568. scale = "row",
  1569. cluster_rows = TRUE,
  1570. cluster_cols = TRUE,
  1571. show_rownames = FALSE,
  1572. show_colnames = TRUE,
  1573. annotation_col = annotation_Sst_M,
  1574. annotation_colors = annotation_colors,
  1575. border_color = NA,
  1576. fontsize = 8,
  1577. main = "")
  1578. ```
  1579. Sst-IN - F vs. M DEG volcano
  1580. ```{r}
  1581. # Convert DESeq2 results to a data frame
  1582. res_Sst_F_df <- as.data.frame(res_Sst_F)
  1583. res_Sst_F_df$gene <- rownames(res_Sst_F_df)
  1584. res_Sst_M_df <- as.data.frame(res_Sst_M)
  1585. res_Sst_M_df$gene <- rownames(res_Sst_M_df)
  1586. # Remove any NA values
  1587. res_Sst_F_df <- na.omit(res_Sst_F_df)
  1588. res_Sst_M_df <- na.omit(res_Sst_M_df)
  1589. # Add a new column to categorize genes for coloring
  1590. res_Sst_F_df$Significance <- "Not Significant"
  1591. res_Sst_F_df$Significance[res_Sst_F_df$padj < padj_threshold & abs(res_Sst_F_df$log2FoldChange) > log2FoldChange_threshold] <- "Significant"
  1592. res_Sst_M_df$Significance <- "Not Significant"
  1593. res_Sst_M_df$Significance[res_Sst_M_df$padj < padj_threshold & abs(res_Sst_M_df$log2FoldChange) > log2FoldChange_threshold] <- "Significant"
  1594. # Generate volcano plot with specific genes of interest labeled
  1595. # Define genes of interest
  1596. genes_of_interest_Sst_F <- c("Kcnd3", "Kcnq3", "Kcnt2", "Shank1", "Shank2", "Gria1", "Grid1", "Grik3", "Gabra5")
  1597. genes_of_interest_Sst_M <- c("Kcnd3", "Kcnt2", "Kcnh1", "Shank1", "Shank2", "Grik3")
  1598. # Generate Volcano plot
  1599. volcano_plot_Sst_F <- ggplot(res_Sst_F_df, aes(x = log2FoldChange, y = -log10(padj))) +
  1600. geom_point(data = res_Sst_F_df %>% dplyr::filter(Significance == "Not Significant"),
  1601. aes(x = log2FoldChange, y = -log10(padj)),
  1602. color = "gray", alpha = 0.5, size = 1) +
  1603. geom_point(data = res_Sst_F_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange > 0),
  1604. aes(x = log2FoldChange, y = -log10(padj)),
  1605. color = "red", alpha = 0.5, size = 1) +
  1606. geom_point(data = res_Sst_F_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange < 0),
  1607. aes(x = log2FoldChange, y = -log10(padj)),
  1608. color = "blue", alpha = 0.5, size = 1) +
  1609. geom_label_repel(
  1610. aes(label = ifelse(gene %in% genes_of_interest_Sst_F, gene, "")),
  1611. size = 7,
  1612. box.padding = 0.75,
  1613. label.padding = 0.35,
  1614. fill = alpha("white", 0),
  1615. color = "black",
  1616. segment.color = "black",
  1617. segment.size = 0.8,
  1618. segment.alpha = 0.8,
  1619. min.segment.length = 0,
  1620. force = 5,
  1621. max.overlaps = Inf
  1622. ) +
  1623. geom_vline(xintercept = c(-0.5, 0.5), linetype = "dotted", color = "black") +
  1624. geom_hline(yintercept = -log10(0.05), linetype = "dotted", color = "black") +
  1625. theme_minimal() +
  1626. labs(title = "Sst-IN F",
  1627. x = "Log2 Fold Change",
  1628. y = "-Log10 Adjusted P-Value") +
  1629. theme(
  1630. legend.position = "right",
  1631. axis.title.x = element_text(size = 16), # X-axis label size
  1632. axis.title.y = element_text(size = 16), # Y-axis label size
  1633. axis.text.x = element_text(size = 14), # X-axis tick labels
  1634. axis.text.y = element_text(size = 14), # Y-axis tick labels
  1635. plot.title = element_text(size = 20, face = "bold", hjust = 0.5, margin = margin(b = 10)),
  1636. plot.margin = margin(t = 10, r = 10, b = 10, l = 10) # adds space above the whole plot
  1637. )
  1638. volcano_plot_Sst_M <- ggplot(res_Sst_M_df, aes(x = log2FoldChange, y = -log10(padj))) +
  1639. geom_point(data = res_Sst_M_df %>% dplyr::filter(Significance == "Not Significant"),
  1640. aes(x = log2FoldChange, y = -log10(padj)),
  1641. color = "gray", alpha = 0.5, size = 1) +
  1642. geom_point(data = res_Sst_M_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange > 0),
  1643. aes(x = log2FoldChange, y = -log10(padj)),
  1644. color = "red", alpha = 0.5, size = 1) +
  1645. geom_point(data = res_Sst_M_df %>% dplyr::filter(Significance == "Significant" & log2FoldChange < 0),
  1646. aes(x = log2FoldChange, y = -log10(padj)),
  1647. color = "blue", alpha = 0.5, size = 1) +
  1648. geom_label_repel(
  1649. aes(label = ifelse(gene %in% genes_of_interest_Sst_M, gene, "")),
  1650. size = 7,
  1651. box.padding = 0.75,
  1652. label.padding = 0.35,
  1653. fill = alpha("white", 0),
  1654. color = "black",
  1655. segment.color = "black",
  1656. segment.size = 0.8,
  1657. segment.alpha = 0.8,
  1658. min.segment.length = 0,
  1659. force = 5,
  1660. max.overlaps = Inf
  1661. ) +
  1662. geom_vline(xintercept = c(-0.5, 0.5), linetype = "dotted", color = "black") +
  1663. geom_hline(yintercept = -log10(0.05), linetype = "dotted", color = "black") +
  1664. theme_minimal() +
  1665. labs(title = "Sst-IN M",
  1666. x = "Log2 Fold Change",
  1667. y = "-Log10 Adjusted P-Value") +
  1668. theme(
  1669. legend.position = "right",
  1670. axis.title.x = element_text(size = 16), # X-axis label size
  1671. axis.title.y = element_text(size = 16), # Y-axis label size
  1672. axis.text.x = element_text(size = 14), # X-axis tick labels
  1673. axis.text.y = element_text(size = 14), # Y-axis tick labels
  1674. plot.title = element_text(size = 20, face = "bold", hjust = 0.5, margin = margin(b = 10)),
  1675. plot.margin = margin(t = 10, r = 10, b = 10, l = 10) # adds space above the whole plot
  1676. )
  1677. # Print the plot
  1678. print(volcano_plot_Sst_F)
  1679. print(volcano_plot_Sst_M)
  1680. ```
  1681. Sst-IN DEG - F vs. M list comparison
  1682. ```{r}
  1683. # Get significant gene names
  1684. sig_genes_Sst_F <- rownames(res_Sst_F[which(res_Sst_F$padj < padj_cutoff), ])
  1685. sig_genes_Sst_M <- rownames(res_Sst_M[which(res_Sst_M$padj < padj_cutoff), ])
  1686. # Prepare a named list of vectors (each becomes a sheet)
  1687. deg_lists <- list(
  1688. DEGs_Male = data.frame(Gene = sig_genes_Sst_M),
  1689. DEGs_Female = data.frame(Gene = sig_genes_Sst_F),
  1690. Shared_DEGs = data.frame(Gene = intersect(sig_genes_Sst_M, sig_genes_Sst_F)),
  1691. Male_only = data.frame(Gene = setdiff(sig_genes_Sst_M, sig_genes_Sst_F)),
  1692. Female_only = data.frame(Gene = setdiff(sig_genes_Sst_F, sig_genes_Sst_M))
  1693. )
  1694. # Save to Excel file
  1695. write_xlsx(deg_lists, path = "~/Risperidone_Proj/R_analysis/DE_modified/Proj4_C_v_R_Sst_FvM.xlsx")
  1696. ```
  1697. EnrichGO - PV-IN
  1698. ```{r}
  1699. # Filter DEG list
  1700. res_Pvalb_enrichGO <- rownames(res_Pvalb[!is.na(res_Pvalb$padj) &
  1701. res_Pvalb$padj < 0.05 &
  1702. abs(res_Pvalb$log2FoldChange) > 0.5, ])
  1703. # Run EnrichGO - BP
  1704. BP_GO_Pvalb <- enrichGO(
  1705. gene = res_Pvalb_enrichGO,
  1706. OrgDb = org.Mm.eg.db, # Use org.Mm.eg.db for mouse
  1707. keyType = "SYMBOL",
  1708. ont = "BP", # "BP" (Biological Process), "MF" (Molecular Function), "CC" (Cellular Component)
  1709. pAdjustMethod = "BH",
  1710. pvalueCutoff = 0.05,
  1711. qvalueCutoff = 0.05
  1712. )
  1713. # View the first few enriched GO terms
  1714. head(BP_GO_Pvalb)
  1715. # Run EnrichGO - MF
  1716. MF_GO_Pvalb <- enrichGO(
  1717. gene = res_Pvalb_enrichGO,
  1718. OrgDb = org.Mm.eg.db, # Use org.Mm.eg.db for mouse
  1719. keyType = "SYMBOL",
  1720. ont = "MF", # "BP" (Biological Process), "MF" (Molecular Function), "CC" (Cellular Component)
  1721. pAdjustMethod = "BH",
  1722. pvalueCutoff = 0.05,
  1723. qvalueCutoff = 0.05
  1724. )
  1725. # View the first few enriched GO terms
  1726. head(MF_GO_Pvalb)
  1727. # Run EnrichGO - CC
  1728. CC_GO_Pvalb <- enrichGO(
  1729. gene = res_Pvalb_enrichGO,
  1730. OrgDb = org.Mm.eg.db, # Use org.Mm.eg.db for mouse
  1731. keyType = "SYMBOL",
  1732. ont = "CC", # "BP" (Biological Process), "MF" (Molecular Function), "CC" (Cellular Component)
  1733. pAdjustMethod = "BH",
  1734. pvalueCutoff = 0.05,
  1735. qvalueCutoff = 0.05
  1736. )
  1737. # View the first few enriched GO terms
  1738. head(CC_GO_Pvalb)
  1739. # Save as Excel file
  1740. write.xlsx(
  1741. list(
  1742. BP = as.data.frame(BP_GO_Pvalb),
  1743. MF = as.data.frame(MF_GO_Pvalb),
  1744. CC = as.data.frame(CC_GO_Pvalb)
  1745. ),
  1746. file = "~/Risperidone_Proj/R_analysis/EnrichGO/Proj4_Pvalb_GO.xlsx"
  1747. )
  1748. ```
  1749. EnrichGO - PV-IN (up/down separate)
  1750. ```{r}
  1751. # Convert the rownames into a new column of gene symbols
  1752. res_df_Pvalb <- as.data.frame(res_Pvalb)
  1753. res_df_Pvalb$gene <- rownames(res_df_Pvalb)
  1754. # Upregulated genes (padj < 0.05 & log2FC > 0.5)
  1755. up_Pvalb <- res_df_Pvalb %>%
  1756. dplyr::filter(padj < 0.05 & log2FoldChange > 0.5) %>%
  1757. dplyr::pull(gene)
  1758. # Downregulated genes (padj < 0.05 & log2FC < -0.5)
  1759. down_Pvalb <- res_df_Pvalb %>%
  1760. dplyr::filter(padj < 0.05, log2FoldChange < -0.5) %>%
  1761. dplyr::pull(gene)
  1762. ## BP
  1763. # Run GO enrichment
  1764. BP_up_Pvalb <- enrichGO(gene = up_Pvalb, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1765. ont = "BP", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1766. BP_down_Pvalb <- enrichGO(gene = down_Pvalb, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1767. ont = "BP", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1768. # Convert results to data frame
  1769. df_BP_up_Pvalb <- as.data.frame(BP_up_Pvalb)
  1770. df_BP_down_Pvalb <- as.data.frame(BP_down_Pvalb)
  1771. # Prepare subset for plotting (top 20 each)
  1772. df_BP_up_Pvalb_plot <- df_BP_up_Pvalb[1:min(20, nrow(df_BP_up_Pvalb)), ] %>%
  1773. mutate(Direction = "Up", log_padj = -log10(p.adjust))
  1774. df_BP_down_Pvalb_plot <- df_BP_down_Pvalb[1:min(20, nrow(df_BP_down_Pvalb)), ] %>%
  1775. mutate(Direction = "Down", log_padj = log10(p.adjust)) # keep positive for plotting
  1776. combined_BP_Pvalb <- bind_rows(df_BP_up_Pvalb_plot, df_BP_down_Pvalb_plot)
  1777. # Plot
  1778. ggplot(combined_BP_Pvalb, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  1779. geom_bar(stat = "identity") +
  1780. coord_flip() +
  1781. labs(x = "GO Term", y = "-log10 Adjusted p-value", title = "GO Enrichment- PV-IN (BP)") +
  1782. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  1783. theme_minimal()
  1784. # Plot - just downregulated
  1785. ggplot(df_BP_down_Pvalb_plot, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  1786. geom_bar(stat = "identity") +
  1787. coord_flip() +
  1788. labs(x = "GO Term", y = "-log10 Adjusted p-value", title = "PV-IN (BP)") +
  1789. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  1790. theme_minimal() +
  1791. theme(
  1792. legend.position = "none",
  1793. axis.text.y = element_text(size = 14), # bigger GO term labels
  1794. axis.title.x = element_text(size = 16),
  1795. axis.title.y = element_text(size = 16),
  1796. plot.title = element_text(size = 18, face = "bold", hjust = 0.5)
  1797. )
  1798. ## MF
  1799. # Run GO enrichment
  1800. MF_up_Pvalb <- enrichGO(gene = up_Pvalb, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1801. ont = "MF", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1802. MF_down_Pvalb <- enrichGO(gene = down_Pvalb, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1803. ont = "MF", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1804. # Convert results to data frame
  1805. df_MF_up_Pvalb <- as.data.frame(MF_up_Pvalb)
  1806. df_MF_down_Pvalb <- as.data.frame(MF_down_Pvalb)
  1807. # Prepare subset for plotting (top 20 each)
  1808. df_MF_up_Pvalb_plot <- df_MF_up_Pvalb[1:min(20, nrow(df_MF_up_Pvalb)), ] %>%
  1809. mutate(Direction = "Up", log_padj = -log10(p.adjust))
  1810. df_MF_down_Pvalb_plot <- df_MF_down_Pvalb[1:min(20, nrow(df_MF_down_Pvalb)), ] %>%
  1811. mutate(Direction = "Down", log_padj = log10(p.adjust)) # keep positive for plotting
  1812. combined_MF_Pvalb <- bind_rows(df_MF_up_Pvalb_plot, df_MF_down_Pvalb_plot)
  1813. # Plot
  1814. ggplot(combined_MF_Pvalb, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  1815. geom_bar(stat = "identity") +
  1816. coord_flip() +
  1817. labs(x = "GO Term", y = "-log10 Adjusted p-value", title = "GO Enrichment- PV-IN (MF)") +
  1818. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  1819. theme_minimal()
  1820. # Plot - just downregulated
  1821. ggplot(df_MF_down_Pvalb_plot, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  1822. geom_bar(stat = "identity") +
  1823. coord_flip() +
  1824. labs(x = "GO Term", y = "-log10 Adjusted p-value", title = "PV-IN (MF)") +
  1825. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  1826. theme_minimal() +
  1827. theme(
  1828. legend.position = "none",
  1829. axis.text.y = element_text(size = 14), # bigger GO term labels
  1830. axis.title.x = element_text(size = 16),
  1831. axis.title.y = element_text(size = 16),
  1832. plot.title = element_text(size = 18, face = "bold", hjust = 0.5)
  1833. )
  1834. ## CC
  1835. # Run GO enrichment
  1836. CC_up_Pvalb <- enrichGO(gene = up_Pvalb, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1837. ont = "CC", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1838. CC_down_Pvalb <- enrichGO(gene = down_Pvalb, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1839. ont = "CC", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1840. # Convert results to data frame
  1841. df_CC_up_Pvalb <- as.data.frame(CC_up_Pvalb)
  1842. df_CC_down_Pvalb <- as.data.frame(CC_down_Pvalb)
  1843. # Prepare subset for plotting (top 20 each)
  1844. df_CC_up_Pvalb_plot <- df_CC_up_Pvalb[1:min(20, nrow(df_CC_up_Pvalb)), ] %>%
  1845. mutate(Direction = "Up", log_padj = -log10(p.adjust))
  1846. df_CC_down_Pvalb_plot <- df_CC_down_Pvalb[1:min(20, nrow(df_CC_down_Pvalb)), ] %>%
  1847. mutate(Direction = "Down", log_padj = log10(p.adjust)) # keep positive for plotting
  1848. combined_CC_Pvalb <- bind_rows(df_CC_up_Pvalb_plot, df_CC_down_Pvalb_plot)
  1849. # Plot
  1850. ggplot(combined_CC_Pvalb, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  1851. geom_bar(stat = "identity") +
  1852. coord_flip() +
  1853. labs(x = "GO Term", y = "-log10 Adjusted p-value", title = "GO Enrichment- PV-IN (CC)") +
  1854. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  1855. theme_minimal()
  1856. # Save all enrichment results to Excel
  1857. # Create workbook
  1858. wb <- createWorkbook()
  1859. # Add BP data
  1860. addWorksheet(wb, "Up_BP")
  1861. addWorksheet(wb, "Down_BP")
  1862. writeData(wb, "Up_BP", df_BP_up_Pvalb)
  1863. writeData(wb, "Down_BP", df_BP_down_Pvalb)
  1864. addWorksheet(wb, "Up_MF")
  1865. addWorksheet(wb, "Down_MF")
  1866. writeData(wb, "Up_MF", df_MF_up_Pvalb)
  1867. writeData(wb, "Down_MF", df_MF_down_Pvalb)
  1868. addWorksheet(wb, "Up_CC")
  1869. addWorksheet(wb, "Down_CC")
  1870. writeData(wb, "Up_CC", df_CC_up_Pvalb)
  1871. writeData(wb, "Down_CC", df_CC_down_Pvalb)
  1872. # Save excel file
  1873. saveWorkbook(wb, "~/Risperidone_Proj/R_analysis/EnrichGO/Proj4_Pvalb_updown.xlsx", overwrite = TRUE)
  1874. ```
  1875. EnrichGO - Glut (up/down separate)
  1876. ```{r}
  1877. # Convert the rownames into a new column of gene symbols
  1878. res_df_Glut <- as.data.frame(res_Glut)
  1879. res_df_Glut$gene <- rownames(res_df_Glut)
  1880. # Upregulated genes (padj < 0.05 & log2FC > 0.5)
  1881. up_Glut <- res_df_Glut %>%
  1882. dplyr::filter(padj < 0.05, log2FoldChange > 0.5) %>%
  1883. dplyr::pull(gene)
  1884. # Downregulated genes (padj < 0.05 & log2FC < -0.5)
  1885. down_Glut <- res_df_Glut %>%
  1886. dplyr::filter(padj < 0.05, log2FoldChange < -0.5) %>%
  1887. dplyr::pull(gene)
  1888. ## BP
  1889. # Run GO enrichment
  1890. BP_up_Glut <- enrichGO(gene = up_Glut, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1891. ont = "BP", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1892. BP_down_Glut <- enrichGO(gene = down_Glut, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1893. ont = "BP", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1894. # Convert results to data frame
  1895. df_BP_up_Glut <- as.data.frame(BP_up_Glut)
  1896. df_BP_down_Glut <- as.data.frame(BP_down_Glut)
  1897. # Prepare subset for plotting (top 20 each)
  1898. df_BP_up_Glut_plot <- df_BP_up_Glut[1:min(20, nrow(df_BP_up_Glut)), ] %>%
  1899. mutate(Direction = "Up", log_padj = -log10(p.adjust))
  1900. df_BP_down_Glut_plot <- df_BP_down_Glut[1:min(20, nrow(df_BP_down_Glut)), ] %>%
  1901. mutate(Direction = "Down", log_padj = log10(p.adjust)) # keep positive for plotting
  1902. combined_BP_Glut <- bind_rows(df_BP_up_Glut_plot, df_BP_down_Glut_plot)
  1903. # Plot
  1904. ggplot(combined_BP_Glut, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  1905. geom_bar(stat = "identity") +
  1906. coord_flip() +
  1907. labs(x = "GO Term", y = "-log10 Adjusted p-value", title = "GO Enrichment- Glut (BP)") +
  1908. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  1909. theme_minimal()
  1910. ## MF
  1911. # Run GO enrichment
  1912. MF_up_Glut <- enrichGO(gene = up_Glut, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1913. ont = "MF", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1914. MF_down_Glut <- enrichGO(gene = down_Glut, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1915. ont = "MF", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1916. # Convert results to data frame
  1917. df_MF_up_Glut <- as.data.frame(MF_up_Glut)
  1918. df_MF_down_Glut <- as.data.frame(MF_down_Glut)
  1919. # Prepare subset for plotting (top 20 each)
  1920. df_MF_up_Glut_plot <- df_MF_up_Glut[1:min(20, nrow(df_MF_up_Glut)), ] %>%
  1921. mutate(Direction = "Up", log_padj = -log10(p.adjust))
  1922. df_MF_down_Glut_plot <- df_MF_down_Glut[1:min(20, nrow(df_MF_down_Glut)), ] %>%
  1923. mutate(Direction = "Down", log_padj = log10(p.adjust)) # keep positive for plotting
  1924. combined_MF_Glut <- bind_rows(df_MF_up_Glut_plot, df_MF_down_Glut_plot)
  1925. # Plot
  1926. ggplot(combined_MF_Glut, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  1927. geom_bar(stat = "identity") +
  1928. coord_flip() +
  1929. labs(x = "GO Term", y = "-log10 Adjusted p-value", title = "GO Enrichment- Glut (MF)") +
  1930. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  1931. theme_minimal()
  1932. # Plot - just downregulated
  1933. ggplot(df_MF_down_Glut_plot, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  1934. geom_bar(stat = "identity") +
  1935. coord_flip() +
  1936. labs(x = "GO Term", y = "-log10 Adjusted p-value", title = "Glut (MF)") +
  1937. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  1938. theme_minimal() +
  1939. theme(
  1940. legend.position = "none",
  1941. axis.text.y = element_text(size = 14), # bigger GO term labels
  1942. axis.title.x = element_text(size = 16),
  1943. axis.title.y = element_text(size = 16),
  1944. plot.title = element_text(size = 18, face = "bold", hjust = 0.5)
  1945. )
  1946. ## CC
  1947. # Run GO enrichment
  1948. CC_up_Glut <- enrichGO(gene = up_Glut, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1949. ont = "CC", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1950. CC_down_Glut <- enrichGO(gene = down_Glut, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  1951. ont = "CC", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  1952. # Convert results to data frame
  1953. df_CC_up_Glut <- as.data.frame(CC_up_Glut)
  1954. df_CC_down_Glut <- as.data.frame(CC_down_Glut)
  1955. # Prepare subset for plotting (top 20 each)
  1956. df_CC_up_Glut_plot <- df_CC_up_Glut[1:min(20, nrow(df_CC_up_Glut)), ] %>%
  1957. mutate(Direction = "Up", log_padj = -log10(p.adjust))
  1958. df_CC_down_Glut_plot <- df_CC_down_Glut[1:min(20, nrow(df_CC_down_Glut)), ] %>%
  1959. mutate(Direction = "Down", log_padj = log10(p.adjust)) # keep positive for plotting
  1960. combined_CC_Glut <- bind_rows(df_CC_up_Glut_plot, df_CC_down_Glut_plot)
  1961. # Plot
  1962. ggplot(combined_CC_Glut, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  1963. geom_bar(stat = "identity") +
  1964. coord_flip() +
  1965. labs(x = "GO Term", y = "-log10 Adjusted p-value", title = "GO Enrichment- Glut (CC)") +
  1966. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  1967. theme_minimal()
  1968. # Save all enrichment results to Excel
  1969. # Create workbook
  1970. wb <- createWorkbook()
  1971. # Add BP data
  1972. addWorksheet(wb, "Up_BP")
  1973. addWorksheet(wb, "Down_BP")
  1974. writeData(wb, "Up_BP", df_BP_up_Glut)
  1975. writeData(wb, "Down_BP", df_BP_down_Glut)
  1976. addWorksheet(wb, "Up_MF")
  1977. addWorksheet(wb, "Down_MF")
  1978. writeData(wb, "Up_MF", df_MF_up_Glut)
  1979. writeData(wb, "Down_MF", df_MF_down_Glut)
  1980. addWorksheet(wb, "Up_CC")
  1981. addWorksheet(wb, "Down_CC")
  1982. writeData(wb, "Up_CC", df_CC_up_Glut)
  1983. writeData(wb, "Down_CC", df_CC_down_Glut)
  1984. # Save excel file
  1985. saveWorkbook(wb, "~/Risperidone_Proj/R_analysis/EnrichGO/Proj4_Glut_updown.xlsx", overwrite = TRUE)
  1986. ```
  1987. EnrichGO - Sst-IN (up/down separate)
  1988. ```{r}
  1989. # Convert the rownames into a new column of gene symbols
  1990. res_df_Sst <- as.data.frame(res_Sst)
  1991. res_df_Sst$gene <- rownames(res_df_Sst)
  1992. # Upregulated genes (padj < 0.05 & log2FC > 0.5)
  1993. up_Sst <- res_df_Sst %>%
  1994. dplyr::filter(padj < 0.05, log2FoldChange > 0.5) %>%
  1995. dplyr::pull(gene)
  1996. # Downregulated genes (padj < 0.05 & log2FC < -0.5)
  1997. down_Sst <- res_df_Sst %>%
  1998. dplyr::filter(padj < 0.05, log2FoldChange < -0.5) %>%
  1999. dplyr::pull(gene)
  2000. ## BP
  2001. # Run GO enrichment
  2002. BP_up_Sst <- enrichGO(gene = up_Sst, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  2003. ont = "BP", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  2004. BP_down_Sst <- enrichGO(gene = down_Sst, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  2005. ont = "BP", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  2006. # Convert results to data frame
  2007. df_BP_up_Sst <- as.data.frame(BP_up_Sst)
  2008. df_BP_down_Sst <- as.data.frame(BP_down_Sst)
  2009. # Prepare subset for plotting (top 20 each)
  2010. df_BP_up_Sst_plot <- df_BP_up_Sst[1:min(20, nrow(df_BP_up_Sst)), ] %>%
  2011. mutate(Direction = "Up", log_padj = -log10(p.adjust))
  2012. df_BP_down_Sst_plot <- df_BP_down_Sst[1:min(20, nrow(df_BP_down_Sst)), ] %>%
  2013. mutate(Direction = "Down", log_padj = log10(p.adjust)) # keep positive for plotting
  2014. combined_BP_Sst <- bind_rows(df_BP_up_Sst_plot, df_BP_down_Sst_plot)
  2015. # Plot
  2016. ggplot(combined_BP_Sst, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  2017. geom_bar(stat = "identity") +
  2018. coord_flip() +
  2019. labs(
  2020. x = "GO Term",
  2021. y = "-log10 Adjusted p-value",
  2022. title = "Sst-IN (BP)"
  2023. ) +
  2024. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  2025. theme_minimal() +
  2026. theme(
  2027. axis.text.y = element_text(size = 12), # increase GO term text size
  2028. axis.text.x = element_text(size = 10), # adjust x-axis text size
  2029. axis.title = element_text(size = 12) # increase axis title size
  2030. )
  2031. ## MF
  2032. # Run GO enrichment
  2033. MF_up_Sst <- enrichGO(gene = up_Sst, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  2034. ont = "MF", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  2035. MF_down_Sst <- enrichGO(gene = down_Sst, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  2036. ont = "MF", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  2037. # Convert results to data frame
  2038. df_MF_up_Sst <- as.data.frame(MF_up_Sst)
  2039. df_MF_down_Sst <- as.data.frame(MF_down_Sst)
  2040. # Prepare subset for plotting (top 20 each)
  2041. df_MF_up_Sst_plot <- df_MF_up_Sst[1:min(20, nrow(df_MF_up_Sst)), ] %>%
  2042. mutate(Direction = "Up", log_padj = -log10(p.adjust))
  2043. df_MF_down_Sst_plot <- df_MF_down_Sst[1:min(20, nrow(df_MF_down_Sst)), ] %>%
  2044. mutate(Direction = "Down", log_padj = log10(p.adjust)) # keep positive for plotting
  2045. combined_MF_Sst <- bind_rows(df_MF_up_Sst_plot, df_MF_down_Sst_plot)
  2046. # Plot
  2047. ggplot(combined_MF_Sst, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  2048. geom_bar(stat = "identity") +
  2049. coord_flip() +
  2050. labs(
  2051. x = "GO Term",
  2052. y = "-log10 Adjusted p-value",
  2053. title = "Sst-IN (MF)"
  2054. ) +
  2055. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  2056. theme_minimal() +
  2057. theme(
  2058. axis.text.y = element_text(size = 12), # increase GO term text size
  2059. axis.text.x = element_text(size = 10), # adjust x-axis text size
  2060. axis.title = element_text(size = 12) # increase axis title size
  2061. )
  2062. ## CC
  2063. # Run GO enrichment
  2064. CC_up_Sst <- enrichGO(gene = up_Sst, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  2065. ont = "CC", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  2066. CC_down_Sst <- enrichGO(gene = down_Sst, OrgDb = org.Mm.eg.db, keyType = "SYMBOL",
  2067. ont = "CC", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05)
  2068. # Convert results to data frame
  2069. df_CC_up_Sst <- as.data.frame(CC_up_Sst)
  2070. df_CC_down_Sst <- as.data.frame(CC_down_Sst)
  2071. # Prepare subset for plotting (top 20 each)
  2072. df_CC_up_Sst_plot <- df_CC_up_Sst[1:min(20, nrow(df_CC_up_Sst)), ] %>%
  2073. mutate(Direction = "Up", log_padj = -log10(p.adjust))
  2074. df_CC_down_Sst_plot <- df_CC_down_Sst[1:min(20, nrow(df_CC_down_Sst)), ] %>%
  2075. mutate(Direction = "Down", log_padj = log10(p.adjust)) # keep positive for plotting
  2076. combined_CC_Sst <- bind_rows(df_CC_up_Sst_plot, df_CC_down_Sst_plot)
  2077. # Plot
  2078. ggplot(combined_CC_Sst, aes(x = reorder(Description, log_padj), y = log_padj, fill = Direction)) +
  2079. geom_bar(stat = "identity") +
  2080. coord_flip() +
  2081. labs(
  2082. x = "GO Term",
  2083. y = "-log10 Adjusted p-value",
  2084. title = "Sst-IN (CC)"
  2085. ) +
  2086. scale_fill_manual(values = c("Up" = "tomato", "Down" = "skyblue")) +
  2087. theme_minimal() +
  2088. theme(
  2089. axis.text.y = element_text(size = 12), # increase GO term text size
  2090. axis.text.x = element_text(size = 10), # adjust x-axis text size
  2091. axis.title = element_text(size = 12) # increase axis title size
  2092. )
  2093. # Save all enrichment results to Excel
  2094. # Create workbook
  2095. wb <- createWorkbook()
  2096. # Add BP data
  2097. addWorksheet(wb, "Up_BP")
  2098. addWorksheet(wb, "Down_BP")
  2099. writeData(wb, "Up_BP", df_BP_up_Sst)
  2100. writeData(wb, "Down_BP", df_BP_down_Sst)
  2101. addWorksheet(wb, "Up_MF")
  2102. addWorksheet(wb, "Down_MF")
  2103. writeData(wb, "Up_MF", df_MF_up_Sst)
  2104. writeData(wb, "Down_MF", df_MF_down_Sst)
  2105. addWorksheet(wb, "Up_CC")
  2106. addWorksheet(wb, "Down_CC")
  2107. writeData(wb, "Up_CC", df_CC_up_Sst)
  2108. writeData(wb, "Down_CC", df_CC_down_Sst)
  2109. # Save excel file
  2110. saveWorkbook(wb, "~/Risperidone_Proj/R_analysis/EnrichGO/Proj4_Sst_updown.xlsx", overwrite = TRUE)
  2111. ```
  2112. hdWGCNA
  2113. ```{r}
  2114. # using the cowplot theme for ggplot
  2115. theme_set(theme_cowplot())
  2116. # set random seed for reproducibility
  2117. set.seed(12345)
  2118. # optionally enable multithreading - allowing parallel execution with up to 8 working processes.
  2119. enableWGCNAThreads(nThreads = 8)
  2120. # Set up Seurat object for WGCNA - do not subset this seurat object after this has been run.
  2121. Mcortex_QC_WGCNA <- SetupForWGCNA(
  2122. Mcortex_QC,
  2123. gene_select = "fraction", # the gene selection approach, can also select variable or custom
  2124. fraction = 0.05, # genes expressed in 5% of cells. Fraction of cells that a gene needs to be expressed in order to be included
  2125. wgcna_name = "hdWGCNA" # the name of the hdWGCNA experiment
  2126. )
  2127. # Extract sample_id from barcode names for the Seurat object
  2128. Mcortex_QC_WGCNA$sample_id <- sapply(strsplit(Cells(Mcortex_QC_WGCNA), "_"), `[`, 1)
  2129. # construct metacells in each group
  2130. Mcortex_QC_WGCNA <- MetacellsByGroups(
  2131. seurat_obj = Mcortex_QC_WGCNA,
  2132. group.by = c("celltype1", "sample_id"), # specify the columns in [email hidden] to group by
  2133. reduction = 'pca', # select the dimensionality reduction to perform KNN on
  2134. k = 65, # nearest-neighbors parameter
  2135. max_shared = 10, # maximum number of shared cells between two metacells
  2136. ident.group = 'celltype1' # set the Idents of the metacell seurat object
  2137. )
  2138. # normalize metacell expression matrix:
  2139. Mcortex_QC_WGCNA <- NormalizeMetacells(Mcortex_QC_WGCNA)
  2140. # View what layers exist in the WGCNA Seurat object, and check which default assay.
  2141. DefaultAssay(Mcortex_QC_WGCNA)
  2142. DefaultAssay(Mcortex_QC_WGCNA) <- "SCT"
  2143. Layers(Mcortex_QC_WGCNA[["SCT"]])
  2144. saveRDS(Mcortex_QC_WGCNA, file='~/Risperidone_Proj/R_analysis/RDS_files/hdWGCNA_object.rds')
  2145. Mcortex_QC_WGCNA <- readRDS("~/Risperidone_Proj/R_analysis/RDS_files/hdWGCNA_object.rds")
  2146. ```
  2147. hdWGCNA continued - analysis of PV-IN
  2148. ```{r}
  2149. # Set up the expression matrix for 3 cell types of interest
  2150. Mcortex_QC_WGCNA <- SetDatExpr(
  2151. Mcortex_QC_WGCNA,
  2152. group_name = "GABAergic Pvalb",
  2153. group.by = "celltype1",
  2154. assay = "SCT",
  2155. layer = "data"
  2156. )
  2157. # Select soft-power threshold
  2158. # Test different soft powers:
  2159. Mcortex_QC_WGCNA <- TestSoftPowers(
  2160. Mcortex_QC_WGCNA,
  2161. networkType = 'signed') # you can also use "unsigned" or "signed hybrid"
  2162. # plot the results:
  2163. plot_list <- PlotSoftPowers(Mcortex_QC_WGCNA)
  2164. # assemble with patchwork
  2165. wrap_plots(plot_list, ncol=2)
  2166. # Construct co-expression network
  2167. Mcortex_QC_WGCNA <- ConstructNetwork(
  2168. Mcortex_QC_WGCNA,
  2169. tom_name = 'PV-IN') # name of the topoligical overlap matrix written to disk
  2170. # Compute harmonized module eingengenes
  2171. # need to re-run ScaleData because sample_id metadata added after SCTransform:
  2172. Mcortex_QC_WGCNA <- ScaleData(Mcortex_QC_WGCNA, features=VariableFeatures(Mcortex_QC_WGCNA))
  2173. Mcortex_QC_WGCNA <- ModuleEigengenes(
  2174. Mcortex_QC_WGCNA,
  2175. group.by.vars="sample_id")
  2176. # Get module eigengenes (Harmonized by default)
  2177. hMEs <- GetMEs(Mcortex_QC_WGCNA)
  2178. # To get non-harmonized module eigengenes (not run)
  2179. MEs <- GetMEs(Mcortex_QC_WGCNA, harmonized=FALSE)
  2180. # Compute eigengene-based module connectivity (kME)
  2181. Mcortex_QC_WGCNA <- ModuleConnectivity(
  2182. Mcortex_QC_WGCNA,
  2183. group.by = 'celltype1', group_name = 'GABAergic Pvalb')
  2184. # Look inside the hdWGCNA network parameters to check softpower beta
  2185. Mcortex_QC_WGCNA@misc$hdWGCNA$wgcna_params
  2186. # rename the modules for convenience
  2187. Mcortex_QC_WGCNA <- ResetModuleNames(
  2188. Mcortex_QC_WGCNA,
  2189. new_name = "PV-IN-M")
  2190. # Change color of modules
  2191. # get the module table
  2192. modules <- GetModules(Mcortex_QC_WGCNA)
  2193. mods <- unique(modules$module)
  2194. # make a table of the module-color pairings
  2195. mod_colors_df <- dplyr::select(modules, c(module, color)) %>%
  2196. distinct %>% arrange(module)
  2197. rownames(mod_colors_df) <- mod_colors_df$module
  2198. # print the dataframe
  2199. mod_colors_df
  2200. # load MetBrewer color scheme package
  2201. library(MetBrewer)
  2202. # get a table of just the module and it's unique color
  2203. mod_color_df <- GetModules(Mcortex_QC_WGCNA) %>%
  2204. dplyr::select(c(module, color)) %>%
  2205. distinct %>% arrange(module)
  2206. # the number of unique modules (subtract 1 because the grey module stays grey):
  2207. n_mods <- nrow(mod_color_df) - 1
  2208. # using the "Signac" palette from metbrewer, selecting for the number of modules
  2209. new_colors <- paste0(met.brewer("Signac", n=n_mods))
  2210. # reset the module colors
  2211. Mcortex_QC_WGCNA <- ResetModuleColors(Mcortex_QC_WGCNA, new_colors)
  2212. # Plot dendogram
  2213. PlotDendrogram(Mcortex_QC_WGCNA, main='hdWGCNA Dendrogram for PV-IN')
  2214. # plot genes ranked by kME for each module
  2215. PlotKMEs(Mcortex_QC_WGCNA, ncol=3)
  2216. # get the module assignment table:
  2217. modules <- GetModules(Mcortex_QC_WGCNA) %>% subset(module != 'grey')
  2218. # show the first 6 columns:
  2219. head(modules[,1:6])
  2220. # save to Excel
  2221. write_xlsx(modules, "~/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_module_assignments.xlsx")
  2222. # get hub genes
  2223. hub_df <- GetHubGenes(Mcortex_QC_WGCNA, n_hubs = 100)
  2224. head(hub_df)
  2225. # save to Excel
  2226. write_xlsx(hub_df, "~/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_top100_hubgenes.xlsx")
  2227. ```
  2228. Visualization of hdWGCNA results - PV-IN
  2229. ```{r}
  2230. # make a featureplot of hMEs for each module
  2231. plot_list <- ModuleFeaturePlot(
  2232. Mcortex_QC_WGCNA,
  2233. features='hMEs', # plot the hMEs
  2234. order=TRUE # order so the points with highest hMEs are on top
  2235. )
  2236. # stitch together with patchwork
  2237. wrap_plots(plot_list, ncol=3)
  2238. # plot module correlagram
  2239. ModuleCorrelogram(Mcortex_QC_WGCNA)
  2240. # Dot plot of hME's
  2241. # Get hME's and module tables again
  2242. MEs <- GetMEs(Mcortex_QC_WGCNA, harmonized=TRUE)
  2243. modules <- GetModules(Mcortex_QC_WGCNA)
  2244. mods <- levels(modules$module); mods <- mods[mods != 'grey']
  2245. # add hMEs to Seurat meta-data:
  2246. [email hidden] <- cbind([email hidden], MEs)
  2247. # plot with Seurat's DotPlot function
  2248. p <- DotPlot(Mcortex_QC_WGCNA, features=mods, group.by = 'celltype1')
  2249. # flip the x/y axes, rotate the axis labels, and change color scheme:
  2250. p <- p +
  2251. RotatedAxis() +
  2252. scale_color_gradient2(high='red', mid='grey95', low='blue')
  2253. # plot output
  2254. p
  2255. # Individual module network plot
  2256. ModuleNetworkPlot(
  2257. Mcortex_QC_WGCNA,
  2258. outdir='ModuleNetworks_PV-IN', # new folder name
  2259. n_inner = 10, # number of genes in inner ring
  2260. n_outer = 15, # number of genes in outer ring
  2261. n_conns = Inf, # show all of the connections
  2262. plot_size=c(5,5), # larger plotting area
  2263. vertex.label.cex=1 # font size
  2264. )
  2265. # UMAP with network
  2266. # Increased allowed globals size
  2267. options(future.globals.maxSize = 20 * 1024^3) # allow up to 20 GB
  2268. # Run Module UMAP
  2269. Mcortex_QC_WGCNA <- RunModuleUMAP(
  2270. Mcortex_QC_WGCNA,
  2271. n_hubs = 5, # number of hub genes to include for the UMAP embedding
  2272. n_neighbors=10, # neighbors parameter for UMAP
  2273. min_dist=0.3 # min distance between points in UMAP space
  2274. )
  2275. # Plot UMAP of genes and their co-expression relationship
  2276. ModuleUMAPPlot(
  2277. Mcortex_QC_WGCNA,
  2278. edge.alpha=0.15,
  2279. sample_edges=TRUE, # If true, downsampling edges
  2280. edge_prop=0.1, # proportion of edges to sample (10% here)
  2281. label_hubs=1, # how many hub genes to plot per module?
  2282. vertex.label.cex = 0.5,
  2283. )
  2284. # hubgene network
  2285. HubGeneNetworkPlot(
  2286. Mcortex_QC_WGCNA,
  2287. n_hubs = 3, n_other=5,
  2288. edge_prop = 1,
  2289. mods = 'all',
  2290. vertex.label.cex = 0.75,
  2291. hub.vertex.size = 4,
  2292. other.vertex.size = 1
  2293. )
  2294. ```
  2295. Correlation of hdGCNA results with treatment variables - PV-IN
  2296. ```{r}
  2297. # --- Create a modified version of hdWGCNA::ModuleTraitCorrelation ---
  2298. ModuleTraitCorrelation_mod <- function(seurat_obj, traits, group.by = NULL, features = "hMEs",
  2299. cor_method = "pearson", subset_by = NULL, subset_groups = NULL,
  2300. wgcna_name = NULL, ...) {
  2301. if (is.null(wgcna_name)) {
  2302. wgcna_name <- seurat_obj@misc$active_wgcna
  2303. }
  2304. hdWGCNA:::CheckWGCNAName(seurat_obj, wgcna_name)
  2305. if (features == "hMEs") {
  2306. MEs <- hdWGCNA:::GetMEs(seurat_obj, TRUE, wgcna_name)
  2307. } else if (features == "MEs") {
  2308. MEs <- hdWGCNA:::GetMEs(seurat_obj, FALSE, wgcna_name)
  2309. } else if (features == "scores") {
  2310. MEs <- hdWGCNA:::GetModuleScores(seurat_obj, wgcna_name)
  2311. } else {
  2312. stop("Invalid feature selection. Valid choices: hMEs, MEs, scores, average")
  2313. }
  2314. if (!is.null(subset_by)) {
  2315. print("subsetting")
  2316. seurat_full <- seurat_obj
  2317. MEs <- MEs[[email hidden][[subset_by]] %in% subset_groups, ]
  2318. seurat_obj <- seurat_obj[, [email hidden][[subset_by]] %in% subset_groups]
  2319. }
  2320. if (sum(traits %in% colnames([email hidden])) != length(traits)) {
  2321. stop(paste("Some of the provided traits were not found in the Seurat obj:",
  2322. paste(traits[!(traits %in% colnames([email hidden]))], collapse = ", ")))
  2323. }
  2324. if (is.null(group.by)) {
  2325. group.by <- "temp_ident"
  2326. seurat_obj$temp_ident <- Idents(seurat_obj)
  2327. }
  2328. valid_types <- c("numeric", "factor", "integer")
  2329. data_types <- sapply(traits, function(x) class([email hidden][, x]))
  2330. if (!all(data_types %in% valid_types)) {
  2331. incorrect <- traits[!(data_types %in% valid_types)]
  2332. stop(paste0("Invalid data types for ", paste(incorrect, collapse = ", "),
  2333. ". Accepted data types are numeric, factor, integer."))
  2334. }
  2335. if (any(data_types == "factor")) {
  2336. factor_traits <- traits[data_types == "factor"]
  2337. for (tr in factor_traits) {
  2338. warning(paste0("Trait ", tr, " is a factor with levels ",
  2339. paste0(levels([email hidden][, tr]), collapse = ", "),
  2340. ". Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order?"))
  2341. }
  2342. }
  2343. modules <- hdWGCNA:::GetModules(seurat_obj, wgcna_name)
  2344. mods <- levels(modules$module)
  2345. mods <- mods[mods != "grey"]
  2346. trait_df <- [email hidden][, traits, drop = FALSE]
  2347. # Modified: Correctly detect single-trait case
  2348. if (length(traits) == 1) {
  2349. trait_df <- data.frame(x = trait_df)
  2350. colnames(trait_df) <- traits
  2351. }
  2352. if (any(data_types == "factor")) {
  2353. factor_traits <- traits[data_types == "factor"]
  2354. for (tr in factor_traits) {
  2355. trait_df[, tr] <- as.numeric(trait_df[, tr])
  2356. }
  2357. }
  2358. cor_list <- list()
  2359. pval_list <- list()
  2360. fdr_list <- list()
  2361. temp <- Hmisc::rcorr(as.matrix(trait_df), as.matrix(MEs), type = cor_method)
  2362. cur_cor <- temp$r[traits, mods, drop = FALSE]
  2363. cur_p <- temp$P[traits, mods, drop = FALSE]
  2364. p_df <- reshape2::melt(cur_p)
  2365. if (length(traits) == 1) {
  2366. tmp <- rep(mods, length(traits))
  2367. tmp <- factor(tmp, levels = mods)
  2368. tmp <- tmp[order(tmp)]
  2369. p_df$Var1 <- traits
  2370. p_df$Var2 <- tmp
  2371. rownames(p_df) <- 1:nrow(p_df)
  2372. p_df <- dplyr::select(p_df, c(Var1, Var2, value))
  2373. }
  2374. p_df <- p_df %>%
  2375. dplyr::mutate(fdr = p.adjust(value, method = "fdr")) %>%
  2376. dplyr::select(c(Var1, Var2, fdr))
  2377. cur_fdr <- reshape2::dcast(p_df, Var1 ~ Var2, value.var = "fdr")
  2378. rownames(cur_fdr) <- cur_fdr$Var1
  2379. cur_fdr <- cur_fdr[, -1, drop = FALSE]
  2380. cor_list[["all_cells"]] <- cur_cor
  2381. pval_list[["all_cells"]] <- cur_p
  2382. fdr_list[["all_cells"]] <- cur_fdr
  2383. trait_df <- cbind(trait_df, [email hidden][, group.by])
  2384. colnames(trait_df)[ncol(trait_df)] <- "group"
  2385. MEs <- cbind(as.data.frame(MEs), [email hidden][, group.by])
  2386. colnames(MEs)[ncol(MEs)] <- "group"
  2387. if (class([email hidden][, group.by]) == "factor") {
  2388. group_names <- levels([email hidden][, group.by])
  2389. } else {
  2390. group_names <- levels(as.factor([email hidden][, group.by]))
  2391. }
  2392. trait_list <- dplyr::group_split(trait_df, group, .keep = FALSE)
  2393. ME_list <- dplyr::group_split(MEs, group, .keep = FALSE)
  2394. names(trait_list) <- group_names
  2395. names(ME_list) <- group_names
  2396. for (i in names(trait_list)) {
  2397. temp <- Hmisc::rcorr(as.matrix(trait_list[[i]]), as.matrix(ME_list[[i]]))
  2398. cur_cor <- temp$r[traits, mods, drop = FALSE]
  2399. cur_p <- temp$P[traits, mods, drop = FALSE]
  2400. p_df <- reshape2::melt(cur_p)
  2401. if (length(traits) == 1) {
  2402. tmp <- rep(mods, length(traits))
  2403. tmp <- factor(tmp, levels = mods)
  2404. tmp <- tmp[order(tmp)]
  2405. p_df$Var1 <- traits
  2406. p_df$Var2 <- tmp
  2407. rownames(p_df) <- 1:nrow(p_df)
  2408. p_df <- dplyr::select(p_df, c(Var1, Var2, value))
  2409. }
  2410. p_df <- p_df %>%
  2411. dplyr::mutate(fdr = p.adjust(value, method = "fdr")) %>%
  2412. dplyr::select(c(Var1, Var2, fdr))
  2413. cur_fdr <- reshape2::dcast(p_df, Var1 ~ Var2, value.var = "fdr")
  2414. rownames(cur_fdr) <- cur_fdr$Var1
  2415. cur_fdr <- cur_fdr[, -1, drop = FALSE]
  2416. cor_list[[i]] <- cur_cor
  2417. pval_list[[i]] <- cur_p
  2418. fdr_list[[i]] <- as.matrix(cur_fdr)
  2419. }
  2420. mt_cor <- list(cor = cor_list, pval = pval_list, fdr = fdr_list)
  2421. if (!is.null(subset_by)) {
  2422. seurat_full <- hdWGCNA:::SetModuleTraitCorrelation(seurat_full, mt_cor, wgcna_name)
  2423. seurat_obj <- seurat_full
  2424. } else {
  2425. seurat_obj <- hdWGCNA:::SetModuleTraitCorrelation(seurat_obj, mt_cor, wgcna_name)
  2426. }
  2427. seurat_obj
  2428. }
  2429. # convert treatment to factor
  2430. Mcortex_QC_WGCNA$Tx <- as.factor(Mcortex_QC_WGCNA$Tx)
  2431. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Predicted_Sex is a factor with levels Female, Male, Unknown. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order? --> can't use it actually because only allows 2 variables. Need to subset the seurat object earlier on for just female and male, and then redo this.
  2432. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Tx is a factor with levels Control, Risperidone. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order?
  2433. # list of traits to correlate
  2434. cur_traits <- c('Tx')
  2435. Mcortex_QC_WGCNA <- ModuleTraitCorrelation_mod(
  2436. Mcortex_QC_WGCNA,
  2437. traits = cur_traits,
  2438. group.by='celltype1'
  2439. )
  2440. # get the mt-correlation results
  2441. mt_cor <- GetModuleTraitCorrelation(Mcortex_QC_WGCNA)
  2442. names(mt_cor)
  2443. names(mt_cor$cor)
  2444. head(mt_cor$cor$`GABAergic Pvalb`[,1:5])
  2445. # Create a new workbook
  2446. wb <- createWorkbook()
  2447. # Loop through each cell type / group
  2448. for (celltype in names(mt_cor$cor)) {
  2449. # Extract correlation, p-value, and FDR matrices
  2450. cor_mat <- mt_cor$cor[[celltype]]
  2451. pval_mat <- mt_cor$pval[[celltype]]
  2452. fdr_mat <- mt_cor$fdr[[celltype]]
  2453. # Convert to data.frames for writing
  2454. cor_df <- as.data.frame(cor_mat)
  2455. pval_df <- as.data.frame(pval_mat)
  2456. fdr_df <- as.data.frame(fdr_mat)
  2457. # Add worksheets
  2458. addWorksheet(wb, paste0(celltype, ""))
  2459. addWorksheet(wb, paste0(celltype, "_pval"))
  2460. addWorksheet(wb, paste0(celltype, "_fdr"))
  2461. # Write data to the workbook
  2462. writeData(wb, paste0(celltype, ""), cor_df, rowNames = TRUE)
  2463. writeData(wb, paste0(celltype, "_pval"), pval_df, rowNames = TRUE)
  2464. writeData(wb, paste0(celltype, "_fdr"), fdr_df, rowNames = TRUE)
  2465. }
  2466. # Save the workbook
  2467. output_path <- "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_moduletraitcor.xlsx"
  2468. saveWorkbook(wb, output_path, overwrite = TRUE)
  2469. # Plot heatmap for the correlation result
  2470. PlotModuleTraitCorrelation(
  2471. Mcortex_QC_WGCNA,
  2472. label = 'fdr',
  2473. label_symbol = 'stars',
  2474. text_size = 3,
  2475. text_digits = 2,
  2476. text_color = 'black',
  2477. high_color = '#db2763',
  2478. mid_color = 'white',
  2479. low_color = '#3772ff',
  2480. plot_max = 0.5,
  2481. combine=TRUE
  2482. )
  2483. ```
  2484. hdWGCNA continued - enrichment analysis- PV-IN
  2485. ```{r}
  2486. # define the enrichr databases to test
  2487. dbs <- c('GO_Biological_Process_2023','GO_Cellular_Component_2023','GO_Molecular_Function_2023')
  2488. # perform enrichment tests
  2489. Mcortex_QC_WGCNA <- RunEnrichr(
  2490. Mcortex_QC_WGCNA,
  2491. dbs=dbs,
  2492. max_genes = 100 # use max_genes = Inf to choose all genes
  2493. )
  2494. # retrieve the output table
  2495. enrich_df <- GetEnrichrTable(Mcortex_QC_WGCNA)
  2496. # look at the results
  2497. head(enrich_df)
  2498. # save to Excel
  2499. write_xlsx(enrich_df, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_enrichR_100.xlsx")
  2500. # make GO term bar plots - didn't re-run
  2501. EnrichrBarPlot(
  2502. Mcortex_QC_WGCNA,
  2503. outdir = "enrichr_plots", # name of output directory
  2504. n_terms = 10, # number of enriched terms to show (sometimes more are shown if there are ties)
  2505. plot_size = c(5,7), # width, height of the output .pdfs
  2506. logscale=TRUE # do you want to show the enrichment as a log scale?
  2507. )
  2508. # enrichr dotplot - did not re-run
  2509. EnrichrDotPlot(
  2510. Mcortex_QC_WGCNA,
  2511. mods = "all",
  2512. database = "GO_Molecular_Function_2023",
  2513. n_terms = 2,
  2514. term_size = 13,
  2515. p_adj = TRUE
  2516. ) +
  2517. scale_color_stepsn(colors = rev(viridis::magma(256))) +
  2518. theme(
  2519. axis.text.x = element_text(size = 13), # X-axis tick label size
  2520. )
  2521. # Define the order of modules you want (e.g., numeric order)
  2522. module_order <- c("PV-IN-M1", "PV-IN-M2", "PV-IN-M3", "PV-IN-M4", "PV-IN-M5", "PV-IN-M6", "PV-IN-M7", "PV-IN-M8", "PV-IN-M9")
  2523. # Filter enrichment table for your database
  2524. db_to_plot <- "GO_Molecular_Function_2023"
  2525. # Clean and organize enrichment table
  2526. enrich_df_clean <- enrich_df %>%
  2527. dplyr::filter(db == db_to_plot) %>%
  2528. group_by(module) %>%
  2529. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  2530. slice_head(n = 2) %>%
  2531. ungroup() %>%
  2532. mutate(
  2533. # Remove "(GO:xxxx)" suffix
  2534. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  2535. # Wrap long GO terms to two lines if needed
  2536. Term_clean = str_wrap(Term_clean, width = 50),
  2537. # Keep numeric ordering of modules
  2538. module = factor(module, levels = module_order),
  2539. # log10 transform Combined.Score for better scaling
  2540. log10_combined = log10(Combined.Score)
  2541. )
  2542. # Reorder terms so they're grouped by module, with best p-values at top
  2543. enrich_df_clean <- enrich_df_clean %>%
  2544. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  2545. # Plot
  2546. p <- ggplot(enrich_df_clean,
  2547. aes(x = module, y = Term_clean,
  2548. size = log10_combined)) +
  2549. # Main points: filled by -log10(FDR)
  2550. geom_point(
  2551. aes(fill = -log10(Adjusted.P.value),
  2552. shape = Adjusted.P.value <= 0.05),
  2553. color = "black", alpha = 0.9, stroke = 0.7
  2554. ) +
  2555. # Set shapes manually: filled circle for sig, hollow for ns
  2556. scale_shape_manual(
  2557. values = c("TRUE" = 21, "FALSE" = 1),
  2558. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  2559. name = "Significance"
  2560. ) +
  2561. scale_fill_stepsn(
  2562. colors = rev(viridis::magma(256)),
  2563. name = expression(-log[10]("FDR"))
  2564. ) +
  2565. scale_size_continuous(
  2566. name = expression(log[10]("Enrichment"))
  2567. ) +
  2568. theme_minimal(base_size = 13) +
  2569. theme(
  2570. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  2571. axis.text.y = element_text(size = 11),
  2572. legend.position = "right"
  2573. ) +
  2574. labs(
  2575. title = paste0("PV-IN - ", db_to_plot),
  2576. x = "Module",
  2577. y = "GO Term"
  2578. )
  2579. print(p)
  2580. ```
  2581. hdWGCNA continued - analysis of Sst-IN
  2582. ```{r}
  2583. # Set up the expression matrix for 3 cell types of interest
  2584. Mcortex_QC_WGCNA <- SetDatExpr(
  2585. Mcortex_QC_WGCNA,
  2586. group_name = "GABAergic Sst",
  2587. group.by = "celltype1",
  2588. assay = "SCT",
  2589. layer = "data"
  2590. )
  2591. # Select soft-power threshold
  2592. # Test different soft powers:
  2593. Mcortex_QC_WGCNA <- TestSoftPowers(
  2594. Mcortex_QC_WGCNA,
  2595. networkType = 'signed') # you can also use "unsigned" or "signed hybrid"
  2596. # plot the results:
  2597. plot_list <- PlotSoftPowers(Mcortex_QC_WGCNA)
  2598. # assemble with patchwork
  2599. wrap_plots(plot_list, ncol=2)
  2600. # Construct co-expression network
  2601. Mcortex_QC_WGCNA <- ConstructNetwork(
  2602. Mcortex_QC_WGCNA,
  2603. soft_power = 18,
  2604. tom_name = 'Sst-IN') # name of the topological overlap matrix written to disk
  2605. # Compute harmonized module eingengenes
  2606. # need to re-run ScaleData because sample_id metadata added after SCTransform:
  2607. Mcortex_QC_WGCNA <- ScaleData(Mcortex_QC_WGCNA, features=VariableFeatures(Mcortex_QC_WGCNA))
  2608. Mcortex_QC_WGCNA <- ModuleEigengenes(
  2609. Mcortex_QC_WGCNA,
  2610. group.by.vars="sample_id")
  2611. # Get module eigengenes (Harmonized by default)
  2612. hMEs <- GetMEs(Mcortex_QC_WGCNA)
  2613. # To get non-harmonized module eigengenes (not run)
  2614. MEs <- GetMEs(Mcortex_QC_WGCNA, harmonized=FALSE)
  2615. # Compute eigengene-based module connectivity (kME)
  2616. Mcortex_QC_WGCNA <- ModuleConnectivity(
  2617. Mcortex_QC_WGCNA,
  2618. group.by = 'celltype1', group_name = 'GABAergic Sst')
  2619. # Look inside the hdWGCNA network parameters to check softpower beta
  2620. Mcortex_QC_WGCNA@misc$hdWGCNA$wgcna_params
  2621. # rename the modules for convenience
  2622. Mcortex_QC_WGCNA <- ResetModuleNames(
  2623. Mcortex_QC_WGCNA,
  2624. new_name = "Sst-IN-M")
  2625. # Change color of modules
  2626. # get the module table
  2627. modules <- GetModules(Mcortex_QC_WGCNA)
  2628. mods <- unique(modules$module)
  2629. # make a table of the module-color pairings
  2630. mod_colors_df <- dplyr::select(modules, c(module, color)) %>%
  2631. distinct %>% arrange(module)
  2632. rownames(mod_colors_df) <- mod_colors_df$module
  2633. # print the dataframe
  2634. mod_colors_df
  2635. # load MetBrewer color scheme package
  2636. library(MetBrewer)
  2637. # get a table of just the module and it's unique color
  2638. mod_color_df <- GetModules(Mcortex_QC_WGCNA) %>%
  2639. dplyr::select(c(module, color)) %>%
  2640. distinct %>% arrange(module)
  2641. # the number of unique modules (subtract 1 because the grey module stays grey):
  2642. n_mods <- nrow(mod_color_df) - 1
  2643. # using the "Signac" palette from metbrewer, selecting for the number of modules
  2644. new_colors <- paste0(met.brewer("Signac", n=n_mods))
  2645. # reset the module colors
  2646. Mcortex_QC_WGCNA <- ResetModuleColors(Mcortex_QC_WGCNA, new_colors)
  2647. # Plot dendogram
  2648. PlotDendrogram(Mcortex_QC_WGCNA, main='hdWGCNA Dendrogram for Sst-IN')
  2649. # plot genes ranked by kME for each module
  2650. PlotKMEs(Mcortex_QC_WGCNA, ncol=3)
  2651. # get the module assignment table:
  2652. modules <- GetModules(Mcortex_QC_WGCNA) %>% subset(module != 'grey')
  2653. # show the first 6 columns:
  2654. head(modules[,1:6])
  2655. # save to Excel
  2656. write_xlsx(modules, "~/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_module_assignments.xlsx")
  2657. # get hub genes
  2658. hub_df <- GetHubGenes(Mcortex_QC_WGCNA, n_hubs = 100)
  2659. head(hub_df)
  2660. # save to Excel
  2661. write_xlsx(hub_df, "~/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_top100_hubgenes.xlsx")
  2662. ```
  2663. Visualization of hdWGCNA results - Sst-IN
  2664. ```{r}
  2665. # make a featureplot of hMEs for each module
  2666. plot_list <- ModuleFeaturePlot(
  2667. Mcortex_QC_WGCNA,
  2668. features='hMEs', # plot the hMEs
  2669. order=TRUE # order so the points with highest hMEs are on top
  2670. )
  2671. # stitch the plot together with patchwork
  2672. wrap_plots(plot_list, ncol=4)
  2673. # plot module correlagram
  2674. ModuleCorrelogram(Mcortex_QC_WGCNA)
  2675. # Dot plot of hME's
  2676. # Get hME's and module tables again
  2677. MEs <- GetMEs(Mcortex_QC_WGCNA, harmonized=TRUE)
  2678. modules <- GetModules(Mcortex_QC_WGCNA)
  2679. mods <- levels(modules$module); mods <- mods[mods != 'grey']
  2680. # add hMEs to Seurat meta-data:
  2681. [email hidden] <- cbind([email hidden], MEs)
  2682. # plot with Seurat's DotPlot function
  2683. p <- DotPlot(Mcortex_QC_WGCNA, features=mods, group.by = 'celltype1')
  2684. # flip the x/y axes, rotate the axis labels, and change color scheme:
  2685. p <- p +
  2686. RotatedAxis() +
  2687. scale_color_gradient2(high='red', mid='grey95', low='blue')
  2688. # plot output
  2689. p
  2690. # Individual module network plot
  2691. ModuleNetworkPlot(
  2692. Mcortex_QC_WGCNA,
  2693. outdir='ModuleNetworks_Sst-IN', # new folder name
  2694. n_inner = 10, # number of genes in inner ring
  2695. n_outer = 15, # number of genes in outer ring
  2696. n_conns = Inf, # show all of the connections
  2697. plot_size=c(5,5), # larger plotting area
  2698. vertex.label.cex=1 # font size
  2699. )
  2700. # UMAP with network
  2701. # Increased allowed globals size
  2702. options(future.globals.maxSize = 20 * 1024^3) # allow up to 20 GB
  2703. # Run Module UMAP
  2704. Mcortex_QC_WGCNA <- RunModuleUMAP(
  2705. Mcortex_QC_WGCNA,
  2706. n_hubs = 5, # number of hub genes to include for the UMAP embedding
  2707. n_neighbors=10, # neighbors parameter for UMAP
  2708. min_dist=0.3 # min distance between points in UMAP space
  2709. )
  2710. # Plot UMAP of genes and their co-expression relationship
  2711. ModuleUMAPPlot(
  2712. Mcortex_QC_WGCNA,
  2713. edge.alpha=0.15,
  2714. sample_edges=TRUE, # If true, downsampling edges
  2715. edge_prop=0.1, # proportion of edges to sample (10% here)
  2716. label_hubs=1, # how many hub genes to plot per module?
  2717. vertex.label.cex = 0.5,
  2718. )
  2719. # hubgene network
  2720. HubGeneNetworkPlot(
  2721. Mcortex_QC_WGCNA,
  2722. n_hubs = 3, n_other=5,
  2723. edge_prop = 1,
  2724. mods = 'all',
  2725. vertex.label.cex = 0.75,
  2726. hub.vertex.size = 4,
  2727. other.vertex.size = 1
  2728. )
  2729. ```
  2730. Correlation of hdGCNA results with treatment variables - Sst-IN
  2731. ```{r}
  2732. # convert treatment to factor
  2733. Mcortex_QC_WGCNA$Tx <- as.factor(Mcortex_QC_WGCNA$Tx)
  2734. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Predicted_Sex is a factor with levels Female, Male, Unknown. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order? --> can't use it actually because only allows 2 variables. Need to subset the seurat object earlier on for just female and male, and then redo this.
  2735. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Tx is a factor with levels Control, Risperidone. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order?
  2736. # list of traits to correlate
  2737. cur_traits <- c('Tx')
  2738. Mcortex_QC_WGCNA <- ModuleTraitCorrelation_mod(
  2739. Mcortex_QC_WGCNA,
  2740. traits = cur_traits,
  2741. group.by='celltype1'
  2742. )
  2743. # get the mt-correlation results
  2744. mt_cor <- GetModuleTraitCorrelation(Mcortex_QC_WGCNA)
  2745. names(mt_cor)
  2746. names(mt_cor$cor)
  2747. head(mt_cor$cor$`GABAergic Sst`[,1:5])
  2748. # Create a new workbook
  2749. wb <- createWorkbook()
  2750. # Loop through each cell type / group
  2751. for (celltype in names(mt_cor$cor)) {
  2752. # Extract correlation, p-value, and FDR matrices
  2753. cor_mat <- mt_cor$cor[[celltype]]
  2754. pval_mat <- mt_cor$pval[[celltype]]
  2755. fdr_mat <- mt_cor$fdr[[celltype]]
  2756. # Convert to data.frames for writing
  2757. cor_df <- as.data.frame(cor_mat)
  2758. pval_df <- as.data.frame(pval_mat)
  2759. fdr_df <- as.data.frame(fdr_mat)
  2760. # Add worksheets
  2761. addWorksheet(wb, paste0(celltype, ""))
  2762. addWorksheet(wb, paste0(celltype, "_pval"))
  2763. addWorksheet(wb, paste0(celltype, "_fdr"))
  2764. # Write data to the workbook
  2765. writeData(wb, paste0(celltype, ""), cor_df, rowNames = TRUE)
  2766. writeData(wb, paste0(celltype, "_pval"), pval_df, rowNames = TRUE)
  2767. writeData(wb, paste0(celltype, "_fdr"), fdr_df, rowNames = TRUE)
  2768. }
  2769. # Save the workbook
  2770. output_path <- "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_moduletraitcor.xlsx"
  2771. saveWorkbook(wb, output_path, overwrite = TRUE)
  2772. # Plot heatmap for the correlation result
  2773. PlotModuleTraitCorrelation(
  2774. Mcortex_QC_WGCNA,
  2775. label = 'fdr',
  2776. label_symbol = 'stars',
  2777. text_size = 3,
  2778. text_digits = 2,
  2779. text_color = 'black',
  2780. high_color = '#db2763',
  2781. mid_color = 'white',
  2782. low_color = '#3772ff',
  2783. plot_max = 0.5,
  2784. combine=TRUE
  2785. )
  2786. ```
  2787. hdWGCNA continued - enrichment analysis- Sst-IN
  2788. ```{r}
  2789. # define the enrichr databases to test
  2790. dbs <- c('GO_Biological_Process_2023','GO_Cellular_Component_2023','GO_Molecular_Function_2023')
  2791. # perform enrichment tests
  2792. Mcortex_QC_WGCNA <- RunEnrichr(
  2793. Mcortex_QC_WGCNA,
  2794. dbs=dbs,
  2795. max_genes = 100 # use max_genes = Inf to choose all genes
  2796. )
  2797. # retrieve the output table
  2798. enrich_df <- GetEnrichrTable(Mcortex_QC_WGCNA)
  2799. # look at the results
  2800. head(enrich_df)
  2801. # save to Excel
  2802. write_xlsx(enrich_df, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_enrichR_100.xlsx")
  2803. # make GO term barplot - did not rerun
  2804. EnrichrBarPlot(
  2805. Mcortex_QC_WGCNA,
  2806. outdir = "enrichr_plots", # name of output directory
  2807. n_terms = 10, # number of enriched terms to show (sometimes more are shown if there are ties)
  2808. plot_size = c(5,7), # width, height of the output .pdfs
  2809. logscale=TRUE # do you want to show the enrichment as a log scale?
  2810. )
  2811. # enrichr dotplot - did not rerun
  2812. EnrichrDotPlot(
  2813. Mcortex_QC_WGCNA,
  2814. mods = "all",
  2815. database = "GO_Molecular_Function_2023",
  2816. n_terms = 2,
  2817. term_size = 13,
  2818. p_adj = TRUE
  2819. ) +
  2820. scale_color_stepsn(colors = rev(viridis::magma(256))) +
  2821. theme(
  2822. axis.text.x = element_text(size = 12), # X-axis tick label size
  2823. )
  2824. # Define the order of modules you want (e.g., numeric order)
  2825. module_order <- c("Sst-IN-M1", "Sst-IN-M2", "Sst-IN-M3", "Sst-IN-M4", "Sst-IN-M5",
  2826. "Sst-IN-M6", "Sst-IN-M7", "Sst-IN-M8", "Sst-IN-M9", "Sst-IN-M10", "Sst-IN-M11")
  2827. # Filter enrichment table for your database
  2828. db_to_plot <- "GO_Molecular_Function_2023"
  2829. # Clean and organize enrichment table
  2830. enrich_df_clean <- enrich_df %>%
  2831. dplyr::filter(db == db_to_plot) %>%
  2832. group_by(module) %>%
  2833. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  2834. slice_head(n = 2) %>%
  2835. ungroup() %>%
  2836. mutate(
  2837. # Remove "(GO:xxxx)" suffix
  2838. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  2839. # Wrap long GO terms to two lines if needed
  2840. Term_clean = str_wrap(Term_clean, width = 55),
  2841. # Keep numeric ordering of modules
  2842. module = factor(module, levels = module_order),
  2843. # log10 transform Combined.Score for better scaling
  2844. log10_combined = log10(Combined.Score)
  2845. )
  2846. # Reorder terms so they're grouped by module, with best p-values at top
  2847. enrich_df_clean <- enrich_df_clean %>%
  2848. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  2849. # Plot
  2850. p <- ggplot(enrich_df_clean,
  2851. aes(x = module, y = Term_clean,
  2852. size = log10_combined)) +
  2853. # Main points: filled by -log10(FDR)
  2854. geom_point(
  2855. aes(fill = -log10(Adjusted.P.value),
  2856. shape = Adjusted.P.value <= 0.05),
  2857. color = "black", alpha = 0.9, stroke = 0.7
  2858. ) +
  2859. # Set shapes manually: filled circle for sig, hollow for ns
  2860. scale_shape_manual(
  2861. values = c("TRUE" = 21, "FALSE" = 1),
  2862. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  2863. name = "Significance"
  2864. ) +
  2865. scale_fill_stepsn(
  2866. colors = rev(viridis::magma(256)),
  2867. name = expression(-log[10]("FDR"))
  2868. ) +
  2869. scale_size_continuous(
  2870. name = expression(log[10]("Enrichment"))
  2871. ) +
  2872. theme_minimal(base_size = 13) +
  2873. theme(
  2874. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  2875. axis.text.y = element_text(size = 11),
  2876. legend.position = "right"
  2877. ) +
  2878. labs(
  2879. title = paste0("Sst-IN - ", db_to_plot),
  2880. x = "Module",
  2881. y = "GO Term"
  2882. )
  2883. print(p)
  2884. ```
  2885. hdWGCNA continued - analysis of Glut
  2886. ```{r}
  2887. # Set up the expression matrix for 3 cell types of interest
  2888. Mcortex_QC_WGCNA <- SetDatExpr(
  2889. Mcortex_QC_WGCNA,
  2890. group_name = "Glutamatergic neurons",
  2891. group.by = "celltype1",
  2892. assay = "SCT",
  2893. layer = "data"
  2894. )
  2895. # Select soft-power threshold
  2896. # Test different soft powers:
  2897. Mcortex_QC_WGCNA <- TestSoftPowers(
  2898. Mcortex_QC_WGCNA,
  2899. networkType = 'signed') # you can also use "unsigned" or "signed hybrid"
  2900. # plot the results:
  2901. plot_list <- PlotSoftPowers(Mcortex_QC_WGCNA)
  2902. # assemble with patchwork
  2903. wrap_plots(plot_list, ncol=2)
  2904. # Construct co-expression network
  2905. Mcortex_QC_WGCNA <- ConstructNetwork(
  2906. Mcortex_QC_WGCNA,
  2907. tom_name = 'Glut') # name of the topological overlap matrix written to disk
  2908. # Compute harmonized module eingengenes
  2909. # need to re-run ScaleData because sample_id metadata added after SCTransform:
  2910. Mcortex_QC_WGCNA <- ScaleData(Mcortex_QC_WGCNA, features=VariableFeatures(Mcortex_QC_WGCNA))
  2911. Mcortex_QC_WGCNA <- ModuleEigengenes(
  2912. Mcortex_QC_WGCNA,
  2913. group.by.vars="sample_id")
  2914. # Get module eigengenes (Harmonized by default)
  2915. hMEs <- GetMEs(Mcortex_QC_WGCNA)
  2916. # To get non-harmonized module eigengenes (not run)
  2917. MEs <- GetMEs(Mcortex_QC_WGCNA, harmonized=FALSE)
  2918. # Compute eigengene-based module connectivity (kME)
  2919. Mcortex_QC_WGCNA <- ModuleConnectivity(
  2920. Mcortex_QC_WGCNA,
  2921. group.by = 'celltype1', group_name = 'Glutamatergic neurons')
  2922. # Look inside the hdWGCNA network parameters to check softpower beta
  2923. Mcortex_QC_WGCNA@misc$hdWGCNA$wgcna_params
  2924. # rename the modules for convenience
  2925. Mcortex_QC_WGCNA <- ResetModuleNames(
  2926. Mcortex_QC_WGCNA,
  2927. new_name = "Glut-M")
  2928. # Change color of modules
  2929. # get the module table
  2930. modules <- GetModules(Mcortex_QC_WGCNA)
  2931. mods <- unique(modules$module)
  2932. # make a table of the module-color pairings
  2933. mod_colors_df <- dplyr::select(modules, c(module, color)) %>%
  2934. distinct %>% arrange(module)
  2935. rownames(mod_colors_df) <- mod_colors_df$module
  2936. # print the dataframe
  2937. mod_colors_df
  2938. # load MetBrewer color scheme package
  2939. library(MetBrewer)
  2940. # get a table of just the module and it's unique color
  2941. mod_color_df <- GetModules(Mcortex_QC_WGCNA) %>%
  2942. dplyr::select(c(module, color)) %>%
  2943. distinct %>% arrange(module)
  2944. # the number of unique modules (subtract 1 because the grey module stays grey):
  2945. n_mods <- nrow(mod_color_df) - 1
  2946. # using the "Signac" palette from metbrewer, selecting for the number of modules
  2947. new_colors <- paste0(met.brewer("Signac", n=n_mods))
  2948. # reset the module colors
  2949. Mcortex_QC_WGCNA <- ResetModuleColors(Mcortex_QC_WGCNA, new_colors)
  2950. # Plot dendogram
  2951. PlotDendrogram(Mcortex_QC_WGCNA, main='hdWGCNA Dendrogram for Glutamatergic neurons')
  2952. # plot genes ranked by kME for each module
  2953. PlotKMEs(Mcortex_QC_WGCNA, ncol=3)
  2954. # get the module assignment table:
  2955. modules <- GetModules(Mcortex_QC_WGCNA) %>% subset(module != 'grey')
  2956. # show the first 6 columns:
  2957. head(modules[,1:6])
  2958. # save to Excel
  2959. write_xlsx(modules, "~/Risperidone_Proj/R_analysis/hdWGCNA/Glut_module_assignments.xlsx")
  2960. # get hub genes
  2961. hub_df <- GetHubGenes(Mcortex_QC_WGCNA, n_hubs = 100)
  2962. head(hub_df)
  2963. # save to Excel
  2964. write_xlsx(hub_df, "~/Risperidone_Proj/R_analysis/hdWGCNA/Glut_top100_hubgenes.xlsx")
  2965. ```
  2966. Visualization of hdWGCNA results - Glut
  2967. ```{r}
  2968. # make a featureplot of hMEs for each module
  2969. plot_list <- ModuleFeaturePlot(
  2970. Mcortex_QC_WGCNA,
  2971. features='hMEs', # plot the hMEs
  2972. order=TRUE # order so the points with highest hMEs are on top
  2973. )
  2974. # stitch the plot together with patchwork
  2975. wrap_plots(plot_list, ncol=3)
  2976. # plot module correlagram
  2977. ModuleCorrelogram(Mcortex_QC_WGCNA)
  2978. # Dot plot of hME's
  2979. # Get hME's and module tables again
  2980. MEs <- GetMEs(Mcortex_QC_WGCNA, harmonized=TRUE)
  2981. modules <- GetModules(Mcortex_QC_WGCNA)
  2982. mods <- levels(modules$module); mods <- mods[mods != 'grey']
  2983. # add hMEs to Seurat meta-data:
  2984. [email hidden] <- cbind([email hidden], MEs)
  2985. # plot with Seurat's DotPlot function
  2986. p <- DotPlot(Mcortex_QC_WGCNA, features=mods, group.by = 'celltype1')
  2987. # flip the x/y axes, rotate the axis labels, and change color scheme:
  2988. p <- p +
  2989. RotatedAxis() +
  2990. scale_color_gradient2(high='red', mid='grey95', low='blue')
  2991. # plot output
  2992. p
  2993. # Individual module network plot
  2994. ModuleNetworkPlot(
  2995. Mcortex_QC_WGCNA,
  2996. outdir='ModuleNetworks_Glut', # new folder name
  2997. n_inner = 10, # number of genes in inner ring
  2998. n_outer = 15, # number of genes in outer ring
  2999. n_conns = Inf, # show all of the connections
  3000. plot_size=c(5,5), # larger plotting area
  3001. vertex.label.cex=1 # font size
  3002. )
  3003. # UMAP with network
  3004. # Increased allowed globals size
  3005. options(future.globals.maxSize = 20 * 1024^3) # allow up to 20 GB
  3006. # Run Module UMAP
  3007. Mcortex_QC_WGCNA <- RunModuleUMAP(
  3008. Mcortex_QC_WGCNA,
  3009. n_hubs = 5, # number of hub genes to include for the UMAP embedding
  3010. n_neighbors=10, # neighbors parameter for UMAP
  3011. min_dist=0.3 # min distance between points in UMAP space
  3012. )
  3013. # Plot UMAP of genes and their co-expression relationship
  3014. ModuleUMAPPlot(
  3015. Mcortex_QC_WGCNA,
  3016. edge.alpha=0.15,
  3017. sample_edges=TRUE, # If true, downsampling edges
  3018. edge_prop=0.1, # proportion of edges to sample (10% here)
  3019. label_hubs=1, # how many hub genes to plot per module?
  3020. vertex.label.cex = 0.5,
  3021. )
  3022. # hubgene network
  3023. HubGeneNetworkPlot(
  3024. Mcortex_QC_WGCNA,
  3025. n_hubs = 3, n_other=5,
  3026. edge_prop = 1,
  3027. mods = 'all',
  3028. vertex.label.cex = 0.75,
  3029. hub.vertex.size = 4,
  3030. other.vertex.size = 1
  3031. )
  3032. ```
  3033. Correlation of hdGCNA results with treatment variables - Glut
  3034. ```{r}
  3035. # convert treatment to factor
  3036. Mcortex_QC_WGCNA$Tx <- as.factor(Mcortex_QC_WGCNA$Tx)
  3037. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Predicted_Sex is a factor with levels Female, Male, Unknown. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order? --> can't use it actually because only allows 2 variables. Need to subset the seurat object earlier on for just female and male, and then redo this.
  3038. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Tx is a factor with levels Control, Risperidone. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order?
  3039. # list of traits to correlate
  3040. cur_traits <- c('Tx')
  3041. Mcortex_QC_WGCNA <- ModuleTraitCorrelation_mod(
  3042. Mcortex_QC_WGCNA,
  3043. traits = cur_traits,
  3044. group.by='celltype1'
  3045. )
  3046. # get the mt-correlation results
  3047. mt_cor <- GetModuleTraitCorrelation(Mcortex_QC_WGCNA)
  3048. names(mt_cor)
  3049. names(mt_cor$cor)
  3050. head(mt_cor$cor$`Glutamatergic neurons`[,1:5])
  3051. # Create a new workbook
  3052. wb <- createWorkbook()
  3053. # Loop through each cell type / group
  3054. for (celltype in names(mt_cor$cor)) {
  3055. # Extract correlation, p-value, and FDR matrices
  3056. cor_mat <- mt_cor$cor[[celltype]]
  3057. pval_mat <- mt_cor$pval[[celltype]]
  3058. fdr_mat <- mt_cor$fdr[[celltype]]
  3059. # Convert to data.frames for writing
  3060. cor_df <- as.data.frame(cor_mat)
  3061. pval_df <- as.data.frame(pval_mat)
  3062. fdr_df <- as.data.frame(fdr_mat)
  3063. # Add worksheets
  3064. addWorksheet(wb, paste0(celltype, ""))
  3065. addWorksheet(wb, paste0(celltype, "_pval"))
  3066. addWorksheet(wb, paste0(celltype, "_fdr"))
  3067. # Write data to the workbook
  3068. writeData(wb, paste0(celltype, ""), cor_df, rowNames = TRUE)
  3069. writeData(wb, paste0(celltype, "_pval"), pval_df, rowNames = TRUE)
  3070. writeData(wb, paste0(celltype, "_fdr"), fdr_df, rowNames = TRUE)
  3071. }
  3072. # Save the workbook
  3073. output_path <- "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_moduletraitcor.xlsx"
  3074. saveWorkbook(wb, output_path, overwrite = TRUE)
  3075. # Plot heatmap for the correlation result
  3076. PlotModuleTraitCorrelation(
  3077. Mcortex_QC_WGCNA,
  3078. label = 'fdr',
  3079. label_symbol = 'stars',
  3080. text_size = 3,
  3081. text_digits = 2,
  3082. text_color = 'black',
  3083. high_color = '#db2763',
  3084. mid_color = 'white',
  3085. low_color = '#3772ff',
  3086. plot_max = 0.5,
  3087. combine=TRUE
  3088. )
  3089. ```
  3090. hdWGCNA continued - enrichment analysis- Glut
  3091. ```{r}
  3092. # define the enrichr databases to test
  3093. dbs <- c('GO_Biological_Process_2023','GO_Cellular_Component_2023','GO_Molecular_Function_2023')
  3094. # perform enrichment tests
  3095. Mcortex_QC_WGCNA <- RunEnrichr(
  3096. Mcortex_QC_WGCNA,
  3097. dbs=dbs,
  3098. max_genes = 100 # use max_genes = Inf to choose all genes
  3099. )
  3100. # retrieve the output table
  3101. enrich_df <- GetEnrichrTable(Mcortex_QC_WGCNA)
  3102. # look at the results
  3103. head(enrich_df)
  3104. # save to Excel
  3105. write_xlsx(enrich_df, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_enrichR_100.xlsx")
  3106. # make GO term bar plots - didn't re-run
  3107. EnrichrBarPlot(
  3108. Mcortex_QC_WGCNA,
  3109. outdir = "enrichr_plots", # name of output directory
  3110. n_terms = 10, # number of enriched terms to show (sometimes more are shown if there are ties)
  3111. plot_size = c(5,7), # width, height of the output .pdfs
  3112. logscale=TRUE # do you want to show the enrichment as a log scale?
  3113. )
  3114. # enrichr dotplot - did not re-run
  3115. EnrichrDotPlot(
  3116. Mcortex_QC_WGCNA,
  3117. mods = "all",
  3118. database = "GO_Molecular_Function_2023",
  3119. n_terms = 2,
  3120. term_size = 13,
  3121. p_adj = TRUE
  3122. ) +
  3123. scale_color_stepsn(colors = rev(viridis::magma(256))) +
  3124. theme(
  3125. axis.text.x = element_text(size = 13), # X-axis tick label size
  3126. )
  3127. # Define the order of modules you want (e.g., numeric order)
  3128. module_order <- c("Glut-M1", "Glut-M2", "Glut-M3", "Glut-M4", "Glut-M5")
  3129. # Filter enrichment table for your database
  3130. db_to_plot <- "GO_Molecular_Function_2023"
  3131. # Clean and organize enrichment table
  3132. enrich_df_clean <- enrich_df %>%
  3133. dplyr::filter(db == db_to_plot) %>%
  3134. group_by(module) %>%
  3135. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  3136. slice_head(n = 2) %>%
  3137. ungroup() %>%
  3138. mutate(
  3139. # Remove "(GO:xxxx)" suffix
  3140. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  3141. # Wrap long GO terms to two lines if needed
  3142. Term_clean = str_wrap(Term_clean, width = 50),
  3143. # Keep numeric ordering of modules
  3144. module = factor(module, levels = module_order),
  3145. # log10 transform Combined.Score for better scaling
  3146. log10_combined = log10(Combined.Score)
  3147. )
  3148. # Reorder terms so they're grouped by module, with best p-values at top
  3149. enrich_df_clean <- enrich_df_clean %>%
  3150. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  3151. # Plot
  3152. p <- ggplot(enrich_df_clean,
  3153. aes(x = module, y = Term_clean,
  3154. size = log10_combined)) +
  3155. # Main points: filled by -log10(FDR)
  3156. geom_point(
  3157. aes(fill = -log10(Adjusted.P.value),
  3158. shape = Adjusted.P.value <= 0.05),
  3159. color = "black", alpha = 0.9, stroke = 0.7
  3160. ) +
  3161. # Set shapes manually: filled circle for sig, hollow for ns
  3162. scale_shape_manual(
  3163. values = c("TRUE" = 21, "FALSE" = 1),
  3164. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  3165. name = "Significance"
  3166. ) +
  3167. scale_fill_stepsn(
  3168. colors = rev(viridis::magma(256)),
  3169. name = expression(-log[10]("FDR"))
  3170. ) +
  3171. scale_size_continuous(
  3172. name = expression(log[10]("Enrichment"))
  3173. ) +
  3174. theme_minimal(base_size = 13) +
  3175. theme(
  3176. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  3177. axis.text.y = element_text(size = 11),
  3178. legend.position = "right"
  3179. ) +
  3180. labs(
  3181. title = paste0("Glut - ", db_to_plot),
  3182. x = "Module",
  3183. y = "GO Term"
  3184. )
  3185. print(p)
  3186. ```
  3187. hdWGCNA - sex specific
  3188. Set-up
  3189. ```{r}
  3190. # Subset Seurat object into male and female separately
  3191. Mcortex_QC_F <- subset(Mcortex_QC, Predicted_Sex %in% "Female")
  3192. Mcortex_QC_M <- subset(Mcortex_QC, Predicted_Sex %in% "Male")
  3193. # Filter out all genes with count sum less than 10
  3194. Mcortex_QC_F <- subset(Mcortex_QC_F, features = rownames(Mcortex_QC_F)[Matrix::rowSums(GetAssayData(Mcortex_QC_F, assay = "RNA", layer = "counts")) >= 10])
  3195. Mcortex_QC_M <- subset(Mcortex_QC_M, features = rownames(Mcortex_QC_M)[Matrix::rowSums(GetAssayData(Mcortex_QC_M, assay = "RNA", layer = "counts")) >= 10])
  3196. # using the cowplot theme for ggplot
  3197. theme_set(theme_cowplot())
  3198. # set random seed for reproducibility
  3199. set.seed(12345)
  3200. # optionally enable multithreading - allowing parallel execution with up to 8 working processes.
  3201. enableWGCNAThreads(nThreads = 32)
  3202. # Set up Seurat object for WGCNA - do not subset this seurat object after this has been run.
  3203. Mcortex_QC_F_WGCNA <- SetupForWGCNA(
  3204. Mcortex_QC_F,
  3205. gene_select = "fraction", # the gene selection approach, can also select variable or custom
  3206. fraction = 0.05, # genes expressed in 5% of cells. Fraction of cells that a gene needs to be expressed in order to be included
  3207. wgcna_name = "hdWGCNA_F" # the name of the hdWGCNA experiment
  3208. )
  3209. Mcortex_QC_M_WGCNA <- SetupForWGCNA(
  3210. Mcortex_QC_M,
  3211. gene_select = "fraction", # the gene selection approach, can also select variable or custom
  3212. fraction = 0.05, # genes expressed in 5% of cells. Fraction of cells that a gene needs to be expressed in order to be included
  3213. wgcna_name = "hdWGCNA_M" # the name of the hdWGCNA experiment
  3214. )
  3215. # Extract sample_id from barcode names for the Seurat object
  3216. Mcortex_QC_F_WGCNA$sample_id <- sapply(strsplit(Cells(Mcortex_QC_F_WGCNA), "_"), `[`, 1)
  3217. Mcortex_QC_M_WGCNA$sample_id <- sapply(strsplit(Cells(Mcortex_QC_M_WGCNA), "_"), `[`, 1)
  3218. # construct metacells in each group
  3219. Mcortex_QC_F_WGCNA <- MetacellsByGroups(
  3220. seurat_obj = Mcortex_QC_F_WGCNA,
  3221. group.by = c("celltype1", "sample_id"), # specify the columns in [email hidden] to group by
  3222. reduction = 'pca', # select the dimensionality reduction to perform KNN on
  3223. k = 20, # nearest-neighbors parameter (adjust based on cell number)
  3224. max_shared = 10, # maximum number of shared cells between two metacells
  3225. ident.group = 'celltype1') # set the Idents of the metacell seurat object
  3226. Mcortex_QC_M_WGCNA <- MetacellsByGroups(
  3227. seurat_obj = Mcortex_QC_M_WGCNA,
  3228. group.by = c("celltype1", "sample_id"), # specify the columns in [email hidden] to group by
  3229. reduction = 'pca', # select the dimensionality reduction to perform KNN on
  3230. k = 20, # nearest-neighbors parameter (adjust based on cell number)
  3231. max_shared = 10, # maximum number of shared cells between two metacells
  3232. ident.group = 'celltype1') # set the Idents of the metacell seurat object
  3233. # normalize metacell expression matrix:
  3234. Mcortex_QC_F_WGCNA <- NormalizeMetacells(Mcortex_QC_F_WGCNA)
  3235. Mcortex_QC_M_WGCNA <- NormalizeMetacells(Mcortex_QC_M_WGCNA)
  3236. # View what layers exist in the WGCNA Seurat object, and check which default assay.
  3237. DefaultAssay(Mcortex_QC_M_WGCNA)
  3238. DefaultAssay(Mcortex_QC_F_WGCNA) <- "SCT"
  3239. Layers(Mcortex_QC_M_WGCNA[["SCT"]])
  3240. saveRDS(Mcortex_QC_F_WGCNA, file='~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/RDS_files/Mcortex_QC_F_WGCNA.rds')
  3241. saveRDS(Mcortex_QC_M_WGCNA, file='~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/RDS_files/Mcortex_QC_M_WGCNA.rds')
  3242. Mcortex_QC_F_WGCNA <- readRDS("~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/RDS_files/Mcortex_QC_F_WGCNA.rds")
  3243. Mcortex_QC_M_WGCNA <- readRDS("~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/RDS_files/Mcortex_QC_M_WGCNA.rds")
  3244. ```
  3245. hdWGCNA analysis of Glut - sex specific
  3246. ```{r}
  3247. # Set up the expression matrix for 3 cell types of interest
  3248. Mcortex_QC_F_WGCNA <- SetDatExpr(
  3249. Mcortex_QC_F_WGCNA,
  3250. group_name = "Glutamatergic neurons",
  3251. group.by = "celltype1",
  3252. assay = "SCT",
  3253. layer = "data")
  3254. Mcortex_QC_M_WGCNA <- SetDatExpr(
  3255. Mcortex_QC_M_WGCNA,
  3256. group_name = "Glutamatergic neurons",
  3257. group.by = "celltype1",
  3258. assay = "SCT",
  3259. layer = "data")
  3260. # Select soft-power threshold
  3261. # Test different soft powers:
  3262. Mcortex_QC_F_WGCNA <- TestSoftPowers(
  3263. Mcortex_QC_F_WGCNA,
  3264. networkType = 'signed') # you can also use "unsigned" or "signed hybrid"
  3265. Mcortex_QC_M_WGCNA <- TestSoftPowers(
  3266. Mcortex_QC_M_WGCNA,
  3267. networkType = 'signed') # you can also use "unsigned" or "signed hybrid"
  3268. # plot the results:
  3269. plot_list_F <- PlotSoftPowers(Mcortex_QC_F_WGCNA)
  3270. plot_list_M <- PlotSoftPowers(Mcortex_QC_M_WGCNA)
  3271. # assemble with patchwork
  3272. wrap_plots(plot_list_F, ncol=2)
  3273. wrap_plots(plot_list_M, ncol=2)
  3274. # Construct co-expression network
  3275. Mcortex_QC_F_WGCNA <- ConstructNetwork(
  3276. Mcortex_QC_F_WGCNA,
  3277. tom_name = 'Glut_F') # name of the topological overlap matrix written to disk
  3278. Mcortex_QC_M_WGCNA <- ConstructNetwork(
  3279. Mcortex_QC_M_WGCNA,
  3280. tom_name = 'Glut_M')
  3281. # Compute harmonized module eingengenes
  3282. # need to re-run ScaleData because sample_id metadata added after SCTransform:
  3283. Mcortex_QC_F_WGCNA <- ScaleData(Mcortex_QC_F_WGCNA, features=VariableFeatures(Mcortex_QC_F_WGCNA))
  3284. Mcortex_QC_M_WGCNA <- ScaleData(Mcortex_QC_M_WGCNA, features=VariableFeatures(Mcortex_QC_M_WGCNA))
  3285. Mcortex_QC_F_WGCNA <- ModuleEigengenes(
  3286. Mcortex_QC_F_WGCNA,
  3287. group.by.vars="sample_id")
  3288. Mcortex_QC_M_WGCNA <- ModuleEigengenes(
  3289. Mcortex_QC_M_WGCNA,
  3290. group.by.vars="sample_id")
  3291. # Get module eigengenes (Harmonized by default)
  3292. hMEs <- GetMEs(Mcortex_QC_F_WGCNA)
  3293. hMEs <- GetMEs(Mcortex_QC_M_WGCNA)
  3294. # Compute eigengene-based module connectivity (kME)
  3295. Mcortex_QC_F_WGCNA <- ModuleConnectivity(
  3296. Mcortex_QC_F_WGCNA,
  3297. group.by = 'celltype1', group_name = 'Glutamatergic neurons')
  3298. Mcortex_QC_M_WGCNA <- ModuleConnectivity(
  3299. Mcortex_QC_M_WGCNA,
  3300. group.by = 'celltype1', group_name = 'Glutamatergic neurons')
  3301. # Look inside the hdWGCNA network parameters to check softpower beta
  3302. Mcortex_QC_F_WGCNA@misc$hdWGCNA$wgcna_params
  3303. Mcortex_QC_M_WGCNA@misc$hdWGCNA$wgcna_params
  3304. # rename the modules for convenience
  3305. Mcortex_QC_F_WGCNA <- ResetModuleNames(
  3306. Mcortex_QC_F_WGCNA,
  3307. new_name = "F_Glut-M")
  3308. Mcortex_QC_M_WGCNA <- ResetModuleNames(
  3309. Mcortex_QC_M_WGCNA,
  3310. new_name = "M_Glut-M")
  3311. # Change color of modules - Female
  3312. library(MetBrewer)
  3313. modules <- GetModules(Mcortex_QC_F_WGCNA)
  3314. mods <- unique(modules$module)
  3315. mod_colors_df <- dplyr::select(modules, c(module, color)) %>%
  3316. distinct %>% arrange(module)
  3317. rownames(mod_colors_df) <- mod_colors_df$module
  3318. mod_colors_df
  3319. mod_color_df <- GetModules(Mcortex_QC_F_WGCNA) %>%
  3320. dplyr::select(c(module, color)) %>%
  3321. distinct %>% arrange(module)
  3322. n_mods <- nrow(mod_color_df) - 1
  3323. new_colors_F <- paste0(met.brewer("Signac", n=n_mods))
  3324. Mcortex_QC_F_WGCNA <- ResetModuleColors(Mcortex_QC_F_WGCNA, new_colors_F)
  3325. # Change color of modules - Male
  3326. modules <- GetModules(Mcortex_QC_M_WGCNA)
  3327. mods <- unique(modules$module)
  3328. mod_colors_df <- dplyr::select(modules, c(module, color)) %>%
  3329. distinct %>% arrange(module)
  3330. rownames(mod_colors_df) <- mod_colors_df$module
  3331. mod_colors_df
  3332. mod_color_df <- GetModules(Mcortex_QC_M_WGCNA) %>%
  3333. dplyr::select(c(module, color)) %>%
  3334. distinct %>% arrange(module)
  3335. n_mods <- nrow(mod_color_df) - 1
  3336. new_colors_M <- paste0(met.brewer("Signac", n=n_mods))
  3337. Mcortex_QC_M_WGCNA <- ResetModuleColors(Mcortex_QC_M_WGCNA, new_colors_M)
  3338. # Plot dendogram - did not run
  3339. PlotDendrogram(Mcortex_QC_F_WGCNA, main='Glut_F')
  3340. PlotDendrogram(Mcortex_QC_M_WGCNA, main='Glut_M')
  3341. # plot genes ranked by kME for each module - did not run
  3342. PlotKMEs(Mcortex_QC_F_WGCNA, ncol=3)
  3343. PlotKMEs(Mcortex_QC_M_WGCNA, ncol=3)
  3344. # get the module assignment table:
  3345. modules_F <- GetModules(Mcortex_QC_F_WGCNA) %>% subset(module != 'grey')
  3346. modules_M <- GetModules(Mcortex_QC_M_WGCNA) %>% subset(module != 'grey')
  3347. # save to Excel
  3348. write_xlsx(modules_F, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_F_module_assignments.xlsx")
  3349. write_xlsx(modules_M, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_M_module_assignments.xlsx")
  3350. # get hub genes
  3351. hub_df_F <- GetHubGenes(Mcortex_QC_F_WGCNA, n_hubs = 100)
  3352. hub_df_M <- GetHubGenes(Mcortex_QC_M_WGCNA, n_hubs = 100)
  3353. # save to Excel
  3354. write_xlsx(hub_df_F, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_F_top100_hubgenes.xlsx")
  3355. write_xlsx(hub_df_M, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_M_top100_hubgenes.xlsx")
  3356. ```
  3357. hdWGCN module trait correlation - Glut - sex specific
  3358. ```{r}
  3359. # convert treatment to factor
  3360. Mcortex_QC_F_WGCNA$Tx <- as.factor(Mcortex_QC_F_WGCNA$Tx)
  3361. Mcortex_QC_M_WGCNA$Tx <- as.factor(Mcortex_QC_M_WGCNA$Tx)
  3362. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Predicted_Sex is a factor with levels Female, Male, Unknown. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order? --> can't use it actually because only allows 2 variables. Need to subset the seurat object earlier on for just female and male, and then redo this.
  3363. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Tx is a factor with levels Control, Risperidone. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order?
  3364. # list of traits to correlate
  3365. cur_traits <- c("Tx") # single trait is fine now!
  3366. Mcortex_QC_F_WGCNA <- ModuleTraitCorrelation_mod(
  3367. Mcortex_QC_F_WGCNA,
  3368. traits = cur_traits,
  3369. group.by = "celltype1"
  3370. )
  3371. Mcortex_QC_M_WGCNA <- ModuleTraitCorrelation_mod(
  3372. Mcortex_QC_M_WGCNA,
  3373. traits = cur_traits,
  3374. group.by = "celltype1"
  3375. )
  3376. # get the mt-correlation results
  3377. mt_cor_F <- GetModuleTraitCorrelation(Mcortex_QC_F_WGCNA)
  3378. names(mt_cor_F)
  3379. names(mt_cor_F$cor)
  3380. head(mt_cor_F$cor$`Glutamatergic neurons`[,1:10])
  3381. mt_cor_M <- GetModuleTraitCorrelation(Mcortex_QC_M_WGCNA)
  3382. names(mt_cor_M)
  3383. names(mt_cor_M$cor)
  3384. head(mt_cor_M$cor$`Glutamatergic neurons`[,1:10])
  3385. # Create a new workbook
  3386. wb <- createWorkbook()
  3387. # Loop through each cell type / group
  3388. for (celltype in names(mt_cor_F$cor)) {
  3389. # Extract correlation, p-value, and FDR matrices
  3390. cor_mat <- mt_cor_F$cor[[celltype]]
  3391. pval_mat <- mt_cor_F$pval[[celltype]]
  3392. fdr_mat <- mt_cor_F$fdr[[celltype]]
  3393. # Convert to data.frames for writing
  3394. cor_df <- as.data.frame(cor_mat)
  3395. pval_df <- as.data.frame(pval_mat)
  3396. fdr_df <- as.data.frame(fdr_mat)
  3397. # Add worksheets
  3398. addWorksheet(wb, paste0(celltype, "_cor"))
  3399. addWorksheet(wb, paste0(celltype, "_pval"))
  3400. addWorksheet(wb, paste0(celltype, "_fdr"))
  3401. # Write data to the workbook
  3402. writeData(wb, paste0(celltype, "_cor"), cor_df, rowNames = TRUE)
  3403. writeData(wb, paste0(celltype, "_pval"), pval_df, rowNames = TRUE)
  3404. writeData(wb, paste0(celltype, "_fdr"), fdr_df, rowNames = TRUE)
  3405. }
  3406. # Save the workbook
  3407. output_path <- "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_F_moduletraitcor.xlsx"
  3408. saveWorkbook(wb, output_path, overwrite = TRUE)
  3409. # For male
  3410. wb <- createWorkbook()
  3411. for (celltype in names(mt_cor_M$cor)) {
  3412. cor_mat <- mt_cor_M$cor[[celltype]]
  3413. pval_mat <- mt_cor_M$pval[[celltype]]
  3414. fdr_mat <- mt_cor_M$fdr[[celltype]]
  3415. cor_df <- as.data.frame(cor_mat)
  3416. pval_df <- as.data.frame(pval_mat)
  3417. fdr_df <- as.data.frame(fdr_mat)
  3418. addWorksheet(wb, paste0(celltype, "_cor"))
  3419. addWorksheet(wb, paste0(celltype, "_pval"))
  3420. addWorksheet(wb, paste0(celltype, "_fdr"))
  3421. writeData(wb, paste0(celltype, "_cor"), cor_df, rowNames = TRUE)
  3422. writeData(wb, paste0(celltype, "_pval"), pval_df, rowNames = TRUE)
  3423. writeData(wb, paste0(celltype, "_fdr"), fdr_df, rowNames = TRUE)
  3424. }
  3425. output_path <- "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_M_moduletraitcor.xlsx"
  3426. saveWorkbook(wb, output_path, overwrite = TRUE)
  3427. # Plot heatmap for the correlation result
  3428. PlotModuleTraitCorrelation(
  3429. Mcortex_QC_F_WGCNA,
  3430. label = 'fdr',
  3431. label_symbol = 'stars',
  3432. text_size = 3,
  3433. text_digits = 2,
  3434. text_color = 'black',
  3435. high_color = '#db2763',
  3436. mid_color = 'white',
  3437. low_color = '#3772ff',
  3438. plot_max = 0.6,
  3439. combine=TRUE
  3440. )
  3441. PlotModuleTraitCorrelation(
  3442. Mcortex_QC_M_WGCNA,
  3443. label = 'fdr',
  3444. label_symbol = 'stars',
  3445. text_size = 3,
  3446. text_digits = 2,
  3447. text_color = 'black',
  3448. high_color = '#db2763',
  3449. mid_color = 'white',
  3450. low_color = '#3772ff',
  3451. plot_max = 0.6,
  3452. combine=TRUE
  3453. )
  3454. ```
  3455. hdWGCNA enrichment analysis- Glut - sex specific
  3456. ```{r}
  3457. # define the enrichr databases to test
  3458. dbs <- c('GO_Biological_Process_2023','GO_Cellular_Component_2023','GO_Molecular_Function_2023')
  3459. # perform enrichment tests
  3460. Mcortex_QC_F_WGCNA <- RunEnrichr(
  3461. Mcortex_QC_F_WGCNA,
  3462. dbs=dbs,
  3463. max_genes = Inf # use max_genes = Inf to choose all genes
  3464. )
  3465. Mcortex_QC_M_WGCNA <- RunEnrichr(
  3466. Mcortex_QC_M_WGCNA,
  3467. dbs=dbs,
  3468. max_genes = Inf # use max_genes = Inf to choose all genes
  3469. )
  3470. # retrieve the output table
  3471. enrich_df_F <- GetEnrichrTable(Mcortex_QC_F_WGCNA)
  3472. enrich_df_M <- GetEnrichrTable(Mcortex_QC_M_WGCNA)
  3473. # save to Excel
  3474. write_xlsx(enrich_df_F, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_F_enrichR.xlsx")
  3475. write_xlsx(enrich_df_M, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_M_enrichR.xlsx")
  3476. # Define the order of modules you want (e.g., numeric order)
  3477. module_order_F <- c("F_Glut-M1", "F_Glut-M2", "F_Glut-M3", "F_Glut-M4",
  3478. "F_Glut-M5", "F_Glut-M6", "F_Glut-M7", "F_Glut-M8",
  3479. "F_Glut-M9", "F_Glut-M10")
  3480. module_order_M <- c("M_Glut-M1", "M_Glut-M2", "M_Glut-M3", "M_Glut-M4",
  3481. "M_Glut-M5", "M_Glut-M6", "M_Glut-M7", "M_Glut-M8",
  3482. "M_Glut-M9", "M_Glut-M10")
  3483. # Filter enrichment table for your database
  3484. db_to_plot <- "GO_Molecular_Function_2023"
  3485. # Clean and organize enrichment table
  3486. enrich_df_F_clean <- enrich_df_F %>%
  3487. dplyr::filter(db == db_to_plot) %>%
  3488. group_by(module) %>%
  3489. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  3490. slice_head(n = 2) %>%
  3491. ungroup() %>%
  3492. mutate(
  3493. # Remove "(GO:xxxx)" suffix
  3494. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  3495. # Wrap long GO terms to two lines if needed
  3496. Term_clean = str_wrap(Term_clean, width = 50),
  3497. # Keep numeric ordering of modules
  3498. module = factor(module, levels = module_order_F),
  3499. # log10 transform Combined.Score for better scaling
  3500. log10_combined = log10(Combined.Score)
  3501. )
  3502. enrich_df_M_clean <- enrich_df_M %>%
  3503. dplyr::filter(db == db_to_plot) %>%
  3504. group_by(module) %>%
  3505. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  3506. slice_head(n = 2) %>%
  3507. ungroup() %>%
  3508. mutate(
  3509. # Remove "(GO:xxxx)" suffix
  3510. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  3511. # Wrap long GO terms to two lines if needed
  3512. Term_clean = str_wrap(Term_clean, width = 50),
  3513. # Keep numeric ordering of modules
  3514. module = factor(module, levels = module_order_M),
  3515. # log10 transform Combined.Score for better scaling
  3516. log10_combined = log10(Combined.Score)
  3517. )
  3518. # Reorder terms so they're grouped by module, with best p-values at top
  3519. enrich_df_F_clean <- enrich_df_F_clean %>%
  3520. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  3521. enrich_df_M_clean <- enrich_df_M_clean %>%
  3522. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  3523. # Plot
  3524. p <- ggplot(enrich_df_F_clean,
  3525. aes(x = module, y = Term_clean,
  3526. size = log10_combined)) +
  3527. # Main points: filled by -log10(FDR)
  3528. geom_point(
  3529. aes(fill = -log10(Adjusted.P.value),
  3530. shape = Adjusted.P.value <= 0.05),
  3531. color = "black", alpha = 0.9, stroke = 0.7
  3532. ) +
  3533. # Set shapes manually: filled circle for sig, hollow for ns
  3534. scale_shape_manual(
  3535. values = c("TRUE" = 21, "FALSE" = 1),
  3536. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  3537. name = "Significance"
  3538. ) +
  3539. scale_fill_stepsn(
  3540. colors = rev(viridis::magma(256)),
  3541. name = expression(-log[10]("FDR"))
  3542. ) +
  3543. scale_size_continuous(
  3544. name = expression(log[10]("Enrichment"))
  3545. ) +
  3546. theme_minimal(base_size = 13) +
  3547. theme(
  3548. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  3549. axis.text.y = element_text(size = 11),
  3550. legend.position = "right"
  3551. ) +
  3552. labs(
  3553. title = paste0("Glut_F - ", db_to_plot),
  3554. x = "Module",
  3555. y = "GO Term"
  3556. )
  3557. print(p)
  3558. q <- ggplot(enrich_df_M_clean,
  3559. aes(x = module, y = Term_clean,
  3560. size = log10_combined)) +
  3561. # Main points: filled by -log10(FDR)
  3562. geom_point(
  3563. aes(fill = -log10(Adjusted.P.value),
  3564. shape = Adjusted.P.value <= 0.05),
  3565. color = "black", alpha = 0.9, stroke = 0.7
  3566. ) +
  3567. # Set shapes manually: filled circle for sig, hollow for ns
  3568. scale_shape_manual(
  3569. values = c("TRUE" = 21, "FALSE" = 1),
  3570. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  3571. name = "Significance"
  3572. ) +
  3573. scale_fill_stepsn(
  3574. colors = rev(viridis::magma(256)),
  3575. name = expression(-log[10]("FDR"))
  3576. ) +
  3577. scale_size_continuous(
  3578. name = expression(log[10]("Enrichment"))
  3579. ) +
  3580. theme_minimal(base_size = 13) +
  3581. theme(
  3582. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  3583. axis.text.y = element_text(size = 11),
  3584. legend.position = "right"
  3585. ) +
  3586. labs(
  3587. title = paste0("Glut_M - ", db_to_plot),
  3588. x = "Module",
  3589. y = "GO Term"
  3590. )
  3591. print(q)
  3592. ## Re-run enrichR for max 100 genes saved separately, graph not made)
  3593. # perform enrichment tests
  3594. Mcortex_QC_F_WGCNA_100 <- RunEnrichr(
  3595. Mcortex_QC_F_WGCNA,
  3596. dbs=dbs,
  3597. max_genes = 100 # use max_genes = Inf to choose all genes
  3598. )
  3599. Mcortex_QC_M_WGCNA_100 <- RunEnrichr(
  3600. Mcortex_QC_M_WGCNA,
  3601. dbs=dbs,
  3602. max_genes = 100 # use max_genes = Inf to choose all genes
  3603. )
  3604. # retrieve the output table
  3605. enrich_df_F_100 <- GetEnrichrTable(Mcortex_QC_F_WGCNA_100)
  3606. enrich_df_M_100 <- GetEnrichrTable(Mcortex_QC_M_WGCNA_100)
  3607. # save to Excel
  3608. write_xlsx(enrich_df_F_100, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_F_enrichR_100.xlsx")
  3609. write_xlsx(enrich_df_M_100, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_M_enrichR_100.xlsx")
  3610. # Filter enrichment table for your database
  3611. db_to_plot <- "GO_Molecular_Function_2023"
  3612. # Clean and organize enrichment table
  3613. enrich_df_F_clean_100 <- enrich_df_F_100 %>%
  3614. dplyr::filter(db == db_to_plot) %>%
  3615. group_by(module) %>%
  3616. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  3617. slice_head(n = 2) %>%
  3618. ungroup() %>%
  3619. mutate(
  3620. # Remove "(GO:xxxx)" suffix
  3621. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  3622. # Wrap long GO terms to two lines if needed
  3623. Term_clean = str_wrap(Term_clean, width = 50),
  3624. # Keep numeric ordering of modules
  3625. module = factor(module, levels = module_order_F),
  3626. # log10 transform Combined.Score for better scaling
  3627. log10_combined = log10(Combined.Score)
  3628. )
  3629. enrich_df_M_clean_100 <- enrich_df_M_100 %>%
  3630. dplyr::filter(db == db_to_plot) %>%
  3631. group_by(module) %>%
  3632. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  3633. slice_head(n = 2) %>%
  3634. ungroup() %>%
  3635. mutate(
  3636. # Remove "(GO:xxxx)" suffix
  3637. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  3638. # Wrap long GO terms to two lines if needed
  3639. Term_clean = str_wrap(Term_clean, width = 50),
  3640. # Keep numeric ordering of modules
  3641. module = factor(module, levels = module_order_M),
  3642. # log10 transform Combined.Score for better scaling
  3643. log10_combined = log10(Combined.Score)
  3644. )
  3645. # Reorder terms so they're grouped by module, with best p-values at top
  3646. enrich_df_F_clean_100 <- enrich_df_F_clean_100 %>%
  3647. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  3648. enrich_df_M_clean_100 <- enrich_df_M_clean_100 %>%
  3649. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  3650. # Plot
  3651. p <- ggplot(enrich_df_F_clean_100,
  3652. aes(x = module, y = Term_clean,
  3653. size = log10_combined)) +
  3654. # Main points: filled by -log10(FDR)
  3655. geom_point(
  3656. aes(fill = -log10(Adjusted.P.value),
  3657. shape = Adjusted.P.value <= 0.05),
  3658. color = "black", alpha = 0.9, stroke = 0.7
  3659. ) +
  3660. # Set shapes manually: filled circle for sig, hollow for ns
  3661. scale_shape_manual(
  3662. values = c("TRUE" = 21, "FALSE" = 1),
  3663. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  3664. name = "Significance"
  3665. ) +
  3666. scale_fill_stepsn(
  3667. colors = rev(viridis::magma(256)),
  3668. name = expression(-log[10]("FDR"))
  3669. ) +
  3670. scale_size_continuous(
  3671. name = expression(log[10]("Enrichment"))
  3672. ) +
  3673. theme_minimal(base_size = 13) +
  3674. theme(
  3675. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  3676. axis.text.y = element_text(size = 11),
  3677. legend.position = "right"
  3678. ) +
  3679. labs(
  3680. title = paste0("Glut_F - ", db_to_plot),
  3681. x = "Module",
  3682. y = "GO Term"
  3683. )
  3684. q <- ggplot(enrich_df_M_clean_100,
  3685. aes(x = module, y = Term_clean,
  3686. size = log10_combined)) +
  3687. # Main points: filled by -log10(FDR)
  3688. geom_point(
  3689. aes(fill = -log10(Adjusted.P.value),
  3690. shape = Adjusted.P.value <= 0.05),
  3691. color = "black", alpha = 0.9, stroke = 0.7
  3692. ) +
  3693. # Set shapes manually: filled circle for sig, hollow for ns
  3694. scale_shape_manual(
  3695. values = c("TRUE" = 21, "FALSE" = 1),
  3696. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  3697. name = "Significance"
  3698. ) +
  3699. scale_fill_stepsn(
  3700. colors = rev(viridis::magma(256)),
  3701. name = expression(-log[10]("FDR"))
  3702. ) +
  3703. scale_size_continuous(
  3704. name = expression(log[10]("Enrichment"))
  3705. ) +
  3706. theme_minimal(base_size = 13) +
  3707. theme(
  3708. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  3709. axis.text.y = element_text(size = 11),
  3710. legend.position = "right"
  3711. ) +
  3712. labs(
  3713. title = paste0("Glut_M - ", db_to_plot),
  3714. x = "Module",
  3715. y = "GO Term"
  3716. )
  3717. print(p)
  3718. print(q)
  3719. ```
  3720. hdWGCNA analysis of PV-IN - sex specific
  3721. ```{r}
  3722. # Set up the expression matrix for 3 cell types of interest
  3723. Mcortex_QC_F_WGCNA <- SetDatExpr(
  3724. Mcortex_QC_F_WGCNA,
  3725. group_name = "GABAergic Pvalb",
  3726. group.by = "celltype1",
  3727. assay = "SCT",
  3728. layer = "data")
  3729. Mcortex_QC_M_WGCNA <- SetDatExpr(
  3730. Mcortex_QC_M_WGCNA,
  3731. group_name = "GABAergic Pvalb",
  3732. group.by = "celltype1",
  3733. assay = "SCT",
  3734. layer = "data")
  3735. # Select soft-power threshold
  3736. # Test different soft powers:
  3737. Mcortex_QC_F_WGCNA <- TestSoftPowers(
  3738. Mcortex_QC_F_WGCNA,
  3739. networkType = 'signed') # you can also use "unsigned" or "signed hybrid"
  3740. Mcortex_QC_M_WGCNA <- TestSoftPowers(
  3741. Mcortex_QC_M_WGCNA,
  3742. networkType = 'signed') # you can also use "unsigned" or "signed hybrid"
  3743. # plot the results:
  3744. plot_list_F <- PlotSoftPowers(Mcortex_QC_F_WGCNA)
  3745. plot_list_M <- PlotSoftPowers(Mcortex_QC_M_WGCNA)
  3746. # assemble with patchwork
  3747. wrap_plots(plot_list_F, ncol=2)
  3748. wrap_plots(plot_list_M, ncol=2)
  3749. # Construct co-expression network
  3750. Mcortex_QC_F_WGCNA <- ConstructNetwork(
  3751. Mcortex_QC_F_WGCNA,
  3752. tom_name = 'PV-IN_F') # name of the topological overlap matrix written to disk
  3753. Mcortex_QC_M_WGCNA <- ConstructNetwork(
  3754. Mcortex_QC_M_WGCNA,
  3755. tom_name = 'PV-IN_M')
  3756. # Compute harmonized module eingengenes
  3757. # need to re-run ScaleData because sample_id metadata added after SCTransform:
  3758. Mcortex_QC_F_WGCNA <- ScaleData(Mcortex_QC_F_WGCNA, features=VariableFeatures(Mcortex_QC_F_WGCNA))
  3759. Mcortex_QC_M_WGCNA <- ScaleData(Mcortex_QC_M_WGCNA, features=VariableFeatures(Mcortex_QC_M_WGCNA))
  3760. Mcortex_QC_F_WGCNA <- ModuleEigengenes(
  3761. Mcortex_QC_F_WGCNA,
  3762. group.by.vars="sample_id")
  3763. Mcortex_QC_M_WGCNA <- ModuleEigengenes(
  3764. Mcortex_QC_M_WGCNA,
  3765. group.by.vars="sample_id")
  3766. # Get module eigengenes (Harmonized by default)
  3767. hMEs <- GetMEs(Mcortex_QC_F_WGCNA)
  3768. hMEs <- GetMEs(Mcortex_QC_M_WGCNA)
  3769. # Compute eigengene-based module connectivity (kME)
  3770. Mcortex_QC_F_WGCNA <- ModuleConnectivity(
  3771. Mcortex_QC_F_WGCNA,
  3772. group.by = 'celltype1', group_name = 'GABAergic Pvalb')
  3773. Mcortex_QC_M_WGCNA <- ModuleConnectivity(
  3774. Mcortex_QC_M_WGCNA,
  3775. group.by = 'celltype1', group_name = 'GABAergic Pvalb')
  3776. # Look inside the hdWGCNA network parameters to check softpower beta
  3777. Mcortex_QC_F_WGCNA@misc$hdWGCNA$wgcna_params
  3778. Mcortex_QC_M_WGCNA@misc$hdWGCNA$wgcna_params
  3779. # rename the modules for convenience
  3780. Mcortex_QC_F_WGCNA <- ResetModuleNames(
  3781. Mcortex_QC_F_WGCNA,
  3782. new_name = "F_PV-IN-M")
  3783. Mcortex_QC_M_WGCNA <- ResetModuleNames(
  3784. Mcortex_QC_M_WGCNA,
  3785. new_name = "M_PV-IN-M")
  3786. # Change color of modules - Female
  3787. library(MetBrewer)
  3788. modules <- GetModules(Mcortex_QC_F_WGCNA)
  3789. mods <- unique(modules$module)
  3790. mod_colors_df <- dplyr::select(modules, c(module, color)) %>%
  3791. distinct %>% arrange(module)
  3792. rownames(mod_colors_df) <- mod_colors_df$module
  3793. mod_colors_df
  3794. mod_color_df <- GetModules(Mcortex_QC_F_WGCNA) %>%
  3795. dplyr::select(c(module, color)) %>%
  3796. distinct %>% arrange(module)
  3797. n_mods <- nrow(mod_color_df) - 1
  3798. new_colors_F <- paste0(met.brewer("Signac", n=n_mods))
  3799. Mcortex_QC_F_WGCNA <- ResetModuleColors(Mcortex_QC_F_WGCNA, new_colors_F)
  3800. # Change color of modules - Male
  3801. modules <- GetModules(Mcortex_QC_M_WGCNA)
  3802. mods <- unique(modules$module)
  3803. mod_colors_df <- dplyr::select(modules, c(module, color)) %>%
  3804. distinct %>% arrange(module)
  3805. rownames(mod_colors_df) <- mod_colors_df$module
  3806. mod_colors_df
  3807. mod_color_df <- GetModules(Mcortex_QC_M_WGCNA) %>%
  3808. dplyr::select(c(module, color)) %>%
  3809. distinct %>% arrange(module)
  3810. n_mods <- nrow(mod_color_df) - 1
  3811. new_colors_M <- paste0(met.brewer("Signac", n=n_mods))
  3812. Mcortex_QC_M_WGCNA <- ResetModuleColors(Mcortex_QC_M_WGCNA, new_colors_M)
  3813. # Plot dendogram
  3814. PlotDendrogram(Mcortex_QC_F_WGCNA, main='PV-IN_F')
  3815. PlotDendrogram(Mcortex_QC_M_WGCNA, main='PV-IN_M')
  3816. # plot genes ranked by kME for each module - did not run
  3817. PlotKMEs(Mcortex_QC_F_WGCNA, ncol=3)
  3818. PlotKMEs(Mcortex_QC_M_WGCNA, ncol=3)
  3819. # get the module assignment table:
  3820. modules_F <- GetModules(Mcortex_QC_F_WGCNA) %>% subset(module != 'grey')
  3821. modules_M <- GetModules(Mcortex_QC_M_WGCNA) %>% subset(module != 'grey')
  3822. # save to Excel
  3823. write_xlsx(modules_F, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_F_module_assignments.xlsx")
  3824. write_xlsx(modules_M, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_M_module_assignments.xlsx")
  3825. # get hub genes
  3826. hub_df_F <- GetHubGenes(Mcortex_QC_F_WGCNA, n_hubs = 100)
  3827. hub_df_M <- GetHubGenes(Mcortex_QC_M_WGCNA, n_hubs = 100)
  3828. # save to Excel
  3829. write_xlsx(hub_df_F, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_F_top100_hubgenes.xlsx")
  3830. write_xlsx(hub_df_M, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_M_top100_hubgenes.xlsx")
  3831. ```
  3832. hdWGCN module trait correlation - PV-IN - sex specific
  3833. ```{r}
  3834. # convert treatment to factor
  3835. Mcortex_QC_F_WGCNA$Tx <- as.factor(Mcortex_QC_F_WGCNA$Tx)
  3836. Mcortex_QC_M_WGCNA$Tx <- as.factor(Mcortex_QC_M_WGCNA$Tx)
  3837. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Predicted_Sex is a factor with levels Female, Male, Unknown. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order? --> can't use it actually because only allows 2 variables. Need to subset the seurat object earlier on for just female and male, and then redo this.
  3838. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Tx is a factor with levels Control, Risperidone. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order?
  3839. # list of traits to correlate
  3840. cur_traits <- c("Tx") # single trait is fine now!
  3841. Mcortex_QC_F_WGCNA <- ModuleTraitCorrelation_mod(
  3842. Mcortex_QC_F_WGCNA,
  3843. traits = cur_traits,
  3844. group.by = "celltype1"
  3845. )
  3846. Mcortex_QC_M_WGCNA <- ModuleTraitCorrelation_mod(
  3847. Mcortex_QC_M_WGCNA,
  3848. traits = cur_traits,
  3849. group.by = "celltype1"
  3850. )
  3851. # get the mt-correlation results
  3852. mt_cor_F <- GetModuleTraitCorrelation(Mcortex_QC_F_WGCNA)
  3853. names(mt_cor_F)
  3854. names(mt_cor_F$cor)
  3855. head(mt_cor_F$cor$`GABAergic Pvalb`[,1:5])
  3856. mt_cor_M <- GetModuleTraitCorrelation(Mcortex_QC_M_WGCNA)
  3857. names(mt_cor_M)
  3858. names(mt_cor_M$cor)
  3859. head(mt_cor_M$cor$`GABAergic Pvalb`[,1:5])
  3860. # Create a new workbook
  3861. wb <- createWorkbook()
  3862. # Loop through each cell type / group
  3863. for (celltype in names(mt_cor_F$cor)) {
  3864. # Extract correlation, p-value, and FDR matrices
  3865. cor_mat <- mt_cor_F$cor[[celltype]]
  3866. pval_mat <- mt_cor_F$pval[[celltype]]
  3867. fdr_mat <- mt_cor_F$fdr[[celltype]]
  3868. # Convert to data.frames for writing
  3869. cor_df <- as.data.frame(cor_mat)
  3870. pval_df <- as.data.frame(pval_mat)
  3871. fdr_df <- as.data.frame(fdr_mat)
  3872. # Add worksheets
  3873. addWorksheet(wb, paste0(celltype, "_cor"))
  3874. addWorksheet(wb, paste0(celltype, "_pval"))
  3875. addWorksheet(wb, paste0(celltype, "_fdr"))
  3876. # Write data to the workbook
  3877. writeData(wb, paste0(celltype, "_cor"), cor_df, rowNames = TRUE)
  3878. writeData(wb, paste0(celltype, "_pval"), pval_df, rowNames = TRUE)
  3879. writeData(wb, paste0(celltype, "_fdr"), fdr_df, rowNames = TRUE)
  3880. }
  3881. # Save the workbook
  3882. output_path <- "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_F_moduletraitcor.xlsx"
  3883. saveWorkbook(wb, output_path, overwrite = TRUE)
  3884. # For male
  3885. wb <- createWorkbook()
  3886. for (celltype in names(mt_cor_M$cor)) {
  3887. cor_mat <- mt_cor_M$cor[[celltype]]
  3888. pval_mat <- mt_cor_M$pval[[celltype]]
  3889. fdr_mat <- mt_cor_M$fdr[[celltype]]
  3890. cor_df <- as.data.frame(cor_mat)
  3891. pval_df <- as.data.frame(pval_mat)
  3892. fdr_df <- as.data.frame(fdr_mat)
  3893. addWorksheet(wb, paste0(celltype, "_cor"))
  3894. addWorksheet(wb, paste0(celltype, "_pval"))
  3895. addWorksheet(wb, paste0(celltype, "_fdr"))
  3896. writeData(wb, paste0(celltype, "_cor"), cor_df, rowNames = TRUE)
  3897. writeData(wb, paste0(celltype, "_pval"), pval_df, rowNames = TRUE)
  3898. writeData(wb, paste0(celltype, "_fdr"), fdr_df, rowNames = TRUE)
  3899. }
  3900. output_path <- "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_M_moduletraitcor.xlsx"
  3901. saveWorkbook(wb, output_path, overwrite = TRUE)
  3902. # Plot heatmap for the correlation result
  3903. PlotModuleTraitCorrelation(
  3904. Mcortex_QC_F_WGCNA,
  3905. label = 'fdr',
  3906. label_symbol = 'stars',
  3907. text_size = 3,
  3908. text_digits = 2,
  3909. text_color = 'black',
  3910. high_color = '#db2763',
  3911. mid_color = 'white',
  3912. low_color = '#3772ff',
  3913. plot_max = 0.6,
  3914. combine=TRUE
  3915. )
  3916. PlotModuleTraitCorrelation(
  3917. Mcortex_QC_M_WGCNA,
  3918. label = 'fdr',
  3919. label_symbol = 'stars',
  3920. text_size = 3,
  3921. text_digits = 2,
  3922. text_color = 'black',
  3923. high_color = '#db2763',
  3924. mid_color = 'white',
  3925. low_color = '#3772ff',
  3926. plot_max = 0.6,
  3927. combine=TRUE
  3928. )
  3929. ```
  3930. hdWGCNA enrichment analysis- PV-IN - sex specific
  3931. ```{r}
  3932. # define the enrichr databases to test
  3933. dbs <- c('GO_Biological_Process_2023','GO_Cellular_Component_2023','GO_Molecular_Function_2023')
  3934. # perform enrichment tests
  3935. Mcortex_QC_F_WGCNA <- RunEnrichr(
  3936. Mcortex_QC_F_WGCNA,
  3937. dbs=dbs,
  3938. max_genes = Inf # use max_genes = Inf to choose all genes
  3939. )
  3940. Mcortex_QC_M_WGCNA <- RunEnrichr(
  3941. Mcortex_QC_M_WGCNA,
  3942. dbs=dbs,
  3943. max_genes = Inf # use max_genes = Inf to choose all genes
  3944. )
  3945. # retrieve the output table
  3946. enrich_df_F <- GetEnrichrTable(Mcortex_QC_F_WGCNA)
  3947. enrich_df_M <- GetEnrichrTable(Mcortex_QC_M_WGCNA)
  3948. # save to Excel
  3949. write_xlsx(enrich_df_F, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_F_enrichR.xlsx")
  3950. write_xlsx(enrich_df_M, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_M_enrichR.xlsx")
  3951. # Define the order of modules you want (e.g., numeric order)
  3952. module_order_F <- c("F_PV-IN-M1", "F_PV-IN-M2", "F_PV-IN-M3", "F_PV-IN-M4",
  3953. "F_PV-IN-M5", "F_PV-IN-M6")
  3954. module_order_M <- c("M_PV-IN-M1", "M_PV-IN-M2", "M_PV-IN-M3", "M_PV-IN-M4",
  3955. "M_PV-IN-M5")
  3956. # Filter enrichment table for your database
  3957. db_to_plot <- "GO_Biological_Process_2023"
  3958. # Clean and organize enrichment table
  3959. enrich_df_F_clean <- enrich_df_F %>%
  3960. dplyr::filter(db == db_to_plot) %>%
  3961. group_by(module) %>%
  3962. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  3963. slice_head(n = 2) %>%
  3964. ungroup() %>%
  3965. mutate(
  3966. # Remove "(GO:xxxx)" suffix
  3967. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  3968. # Wrap long GO terms to two lines if needed
  3969. Term_clean = str_wrap(Term_clean, width = 50),
  3970. # Keep numeric ordering of modules
  3971. module = factor(module, levels = module_order_F),
  3972. # log10 transform Combined.Score for better scaling
  3973. log10_combined = log10(Combined.Score)
  3974. )
  3975. enrich_df_M_clean <- enrich_df_M %>%
  3976. dplyr::filter(db == db_to_plot) %>%
  3977. group_by(module) %>%
  3978. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  3979. slice_head(n = 2) %>%
  3980. ungroup() %>%
  3981. mutate(
  3982. # Remove "(GO:xxxx)" suffix
  3983. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  3984. # Wrap long GO terms to two lines if needed
  3985. Term_clean = str_wrap(Term_clean, width = 50),
  3986. # Keep numeric ordering of modules
  3987. module = factor(module, levels = module_order_M),
  3988. # log10 transform Combined.Score for better scaling
  3989. log10_combined = log10(Combined.Score)
  3990. )
  3991. # Reorder terms so they're grouped by module, with best p-values at top
  3992. enrich_df_F_clean <- enrich_df_F_clean %>%
  3993. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  3994. enrich_df_M_clean <- enrich_df_M_clean %>%
  3995. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  3996. # Plot
  3997. p <- ggplot(enrich_df_F_clean,
  3998. aes(x = module, y = Term_clean,
  3999. size = log10_combined)) +
  4000. # Main points: filled by -log10(FDR)
  4001. geom_point(
  4002. aes(fill = -log10(Adjusted.P.value),
  4003. shape = Adjusted.P.value <= 0.05),
  4004. color = "black", alpha = 0.9, stroke = 0.7
  4005. ) +
  4006. # Set shapes manually: filled circle for sig, hollow for ns
  4007. scale_shape_manual(
  4008. values = c("TRUE" = 21, "FALSE" = 1),
  4009. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  4010. name = "Significance"
  4011. ) +
  4012. scale_fill_stepsn(
  4013. colors = rev(viridis::magma(256)),
  4014. name = expression(-log[10]("FDR"))
  4015. ) +
  4016. scale_size_continuous(
  4017. name = expression(log[10]("Enrichment"))
  4018. ) +
  4019. theme_minimal(base_size = 13) +
  4020. theme(
  4021. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  4022. axis.text.y = element_text(size = 11),
  4023. legend.position = "right"
  4024. ) +
  4025. labs(
  4026. title = paste0("PV-IN_F - ", db_to_plot),
  4027. x = "Module",
  4028. y = "GO Term"
  4029. )
  4030. print(p)
  4031. q <- ggplot(enrich_df_M_clean,
  4032. aes(x = module, y = Term_clean,
  4033. size = log10_combined)) +
  4034. # Main points: filled by -log10(FDR)
  4035. geom_point(
  4036. aes(fill = -log10(Adjusted.P.value),
  4037. shape = Adjusted.P.value <= 0.05),
  4038. color = "black", alpha = 0.9, stroke = 0.7
  4039. ) +
  4040. # Set shapes manually: filled circle for sig, hollow for ns
  4041. scale_shape_manual(
  4042. values = c("TRUE" = 21, "FALSE" = 1),
  4043. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  4044. name = "Significance"
  4045. ) +
  4046. scale_fill_stepsn(
  4047. colors = rev(viridis::magma(256)),
  4048. name = expression(-log[10]("FDR"))
  4049. ) +
  4050. scale_size_continuous(
  4051. name = expression(log[10]("Enrichment"))
  4052. ) +
  4053. theme_minimal(base_size = 13) +
  4054. theme(
  4055. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  4056. axis.text.y = element_text(size = 11),
  4057. legend.position = "right"
  4058. ) +
  4059. labs(
  4060. title = paste0("PV-IN_M - ", db_to_plot),
  4061. x = "Module",
  4062. y = "GO Term"
  4063. )
  4064. print(q)
  4065. ## Re-run enrichR for max 100 genes saved separately, graph not made)
  4066. # perform enrichment tests
  4067. Mcortex_QC_F_WGCNA_100 <- RunEnrichr(
  4068. Mcortex_QC_F_WGCNA,
  4069. dbs=dbs,
  4070. max_genes = 100 # use max_genes = Inf to choose all genes
  4071. )
  4072. Mcortex_QC_M_WGCNA_100 <- RunEnrichr(
  4073. Mcortex_QC_M_WGCNA,
  4074. dbs=dbs,
  4075. max_genes = 100 # use max_genes = Inf to choose all genes
  4076. )
  4077. # retrieve the output table
  4078. enrich_df_F_100 <- GetEnrichrTable(Mcortex_QC_F_WGCNA_100)
  4079. enrich_df_M_100 <- GetEnrichrTable(Mcortex_QC_M_WGCNA_100)
  4080. # save to Excel
  4081. write_xlsx(enrich_df_F_100, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_F_enrichR_100.xlsx")
  4082. write_xlsx(enrich_df_M_100, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_M_enrichR_100.xlsx")
  4083. # Filter enrichment table for your database
  4084. db_to_plot <- "GO_Molecular_Function_2023"
  4085. # Clean and organize enrichment table
  4086. enrich_df_F_clean_100 <- enrich_df_F_100 %>%
  4087. dplyr::filter(db == db_to_plot) %>%
  4088. group_by(module) %>%
  4089. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  4090. slice_head(n = 2) %>%
  4091. ungroup() %>%
  4092. mutate(
  4093. # Remove "(GO:xxxx)" suffix
  4094. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  4095. # Wrap long GO terms to two lines if needed
  4096. Term_clean = str_wrap(Term_clean, width = 50),
  4097. # Keep numeric ordering of modules
  4098. module = factor(module, levels = module_order_F),
  4099. # log10 transform Combined.Score for better scaling
  4100. log10_combined = log10(Combined.Score)
  4101. )
  4102. enrich_df_M_clean_100 <- enrich_df_M_100 %>%
  4103. dplyr::filter(db == db_to_plot) %>%
  4104. group_by(module) %>%
  4105. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  4106. slice_head(n = 2) %>%
  4107. ungroup() %>%
  4108. mutate(
  4109. # Remove "(GO:xxxx)" suffix
  4110. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  4111. # Wrap long GO terms to two lines if needed
  4112. Term_clean = str_wrap(Term_clean, width = 50),
  4113. # Keep numeric ordering of modules
  4114. module = factor(module, levels = module_order_M),
  4115. # log10 transform Combined.Score for better scaling
  4116. log10_combined = log10(Combined.Score)
  4117. )
  4118. # Reorder terms so they're grouped by module, with best p-values at top
  4119. enrich_df_F_clean_100 <- enrich_df_F_clean_100 %>%
  4120. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  4121. enrich_df_M_clean_100 <- enrich_df_M_clean_100 %>%
  4122. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  4123. # Plot
  4124. p <- ggplot(enrich_df_F_clean_100,
  4125. aes(x = module, y = Term_clean,
  4126. size = log10_combined)) +
  4127. # Main points: filled by -log10(FDR)
  4128. geom_point(
  4129. aes(fill = -log10(Adjusted.P.value),
  4130. shape = Adjusted.P.value <= 0.05),
  4131. color = "black", alpha = 0.9, stroke = 0.7
  4132. ) +
  4133. # Set shapes manually: filled circle for sig, hollow for ns
  4134. scale_shape_manual(
  4135. values = c("TRUE" = 21, "FALSE" = 1),
  4136. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  4137. name = "Significance"
  4138. ) +
  4139. scale_fill_stepsn(
  4140. colors = rev(viridis::magma(256)),
  4141. name = expression(-log[10]("FDR"))
  4142. ) +
  4143. scale_size_continuous(
  4144. name = expression(log[10]("Enrichment"))
  4145. ) +
  4146. theme_minimal(base_size = 13) +
  4147. theme(
  4148. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  4149. axis.text.y = element_text(size = 11),
  4150. legend.position = "right"
  4151. ) +
  4152. labs(
  4153. title = paste0("PV-IN_F - ", db_to_plot),
  4154. x = "Module",
  4155. y = "GO Term"
  4156. )
  4157. q <- ggplot(enrich_df_M_clean_100,
  4158. aes(x = module, y = Term_clean,
  4159. size = log10_combined)) +
  4160. # Main points: filled by -log10(FDR)
  4161. geom_point(
  4162. aes(fill = -log10(Adjusted.P.value),
  4163. shape = Adjusted.P.value <= 0.05),
  4164. color = "black", alpha = 0.9, stroke = 0.7
  4165. ) +
  4166. # Set shapes manually: filled circle for sig, hollow for ns
  4167. scale_shape_manual(
  4168. values = c("TRUE" = 21, "FALSE" = 1),
  4169. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  4170. name = "Significance"
  4171. ) +
  4172. scale_fill_stepsn(
  4173. colors = rev(viridis::magma(256)),
  4174. name = expression(-log[10]("FDR"))
  4175. ) +
  4176. scale_size_continuous(
  4177. name = expression(log[10]("Enrichment"))
  4178. ) +
  4179. theme_minimal(base_size = 13) +
  4180. theme(
  4181. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  4182. axis.text.y = element_text(size = 11),
  4183. legend.position = "right"
  4184. ) +
  4185. labs(
  4186. title = paste0("PV-IN_M - ", db_to_plot),
  4187. x = "Module",
  4188. y = "GO Term"
  4189. )
  4190. print(p)
  4191. print(q)
  4192. ```
  4193. hdWGCNA analysis of Sst-IN - sex specific
  4194. ```{r}
  4195. # Set up the expression matrix for 3 cell types of interest
  4196. Mcortex_QC_F_WGCNA <- SetDatExpr(
  4197. Mcortex_QC_F_WGCNA,
  4198. group_name = "GABAergic Sst",
  4199. group.by = "celltype1",
  4200. assay = "SCT",
  4201. layer = "data")
  4202. Mcortex_QC_M_WGCNA <- SetDatExpr(
  4203. Mcortex_QC_M_WGCNA,
  4204. group_name = "GABAergic Sst",
  4205. group.by = "celltype1",
  4206. assay = "SCT",
  4207. layer = "data")
  4208. # Select soft-power threshold
  4209. # Test different soft powers:
  4210. Mcortex_QC_F_WGCNA <- TestSoftPowers(
  4211. Mcortex_QC_F_WGCNA,
  4212. networkType = 'signed') # you can also use "unsigned" or "signed hybrid"
  4213. Mcortex_QC_M_WGCNA <- TestSoftPowers(
  4214. Mcortex_QC_M_WGCNA,
  4215. networkType = 'signed') # you can also use "unsigned" or "signed hybrid"
  4216. # plot the results:
  4217. plot_list_F <- PlotSoftPowers(Mcortex_QC_F_WGCNA)
  4218. plot_list_M <- PlotSoftPowers(Mcortex_QC_M_WGCNA)
  4219. # assemble with patchwork
  4220. wrap_plots(plot_list_F, ncol=2)
  4221. wrap_plots(plot_list_M, ncol=2)
  4222. # Construct co-expression network
  4223. Mcortex_QC_F_WGCNA <- ConstructNetwork(
  4224. Mcortex_QC_F_WGCNA,
  4225. tom_name = 'Sst-IN_F') # name of the topological overlap matrix written to disk
  4226. Mcortex_QC_M_WGCNA <- ConstructNetwork(
  4227. Mcortex_QC_M_WGCNA,
  4228. tom_name = 'Sst-IN_M')
  4229. # Compute harmonized module eingengenes
  4230. # need to re-run ScaleData because sample_id metadata added after SCTransform:
  4231. Mcortex_QC_F_WGCNA <- ScaleData(Mcortex_QC_F_WGCNA, features=VariableFeatures(Mcortex_QC_F_WGCNA))
  4232. Mcortex_QC_M_WGCNA <- ScaleData(Mcortex_QC_M_WGCNA, features=VariableFeatures(Mcortex_QC_M_WGCNA))
  4233. Mcortex_QC_F_WGCNA <- ModuleEigengenes(
  4234. Mcortex_QC_F_WGCNA,
  4235. group.by.vars="sample_id")
  4236. Mcortex_QC_M_WGCNA <- ModuleEigengenes(
  4237. Mcortex_QC_M_WGCNA,
  4238. group.by.vars="sample_id")
  4239. # Get module eigengenes (Harmonized by default)
  4240. hMEs <- GetMEs(Mcortex_QC_F_WGCNA)
  4241. hMEs <- GetMEs(Mcortex_QC_M_WGCNA)
  4242. # Compute eigengene-based module connectivity (kME)
  4243. Mcortex_QC_F_WGCNA <- ModuleConnectivity(
  4244. Mcortex_QC_F_WGCNA,
  4245. group.by = 'celltype1', group_name = 'GABAergic Sst')
  4246. Mcortex_QC_M_WGCNA <- ModuleConnectivity(
  4247. Mcortex_QC_M_WGCNA,
  4248. group.by = 'celltype1', group_name = 'GABAergic Sst')
  4249. # Look inside the hdWGCNA network parameters to check softpower beta
  4250. Mcortex_QC_F_WGCNA@misc$hdWGCNA$wgcna_params
  4251. Mcortex_QC_M_WGCNA@misc$hdWGCNA$wgcna_params
  4252. # rename the modules for convenience
  4253. Mcortex_QC_F_WGCNA <- ResetModuleNames(
  4254. Mcortex_QC_F_WGCNA,
  4255. new_name = "F_Sst-IN-M")
  4256. Mcortex_QC_M_WGCNA <- ResetModuleNames(
  4257. Mcortex_QC_M_WGCNA,
  4258. new_name = "M_Sst-IN-M")
  4259. # Change color of modules - Female
  4260. library(MetBrewer)
  4261. modules <- GetModules(Mcortex_QC_F_WGCNA)
  4262. mods <- unique(modules$module)
  4263. mod_colors_df <- dplyr::select(modules, c(module, color)) %>%
  4264. distinct %>% arrange(module)
  4265. rownames(mod_colors_df) <- mod_colors_df$module
  4266. mod_colors_df
  4267. mod_color_df <- GetModules(Mcortex_QC_F_WGCNA) %>%
  4268. dplyr::select(c(module, color)) %>%
  4269. distinct %>% arrange(module)
  4270. n_mods <- nrow(mod_color_df) - 1
  4271. new_colors_F <- paste0(met.brewer("Signac", n=n_mods))
  4272. Mcortex_QC_F_WGCNA <- ResetModuleColors(Mcortex_QC_F_WGCNA, new_colors_F)
  4273. # Change color of modules - Male
  4274. modules <- GetModules(Mcortex_QC_M_WGCNA)
  4275. mods <- unique(modules$module)
  4276. mod_colors_df <- dplyr::select(modules, c(module, color)) %>%
  4277. distinct %>% arrange(module)
  4278. rownames(mod_colors_df) <- mod_colors_df$module
  4279. mod_colors_df
  4280. mod_color_df <- GetModules(Mcortex_QC_M_WGCNA) %>%
  4281. dplyr::select(c(module, color)) %>%
  4282. distinct %>% arrange(module)
  4283. n_mods <- nrow(mod_color_df) - 1
  4284. new_colors_M <- paste0(met.brewer("Signac", n=n_mods))
  4285. Mcortex_QC_M_WGCNA <- ResetModuleColors(Mcortex_QC_M_WGCNA, new_colors_M)
  4286. # Plot dendogram
  4287. PlotDendrogram(Mcortex_QC_F_WGCNA, main='Sst-IN_F')
  4288. PlotDendrogram(Mcortex_QC_M_WGCNA, main='Sst-IN_M')
  4289. # plot genes ranked by kME for each module - did not run
  4290. PlotKMEs(Mcortex_QC_F_WGCNA, ncol=3)
  4291. PlotKMEs(Mcortex_QC_M_WGCNA, ncol=3)
  4292. # get the module assignment table:
  4293. modules_F <- GetModules(Mcortex_QC_F_WGCNA) %>% subset(module != 'grey')
  4294. modules_M <- GetModules(Mcortex_QC_M_WGCNA) %>% subset(module != 'grey')
  4295. # save to Excel
  4296. write_xlsx(modules_F, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_F_module_assignments.xlsx")
  4297. write_xlsx(modules_M, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_M_module_assignments.xlsx")
  4298. # get hub genes
  4299. hub_df_F <- GetHubGenes(Mcortex_QC_F_WGCNA, n_hubs = 100)
  4300. hub_df_M <- GetHubGenes(Mcortex_QC_M_WGCNA, n_hubs = 100)
  4301. # save to Excel
  4302. write_xlsx(hub_df_F, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_F_top100_hubgenes.xlsx")
  4303. write_xlsx(hub_df_M, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_M_top100_hubgenes.xlsx")
  4304. ```
  4305. hdWGCN module trait correlation - Sst-IN - sex specific
  4306. ```{r}
  4307. # convert treatment to factor
  4308. Mcortex_QC_F_WGCNA$Tx <- as.factor(Mcortex_QC_F_WGCNA$Tx)
  4309. Mcortex_QC_M_WGCNA$Tx <- as.factor(Mcortex_QC_M_WGCNA$Tx)
  4310. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Predicted_Sex is a factor with levels Female, Male, Unknown. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order? --> can't use it actually because only allows 2 variables. Need to subset the seurat object earlier on for just female and male, and then redo this.
  4311. ## Warning in ModuleTraitCorrelation(Mcortex_QC_WGCNA, traits = cur_traits, :Trait Tx is a factor with levels Control, Risperidone. Levels will be converted to numeric IN THIS ORDER for the correlation, is this the expected order?
  4312. # list of traits to correlate
  4313. cur_traits <- c("Tx") # single trait is fine now!
  4314. Mcortex_QC_F_WGCNA <- ModuleTraitCorrelation_mod(
  4315. Mcortex_QC_F_WGCNA,
  4316. traits = cur_traits,
  4317. group.by = "celltype1"
  4318. )
  4319. Mcortex_QC_M_WGCNA <- ModuleTraitCorrelation_mod(
  4320. Mcortex_QC_M_WGCNA,
  4321. traits = cur_traits,
  4322. group.by = "celltype1"
  4323. )
  4324. # get the mt-correlation results
  4325. mt_cor_F <- GetModuleTraitCorrelation(Mcortex_QC_F_WGCNA)
  4326. names(mt_cor_F)
  4327. names(mt_cor_F$cor)
  4328. head(mt_cor_F$cor$`GABAergic Sst`[,1:5])
  4329. mt_cor_M <- GetModuleTraitCorrelation(Mcortex_QC_M_WGCNA)
  4330. names(mt_cor_M)
  4331. names(mt_cor_M$cor)
  4332. head(mt_cor_M$cor$`GABAergic Sst`[,1:5])
  4333. # Create a new workbook
  4334. wb <- createWorkbook()
  4335. # Loop through each cell type / group
  4336. for (celltype in names(mt_cor_F$cor)) {
  4337. # Extract correlation, p-value, and FDR matrices
  4338. cor_mat <- mt_cor_F$cor[[celltype]]
  4339. pval_mat <- mt_cor_F$pval[[celltype]]
  4340. fdr_mat <- mt_cor_F$fdr[[celltype]]
  4341. # Convert to data.frames for writing
  4342. cor_df <- as.data.frame(cor_mat)
  4343. pval_df <- as.data.frame(pval_mat)
  4344. fdr_df <- as.data.frame(fdr_mat)
  4345. # Add worksheets
  4346. addWorksheet(wb, paste0(celltype, "_cor"))
  4347. addWorksheet(wb, paste0(celltype, "_pval"))
  4348. addWorksheet(wb, paste0(celltype, "_fdr"))
  4349. # Write data to the workbook
  4350. writeData(wb, paste0(celltype, "_cor"), cor_df, rowNames = TRUE)
  4351. writeData(wb, paste0(celltype, "_pval"), pval_df, rowNames = TRUE)
  4352. writeData(wb, paste0(celltype, "_fdr"), fdr_df, rowNames = TRUE)
  4353. }
  4354. # Save the workbook
  4355. output_path <- "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_F_moduletraitcor.xlsx"
  4356. saveWorkbook(wb, output_path, overwrite = TRUE)
  4357. # For male
  4358. wb <- createWorkbook()
  4359. for (celltype in names(mt_cor_M$cor)) {
  4360. cor_mat <- mt_cor_M$cor[[celltype]]
  4361. pval_mat <- mt_cor_M$pval[[celltype]]
  4362. fdr_mat <- mt_cor_M$fdr[[celltype]]
  4363. cor_df <- as.data.frame(cor_mat)
  4364. pval_df <- as.data.frame(pval_mat)
  4365. fdr_df <- as.data.frame(fdr_mat)
  4366. addWorksheet(wb, paste0(celltype, "_cor"))
  4367. addWorksheet(wb, paste0(celltype, "_pval"))
  4368. addWorksheet(wb, paste0(celltype, "_fdr"))
  4369. writeData(wb, paste0(celltype, "_cor"), cor_df, rowNames = TRUE)
  4370. writeData(wb, paste0(celltype, "_pval"), pval_df, rowNames = TRUE)
  4371. writeData(wb, paste0(celltype, "_fdr"), fdr_df, rowNames = TRUE)
  4372. }
  4373. output_path <- "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_M_moduletraitcor.xlsx"
  4374. saveWorkbook(wb, output_path, overwrite = TRUE)
  4375. # Plot heatmap for the correlation result
  4376. PlotModuleTraitCorrelation(
  4377. Mcortex_QC_F_WGCNA,
  4378. label = 'fdr',
  4379. label_symbol = 'stars',
  4380. text_size = 3,
  4381. text_digits = 2,
  4382. text_color = 'black',
  4383. high_color = '#db2763',
  4384. mid_color = 'white',
  4385. low_color = '#3772ff',
  4386. plot_max = 0.6,
  4387. combine=TRUE
  4388. )
  4389. PlotModuleTraitCorrelation(
  4390. Mcortex_QC_M_WGCNA,
  4391. label = 'fdr',
  4392. label_symbol = 'stars',
  4393. text_size = 3,
  4394. text_digits = 2,
  4395. text_color = 'black',
  4396. high_color = '#db2763',
  4397. mid_color = 'white',
  4398. low_color = '#3772ff',
  4399. plot_max = 0.6,
  4400. combine=TRUE
  4401. )
  4402. ```
  4403. hdWGCNA enrichment analysis- Sst-IN - sex specific
  4404. ```{r}
  4405. # define the enrichr databases to test
  4406. dbs <- c('GO_Biological_Process_2023','GO_Cellular_Component_2023','GO_Molecular_Function_2023')
  4407. # perform enrichment tests
  4408. Mcortex_QC_F_WGCNA <- RunEnrichr(
  4409. Mcortex_QC_F_WGCNA,
  4410. dbs=dbs,
  4411. max_genes = Inf # use max_genes = Inf to choose all genes
  4412. )
  4413. Mcortex_QC_M_WGCNA <- RunEnrichr(
  4414. Mcortex_QC_M_WGCNA,
  4415. dbs=dbs,
  4416. max_genes = Inf # use max_genes = Inf to choose all genes
  4417. )
  4418. # retrieve the output table
  4419. enrich_df_F <- GetEnrichrTable(Mcortex_QC_F_WGCNA)
  4420. enrich_df_M <- GetEnrichrTable(Mcortex_QC_M_WGCNA)
  4421. # save to Excel
  4422. write_xlsx(enrich_df_F, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_F_enrichR.xlsx")
  4423. write_xlsx(enrich_df_M, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_M_enrichR.xlsx")
  4424. # Define the order of modules you want (e.g., numeric order)
  4425. module_order_F <- c("F_Sst-IN-M1", "F_Sst-IN-M2", "F_Sst-IN-M3", "F_Sst-IN-M4",
  4426. "F_Sst-IN-M5", "F_Sst-IN-M6", "F_Sst-IN-M7")
  4427. module_order_M <- c("M_Sst-IN-M1", "M_Sst-IN-M2", "M_Sst-IN-M3", "M_Sst-IN-M4",
  4428. "M_Sst-IN-M5", "M_Sst-IN-M6", "M_Sst-IN-M7")
  4429. # Filter enrichment table for your database
  4430. db_to_plot <- "GO_Molecular_Function_2023"
  4431. # Clean and organize enrichment table
  4432. enrich_df_F_clean <- enrich_df_F %>%
  4433. dplyr::filter(db == db_to_plot) %>%
  4434. group_by(module) %>%
  4435. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  4436. slice_head(n = 2) %>%
  4437. ungroup() %>%
  4438. mutate(
  4439. # Remove "(GO:xxxx)" suffix
  4440. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  4441. # Wrap long GO terms to two lines if needed
  4442. Term_clean = str_wrap(Term_clean, width = 50),
  4443. # Keep numeric ordering of modules
  4444. module = factor(module, levels = module_order_F),
  4445. # log10 transform Combined.Score for better scaling
  4446. log10_combined = log10(Combined.Score)
  4447. )
  4448. enrich_df_M_clean <- enrich_df_M %>%
  4449. dplyr::filter(db == db_to_plot) %>%
  4450. group_by(module) %>%
  4451. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  4452. slice_head(n = 2) %>%
  4453. ungroup() %>%
  4454. mutate(
  4455. # Remove "(GO:xxxx)" suffix
  4456. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  4457. # Wrap long GO terms to two lines if needed
  4458. Term_clean = str_wrap(Term_clean, width = 50),
  4459. # Keep numeric ordering of modules
  4460. module = factor(module, levels = module_order_M),
  4461. # log10 transform Combined.Score for better scaling
  4462. log10_combined = log10(Combined.Score)
  4463. )
  4464. # Reorder terms so they're grouped by module, with best p-values at top
  4465. enrich_df_F_clean <- enrich_df_F_clean %>%
  4466. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  4467. enrich_df_M_clean <- enrich_df_M_clean %>%
  4468. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  4469. # Plot
  4470. p <- ggplot(enrich_df_F_clean,
  4471. aes(x = module, y = Term_clean,
  4472. size = log10_combined)) +
  4473. # Main points: filled by -log10(FDR)
  4474. geom_point(
  4475. aes(fill = -log10(Adjusted.P.value),
  4476. shape = Adjusted.P.value <= 0.05),
  4477. color = "black", alpha = 0.9, stroke = 0.7
  4478. ) +
  4479. # Set shapes manually: filled circle for sig, hollow for ns
  4480. scale_shape_manual(
  4481. values = c("TRUE" = 21, "FALSE" = 1),
  4482. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  4483. name = "Significance"
  4484. ) +
  4485. scale_fill_stepsn(
  4486. colors = rev(viridis::magma(256)),
  4487. name = expression(-log[10]("FDR"))
  4488. ) +
  4489. scale_size_continuous(
  4490. name = expression(log[10]("Enrichment"))
  4491. ) +
  4492. theme_minimal(base_size = 13) +
  4493. theme(
  4494. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  4495. axis.text.y = element_text(size = 11),
  4496. legend.position = "right"
  4497. ) +
  4498. labs(
  4499. title = paste0("Sst-IN_F - ", db_to_plot),
  4500. x = "Module",
  4501. y = "GO Term"
  4502. )
  4503. print(p)
  4504. q <- ggplot(enrich_df_M_clean,
  4505. aes(x = module, y = Term_clean,
  4506. size = log10_combined)) +
  4507. # Main points: filled by -log10(FDR)
  4508. geom_point(
  4509. aes(fill = -log10(Adjusted.P.value),
  4510. shape = Adjusted.P.value <= 0.05),
  4511. color = "black", alpha = 0.9, stroke = 0.7
  4512. ) +
  4513. # Set shapes manually: filled circle for sig, hollow for ns
  4514. scale_shape_manual(
  4515. values = c("TRUE" = 21, "FALSE" = 1),
  4516. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  4517. name = "Significance"
  4518. ) +
  4519. scale_fill_stepsn(
  4520. colors = rev(viridis::magma(256)),
  4521. name = expression(-log[10]("FDR"))
  4522. ) +
  4523. scale_size_continuous(
  4524. name = expression(log[10]("Enrichment"))
  4525. ) +
  4526. theme_minimal(base_size = 13) +
  4527. theme(
  4528. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  4529. axis.text.y = element_text(size = 11),
  4530. legend.position = "right"
  4531. ) +
  4532. labs(
  4533. title = paste0("Sst-IN_M - ", db_to_plot),
  4534. x = "Module",
  4535. y = "GO Term"
  4536. )
  4537. print(q)
  4538. ## Re-run enrichR for max 100 genes saved separately, graph not made)
  4539. # perform enrichment tests
  4540. Mcortex_QC_F_WGCNA_100 <- RunEnrichr(
  4541. Mcortex_QC_F_WGCNA,
  4542. dbs=dbs,
  4543. max_genes = 100 # use max_genes = Inf to choose all genes
  4544. )
  4545. Mcortex_QC_M_WGCNA_100 <- RunEnrichr(
  4546. Mcortex_QC_M_WGCNA,
  4547. dbs=dbs,
  4548. max_genes = 100 # use max_genes = Inf to choose all genes
  4549. )
  4550. # retrieve the output table
  4551. enrich_df_F_100 <- GetEnrichrTable(Mcortex_QC_F_WGCNA_100)
  4552. enrich_df_M_100 <- GetEnrichrTable(Mcortex_QC_M_WGCNA_100)
  4553. # save to Excel
  4554. write_xlsx(enrich_df_F_100, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_F_enrichR_100.xlsx")
  4555. write_xlsx(enrich_df_M_100, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_M_enrichR_100.xlsx")
  4556. # Filter enrichment table for your database
  4557. db_to_plot <- "GO_Molecular_Function_2023"
  4558. # Clean and organize enrichment table
  4559. enrich_df_F_clean_100 <- enrich_df_F_100 %>%
  4560. dplyr::filter(db == db_to_plot) %>%
  4561. group_by(module) %>%
  4562. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  4563. slice_head(n = 2) %>%
  4564. ungroup() %>%
  4565. mutate(
  4566. # Remove "(GO:xxxx)" suffix
  4567. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  4568. # Wrap long GO terms to two lines if needed
  4569. Term_clean = str_wrap(Term_clean, width = 50),
  4570. # Keep numeric ordering of modules
  4571. module = factor(module, levels = module_order_F),
  4572. # log10 transform Combined.Score for better scaling
  4573. log10_combined = log10(Combined.Score)
  4574. )
  4575. enrich_df_M_clean_100 <- enrich_df_M_100 %>%
  4576. dplyr::filter(db == db_to_plot) %>%
  4577. group_by(module) %>%
  4578. arrange(Adjusted.P.value, desc(Combined.Score), .by_group = TRUE) %>%
  4579. slice_head(n = 2) %>%
  4580. ungroup() %>%
  4581. mutate(
  4582. # Remove "(GO:xxxx)" suffix
  4583. Term_clean = str_remove(Term, "\\s*\\(GO:\\d+\\)"),
  4584. # Wrap long GO terms to two lines if needed
  4585. Term_clean = str_wrap(Term_clean, width = 50),
  4586. # Keep numeric ordering of modules
  4587. module = factor(module, levels = module_order_M),
  4588. # log10 transform Combined.Score for better scaling
  4589. log10_combined = log10(Combined.Score)
  4590. )
  4591. # Reorder terms so they're grouped by module, with best p-values at top
  4592. enrich_df_F_clean_100 <- enrich_df_F_clean_100 %>%
  4593. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  4594. enrich_df_M_clean_100 <- enrich_df_M_clean_100 %>%
  4595. mutate(Term_clean = fct_reorder(Term_clean, as.numeric(module), .desc = TRUE))
  4596. # Plot
  4597. p <- ggplot(enrich_df_F_clean_100,
  4598. aes(x = module, y = Term_clean,
  4599. size = log10_combined)) +
  4600. # Main points: filled by -log10(FDR)
  4601. geom_point(
  4602. aes(fill = -log10(Adjusted.P.value),
  4603. shape = Adjusted.P.value <= 0.05),
  4604. color = "black", alpha = 0.9, stroke = 0.7
  4605. ) +
  4606. # Set shapes manually: filled circle for sig, hollow for ns
  4607. scale_shape_manual(
  4608. values = c("TRUE" = 21, "FALSE" = 1),
  4609. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  4610. name = "Significance"
  4611. ) +
  4612. scale_fill_stepsn(
  4613. colors = rev(viridis::magma(256)),
  4614. name = expression(-log[10]("FDR"))
  4615. ) +
  4616. scale_size_continuous(
  4617. name = expression(log[10]("Enrichment"))
  4618. ) +
  4619. theme_minimal(base_size = 13) +
  4620. theme(
  4621. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  4622. axis.text.y = element_text(size = 11),
  4623. legend.position = "right"
  4624. ) +
  4625. labs(
  4626. title = paste0("Sst-IN_F - ", db_to_plot),
  4627. x = "Module",
  4628. y = "GO Term"
  4629. )
  4630. q <- ggplot(enrich_df_M_clean_100,
  4631. aes(x = module, y = Term_clean,
  4632. size = log10_combined)) +
  4633. # Main points: filled by -log10(FDR)
  4634. geom_point(
  4635. aes(fill = -log10(Adjusted.P.value),
  4636. shape = Adjusted.P.value <= 0.05),
  4637. color = "black", alpha = 0.9, stroke = 0.7
  4638. ) +
  4639. # Set shapes manually: filled circle for sig, hollow for ns
  4640. scale_shape_manual(
  4641. values = c("TRUE" = 21, "FALSE" = 1),
  4642. labels = c("TRUE" = "FDR ≤ 0.05", "FALSE" = "FDR > 0.05"),
  4643. name = "Significance"
  4644. ) +
  4645. scale_fill_stepsn(
  4646. colors = rev(viridis::magma(256)),
  4647. name = expression(-log[10]("FDR"))
  4648. ) +
  4649. scale_size_continuous(
  4650. name = expression(log[10]("Enrichment"))
  4651. ) +
  4652. theme_minimal(base_size = 13) +
  4653. theme(
  4654. axis.text.x = element_text(angle = 45, hjust = 1, size = 13),
  4655. axis.text.y = element_text(size = 11),
  4656. legend.position = "right"
  4657. ) +
  4658. labs(
  4659. title = paste0("Sst-IN_M - ", db_to_plot),
  4660. x = "Module",
  4661. y = "GO Term"
  4662. )
  4663. print(p)
  4664. print(q)
  4665. ```
  4666. Finding corresponding modules between male and female
  4667. ```{r}
  4668. library(readxl)
  4669. library(stringr)
  4670. # Function to read one Excel file and organize modules
  4671. read_module_file <- function(file_path) {
  4672. sheets <- excel_sheets(file_path)
  4673. # Extract cell type from file name (assumes format like "Glut_M_top100_hubgenes.xlsx")
  4674. cell_type <- str_extract(basename(file_path), "Glut|PV-IN|Sst-IN")
  4675. module_list <- list()
  4676. for (sh in sheets) {
  4677. df <- read_excel(file_path, sheet = sh)
  4678. # Auto-detect gene name column
  4679. gene_col <- grep("gene|symbol|Gene|Symbol", names(df), value = TRUE)[1]
  4680. genes <- unique(df[[gene_col]])
  4681. # Extract module id (e.g., M1, M2, ...)
  4682. module_id <- str_extract(sh, "M\\d+")
  4683. module_list[[module_id]] <- genes
  4684. }
  4685. return(module_list)
  4686. }
  4687. # ---- Read all files ----
  4688. # Modify paths if needed
  4689. male_files <- c("~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_M_top100_hubgenes_copy.xlsx",
  4690. "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_M_top100_hubgenes_copy.xlsx",
  4691. "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_M_top100_hubgenes_copy.xlsx")
  4692. female_files <- c("~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Glut_F_top100_hubgenes_copy.xlsx",
  4693. "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/PV-IN_F_top100_hubgenes_copy.xlsx",
  4694. "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Sst-IN_F_top100_hubgenes_copy.xlsx")
  4695. male_modules <- list()
  4696. female_modules <- list()
  4697. for (file in male_files) {
  4698. cell_type <- str_extract(file, "Glut|PV-IN|Sst-IN")
  4699. male_modules[[cell_type]] <- read_module_file(file)
  4700. }
  4701. for (file in female_files) {
  4702. cell_type <- str_extract(file, "Glut|PV-IN|Sst-IN")
  4703. female_modules[[cell_type]] <- read_module_file(file)
  4704. }
  4705. # Check the vectors
  4706. names(male_modules) # Should show: "Glut" "PV" "Sst"
  4707. names(male_modules$Glut) # Should show: "M1" "M2" "M3" ...
  4708. male_modules$Glut$M1[1:10] # First 10 hub genes
  4709. ## Extract all genes from Seurat object, restrict to genes expressed in at least 5% of cells (to be set as background genes for Fisher's test)
  4710. Mcortex_QC <- readRDS ("~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/RDS_files/Mcortex_QC.rds")
  4711. counts <- GetAssayData(Mcortex_QC, slot = "counts") # raw counts
  4712. pct_cells <- Matrix::rowSums(counts > 0) / ncol(counts)
  4713. background_genes <- names(pct_cells[pct_cells > 0.05])
  4714. length(background_genes) #7404 (without filtering at least 5%, it was 24253 genes total)
  4715. ## Compare Male vs. Female modules by hubgenes
  4716. library(pheatmap)
  4717. library(dplyr)
  4718. # Function to compute Jaccard similarity
  4719. jaccard <- function(x, y) {
  4720. length(intersect(x, y)) / length(union(x, y))
  4721. }
  4722. # Function to compute module comparison for a single cell type
  4723. compare_modules <- function(cell_type, male_modules, female_modules, background_genes) {
  4724. male_mods <- male_modules[[cell_type]]
  4725. female_mods <- female_modules[[cell_type]]
  4726. male_names <- names(male_mods)
  4727. female_names <- names(female_mods)
  4728. # Initialize matrices
  4729. overlap_mat <- matrix(0, nrow = length(male_names), ncol = length(female_names),
  4730. dimnames = list(male_names, female_names))
  4731. jaccard_mat <- overlap_mat
  4732. fisher_mat <- overlap_mat
  4733. # Compute metrics
  4734. for (m in male_names) {
  4735. for (f in female_names) {
  4736. genes_m <- male_mods[[m]]
  4737. genes_f <- female_mods[[f]]
  4738. # Overlap
  4739. overlap_mat[m, f] <- length(intersect(genes_m, genes_f))
  4740. # Jaccard
  4741. jaccard_mat[m, f] <- jaccard(genes_m, genes_f)
  4742. # Fisher exact test
  4743. a <- length(intersect(genes_m, genes_f))
  4744. b <- length(setdiff(genes_m, genes_f))
  4745. c <- length(setdiff(genes_f, genes_m))
  4746. d <- length(background_genes) - (a + b + c)
  4747. fisher_mat[m, f] <- fisher.test(matrix(c(a,b,c,d), nrow = 2))$p.value
  4748. }
  4749. }
  4750. # Identify best female match for each male module (by Jaccard)
  4751. best_matches <- apply(jaccard_mat, 1, function(x) {
  4752. female_names[which.max(x)]
  4753. })
  4754. # Return as list
  4755. return(list(
  4756. overlap = overlap_mat,
  4757. jaccard = jaccard_mat,
  4758. fisher_p = fisher_mat,
  4759. best_match = best_matches
  4760. ))
  4761. }
  4762. # ---- Run comparison for all cell types ----
  4763. cell_types <- names(male_modules)
  4764. results <- list()
  4765. for (ct in cell_types) {
  4766. results[[ct]] <- compare_modules(ct, male_modules, female_modules, background_genes)
  4767. }
  4768. # View Glut results
  4769. results$Glut$overlap # Overlap counts
  4770. results$Glut$jaccard # Jaccard similarity
  4771. results$Glut$fisher_p # Fisher p-values
  4772. results$Glut$best_match # Best female module per male module
  4773. ## Save the best match table
  4774. library(openxlsx)
  4775. wb <- createWorkbook()
  4776. for (ct in cell_types) {
  4777. df <- data.frame(
  4778. Male_Module = names(results[[ct]]$best_match),
  4779. Best_Female_Module = results[[ct]]$best_match,
  4780. stringsAsFactors = FALSE
  4781. )
  4782. addWorksheet(wb, ct)
  4783. writeData(wb, ct, df)
  4784. }
  4785. saveWorkbook(wb, "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Male_vs_Female_Module_BestMatches.xlsx", overwrite = TRUE)
  4786. ## Plot Heatmap
  4787. library(pheatmap)
  4788. # Function to plot enhanced heatmap for one cell type
  4789. plot_module_heatmap <- function(cell_type, results, fisher_alpha = 0.05) {
  4790. # Extract matrices
  4791. jaccard_mat <- results[[cell_type]]$jaccard
  4792. overlap_mat <- results[[cell_type]]$overlap
  4793. fisher_mat <- results[[cell_type]]$fisher_p
  4794. # Create matrix of labels: overlap counts + optional significance
  4795. label_mat <- matrix("", nrow = nrow(overlap_mat), ncol = ncol(overlap_mat),
  4796. dimnames = dimnames(overlap_mat))
  4797. for (i in 1:nrow(overlap_mat)) {
  4798. for (j in 1:ncol(overlap_mat)) {
  4799. sig_star <- ifelse(fisher_mat[i,j] < fisher_alpha, "*", "")
  4800. label_mat[i,j] <- paste0(overlap_mat[i,j], sig_star)
  4801. }
  4802. }
  4803. # Plot heatmap
  4804. pheatmap(jaccard_mat,
  4805. display_numbers = label_mat, # overlay counts + significance
  4806. number_color = "black",
  4807. main = paste0(cell_type, " Male vs Female Module Similarity"),
  4808. cluster_rows = TRUE,
  4809. cluster_cols = TRUE,
  4810. fontsize_number = 10,
  4811. color = colorRampPalette(c("white", "steelblue"))(50),
  4812. border_color = "grey60",
  4813. fontsize = 12)
  4814. }
  4815. # ---- Plot for all cell types ---- (Heatmap color is Jaccard similarity in 0-1 scddale, numbers inside cells means overlap count, * indicates Fisher p-value <0.05, meaning significant overlap; Rows = male modules, Columns = female modules)
  4816. for (ct in names(results)) {
  4817. plot_module_heatmap(ct, results)
  4818. }
  4819. ## Generate list of overlapping genes between male vs. female modules
  4820. get_common_genes <- function(cell_type, male_modules, female_modules) {
  4821. male_mods <- male_modules[[cell_type]]
  4822. female_mods <- female_modules[[cell_type]]
  4823. common_genes <- list()
  4824. for (m in names(male_mods)) {
  4825. for (f in names(female_mods)) {
  4826. common_genes[[paste0(m, "_vs_", f)]] <- intersect(male_mods[[m]], female_mods[[f]])
  4827. }
  4828. }
  4829. return(common_genes)
  4830. }
  4831. # List the common genes
  4832. common_genes_glut <- get_common_genes("Glut", male_modules, female_modules)
  4833. common_genes_PV <- get_common_genes("PV-IN", male_modules, female_modules)
  4834. common_genes_Sst <- get_common_genes("Sst-IN", male_modules, female_modules)
  4835. # Generate excel file with common gene list
  4836. library(openxlsx)
  4837. write_common_genes_excel <- function(male_modules, female_modules, file = "~/Hahn_Winter/HyowonChoi/RStudioServer/Risperidone_Proj/R_analysis/hdWGCNA/Male_vs_Female_Overlap_Genes.xlsx") {
  4838. wb <- createWorkbook()
  4839. for (ct in names(male_modules)) {
  4840. male_mods <- male_modules[[ct]]
  4841. female_mods <- female_modules[[ct]]
  4842. df_list <- list()
  4843. for (m in names(male_mods)) {
  4844. for (f in names(female_mods)) {
  4845. overlap <- intersect(male_mods[[m]], female_mods[[f]])
  4846. df_list[[paste0(m, "_vs_", f)]] <- paste(overlap, collapse = ", ")
  4847. }
  4848. }
  4849. df <- data.frame(
  4850. Module_Comparison = names(df_list),
  4851. Overlapping_Genes = unlist(df_list),
  4852. stringsAsFactors = FALSE
  4853. )
  4854. addWorksheet(wb, ct)
  4855. writeData(wb, ct, df)
  4856. }
  4857. saveWorkbook(wb, file, overwrite = TRUE)
  4858. }
  4859. write_common_genes_excel(male_modules, female_modules)
  4860. ```
  4861. Checking for module redundancy/module similarity within sex and cell type
  4862. ```{r}
  4863. # Compare modules within a single module list (e.g., male Glut)
  4864. compare_within_modules <- function(module_list, background_genes) {
  4865. mod_names <- names(module_list)
  4866. # Initialize matrices
  4867. overlap_mat <- matrix(0, nrow = length(mod_names), ncol = length(mod_names),
  4868. dimnames = list(mod_names, mod_names))
  4869. jaccard_mat <- overlap_mat
  4870. fisher_mat <- overlap_mat
  4871. for (m1 in mod_names) {
  4872. for (m2 in mod_names) {
  4873. genes1 <- module_list[[m1]]
  4874. genes2 <- module_list[[m2]]
  4875. # Overlap
  4876. a <- length(intersect(genes1, genes2))
  4877. b <- length(setdiff(genes1, genes2))
  4878. c <- length(setdiff(genes2, genes1))
  4879. d <- length(background_genes) - (a + b + c)
  4880. overlap_mat[m1, m2] <- a
  4881. jaccard_mat[m1, m2] <- a / length(union(genes1, genes2))
  4882. # Fisher exact test
  4883. fisher_mat[m1, m2] <- fisher.test(matrix(c(a, b, c, d), nrow = 2))$p.value
  4884. }
  4885. }
  4886. return(list(
  4887. overlap = overlap_mat,
  4888. jaccard = jaccard_mat,
  4889. fisher_p = fisher_mat
  4890. ))
  4891. }
  4892. # Male Glut
  4893. male_glut_results <- compare_within_modules(male_modules$Glut, background_genes)
  4894. male_glut_results$overlap
  4895. male_glut_results$jaccard
  4896. male_glut_results$fisher_p
  4897. # Female Glut
  4898. female_glut_results <- compare_within_modules(female_modules$Glut, background_genes)
  4899. female_glut_results$overlap
  4900. female_glut_results$jaccard
  4901. female_glut_results$fisher_p
  4902. # Male PV-IN
  4903. male_PV_results <- compare_within_modules(male_modules[["PV-IN"]], background_genes)
  4904. male_PV_results$overlap
  4905. male_PV_results$jaccard
  4906. male_PV_results$fisher_p
  4907. # Female PV-IN
  4908. female_PV_results <- compare_within_modules(female_modules[["PV-IN"]], background_genes)
  4909. female_PV_results$overlap
  4910. female_PV_results$jaccard
  4911. female_PV_results$fisher_p
  4912. # Male Sst-IN
  4913. male_Sst_results <- compare_within_modules(male_modules[["Sst-IN"]], background_genes)
  4914. male_Sst_results$overlap
  4915. male_Sst_results$jaccard
  4916. male_Sst_results$fisher_p
  4917. # Female Sst-IN
  4918. female_Sst_results <- compare_within_modules(female_modules[["Sst-IN"]], background_genes)
  4919. female_Sst_results$overlap
  4920. female_Sst_results$jaccard
  4921. female_Sst_results$fisher_p
  4922. # Enhanced heatmap with overlap text
  4923. plot_within_heatmap <- function(results, cell_type, sex, fisher_alpha = 0.05) {
  4924. jaccard_mat <- results$jaccard
  4925. overlap_mat <- results$overlap
  4926. fisher_mat <- results$fisher_p
  4927. # Add overlap + significance
  4928. label_mat <- matrix("", nrow = nrow(overlap_mat), ncol = ncol(overlap_mat),
  4929. dimnames = dimnames(overlap_mat)

Antipsychotic_github.Rmd at commit b768f3a, no license · at the source

Overview

Authors: Abneil D Alicea-Pauneto1,2, Hyowon Choi1,2,3, Wenyu Zhang1,2, Xinjian Li4, Laurence A Busque1,2, Mingxuan Li5, Andrew Wu1,2, Evan Zhang6, Adam D Marc1,2, Jonathan Preall6, Kuan Hong Wang7, Robert E Featherstone8, Steven J Siegel8, Chang-Gyu Hahn1,2,3, Karin E Borgmann-Winter1,2,3
ORCID iDs: Kuan Hong Wang
  1. Department of Neuroscience, Thomas Jefferson University, Philadelphia, PA USA
  2. Vickie & Jack Farber Institute for Neuroscience, Thomas Jefferson University, Philadelphia, PA USA
  3. Department of Psychiatry and Human Behavior, Sidney Kimmel Medical College, Thomas Jefferson University, Philadelphia, PA USA
  4. Department of Neurology of the Second Affiliated Hospital, Interdisciplinary Institute of Neuroscience and Technology, Zhejiang University School of Medicine, Hangzhou, China
  5. Department of Computer Science, Hertford College, University of Oxford, Oxford, UK
  6. Cold Spring Harbor Laboratory Cancer Center, Cold Spring Harbor, NY USA
  7. Department of Neuroscience, University of Rochester Medical Center, Rochester, NY USA
  8. Department of Psychiatry and the Behavioral Sciences, University of Southern California, Los Angeles, CA USA
Dates: received 23 January 2026; accepted 23 June 2026; published online 8 July 2026; in print September 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1038/s41386-026-02483-2 · PMID 42420423 · PMCID PMC13486667 · OpenAlex W7167711737
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: genetics / omics (modality), human (organism), mouse (organism), schizophrenia / psychosis (population)
Methods: Statistics, Smoothing, state filtering, decompositions, fMRI & imaging, Single-unit activity, calcium imaging, Spectral & time-frequency
Keywords: Synaptic development, Cellular neuroscience, Genetics of the nervous system
MeSH: Antipsychotic Agents*, Cerebral Cortex*, Risperidone*, Animals, Anxiety, Female, Male, Mice, Mice, Inbred C57BL, Neurons (* major topic)
Topic: Neuroscience and Neuropharmacology Research (Cellular and Molecular Neuroscience, Neuroscience), according to OpenAlex
Funding: U.S. Department of Health & Human Services | NIH | National Institute of Mental Health (NIMH) (RO1MH138995, RO1MH116463); NIGMS NIH HHS (T32 GM008562); NIMH NIH HHS (R01 MH138995, R01 MH116463); U.S. Department of Health & Human Services | NIH | Eunice Kennedy Shriver National Institute of Child Health and Human Development (NICHD) (T32GM008562)
Citations: not cited yet (Europe PMC); 56 references in the paper

Abstract

Since the introduction of second-generation antipsychotics, antipsychotics have been increasingly prescribed for children and adolescents, raising concerns about their long-term impact on neurodevelopment. Antipsychotics block dopaminergic and serotonergic receptors, potentially disrupting the maturation of neurocognitive processes, which is a public health concern. Previous studies have reported that adolescent antipsychotic treatment can cause persistent neurocognitive dysfunction in rodents, yet the neurobiological underpinnings remain unknown. To address this, we administered risperidone, a commonly used antipsychotic, to C57BL/6 mice during adolescence (3 to 6 weeks of age) and examined behavioral and neurobiological outcomes nine weeks post-treatment. Risperidone-treated mice exhibited subtle deficits in behavioral correlates of anxiety-like behavior. In vivo, two-photon calcium imaging of cortical neurons revealed a remarkable increase in the amplitude of calcium events with subtle sex-specific changes in the frequency, consistent with increased neuronal excitability. Single-nucleus RNA-sequencing (snRNA-seq) analyses showed widespread reductions in transcripts for voltage-sensitive and inwardly rectifying potassium channels in both pyramidal neurons and interneurons. Additionally, both cell types exhibited reduced Grin2a and Grin2b, as well as scaffolding proteins, indicative of weakened synaptic connectivity between excitatory and inhibitory neurons. Interestingly, we observed sex-dependent differences in the directionality of correlation between certain gene co-expression modules and risperidone treatment. Our results suggest that adolescent risperidone treatment induces lasting transcriptomic and functional changes associated with altered excitatory-inhibitory neuronal interactions that may underline cognitive and behavioral dysregulations.

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 4 matches between paragraphs and lines of code.

Hahn-BorgmannWinter/Adolescent_antipsychotics

License: none: the authors keep all their rights
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: b768f3a632e45fccec74c82fd5084bdb451ccd50, 26 January 2026
Languages: R (1)
Size: 2 files, 1 script
Software Heritage: not archived
Found in: “Data availability”
Holds: README, 1 notebook
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: clusterProfiler (1 file), cowplot (1 file), DESeq2 (1 file), ggplot2 (1 file), igraph (1 file), patchwork (1 file), pheatmap (1 file), reshape2 (1 file), Seurat (1 file), tidyverse (1 file), WGCNA (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
2 files

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:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 1 script, each with its path and the digest of its content;
  • 4 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 sequence and raw count matrices generated and analyzed for snRNA-seq experiments are deposited to the Gene Expression Omnibus, GSE316091 (https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE316091) (https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE316091). All code used to generate results for snRNA-seq analysis is available at: https://github.com/Hahn-BorgmannWinter/Adolescent_antipsychotics.

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

Recorded: type, language, journal, volume, issue, pages, dates, 15 authors, 3 keywords, 10 MeSH terms, 4 funders, 56 references.

Cite

This paper

Alicea-Pauneto, A. D., Choi, H., Zhang, W., Li, X., Busque, L. A., Li, M., Wu, A., Zhang, E., Marc, A. D., Preall, J., Wang, K. H., Featherstone, R. E., Siegel, S. J., Hahn, C.-G., & Borgmann-Winter, K. E. (2026). Long-term effects of adolescent risperidone treatment on the mouse cortex. Neuropsychopharmacology : official publication of the American College of Neuropsychopharmacology, 51(10), 1844-1854. https://doi.org/10.1038/s41386-026-02483-2

BibTeX

@article{aliceapauneto2026long,
author = {Alicea-Pauneto, Abneil D and Choi, Hyowon and Zhang, Wenyu and Li, Xinjian and Busque, Laurence A and Li, Mingxuan and Wu, Andrew and Zhang, Evan and Marc, Adam D and Preall, Jonathan and Wang, Kuan Hong and Featherstone, Robert E and Siegel, Steven J and Hahn, Chang-Gyu and Borgmann-Winter, Karin E},
title = {{Long-term effects of adolescent risperidone treatment on the mouse cortex}},
journal = {Neuropsychopharmacology : official publication of the American College of Neuropsychopharmacology},
year = {2026},
month = jul,
volume = {51},
number = {10},
pages = {1844--1854},
publisher = {Nature Publishing Group},
issn = {0893-133X},
doi = {10.1038/s41386-026-02483-2},
url = {https://doi.org/10.1038/s41386-026-02483-2},
pmid = {42420423},
pmcid = {PMC13486667}
}

RIS

TY - JOUR
AU - Alicea-Pauneto, Abneil D
AU - Choi, Hyowon
AU - Zhang, Wenyu
AU - Li, Xinjian
AU - Busque, Laurence A
AU - Li, Mingxuan
AU - Wu, Andrew
AU - Zhang, Evan
AU - Marc, Adam D
AU - Preall, Jonathan
AU - Wang, Kuan Hong
AU - Featherstone, Robert E
AU - Siegel, Steven J
AU - Hahn, Chang-Gyu
AU - Borgmann-Winter, Karin E
TI - Long-term effects of adolescent risperidone treatment on the mouse cortex
T2 - Neuropsychopharmacology : official publication of the American College of Neuropsychopharmacology
J2 - Neuropsychopharmacology
PY - 2026
DA - 2026/07/08
VL - 51
IS - 10
SP - 1844
EP - 1854
SN - 0893-133X
PB - Nature Publishing Group
DO - 10.1038/s41386-026-02483-2
UR - https://doi.org/10.1038/s41386-026-02483-2
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41386-026-02483-2",
"type": "article-journal",
"title": "Long-term effects of adolescent risperidone treatment on the mouse cortex",
"container-title": "Neuropsychopharmacology : official publication of the American College of Neuropsychopharmacology",
"author": [
{
"family": "Alicea-Pauneto",
"given": "Abneil D"
},
{
"family": "Choi",
"given": "Hyowon"
},
{
"family": "Zhang",
"given": "Wenyu"
},
{
"family": "Li",
"given": "Xinjian"
},
{
"family": "Busque",
"given": "Laurence A"
},
{
"family": "Li",
"given": "Mingxuan"
},
{
"family": "Wu",
"given": "Andrew"
},
{
"family": "Zhang",
"given": "Evan"
},
{
"family": "Marc",
"given": "Adam D"
},
{
"family": "Preall",
"given": "Jonathan"
},
{
"family": "Wang",
"given": "Kuan Hong"
},
{
"family": "Featherstone",
"given": "Robert E"
},
{
"family": "Siegel",
"given": "Steven J"
},
{
"family": "Hahn",
"given": "Chang-Gyu"
},
{
"family": "Borgmann-Winter",
"given": "Karin E"
}
],
"container-title-short": "Neuropsychopharmacology",
"volume": "51",
"issue": "10",
"page": "1844-1854",
"DOI": "10.1038/s41386-026-02483-2",
"PMID": "42420423",
"PMCID": "PMC13486667",
"ISSN": "0893-133X",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41386-026-02483-2",
"language": "en",
"issued": {
"date-parts": [
[
2026,
7,
8
]
]
}
}

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.1038/s41380-026-03629-w [code]
Maternal fasting during early gestation induces epigenetic alterations and schizophrenia-related phenotypes.
Journal: Molecular psychiatry
In common: WGCNA, igraph, DESeq2, 8 other tools, schizophrenia / psychosis, genetics / omics, mouse, 1 reference
[2] 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: WGCNA, igraph, DESeq2, 8 other tools, genetics / omics, 1 reference
[3] doi:10.1038/s41593-026-02367-0 [code]
A reproducible three-dimensional model of human brain tissue to investigate physiological and disease-associated microglia phenotypes.
Journal: Nature neuroscience
In common: WGCNA, igraph, DESeq2, 8 other tools, 1 reference
[4] doi:10.1016/j.isci.2026.115657 [code]
Integration of machine learning to develop a disulfidptosis model for predicting glioma prognosis, immunotherapy response, and drug.
Journal: iScience
In common: WGCNA, igraph, DESeq2, 8 other tools
[5] doi:10.1038/s41593-026-02384-z [code]
cGAS-mediated type I IFN signaling contributes to disease progression in drug-refractory epilepsy.
Journal: Nature neuroscience
In common: WGCNA, igraph, clusterProfiler, 7 other tools, mouse, 1 reference
[6] doi:10.1038/s44318-026-00806-z [code]
Interspecific diversity in the neuronal composition of the mammalian cortex arises from heterochrony in neurogenesis.
Journal: The EMBO journal
In common: WGCNA, igraph, DESeq2, 8 other tools
[7] doi:10.1038/s41467-026-73305-8 [code]
Comparative analysis of the cellular landscape in mammalian striatum.
Journal: Nature communications
In common: WGCNA, DESeq2, clusterProfiler, 7 other tools, genetics / omics, mouse
[8] doi:10.1093/bioinformatics/btag592 [code]
Network-based stratification of allele-specific expression reveals patient subgroups in Huntington's disease.
Journal: Bioinformatics (Oxford, England)
In common: WGCNA, igraph, DESeq2, 7 other tools, genetics / omics
[9] doi:10.1038/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: WGCNA, igraph, DESeq2, 7 other tools, mouse
[10] doi:10.1126/sciadv.aeg3223 [code]
The extreme diversity of retinal amacrine cells has deep evolutionary roots.
Journal: Science advances
In common: WGCNA, igraph, DESeq2, 7 other tools, genetics / omics

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.

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: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.