OSCR

MIC-Drop-seq: scalable single-cell phenotyping of mutant vertebrate embryos.

Code ↔ Paper

20 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 20 matches
  1. [1] § Results › MIC-Drop-seq enables multiplexed embryo phenotyping ↔ Figure1_MIC-Drop-seq.Rmd, lines 907–958 · score 0.81 · hoxa9a, hoxb9a, hoxc6b, spinal cord, identified cdx4, clusters
  2. [2] § Methods › Dimensionality reduction, clustering and cell cluster labeling ↔ Figure1_MIC-Drop-seq.Rmd, lines 551–607 · score 0.81 · transfer anchors, 21–26, Predicted cell, reference atlas, Daniocell, hpf
  3. [3] § Methods › Determination of CRISPR editing frequency ↔ Figure1_MIC-Drop-seq.Rmd, lines 442–484 · score 0.80 · rhAmpSeq, cut site, editing frequency, Genomic DNA, indels, sequencing
  4. [4] § Results › MIC-Drop-seq reveals transcriptional and cellular phenotypes ↔ Figure3_MIC-Drop-seq.Rmd, lines 473–498 · score 0.78 · optic tectum, nkx2.7, gata2a, sox11b, dlx1a expression, hypothalamus
  5. [5] § Methods › Differential cell abundance analysis ↔ Figure2_MIC-Drop-seq.Rmd, lines 951–1019 · score 0.76 · Poisson Lognormal models, biological replicate, cell abundance, Monocle3, Hooke, genotype
  6. [6] § Methods › Statistics and reproducibility ↔ Figure4_MIC-Drop-seq.Rmd, lines 912–959 · score 0.75 · pairwise comparisons, post hoc, mRNA, Tukey, rescue, ANOVA
  7. [7] § Results › MIC-Drop-seq reveals transcriptional and cellular phenotypes ↔ Figure3_MIC-Drop-seq.Rmd, lines 473–498 · score 0.74 · optic tectum, nkx2.7, gata2a, sox11b, dlx1a expression, hypothalamus
  8. [8] § Methods › In situ imaging and quantification ↔ Figure3_MIC-Drop-seq.Rmd, lines 285–312 · score 0.71 · pixel area, dlx1a, gata2a, Stained, trunk, head
  9. [9] § Results › MIC-Drop-seq enables multiplexed embryo phenotyping ↔ Figure1_MIC-Drop-seq.Rmd, lines 442–484 · score 0.71 · cut sites, genomic DNA, editing frequency, genotypic composition, bulk, indel
  10. [10] § Methods › Dimensionality reduction, clustering and cell cluster labeling ↔ Figure1_MIC-Drop-seq.Rmd, lines 529–549 · score 0.71 · variable features, remove cells, dimensionality reduction, Seurat, doublets, gRNA
  11. [11] § Methods › Differential gene expression analysis ↔ Figure2_MIC-Drop-seq.Rmd, lines 664–749 · score 0.70 · edgeR, glmQLFit, aggregate, pseudobulk, FDR, gene expression
  12. [12] § Results › MIC-Drop-seq enables multiplexed embryo phenotyping ↔ Figure1_MIC-Drop-seq.Rmd, lines 698–727 · score 0.65 · presomitic mesoderm, tbx16 mutant, tbxta mutant, tyr, accumulation, depletion
  13. [13] § Results › MIC-Drop-seq detects indirect developmental effects ↔ Figure4_MIC-Drop-seq.Rmd, lines 912–959 · score 0.64 · post hoc, mRNA, way ANOVA, CVP, Tukey, outliers
  14. [14] § Methods › Gene expression matrix generation and genotype assignment ↔ Figure2_MIC-Drop-seq.Rmd, lines 159–241 · score 0.62 · gRNAs, multiple gene, mutant genotype, protospacer, doublet, detection
  15. [15] § Results › MIC-Drop-seq reveals transcriptional and cellular phenotypes ↔ Figure4_MIC-Drop-seq.Rmd, lines 169–292 · score 0.61 · presomitic mesoderm, optic tectum, myotome, sclerotome, dorsal, secreted
  16. [16] § Results › MIC-Drop-seq reveals transcriptional and cellular phenotypes ↔ Figure4_MIC-Drop-seq.Rmd, lines 169–292 · score 0.60 · optic tectum, hindbrain, neurons, ventral, MIC Drop seq, precursors
  17. [17] § Results › MIC-Drop-seq detects indirect developmental effects ↔ Figure4_MIC-Drop-seq.Rmd, lines 839–888 · score 0.59 · phenotype class, DEG thresholds, cell extrinsic, lineage, classification, seq
  18. [18] § Results › MIC-Drop-seq detects indirect developmental effects ↔ Figure4_MIC-Drop-seq.Rmd, lines 839–888 · score 0.58 · lineage intrinsic, cell intrinsic, cell extrinsic, threshold, DEGs, classified
  19. [19] § Methods › Determination of cell extrinsic and cell intrinsic effects ↔ Figure4_MIC-Drop-seq.Rmd, lines 635–666 · score 0.52 · cell intrinsic, cell extrinsic, threshold, lineage, classified
  20. [20] § Results › MIC-Drop-seq enables multiplexed embryo phenotyping ↔ Figure1_MIC-Drop-seq.Rmd, lines 698–727 · score 0.52 · hoxb1b, foxa2, hand2, tbx16, tyr, tbxta

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 · 1,137 lines · 37 KB · MIT · 7 matches

  1. ---
  2. title: "Figure 1: MIC-Drop-seq Proof-of-Concept Validation"
  3. author: "Clay Carey"
  4. date: "2024-05-08"
  5. output: html_document
  6. ---
  7. First- set your base directory to the folder with the downloaded 'input_data" folder. This contains all source data to run the code to reprodce figures.
  8. ```{r setup}
  9. # Set working directory for analysis- you MUST download the input dat aand set this directory manually for the code to work
  10. knitr::opts_knit$set(root.dir = "")
  11. ```
  12. # =============================================================================
  13. # SECTION 1: LOAD LIBRARIES
  14. # =============================================================================
  15. ```{r load-libraries, message=FALSE, warning=FALSE}
  16. # Core data manipulation
  17. library(Seurat)
  18. library(dplyr)
  19. library(tidyverse)
  20. library(stringr)
  21. # Single-cell analysis
  22. library(scCustomize)
  23. library(dittoSeq)
  24. library(scDblFinder)
  25. library(SingleCellExperiment)
  26. # Visualization
  27. library(ggplot2)
  28. library(ggridges)
  29. library(viridis)
  30. library(EnhancedVolcano)
  31. # Differential expression
  32. library(edgeR)
  33. library(presto)
  34. # Table formatting
  35. library(gtExtras)
  36. ```
  37. # =============================================================================
  38. # SECTION 2: LOAD AND PROCESS gRNA DATA
  39. # =============================================================================
  40. ## Load Cell Ranger CRISPR output
  41. Cell Ranger generates a "protospacer_calls_per_cell.csv" file that contains:
  42. - cell_barcode: 10X cell barcode
  43. - feature_call: pipe-delimited list of detected gRNA IDs
  44. - num_umis: pipe-delimited list of UMI counts per gRNA
  45. ```{r load-grna-data}
  46. # Load gRNA detection data from Cell Ranger
  47. pilot_CRISPR_data <- read.csv(file = "input_data/protospacer_calls_per_cell.csv")
  48. # Load experimental configuration (maps gRNA IDs to target genes)
  49. exp_config <- read.csv(file = "input_data/feature_reference.csv")
  50. head(pilot_CRISPR_data)
  51. head(exp_config)
  52. ```
  53. ## Parse gRNA detection data
  54. Cell Ranger stores multiple gRNAs per cell as pipe-delimited strings.
  55. We split these into separate columns for downstream classification.
  56. ```{r parse-grna-function}
  57. #' Process Cell Ranger CRISPR output
  58. #'
  59. #' Splits pipe-delimited feature_call and num_umis columns into
  60. #' separate columns (up to 20 features per cell)
  61. #'
  62. #' @param data Dataframe from Cell Ranger protospacer_calls_per_cell.csv
  63. #' @return Dataframe with feature_call_1:20 and num_umis_1:20 columns
  64. process_data <- function(data) {
  65. max_features <- 20
  66. feature_cols <- paste0("feature_call_", 1:max_features)
  67. # Split feature_call column (gRNA IDs)
  68. split_features <- strsplit(as.character(data$feature_call), "\\|")
  69. for (i in 1:max_features) {
  70. data[, feature_cols[i]] <- sapply(split_features, function(x) {
  71. if (length(x) >= i) return(x[i]) else return(0)
  72. })
  73. }
  74. # Split num_umis column (UMI counts)
  75. max_umis <- 20
  76. umis_cols <- paste0("num_umis_", 1:max_umis)
  77. split_umis <- strsplit(as.character(data$num_umis), "\\|")
  78. for (i in 1:max_umis) {
  79. data[, umis_cols[i]] <- sapply(split_umis, function(x) {
  80. if (length(x) >= i) return(x[i]) else return(0)
  81. })
  82. }
  83. return(data)
  84. }
  85. # Apply parsing function
  86. CRdata <- process_data(pilot_CRISPR_data)
  87. ```
  88. ## Classify cells by genotype
  89. For each cell, determine if gRNAs target a single gene or multiple genes.
  90. - Single gene → Assign that gene as genotype
  91. - Multiple genes → Classify as "Multiple" (doublet)
  92. - No gRNA → Will be classified as "ND" (Not Detected) later
  93. ```{r classify-genotypes}
  94. #' Classify cells by gRNA detection pattern
  95. #'
  96. #' Checks each cell across all feature_call columns and determines
  97. #' whether detected gRNAs target a single gene or multiple genes
  98. #'
  99. #' @param df Parsed CRISPR dataframe with feature_call_1:20 columns
  100. #' @param proto_ids Vector of gRNA IDs from experimental config
  101. #' @return Dataframe with 'class' column (gene name or "Multiple")
  102. classifier <- function(df, proto_ids) {
  103. # Create binary detection columns for each gRNA
  104. for (proto in proto_ids) {
  105. df <- df %>%
  106. mutate(!!paste0(proto, "_count") := case_when(
  107. feature_call_1 == proto ~ 1,
  108. feature_call_2 == proto ~ 1,
  109. feature_call_3 == proto ~ 1,
  110. feature_call_4 == proto ~ 1,
  111. feature_call_5 == proto ~ 1,
  112. feature_call_6 == proto ~ 1,
  113. feature_call_7 == proto ~ 1,
  114. feature_call_8 == proto ~ 1,
  115. feature_call_9 == proto ~ 1,
  116. feature_call_10 == proto ~ 1,
  117. feature_call_11 == proto ~ 1,
  118. feature_call_12 == proto ~ 1,
  119. feature_call_13 == proto ~ 1,
  120. feature_call_14 == proto ~ 1,
  121. feature_call_15 == proto ~ 1,
  122. feature_call_16 == proto ~ 1,
  123. feature_call_17 == proto ~ 1,
  124. feature_call_18 == proto ~ 1,
  125. feature_call_19 == proto ~ 1,
  126. feature_call_20 == proto ~ 1,
  127. TRUE ~ 0
  128. ))
  129. }
  130. # Extract detection counts and identify detected gRNAs per cell
  131. temp_df <- select(df, cell_barcode, ends_with("_count"))
  132. temp_df <- temp_df %>%
  133. pivot_longer(-cell_barcode) %>%
  134. filter(value == 1)
  135. # Summarize detected gRNAs per cell
  136. temp_df <- temp_df %>%
  137. group_by(cell_barcode) %>%
  138. summarise(class = paste(unique(name), collapse = ","))
  139. # Clean up gRNA names to gene names
  140. temp_df$all_protos <- temp_df$class
  141. temp_df$all_protos <- gsub("_count", "", temp_df$all_protos)
  142. temp_df$class <- gsub("-\\d+_count", "", temp_df$class)
  143. # Separate into columns to check for multiple targets
  144. temp_df <- separate(temp_df,
  145. class,
  146. into = c("count1", "count2", "count3", "count4", "count5"),
  147. sep = ",",
  148. extra = "merge")
  149. # Classify based on target gene consistency
  150. temp_df <- mutate(temp_df, class = case_when(
  151. is.na(count2) ~ count1,
  152. count1 == count2 & is.na(count3) ~ count1,
  153. count1 == count2 & count2 == count3 & is.na(count4) ~ count1,
  154. count1 == count2 & count2 == count3 & count3 == count4 & is.na(count5) ~ count1,
  155. TRUE ~ "Multiple" # Different genes detected = doublet
  156. ))
  157. # Merge back with original data
  158. temp_df <- select(temp_df, cell_barcode, all_protos, class)
  159. df <- left_join(df, temp_df, by = "cell_barcode")
  160. df <- select(df, cell_barcode, num_features, feature_call, num_umis, all_protos, class)
  161. return(df)
  162. }
  163. # Apply classification
  164. CRdata_classified <- classifier(CRdata, unique(exp_config$id))
  165. head(CRdata_classified)
  166. ```
  167. # =============================================================================
  168. # SECTION 3: CREATE SEURAT OBJECT AND ADD METADATA
  169. # =============================================================================
  170. ## Load 10X data
  171. Data contains two assays:
  172. 1. Gene Expression (RNA)
  173. 2. CRISPR Guide Capture (gRNA counts)
  174. ```{r load-10x-data}
  175. # Read both assays from Cell Ranger output
  176. tenx_data <- Read10X(data.dir = "input_data/micdrop_overload_matrix")
  177. tenx_data.gex <- tenx_data$`Gene Expression`
  178. tenx_data.crispr <- tenx_data$`CRISPR Guide Capture`
  179. # Create Seurat object with RNA assay
  180. mdp <- CreateSeuratObject(counts = tenx_data.gex, min.cells = 3)
  181. # Add CRISPR assay
  182. mdp[['CRISPR']] <- CreateAssayObject(counts = tenx_data.crispr)
  183. ```
  184. ## Merge gRNA classifications into Seurat metadata
  185. ```{r add-grna-metadata}
  186. # Extract metadata and add cell barcodes
  187. mdp_meta <- [email hidden]
  188. mdp_meta$cell_barcode <- rownames(mdp_meta)
  189. # Merge with gRNA classifications
  190. mdp_meta <- left_join(mdp_meta, CRdata_classified, by = "cell_barcode")
  191. rownames(mdp_meta) <- mdp_meta$cell_barcode
  192. # Add back to Seurat object
  193. [email hidden] <- mdp_meta
  194. # Clean up classifications
  195. [email hidden] <- [email hidden] %>%
  196. mutate(
  197. class = ifelse(is.na(class), "ND", class), # Cells without gRNA
  198. class = ifelse(class == "Non-Targeting", "tyr", class) # Rename control
  199. )
  200. table(mdp$class)
  201. ```
  202. # =============================================================================
  203. # SECTION 4: QUALITY CONTROL
  204. # =============================================================================
  205. ## Calculate QC metrics
  206. ```{r calculate-qc}
  207. # Calculate mitochondrial percentage
  208. mdp[["percent.mt"]] <- PercentageFeatureSet(mdp, pattern = "^mt-")
  209. # Visualize QC metrics
  210. DefaultAssay(mdp) <- "RNA"
  211. VlnPlot(mdp, features = c("percent.mt", "nCount_RNA", "nFeature_RNA"))
  212. ```
  213. ## Filter low-quality cells
  214. ```{r filter-cells}
  215. # Apply quality thresholds
  216. mdp <- subset(mdp, subset = nFeature_RNA > 200 &
  217. nFeature_RNA < 9000 &
  218. percent.mt < 15)
  219. cat("Cells after filtering:", ncol(mdp), "\n")
  220. ```
  221. # =============================================================================
  222. # SECTION 5: FIGURE 1B - gRNA UMI DISTRIBUTION
  223. # =============================================================================
  224. Distribution of gRNA UMI counts in cells with detected gRNAs
  225. ```{r figure1B, fig.width=2, fig.height=2}
  226. mdp_meta <- [email hidden]
  227. mdp_meta %>%
  228. filter(class != "ND") %>%
  229. ggplot(aes(x = nCount_CRISPR)) +
  230. geom_histogram(binwidth = 1, fill = "black") +
  231. scale_x_continuous(limits = c(0, 75)) +
  232. theme_classic() +
  233. theme(
  234. text = element_text(family = "Helvetica", size = 12, color = "black"),
  235. axis.text = element_text(size = 12, color = "black", family = "Helvetica"),
  236. axis.title = element_text(size = 12)
  237. ) +
  238. xlab("gRNA UMIs") +
  239. ylab("Cell Count")
  240. ggsave(filename = "outputs_fig1/Figure_1B.eps",
  241. device = "ps",
  242. width = 2, height = 2, units = 'in',
  243. bg = "transparent")
  244. ```
  245. # =============================================================================
  246. # SECTION 6: FIGURE 1C - gRNA TARGET DISTRIBUTION
  247. # =============================================================================
  248. Cells classified by number of gene targets detected
  249. - 0: No gRNA detected
  250. - 1: Single gene target (expected for MIC-Drop)
  251. - 2+: Multiple gene targets (doublets)
  252. ```{r figure1C, fig.width=1.5, fig.height=2}
  253. # Categorize cells by number of targets
  254. mdp_meta <- [email hidden] %>%
  255. mutate(type = case_when(
  256. class == "ND" ~ "0",
  257. class == "Multiple" ~ "2+",
  258. TRUE ~ "1"
  259. ))
  260. # Plot distribution
  261. mdp_meta %>%
  262. dplyr::count(type) %>%
  263. ggplot() +
  264. geom_bar(aes(x = type, y = n / 1000), stat = "identity", fill = "black") +
  265. theme_classic() +
  266. xlab("gRNA targets") +
  267. ylab("Cells (thousands)") +
  268. scale_y_continuous(labels = scales::comma) +
  269. theme(
  270. axis.text = element_text(size = 12, family = "Helvetica", color = "black"),
  271. axis.title = element_text(size = 12, family = "Helvetica")
  272. )
  273. ggsave(filename = "outputs_fig1/Figure_1C.eps",
  274. device = "ps",
  275. width = 1.5, height = 2, units = 'in',
  276. bg = "transparent")
  277. ```
  278. # =============================================================================
  279. # SECTION 7: DOUBLET DETECTION WITH scDblFinder
  280. # =============================================================================
  281. Use computational doublet detection to validate that cells with
  282. multiple gRNA targets are enriched for doublets
  283. ```{r doublet-detection}
  284. # Prepare for scDblFinder (requires matching order)
  285. correctorder <- dimnames(mdp@assays$RNA$counts)[[2]]
  286. mdp <- mdp[, correctorder]
  287. [email hidden] <- [email hidden][match(correctorder, rownames([email hidden])), ]
  288. # Normalize and scale for doublet detection
  289. mdp <- NormalizeData(mdp)
  290. mdp <- ScaleData(mdp)
  291. # Convert to SingleCellExperiment and run scDblFinder
  292. mdp_sce <- as.SingleCellExperiment(mdp)
  293. mdp_sce <- scDblFinder(mdp_sce)
  294. mdp_sce <- as.Seurat(mdp_sce)
  295. # Extract doublet information
  296. dub_info <- data.frame([email hidden]) %>%
  297. select(scDblFinder.class, scDblFinder.score,
  298. scDblFinder.weighted, scDblFinder.cxds_score, class) %>%
  299. mutate(type = case_when(
  300. class == "Multiple" ~ "2+",
  301. TRUE ~ "0-1"
  302. ))
  303. ```
  304. ## Figure S2A: Doublet score distribution
  305. Cells with multiple gRNA targets show higher doublet scores
  306. ```{r figureS2A, fig.width=4, fig.height=3}
  307. ggplot(dub_info, aes(x = scDblFinder.weighted, fill = type)) +
  308. geom_density(alpha = 0.8, position = "identity", color = NA) +
  309. scale_fill_manual(values = c("0-1" = "black", "2+" = "grey")) +
  310. xlab("scDblFinder Doublet Score") +
  311. ylab("Density") +
  312. theme_classic() +
  313. guides(fill = guide_legend(title = "gRNA targets")) +
  314. theme(
  315. axis.text = element_text(size = 12, family = "Helvetica", color = "black"),
  316. axis.title = element_text(size = 12, family = "Helvetica"),
  317. legend.text = element_text(size = 12, family = "Helvetica")
  318. )
  319. ggsave(filename = "outputs_fig1/Figure_S2A.eps",
  320. device = "ps",
  321. width = 4, height = 3, units = 'in',
  322. bg = "transparent")
  323. ```
  324. ## Figure S2B: Doublet classification by gRNA pattern
  325. ```{r figureS2B, fig.width=3.5, fig.height=3}
  326. # Calculate doublet proportions
  327. class_freq <- dub_info %>%
  328. select(type, scDblFinder.class) %>%
  329. group_by(type) %>%
  330. dplyr::count(scDblFinder.class) %>%
  331. left_join(
  332. dub_info %>%
  333. select(type, scDblFinder.class) %>%
  334. group_by(type) %>%
  335. dplyr::count(scDblFinder.class) %>%
  336. summarize(tot = sum(n)),
  337. by = "type"
  338. ) %>%
  339. mutate(pct = n / tot)
  340. # Plot proportions
  341. ggplot(class_freq, aes(x = type, fill = scDblFinder.class, y = pct)) +
  342. scale_fill_manual(values = c("singlet" = "black", "doublet" = "grey")) +
  343. geom_bar(position = "stack", stat = "identity") +
  344. theme_classic() +
  345. theme(
  346. axis.text = element_text(size = 12, family = "Helvetica", color = "black"),
  347. axis.title = element_text(size = 12, family = "Helvetica"),
  348. legend.text = element_text(size = 12, family = "Helvetica")
  349. ) +
  350. guides(fill = guide_legend(title = "scDblFinder Class")) +
  351. ylab("Proportion of Cells") +
  352. xlab("gRNA targets recovered") +
  353. labs(fill = "")
  354. ggsave(filename = "outputs_fig1/Figure_S2B.eps",
  355. device = "ps",
  356. width = 3.5, height = 3, units = 'in',
  357. bg = "transparent")
  358. ```
  359. # =============================================================================
  360. # SECTION 8: FIGURE 1E - MUTAGENESIS EFFICIENCY
  361. # =============================================================================
  362. Compare CRISPR editing frequency (from genomic DNA) to
  363. genotype composition (from gRNA detection)
  364. ```{r load-rhampseq-data}
  365. # Load rhAmpSeq results (bulk DNA sequencing of cut sites)
  366. rhamp <- read.csv(file = "input_data/rhamp_results.csv")
  367. # Extract gene names from target column
  368. rhamp <- mutate(rhamp, class = case_when(
  369. str_detect(target, "^cdx4") ~ "cdx4",
  370. str_detect(target, "^rx3") ~ "rx3",
  371. str_detect(target, "^tbx16") ~ "tbx16",
  372. str_detect(target, "^tbxta") ~ "tbxta",
  373. str_detect(target, "^hand2") ~ "hand2",
  374. str_detect(target, "^hoxb1b") ~ "hoxb1b",
  375. str_detect(target, "^foxa2") ~ "foxa2",
  376. str_detect(target, "^tyr") ~ "tyr",
  377. TRUE ~ "Other"
  378. ))
  379. # Calculate percentage of cells with each genotype
  380. cellfreq <- data.frame(table(mdp$class)) %>%
  381. filter(Var1 != "ND", Var1 != "Multiple") %>%
  382. mutate(pct = (Freq / sum(Freq)) * 100) %>%
  383. select(Var1, pct)
  384. names(cellfreq) <- c("class", "cell_pct")
  385. cellfreq$class <- gsub("Non-Targeting", "tyr", cellfreq$class)
  386. # Merge with rhAmpSeq data, keep highest edited site per gene
  387. rhamp <- rhamp %>%
  388. left_join(cellfreq, by = "class") %>%
  389. select(class, target, pct_indel, wt_indel, cell_pct) %>%
  390. group_by(class) %>%
  391. filter(pct_indel == max(pct_indel)) %>%
  392. ungroup() %>%
  393. mutate(class = factor(class, levels = c("hoxb1b", "rx3", "cdx4", "hand2",
  394. "tbx16", "tbxta", "foxa2", "tyr")))
  395. ```
  396. ```{r figure1E, fig.width=2.5, fig.height=3}
  397. # Normalize indel rate by subtracting background
  398. rhamp_normalized <- rhamp %>%
  399. mutate(indel_normalized = pct_indel - wt_indel)
  400. # Dumbbell plot comparing DNA editing to gRNA detection
  401. ggplot(rhamp_normalized) +
  402. geom_segment(aes(x = class, xend = class,
  403. y = indel_normalized, yend = cell_pct),
  404. color = "grey") +
  405. geom_point(aes(x = class, y = indel_normalized,
  406. color = factor("% DNA with indel",
  407. levels = c("% DNA with indel", "% Cells with gRNA"))),
  408. size = 3) +
  409. geom_point(aes(x = class, y = cell_pct,
  410. color = factor("% Cells with gRNA",
  411. levels = c("% DNA with indel", "% Cells with gRNA"))),
  412. size = 3) +
  413. scale_color_manual(values = c("black", "#888888")) +
  414. coord_flip() +
  415. scale_y_continuous(limits = c(0, 17), breaks = c(0, 5, 10, 15)) +
  416. theme_classic() +
  417. theme(
  418. text = element_text(family = "Helvetica"),
  419. axis.text.x = element_text(size = 12),
  420. axis.text.y = element_text(size = 12, face = "italic", color = "black"),
  421. axis.title = element_text(size = 12),
  422. legend.text = element_text(size = 12),
  423. legend.title = element_blank(),
  424. legend.position = c(0.4, -0.25),
  425. plot.margin = margin(b = 70),
  426. legend.background = element_rect(fill = alpha("white", 0))
  427. ) +
  428. xlab("") +
  429. ylab(element_blank()) +
  430. guides(color = guide_legend(title = "", ncol = 1))
  431. ggsave(filename = "outputs_fig1/Figure_1E.eps",
  432. device = "ps",
  433. width = 2.5, height = 3, units = 'in',
  434. bg = "transparent")
  435. ```
  436. # =============================================================================
  437. # SECTION 9: DIMENSIONALITY REDUCTION AND CLUSTERING
  438. # =============================================================================
  439. Remove doublets and perform standard Seurat workflow
  440. ```{r clustering}
  441. # Remove cells with multiple gRNA targets (doublets)
  442. mdp_filt <- subset(mdp, subset = class != "Multiple")
  443. # Standard Seurat workflow
  444. mdp_filt <- NormalizeData(mdp_filt)
  445. mdp_filt <- FindVariableFeatures(mdp_filt, selection.method = "vst", nfeatures = 2000)
  446. mdp_filt <- ScaleData(mdp_filt)
  447. mdp_filt <- RunPCA(mdp_filt, features = VariableFeatures(object = mdp_filt))
  448. mdp_filt <- FindNeighbors(mdp_filt, dims = 1:30)
  449. mdp_filt <- FindClusters(mdp_filt, resolution = 0.5)
  450. mdp_filt <- RunUMAP(mdp_filt, dims = 1:30, min.dist = 0.4)
  451. DimPlot(mdp_filt)
  452. ```
  453. # =============================================================================
  454. # SECTION 10: CELL TYPE ANNOTATION VIA LABEL TRANSFER
  455. # =============================================================================
  456. Use Daniocell reference atlas to annotate cell types
  457. ```{r label-transfer}
  458. # Load Daniocell reference (21-26 hpf timepoints)
  459. dcell_ref <- readRDS(file = "input_data/dcell_21_26.rds")
  460. # Prepare reference
  461. dcell_ref <- RunPCA(dcell_ref, dims = 1:30)
  462. dcell_ref <- RunUMAP(dcell_ref, dims = 1:30, return.model = TRUE)
  463. # Separate cell type hierarchy into columns
  464. [email hidden] <- separate([email hidden],
  465. full_ident,
  466. into = c("tissue", "cell_type", "sub_type"),
  467. sep = "[|>]",
  468. remove = FALSE)
  469. # Find transfer anchors and transfer labels
  470. xfer_anchors <- FindTransferAnchors(
  471. reference = dcell_ref,
  472. query = mdp_filt,
  473. dims = 1:30,
  474. reference.assay = "RNA",
  475. query.assay = "RNA",
  476. reference.reduction = "pca"
  477. )
  478. predictions <- TransferData(
  479. anchorset = xfer_anchors,
  480. refdata = dcell_ref$full_ident,
  481. dims = 1:30
  482. )
  483. # Add predictions to query
  484. mdp_filt <- AddMetaData(mdp_filt, metadata = predictions)
  485. # Map query to reference UMAP
  486. mdp_filt <- MapQuery(
  487. anchorset = xfer_anchors,
  488. reference = dcell_ref,
  489. query = mdp_filt,
  490. refdata = "full_ident",
  491. reference.reduction = "pca",
  492. reduction.model = "umap"
  493. )
  494. # Separate predicted cell type hierarchy
  495. [email hidden] <- separate([email hidden],
  496. predicted.id,
  497. into = c("tissue", "cell_type", "sub_type"),
  498. sep = "[|>]",
  499. remove = FALSE)
  500. ```
  501. ## Figure S4: Label transfer validation
  502. ```{r figureS4A, fig.width=4, fig.height=4}
  503. # S4A: Reference atlas tissue types
  504. p1 <- DimPlot(dcell_ref, group.by = "tissue", label = FALSE, reduction = 'umap')
  505. LabelClusters(p1, id = "tissue", repel = TRUE) +
  506. NoLegend() + NoAxes() +
  507. ggtitle("Daniocell reference tissue types") +
  508. theme(plot.title = element_text(size = 12, family = "Helvetica"))
  509. ggsave(filename = "outputs_fig1/Figure_S4A.eps",
  510. device = "ps",
  511. width = 4, height = 4, units = 'in',
  512. bg = "transparent")
  513. ```
  514. ```{r figureS4B, fig.width=4, fig.height=4}
  515. # S4B: Query cells projected to reference
  516. DimPlot(mdp_filt, group.by = "tissue", label = FALSE, reduction = 'ref.umap') +
  517. NoLegend() + NoAxes() +
  518. ggtitle("MIC-Drop-seq cells projected to reference") +
  519. theme(plot.title = element_text(size = 12, family = "Helvetica"))
  520. ggsave(filename = "outputs_fig1/Figure_S4B.eps",
  521. device = "ps",
  522. width = 4, height = 4, units = 'in',
  523. bg = "transparent")
  524. ```
  525. ## Assign consensus cell types to clusters
  526. Take the most frequent predicted cell type for each cluster
  527. ```{r consensus-labels}
  528. consensus_assignments <- [email hidden] %>%
  529. group_by(seurat_clusters) %>%
  530. dplyr::count(predicted.id) %>%
  531. top_n(n = 1, wt = n) %>%
  532. select(seurat_clusters, predicted.id) %>%
  533. separate(predicted.id,
  534. into = c("consensus_tissue", "consensus_cell_type", "consensus_sub_type"),
  535. sep = "[|>]",
  536. remove = FALSE) %>%
  537. dplyr::rename("consensus_predicted.id" = "predicted.id")
  538. # Merge back with metadata
  539. [email hidden] <- [email hidden] %>%
  540. left_join(consensus_assignments, by = "seurat_clusters")
  541. rownames([email hidden]) <- [email hidden]$cell_barcode
  542. ```
  543. ```{r figureS4C, fig.width=4, fig.height=4}
  544. # S4C: Consensus tissue labels
  545. p1 <- DimPlot(mdp_filt, group.by = "consensus_tissue", label = FALSE)
  546. LabelClusters(p1, id = "consensus_tissue", repel = TRUE, size = 4) +
  547. NoLegend() + NoAxes() +
  548. ggtitle("MIC-Drop-seq consensus tissue labels") +
  549. theme(plot.title = element_text(size = 12, family = "Helvetica"))
  550. ggsave(filename = "outputs_fig1/Figure_S4C.eps",
  551. device = "ps",
  552. width = 4, height = 4, units = 'in',
  553. bg = "transparent")
  554. ```
  555. ## Figure 1D: Cluster UMAP
  556. ```{r figure1D, fig.width=5, fig.height=5}
  557. # Custom color palette for 35 clusters
  558. palette <- c('#AADAEEFF', '#FCDACAFF', '#DCD4E6FF', '#92C8E0FF', '#FFBDF2FF',
  559. '#7BB6D3FF', '#64A4C5FF', '#C4DFB6FF', '#FCE4A6FF', '#EC85D8FF',
  560. '#ACCF9FFF', '#EBC576FF', '#F0ABAEFF', '#458DB3FF', '#D69E3BFF',
  561. '#AF7623FF', '#95C089FF', '#2675A1FF', '#1A6088FF', '#D35C61FF',
  562. '#7EB173FF', '#619F57FF', '#9A70ABFF', '#545454FF', '#8B1713FF',
  563. '#104B6FFF', '#428B39FF', '#D747BBFF', '#B90497FF', '#44236EFF',
  564. '#277822FF', '#1D6623FF', '#7C000CFF', '#770262FF', '#135524FF')
  565. p1 <- DimPlot(mdp_filt, cols = palette, group.by = 'seurat_clusters') +
  566. NoLegend() + NoAxes() + ggtitle("")
  567. LabelClusters(p1, id = "seurat_clusters", bg.color = "white")
  568. ggsave(filename = "outputs_fig1/Figure_1D.eps",
  569. device = "ps",
  570. width = 5, height = 5, units = 'in',
  571. bg = "transparent")
  572. ```
  573. # =============================================================================
  574. # SECTION 11: PHENOTYPE VALIDATION
  575. # =============================================================================
  576. ## Presomitic Mesoderm (tbx16, tbxta)
  577. Known phenotypes:
  578. - tbx16 mutants: Accumulation of presomitic mesoderm
  579. - tbxta mutants: Depletion of presomitic mesoderm
  580. ```{r presomitic-mesoderm}
  581. # Add presomitic mesoderm annotation
  582. [email hidden] <- mutate([email hidden], psm = case_when(
  583. seurat_clusters == 15 ~ "Presomitic Mesoderm",
  584. TRUE ~ "Other"
  585. ))
  586. # Calculate percentage of cells per genotype in PSM
  587. psmstats <- data.frame(table(mdp_filt$psm, mdp_filt$class))
  588. totals <- psmstats %>% group_by(Var2) %>% summarise(total = sum(Freq))
  589. psmstats <- left_join(psmstats, totals, by = "Var2") %>%
  590. mutate(pct = (Freq / total) * 100) %>%
  591. filter(Var1 == "Presomitic Mesoderm", Var2 != "ND", Var2 != "Multiple")
  592. psmstats$Var2 <- gsub("Non-Targeting", "tyr", psmstats$Var2)
  593. psmstats$Var2 <- factor(psmstats$Var2,
  594. levels = c("cdx4", "foxa2", "hand2", "hoxb1b",
  595. "rx3", "tbx16", "tbxta", "tyr"))
  596. ```
  597. ### Figure 1F: PSM UMAP split by genotype
  598. ```{r figure1F, fig.width=8, fig.height=1.5}
  599. Idents(mdp_filt) <- "seurat_clusters"
  600. PSM <- subset(mdp_filt, idents = "15")
  601. [email hidden] <- mutate([email hidden], psmplot = case_when(
  602. class == "tbx16" ~ "tbx16",
  603. class == "tyr" ~ "tyr",
  604. class == "tbxta" ~ "tbxta",
  605. TRUE ~ "Other"
  606. ))
  607. dittoDimPlot(PSM, "psmplot", split.by = "psmplot",
  608. color.panel = c("#000000", "black", "black", "black"),
  609. size = 0.5, split.nrow = 1) +
  610. NoAxes() + NoLegend() +
  611. coord_cartesian(xlim = c(-14, -9), ylim = c(-1, 2.5)) +
  612. theme(strip.text = element_text(size = 12, face = "italic", family = "Helvetica"),
  613. strip.background = element_rect(fill = "white")) +
  614. ggtitle("")
  615. ggsave(filename = "outputs_fig1/Figure_1F.eps",
  616. device = "ps",
  617. width = 8, height = 1.5, units = 'in',
  618. bg = "transparent")
  619. ```
  620. ### Figure 1G: PSM percentage barplot
  621. ```{r figure1G, fig.width=3, fig.height=2}
  622. ggplot(data = psmstats, aes(x = Var2, y = pct)) +
  623. geom_bar(stat = "identity", fill = "black") +
  624. theme_classic() +
  625. ylab("% cells in cluster") +
  626. xlab("Mutation") +
  627. theme(
  628. axis.text.x = element_text(size = 12, family = "Helvetica",
  629. color = "black", face = "italic",
  630. angle = 45, hjust = 1),
  631. axis.text.y = element_text(size = 12, family = "Helvetica", color = "black"),
  632. axis.title = element_text(size = 12, family = "Helvetica")
  633. )
  634. ggsave(filename = "outputs_fig1/Figure_1G.eps",
  635. device = "ps",
  636. width = 3, height = 2, units = 'in',
  637. bg = "transparent")
  638. ```
  639. ## Optic Primordia (rx3)
  640. Known phenotype: rx3 mutants lack eyes (depletion of retinal cells)
  641. ```{r optic-primordia}
  642. # Add optic primordia annotation
  643. [email hidden] <- mutate([email hidden], eye = case_when(
  644. seurat_clusters %in% c(2, 22) ~ "Optic Primordia",
  645. TRUE ~ "Other"
  646. ))
  647. # Calculate percentage of cells per genotype in optic primordia
  648. eyestats <- data.frame(table(mdp_filt$eye, mdp_filt$class))
  649. totals <- eyestats %>% group_by(Var2) %>% summarise(total = sum(Freq))
  650. eyestats <- left_join(eyestats, totals, by = "Var2") %>%
  651. mutate(pct = (Freq / total) * 100) %>%
  652. filter(Var1 == "Optic Primordia", Var2 != "ND", Var2 != "Multiple")
  653. eyestats$Var2 <- gsub("Non-Targeting", "tyr", eyestats$Var2)
  654. eyestats$Var2 <- factor(eyestats$Var2,
  655. levels = c("cdx4", "foxa2", "hand2", "hoxb1b",
  656. "rx3", "tbx16", "tbxta", "tyr"))
  657. ```
  658. ### Figure S5A: Optic primordia UMAP
  659. ```{r figureS5A, fig.width=6, fig.height=1.5}
  660. optic <- subset(mdp_filt, idents = c(2, 22))
  661. [email hidden] <- mutate([email hidden], opticplot = case_when(
  662. class == "rx3" ~ "rx3",
  663. class == "tyr" ~ "tyr",
  664. TRUE ~ "Other"
  665. ))
  666. dittoDimPlot(optic, "opticplot", split.by = "opticplot",
  667. color.panel = c("#000000", "black", "black", "black"),
  668. size = 0.5, split.nrow = 1) +
  669. NoAxes() + NoLegend() +
  670. coord_cartesian(xlim = c(2, 11), ylim = c(-7, -2)) +
  671. theme(strip.text = element_text(size = 12, face = "italic", family = "Helvetica"),
  672. strip.background = element_rect(fill = "white")) +
  673. ggtitle("")
  674. ggsave(filename = "outputs_fig1/Figure_S5A.eps",
  675. device = "ps",
  676. width = 6, height = 1.5, units = 'in',
  677. bg = "transparent")
  678. ```
  679. ### Figure S5B: Optic primordia percentage
  680. ```{r figureS5B, fig.width=3, fig.height=2}
  681. ggplot(data = eyestats, aes(x = Var2, y = pct)) +
  682. geom_bar(stat = "identity", fill = 'black') +
  683. theme_classic() +
  684. ylab("% cells in cluster") +
  685. xlab("Mutation") +
  686. theme(
  687. axis.text.x = element_text(size = 12, family = "Helvetica",
  688. color = "black", face = "italic",
  689. angle = 45, hjust = 1),
  690. axis.text.y = element_text(size = 12, family = "Helvetica", color = "black"),
  691. axis.title = element_text(size = 12, family = "Helvetica")
  692. )
  693. ggsave(filename = "outputs_fig1/Figure_S5B.eps",
  694. device = "ps",
  695. width = 3, height = 2, units = 'in',
  696. bg = "transparent")
  697. ```
  698. ## Spinal Cord (cdx4)
  699. Known phenotype: cdx4 regulates hox gene expression in spinal cord
  700. ```{r spinal-cord-deg}
  701. # Add cdx4 classification
  702. [email hidden] <- [email hidden] %>%
  703. mutate(cdx = ifelse(class == "cdx4", "cdx4", "other"))
  704. ```
  705. ### Figure 1H: Spinal cord UMAP
  706. ```{r figure1H, fig.width=3, fig.height=1.5}
  707. Idents(mdp_filt) <- "consensus_cell_type"
  708. sc <- subset(mdp_filt, idents = "spinal cord")
  709. [email hidden] <- mutate([email hidden], cdx = ifelse(class == "cdx4", "cdx4", "other"))
  710. dittoDimPlot(sc, "cdx", split.by = "cdx",
  711. color.panel = c("#000000", "black"),
  712. size = 0.5, split.nrow = 1) +
  713. NoAxes() + NoLegend() +
  714. coord_cartesian(xlim = c(-5, 0), ylim = c(-5, 2)) +
  715. theme(strip.text = element_text(size = 12, face = c("italic", "plain"), family = "Helvetica"),
  716. strip.background = element_rect(fill = "white")) +
  717. ggtitle("")
  718. ggsave(filename = "outputs_fig1/Figure_1H.eps",
  719. device = "ps",
  720. width = 3, height = 1.5, units = 'in',
  721. bg = "transparent")
  722. ```
  723. ### Figure 1I: Hox gene expression in spinal cord
  724. ```{r figure1I, fig.width=3, fig.height=2.5}
  725. Idents(mdp_filt) <- "consensus_tissue"
  726. VlnPlot(mdp_filt,
  727. group.by = "cdx",
  728. features = c('elavl3', 'hoxb9a', 'hoxc6b', 'hoxa9a'),
  729. idents = "spinal cord",
  730. stack = TRUE,
  731. flip = TRUE,
  732. cols = rep("darkgrey", 5)) +
  733. NoLegend() +
  734. scale_x_discrete(labels = c(expression(italic(cdx4), "other"))) +
  735. xlab("Mutation")
  736. ggsave(filename = "outputs_fig1/Figure_1I.eps",
  737. device = "ps",
  738. width = 3, height = 2.5, units = 'in',
  739. bg = "transparent")
  740. ```
  741. ### Figure S5C: cdx4 volcano plot
  742. ```{r figureS5C, fig.width=3, fig.height=3}
  743. # Identify cdx4 and control cells in spinal cord clusters
  744. cdx_spinal_cells <- [email hidden] %>%
  745. filter(seurat_clusters %in% c(4, 28), class == 'cdx4') %>%
  746. pull(cell_barcode)
  747. control_cells <- [email hidden] %>%
  748. filter(seurat_clusters %in% c(4, 28), class != "cdx4") %>%
  749. pull(cell_barcode)
  750. # Find differentially expressed genes
  751. cdx_deg <- FindMarkers(mdp_filt,
  752. ident.1 = cdx_spinal_cells,
  753. ident.2 = control_cells)
  754. # Prepare for plotting
  755. genes_of_interest <- c("hoxb9a", "hoxa9a", "hoxc6b")
  756. cdx_deg <- cdx_deg %>%
  757. rownames_to_column("gene") %>%
  758. mutate(
  759. is_highlight = gene %in% genes_of_interest,
  760. log_p = -log10(p_val_adj)
  761. )
  762. highlight_subset <- cdx_deg %>% filter(is_highlight)
  763. # Volcano plot
  764. ggplot(cdx_deg, aes(x = avg_log2FC, y = log_p)) +
  765. geom_point(color = "grey70", alpha = 0.6, size = 1.5) +
  766. geom_point(data = highlight_subset, color = "black", size = 3) +
  767. geom_label_repel(data = highlight_subset,
  768. aes(label = gene),
  769. fontface = "italic",
  770. force = 2) +
  771. theme_classic() +
  772. labs(
  773. title = expression(italic("cdx4") ~ "- Spinal Cord DEGs"),
  774. x = "Average Log2 Fold Change",
  775. y = "-Log10 Adjusted P-value"
  776. ) +
  777. geom_vline(xintercept = c(-1, 1), linetype = "dashed", color = "grey50") +
  778. geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "grey50") +
  779. theme(plot.title = element_text(hjust = 0.5))
  780. ggsave(filename = "outputs_fig1/Figure_S5C.eps",
  781. device = "ps",
  782. width = 3, height = 3, units = 'in',
  783. bg = "transparent")
  784. ```
  785. # =============================================================================
  786. # SECTION 12: SUPPLEMENTARY FIGURES
  787. # =============================================================================
  788. ## Figure S3A: Cells per genotype
  789. ```{r figureS3A, fig.width=4, fig.height=3}
  790. [email hidden] <- [email hidden] %>%
  791. mutate(class = factor(class,
  792. levels = c("hoxb1b", "rx3", "cdx4", "hand2",
  793. "tbx16", "tbxta", "foxa2", "tyr", "ND")))
  794. [email hidden] %>%
  795. dplyr::count(class) %>%
  796. ggplot(aes(x = class, y = n)) +
  797. geom_bar(stat = "identity", fill = "black") +
  798. theme_classic() +
  799. labs(y = "Assigned Cells", x = "Genotype") +
  800. scale_y_continuous(breaks = seq(0, 9000, by = 1000)) +
  801. theme(
  802. axis.title = element_text(size = 12, family = "Helvetica"),
  803. axis.text.y = element_text(size = 12, family = "Helvetica"),
  804. axis.text.x = element_text(angle = 45, hjust = 1, size = 12,
  805. face = c(rep("italic", 8), 'plain'),
  806. family = "Helvetica")
  807. )
  808. ggsave(filename = "outputs_fig1/Figure_S3A.eps",
  809. device = "ps",
  810. width = 4, height = 3, units = 'in',
  811. bg = "transparent")
  812. ```
  813. ## Figure S3B: UMAP split by genotype
  814. ```{r figureS3B, fig.width=6, fig.height=6}
  815. dittoDimPlot(mdp_filt, "class", split.by = "class") +
  816. NoLegend() + NoAxes() +
  817. theme(strip.text = element_text(size = 12,
  818. face = c(rep("italic", 8), "plain"),
  819. family = "Helvetica")) +
  820. ggtitle("")
  821. ggsave(filename = "outputs_fig1/Figure_S3B.eps",
  822. device = "ps",
  823. width = 6, height = 6, units = 'in',
  824. bg = "transparent")
  825. ```
  826. Figure S3D
  827. ```{r}
  828. #read amplican results
  829. amp_res <- read.csv(file = "input_data/amplican_results_summary.csv")
  830. amp_res_normalized <- amp_res %>%
  831. #calculate the percentage of reads frameshifted
  832. mutate(frameshift_pct = Reads_Frameshifted / Reads_Filtered * 100) %>%
  833. #calculate the proportion of frameshifted reads relative to the percentage of cells assigned the genotype
  834. mutate(non_frameshift_pr_normalized = 1 - (frameshift_pct / Cell_pct),
  835. frameshift_pr_normalized = (frameshift_pct / Cell_pct))
  836. cumul_frameshift <- amp_res_normalized %>%
  837. #Now we can group the rows by mutation, and then we summarize to a new column to show the cumulative frameshift efficiency
  838. group_by(Group) %>%
  839. summarise(cumulative_frameshift_efficiency = 1 - prod(non_frameshift_pr_normalized) )
  840. amp_results_final <- amp_res_normalized %>%
  841. left_join(cumul_frameshift, by = "Group") %>%
  842. mutate(Group = gsub("Non-Targeting","tyr",.$Group))
  843. amp_results_plot_data <- amp_results_final %>%
  844. #select only relevant columns
  845. dplyr::select(ID, Group, frameshift_pr_normalized, cumulative_frameshift_efficiency ) %>%
  846. pivot_longer(names_to = "name", cols = -c(Group, ID))
  847. p1 <- ggplot(amp_results_plot_data, aes(x = value, y = Group, color = name)) +
  848. geom_point(size = 3) +
  849. scale_x_continuous(limits = c(0,1)) +
  850. scale_color_manual(
  851. values = c("dodgerblue", "darkgrey"),
  852. labels = c("Cumulative Frameshift Probability", "Individual Guide Frameshift Frequency")
  853. ) +
  854. labs(
  855. x = "Normalized Frameshift Frequency",
  856. y = "Target Gene",
  857. color = "" # Blank legend title
  858. ) +
  859. theme_minimal() +
  860. theme(
  861. text = element_text(size = 12),
  862. axis.text = element_text(size = 12), # Axis numbers/labels
  863. axis.title = element_text(size = 12), # Axis titles
  864. legend.text = element_text(size = 12), # Legend text
  865. plot.title = element_text(size = 12), # Plot title (if you add one)
  866. panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),
  867. legend.position = "bottom",
  868. legend.direction = "vertical"
  869. )
  870. p1
  871. ggsave(filename = "outputs_fig1/Figure_S3D.eps",
  872. device = "ps",
  873. width = 3, height = 3, units = 'in',
  874. bg = "transparent")
  875. ```
  876. Figure S1C plot
  877. ```{r}
  878. # Load libraries
  879. library(ggplot2)
  880. library(dplyr)
  881. # 1. Data Setup (based on your table)
  882. data <- data.frame(
  883. gRNA = rep(c("Unmodified gRNA", "Modified gRNA"), each = 6),
  884. phenotype = rep(c("Full", "Full", "Partial", "Partial", "WT", "WT"), 2),
  885. replicate = rep(c(1, 2), 6),
  886. percentage = c(88, 94.7, 12, 5.3, 0, 0, # Unmodified
  887. 90.4, 94.1, 9.6, 5.9, 0, 0) # Modified
  888. )
  889. # 2. Data Processing
  890. # Set 'Full' as the base layer
  891. data$phenotype <- factor(data$phenotype, levels = c("Full", "Partial", "WT"))
  892. # Calculate means for the bars
  893. bar_data <- data %>%
  894. group_by(gRNA, phenotype) %>%
  895. summarize(mean_perc = mean(percentage), .groups = 'drop')
  896. # Filter dots to show ONLY the 'Full' phenotype variance
  897. dot_data <- data %>%
  898. filter(phenotype == "Full")
  899. # 3. Create the Plot
  900. p1 <- ggplot() +
  901. # Bars: Show the average composition
  902. geom_col(data = bar_data, aes(x = gRNA, y = mean_perc, fill = phenotype),
  903. color = "black", width = 0.6, position = position_stack(reverse = TRUE)) +
  904. # Dots: Show individual variance for the 'Full' phenotype only
  905. geom_point(data = dot_data,
  906. aes(x = gRNA, y = percentage),
  907. shape = 21,
  908. fill = "black", # White fill makes dots pop against black bars
  909. color = "white",
  910. size = 3.5,
  911. stroke = 1,
  912. position = position_dodge(width = 0.4),
  913. show.legend = FALSE) +
  914. # Aesthetics and Styling
  915. scale_fill_manual(values = c("Full" = "black",
  916. "Partial" = "grey70",
  917. "WT" = "white")) +
  918. scale_y_continuous(limits = c(0, 105), expand = c(0, 0), breaks = seq(0, 100, 20)) +
  919. labs(y = "% embryos with phenotype", x = NULL, fill = NULL) +
  920. theme_classic() +
  921. theme(
  922. axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1, size = 12, color = "black"),
  923. axis.text.y = element_text(size = 12, color = "black"),
  924. legend.position = "right"
  925. )
  926. p1
  927. ggsave(filename = "outputs_fig1/Figure_S1C.eps",
  928. device = "ps",
  929. width = 3, height = 4, units = 'in',
  930. bg = "transparent")
  931. ```

Figure1_MIC-Drop-seq.Rmd at commit 9de3c19, under MIT · at the source

Overview

Authors: Clayton M. Carey1, Saba Parvez2,3, Zachary J. Brandt2, Brent W. Bisgrove1,2, Christopher J. Yates2, Randall T. Peterson2, James A. Gagnon1,4
  1. School of Biological Sciences, University of Utah,Salt Lake City, UT USA
  2. Department of Pharmacology and Toxicology, College of Pharmacy, University of Utah,Salt Lake City, UT USA
  3. Department of Cell & Developmental Biology, Feinberg School of Medicine, Northwestern University,Chicago, IL USA
  4. Henry Eyring Center for Cell & Genome Science, University of Utah,Salt Lake City, UT USA
Institutions: University of Utah (United States); Northwestern University (United States)
Journal: Nature communications, volume 17, issue 1, article 4738
Dates: received 9 June 2025; accepted 10 March 2026; published online 1 April 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1038/s41467-026-70989-w · PMID 41922342 · PMCID PMC13216532 · OpenAlex W7147444157
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: zebrafish (organism)
Methods: Statistics, Smoothing, state filtering, decompositions, Evoked potentials, fMRI & imaging
Keywords: Cell lineage, Development, Genomic engineering, CRISPR-Cas systems
MeSH: Embryo, Nonmammalian*, Single-Cell Analysis*, Zebrafish*, Animals, CRISPR-Cas Systems, Gene Expression Regulation, Developmental, Gene Regulatory Networks, Mesoderm, Mutation, Phenotype, Sequence Analysis, RNA, Single-Cell Gene Expression Analysis, Transcription Factors, Zebrafish Proteins (* major topic)
Topic: Single-cell and spatial transcriptomics (Molecular Biology, Biochemistry, Genetics and Molecular Biology), according to OpenAlex
Funding: NIH (F32HL156644, K01HG013682, R00HG012593, R01GM134069, R35GM142950, R24OD035409)
Citations: not cited yet (Europe PMC); 65 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repositories

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

clay-carey/MIC-Drop-seq

License: MIT
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Commit: 9de3c197ea1f6a13758e52b6d2b419ceb3cb0582, 11 February 2026
Languages: R (4)
Size: 8 files, 4 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file, 4 notebooks
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: ggplot2 (4 files), Seurat (4 files), tidyverse (4 files), ComplexHeatmap (3 files), edgeR (2 files), ggpubr (2 files), patchwork (2 files), rstatix (2 files), circlize (1 file), cowplot (1 file), igraph (1 file), Monocle 3 (1 file), SingleCellExperiment (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers
  • 28 September 2026: the link answers
6 files

Zenodo 18615355

License: MIT
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Size: 1 file
Software Heritage: not checked
Found in: “Code availability”
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: ggplot2 (4 files), Seurat (4 files), tidyverse (4 files), ComplexHeatmap (3 files), edgeR (2 files), ggpubr (2 files), patchwork (2 files), rstatix (2 files), circlize (1 file), cowplot (1 file), igraph (1 file), Monocle 3 (1 file), SingleCellExperiment (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers (HTTP 200)
  • 28 September 2026: the link answers (HTTP 200)
6 files
At the source:

Code availability statement

The paper has a code availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s41467-026-70989-w.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

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

Code and data availability statement

The paper has a code and data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s41467-026-70989-w.

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

Recorded: type, language, journal, volume, issue, pages, dates, 7 authors, 4 keywords, 14 MeSH terms, 1 funder, 64 references.

Cite

This paper

Carey, C. M., Parvez, S., Brandt, Z. J., Bisgrove, B. W., Yates, C. J., Peterson, R. T., & Gagnon, J. A. (2026). MIC-Drop-seq: scalable single-cell phenotyping of mutant vertebrate embryos. Nature communications, 17(1), 4738. https://doi.org/10.1038/s41467-026-70989-w

BibTeX

@article{carey2026mic,
author = {Carey, Clayton M. and Parvez, Saba and Brandt, Zachary J. and Bisgrove, Brent W. and Yates, Christopher J. and Peterson, Randall T. and Gagnon, James A.},
title = {{MIC-Drop-seq: scalable single-cell phenotyping of mutant vertebrate embryos}},
journal = {Nature communications},
year = {2026},
month = apr,
volume = {17},
number = {1},
pages = {4738},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/s41467-026-70989-w},
url = {https://doi.org/10.1038/s41467-026-70989-w},
pmid = {41922342},
pmcid = {PMC13216532}
}

RIS

TY - JOUR
AU - Carey, Clayton M.
AU - Parvez, Saba
AU - Brandt, Zachary J.
AU - Bisgrove, Brent W.
AU - Yates, Christopher J.
AU - Peterson, Randall T.
AU - Gagnon, James A.
TI - MIC-Drop-seq: scalable single-cell phenotyping of mutant vertebrate embryos
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/04/01
VL - 17
IS - 1
SP - 4738
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/s41467-026-70989-w
UR - https://doi.org/10.1038/s41467-026-70989-w
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41467-026-70989-w",
"type": "article-journal",
"title": "MIC-Drop-seq: scalable single-cell phenotyping of mutant vertebrate embryos",
"container-title": "Nature communications",
"author": [
{
"family": "Carey",
"given": "Clayton M."
},
{
"family": "Parvez",
"given": "Saba"
},
{
"family": "Brandt",
"given": "Zachary J."
},
{
"family": "Bisgrove",
"given": "Brent W."
},
{
"family": "Yates",
"given": "Christopher J."
},
{
"family": "Peterson",
"given": "Randall T."
},
{
"family": "Gagnon",
"given": "James A."
}
],
"container-title-short": "Nat Commun",
"volume": "17",
"issue": "1",
"page": "4738",
"DOI": "10.1038/s41467-026-70989-w",
"PMID": "41922342",
"PMCID": "PMC13216532",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41467-026-70989-w",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
1
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.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: Monocle 3, SingleCellExperiment, edgeR, 9 other tools, 2 references
[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: Monocle 3, SingleCellExperiment, edgeR, 9 other tools, 2 references
[3] doi:10.1002/imt2.70163 [code]
Spatial multi-omics unveils sphingolipid metabolic reprogramming within the retinal pathological niche.
Journal: iMeta
In common: Monocle 3, SingleCellExperiment, edgeR, 10 other tools
[4] doi:10.1186/s12967-026-08266-z [code]
Single-cell multi-omic integration analysis prioritizes druggable genes and reveals cell-type-specific causal effects in glioblastomagenesis.
Journal: Journal of translational medicine
In common: Monocle 3, edgeR, igraph, 8 other tools, 2 references
[5] doi:10.1038/s41586-026-10214-2 [code]
Multidimensional profiling of heterogeneity in supratentorial ependymomas.
Journal: Nature
In common: Monocle 3, SingleCellExperiment, edgeR, 9 other tools
[6] doi:10.1038/s41467-026-76341-6 [code]
Neonatal inflammation disrupts a temporally restricted postnatal Numb-enriched microglial state in mice.
Journal: Nature communications
In common: Monocle 3, SingleCellExperiment, igraph, 8 other tools, 1 reference
[7] doi:10.1038/s41398-026-04200-5 [code]
Postmortem brain single-nucleus and bulk gene expression analyses identify shared and distinct abnormalities in bipolar disorder and major depressive disorder.
Journal: Translational psychiatry
In common: SingleCellExperiment, edgeR, rstatix, 8 other tools, 1 reference
[8] 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: Monocle 3, SingleCellExperiment, igraph, 8 other tools, 1 reference
[9] doi:10.1016/j.celrep.2026.117500 [code]
Spatio-molecular gene expression reflects dorsal anterior cingulate cortex structure and function in the human brain.
Journal: Cell reports
In common: SingleCellExperiment, edgeR, igraph, 8 other tools, 1 reference
[10] doi:10.1038/s41467-026-71595-6 [code]
A single-cell and spatial atlas of early human olfactory development.
Journal: Nature communications
In common: SingleCellExperiment, igraph, circlize, 7 other tools, 2 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

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.