Brain Transcriptomic Changes Associated With the Socially Regulated Behavioural Specialisation of Ant Queens.
The 9 matches
- [1] § Results › Effect of the Presence of Larvae on the Expression of the Genes of Interest (Experiment C) ↔ R script_Mol_Ecol_2026.R, lines 577 to 650 · score 1.00 · Pheromone binding protein, Lnig_g15862, gLnigGR81, Juvenile hormone esterase, Lnig_g01559, Lnig_g04508 · Report a mismatch
- [2] § Results › Effect of Separated Workers on the Expression of the Genes of Interest (Experiment B) ↔ R script_Mol_Ecol_2026.R, lines 577 to 650 · score 0.98 · Juvenile hormone esterase, Lnig_g01559, Lnig_g04508, Lnig_g11740, Lnig_g11948, Lnig_g13064 · Report a mismatch
- [3] § Methods › Gene Expression Analyses › Analysis of the Effect of Worker Presence on Queen Brain Gene Expression ↔ R script_Mol_Ecol_2026.R, lines 378 to 416 · score 0.83 · topGO, GO annotation, biological process, GO terms, Fisher, Ontology · Report a mismatch
- [4] § Methods › Gene Expression Analyses › Analysis of the Effect of Worker Presence on Queen Brain Gene Expression ↔ R script_Mol_Ecol_2026.R, lines 337 to 375 · score 0.81 · explanatory variables, full model, reduced model, DESeq2, LRT, batch · Report a mismatch
- [5] § Results › Effect of Worker Removal on the Expression of the Genes of Interest (Experiment A) ↔ R script_Mol_Ecol_2026.R, lines 786 to 827 · score 0.75 · Juvenile hormone esterase, Lnig_g17128, Lnig_g01448, Lnig_g08195, Kr h1, Insulin · Report a mismatch
- [6] § Methods › Sample Collection › Effect of the Experimental Addition of Workers and Separated Workers ↔ R script_Mol_Ecol_2026.R, lines 1407 to 1477 · score 0.68 · wire mesh, antennal contacts, separated workers, queens passed, touching · Report a mismatch
- [7] § Results › Effect of the Presence of Workers on Brain Gene Expression in Queens ↔ R script_Mol_Ecol_2026.R, lines 418 to 456 · score 0.55 · biological processes, molecular functions, GO term, genes · Report a mismatch
- [8] § Results › Effect of Separated Workers on the Expression of the Genes of Interest (Experiment B) ↔ R script_Mol_Ecol_2026.R, lines 1407 to 1477 · score 0.54 · wire mesh, antennal contacts, separated workers, behaviour, queen · Report a mismatch
- [9] § Results › Effect of the Presence of Workers on Brain Gene Expression in Queens ↔ R script_Mol_Ecol_2026.R, lines 418 to 456 · score 0.52 · biological processes, molecular functions, GO term, DEG, gene · Report a mismatch
Paper
Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
R · 1,888 lines · 59 KB · no license · 9 matches
- #R code for the statistical analyses of :
- #Transcriptomic changes associated with the socially regulated behavioral specialization of ant queens
- #2026
- #Hugo Le Lay, Maximilian F. Bolder, Thomas J. Colgan, Romain Libbrecht
- rm(list=ls())
- #Load packages-----
- library(viridis)
- library(readxl) # Import Excel files (.xls, .xlsx)
- library(car) # Tools for regression analysis and ANOVA
- library(lme4) # Linear and generalized linear mixed-effects models (LMM, GLMM)
- library(emmeans) # Estimated marginal means and post-hoc comparisons
- library(DHARMa) # Model diagnostics using simulated residuals
- library(tximport) # Import and summarize transcript-level RNA-seq quantification data
- library(DESeq2) # Differential gene expression analysis for RNA-seq data
- library(topGO) # Gene Ontology (GO) enrichment analysis
- library(tidyverse) # Collection of packages for data manipulation and visualization
- library(ggrepel) # Add non-overlapping text labels to ggplot2 plots
- library(ggpubr) # Easy-to-use functions for publication-ready plots
- library(smplot2) # Themes and functions for scientific data visualization
- library(MASS) # Advanced statistical methods and distributions
- library(dplyr) # Data manipulation (filter, mutate, summarise, etc.)
- library(stats) # Base R statistical functions (tests, linear models, etc.)
- library(ggplot2) # Data visualization using the grammar of graphics
- library(grid) # Low-level graphical system for fine plot control
- library(GO.db) # Gene Ontology annotation database
- library(dplyr) # Data manipulation (loaded again here)
- library(stringr) # String manipulation functions
- library(cowplot) # Plot arrangement and annotation for ggplot2
- library(svglite) # Export plots to SVG format
- library(multcomp) # Multiple comparisons and post-hoc tests
- library(patchwork) # Combine multiple ggplot2 plots into one layout
- library(openxlsx) # Export table in excel files
- #Build functions to produce plots------
- # Create a gene expression plot showing normalized counts
- # across worker conditions, with jittered points, mean ± SE,
- # formatted adjusted p-value in the subtitle, and layout control for multi-panel grids.
- make_gene_plot <- function(row, i, ncol_grid = 3) {
- counts <- plotCounts(
- dds50_Q1,
- gene = row$gene_id,
- intgroup = c("batch","workers"),
- returnData = TRUE,
- normalized = TRUE
- )
- adj_pval_txt <- fmt_adj_pval(padj_vals[row$padj_key])
- if (nzchar(row$extra_desc)) {
- subtitle_txt <- sprintf("(%s, %s, %s)",
- row$gene_id,
- row$extra_desc,
- adj_pval_txt)
- } else {
- subtitle_txt <- sprintf("(%s, %s)",
- row$gene_id,
- adj_pval_txt)
- }
- p <- ggplot(counts,
- aes(x = workers, y = count)) +
- geom_jitter(
- colour = jitter_pt_colour,
- fill = jitter_pt_fill,
- shape = jitter_pt_shape,
- size = jitter_pt_size,
- width = 0.1,
- height = 0
- ) +
- stat_summary(
- aes(colour = workers),
- fun.data = mean_se,
- geom = "pointrange",
- size = mean_se_pt_size,
- show.legend = FALSE
- ) +
- labs(
- title = row$display_name,
- subtitle = subtitle_txt,
- x = NULL,
- y = "Normalized read counts"
- ) +
- scale_color_manual(values = worker_cols) +
- scale_x_discrete(labels = c("Without \nworkers", "With \nworkers")) +
- theme_classic(base_size = 18) +
- theme(
- plot.title = element_text(size = title_txt_size, face = "bold.italic"),
- plot.subtitle = element_text(size = subtitle_txt_size),
- axis.text.x = element_text(size = x_axis_txt_size),
- axis.text.y = element_text(size = y_axis_txt_size),
- axis.title.y = element_text(size = axis_title_y_sz),
- panel.border = element_blank(),
- panel.grid.major = element_blank(),
- panel.grid.minor = element_blank(),
- axis.line = element_line(colour = "black")
- )
- col_index <- ((i - 1) %% ncol_grid) + 1
- if (col_index != 1) {
- p <- p + theme(axis.title.y = element_blank())
- }
- p
- }
- # Create a gene expression plot using dataset dds50_3.1,
- # displaying normalized counts across three worker conditions,
- # adding mean ± SE, dynamic y-axis scaling, optional compact letter display (CLD)
- # for statistical group comparisons, and grid-aware y-axis formatting.
- make_q3_panel <- function(row, i, ncol_grid = 3, cld_df = NULL) {
- counts <- plotCounts(
- dds50_3.1,
- gene = row$gene_id,
- intgroup = c("batch","workers"),
- returnData = TRUE,
- normalized = TRUE
- )
- padj_val <- padj_vec_3[row$padj_key]
- subtitle_txt <- sprintf("(%s%s, %s)",
- row$gene_id,
- ifelse(nzchar(row$extra_desc),
- paste0(", ", row$extra_desc), ""),
- fmt_adj_pval(padj_val))
- p <- ggplot(counts, aes(x = workers, y = count)) +
- geom_jitter(colour = "grey", fill = "grey",
- size = 3, width = 0.1, height = 0) +
- labs(title = row$display_name,
- subtitle = subtitle_txt,
- x = NULL,
- y = "Normalized read counts") +
- scale_color_manual(values = cb_palette) +
- scale_x_discrete(labels = c("Without \nworkers",
- "With \nworkers",
- "Workers \nremoved")) +
- theme_classic(base_size = 18) +
- theme(
- plot.title = element_text(size = 20, face = "bold.italic",
- colour = title_col[i]),
- plot.subtitle = element_text(size = 18),
- axis.text.x = element_text(size = 18),
- axis.text.y = element_text(size = 20),
- axis.title.y = element_text(size = 20),
- panel.border = element_blank(),
- panel.grid = element_blank(),
- axis.line = element_line(colour = "black")
- ) +
- stat_summary(aes(colour = workers),
- fun.data = mean_se,
- geom = "pointrange",
- size = 2,
- show.legend = FALSE)
- max_y <- max(counts$count, na.rm = TRUE)
- p <- p + scale_y_continuous(limits = c(0, max_y * 1.2))
- if (!is.null(cld_df) && nrow(cld_df) > 0) {
- ypos <- max_y * 1.2
- cld_df$ypos <- ypos
- p <- p + geom_text(data = cld_df,
- aes(x = workers, y = ypos, label = letter),
- size = 6, colour = "black")
- }
- if ((i - 1) %% ncol_grid != 0) {
- p <- p + theme(axis.title.y = element_blank())
- }
- p
- }
- # Create a gene expression plot using dataset dds50_3.2,
- # displaying normalized counts across three worker conditions,
- # adding mean ± SE, dynamic y-axis scaling, optional compact letter display (CLD)
- # for statistical group comparisons, and grid-aware y-axis formatting.
- make_q4_panel <- function(row, i, ncol_grid = 3, cld_df = NULL) {
- counts <- plotCounts(
- dds50_3.2,
- gene = row$gene_id,
- intgroup = c("batch","workers"),
- returnData = TRUE,
- normalized = TRUE
- )
- padj_val <- padj_vec_4[row$padj_key]
- subtitle_txt <- sprintf("(%s%s, %s)",
- row$gene_id,
- ifelse(nzchar(row$extra_desc),
- paste0(", ", row$extra_desc), ""),
- fmt_adj_pval(padj_val))
- p <- ggplot(counts, aes(x = workers, y = count)) +
- geom_jitter(colour = "grey", fill = "grey",
- size = 3, width = 0.1, height = 0) +
- labs(title = row$display_name,
- subtitle = subtitle_txt,
- x = NULL,
- y = "Normalized read counts") +
- scale_color_manual(values = cb_palette_4) +
- scale_x_discrete(labels = c("Without\nworkers",
- "With\nworkers",
- "Workers\nseparated")) +
- theme_classic(base_size = 18) +
- theme(
- plot.title = element_text(size = 20, face = "bold.italic",
- colour = title_col[i]),
- plot.subtitle = element_text(size = 18),
- axis.text.x = element_text(size = 18),
- axis.text.y = element_text(size = 20),
- axis.title.y = element_text(size = 20),
- panel.border = element_blank(),
- panel.grid = element_blank(),
- axis.line = element_line(colour = "black")
- ) +
- stat_summary(aes(colour = workers),
- fun.data = mean_se,
- geom = "pointrange",
- size = 2,
- show.legend = FALSE)
- max_y <- max(counts$count, na.rm = TRUE)
- p <- p + scale_y_continuous(limits = c(0, max_y * 1.2))
- if (!is.null(cld_df) && nrow(cld_df) > 0 && any(cld_df$letter != "")) {
- ypos <- max_y * 1.2
- cld_df$ypos <- ypos
- p <- p + geom_text(data = cld_df,
- aes(x = workers, y = ypos, label = letter),
- size = 6, colour = "black")
- }
- if ((i - 1) %% ncol_grid != 0) {
- p <- p + theme(axis.title.y = element_blank())
- }
- p
- }
- # Create a gene expression plot using dataset dds50_3.3,
- # comparing queens with and without larvae,
- # showing jittered normalized counts, mean ± SE,
- # formatted adjusted p-values, dynamic y-axis limits,
- # and grid-aware y-axis formatting.
- make_q5_panel <- function(row, i, ncol_grid = 3) {
- counts <- plotCounts(
- dds50_3.3,
- gene = row$gene_id,
- intgroup = c("batch","workers"),
- returnData = TRUE,
- normalized = TRUE
- )
- counts$workers <- factor(counts$workers,
- levels = c("with_larvae","without_larvae"))
- padj_val <- padj_vec_5[row$padj_key]
- subtitle_txt <- sprintf("(%s%s, %s)",
- row$gene_id,
- ifelse(nzchar(row$extra_desc),
- paste0(", ", row$extra_desc), ""),
- fmt_adj_pval(padj_val))
- p <- ggplot(counts, aes(x = workers, y = count)) +
- geom_jitter(colour = "grey", fill = "grey",
- size = 3, width = 0.1, height = 0) +
- stat_summary(aes(colour = workers),
- fun.data = mean_se,
- geom = "pointrange",
- size = 2,
- show.legend = FALSE) +
- labs(title = row$display_name,
- subtitle = subtitle_txt,
- x = NULL,
- y = "Normalized read counts") +
- scale_color_manual(values = cb_palette_5) +
- scale_x_discrete(labels = c(
- without_larvae = "Without\nlarvae",
- with_larvae = "With\nlarvae"
- )) +
- theme_classic(base_size = 18) +
- theme(
- plot.title = element_text(size = 20, face = "bold.italic",
- colour = title_col[i]),
- plot.subtitle = element_text(size = 18),
- axis.text.x = element_text( size = 18),
- axis.text.y = element_text(size = 20),
- axis.title.y = element_text(size = 20),
- panel.border = element_blank(),
- panel.grid = element_blank(),
- axis.line = element_line(colour = "black")
- )
- max_y <- max(counts$count, na.rm = TRUE)
- p <- p + scale_y_continuous(limits = c(0, max_y * 1.2))
- if ((i - 1) %% ncol_grid != 0) {
- p <- p + theme(axis.title.y = element_blank())
- }
- p
- }
- #P-value adjustment function to homogenize naming and threshold
- fmt_adj_pval <- function(p) {
- if (is.na(p)) {
- return("adjusted-pvalue = NA")
- }
- if (p < 0.0001) {
- return("adjusted-pvalue < 0.0001")
- }
- return(sprintf("adjusted-pvalue = %.2g", p))
- }
- #Set the working directory-----
- #Path to the RDS files
- setwd(choose.dir())
- #Part 1: Comparison of queens with and without workers-----
- ##1.1. Load count table and metadata information------
- txi_with_without_workers <- readRDS("txi_with_without_workers.rds")
- ##1.2. Differential expression analysis-----
- #Create dds with batch (i.e., experiment) and presence of workers in the full model
- dds_Q1=DESeqDataSetFromMatrix(countData = txi_with_without_workers$counts,
- colData= txi_with_without_workers$meta,
- design=~batch+workers)
- #To only keep genes expressed in more than half of the samples,
- #we only keep rows with at least 25 samples with a non-zero value
- dds50_Q1=dds_Q1[rowSums(counts(dds_Q1) >0)>= 25]
- #Analysis of the impact of the presence of workers, while controlling for batch,
- #by conducting a LRT comparison of the full model with a reduced model only containing batch as explanatory variable
- dds_test_Q1=DESeq(dds50_Q1, test="LRT", reduced=~batch)
- #Produce the result table
- res_Q1=results(dds_test_Q1, alpha=0.05)
- summary(res_Q1)
- #Extract the genes with adjusted-p<0.05
- DEG_Q1=subset(res_Q1, padj<0.05)
- rownames(DEG_Q1)
- nrow(DEG_Q1)
- #Note: positive log-fold = With workers > Without workers
- #Produce an Excel table with the output of the analysis for the DEG
- #DEG_Q1_Supplementary=DEG_Q1
- #DEG_Q1_Supplementary$Gene_names=rownames(DEG_Q1_Supplementary)
- #write.xlsx(DEG_Q1_Supplementary, file = "DEG_Q1.xlsx")
- ##1.3. Run the GO term analysis-----
- GO=read.table("GO_terms.txt")
- colnames(GO) = c("Transcripts", "GOterms")
- all(GO$Transcripts %in% txi_with_without_workers$tx2gene$transcript)
- # Merge GO annotations with transcript-to-gene mapping,
- # keeping all rows from GO (left join style)
- GO_merged = merge(GO, txi_with_without_workers$tx2gene, by.x = "Transcripts", by.y = "transcript", all.x = TRUE)
- colnames(GO_merged) = c("Transcripts", "GOterms", "Genes")
- # Create a list mapping each gene to its associated GO terms
- gene2GO = split(GO_merged$GOterms, GO_merged$Genes)
- length(gene2GO)
- head(gene2GO)
- #Create a factor where:
- #1 means the gene is in the DEG list
- #0 means the gene is in the background (all genes with GO annotation)
- all_genes = unique(txi_with_without_workers$tx2gene$gene)
- all_genes = all_genes[all_genes %in% rownames(res_Q1)]
- gene_list = factor(as.integer(all_genes %in% rownames(DEG_Q1)))
- names(gene_list) = all_genes
- #Create a topGO Object for Biological process
- GO_data_Q1_BP = new("topGOdata",
- ontology = "BP",
- allGenes = gene_list,
- annot = annFUN.gene2GO,
- gene2GO = gene2GO)
- #Run Fisher's Exact Test
- resultFisher_GO_Q1_BP = runTest(GO_data_Q1_BP, algorithm = "weight01", statistic = "fisher")
- print(resultFisher_GO_Q1_BP)
- #Retrieve Significant GO Terms represented by at least three genes in the list of DEG
- GO_results_Q1_BP = GenTable(GO_data_Q1_BP, resultFisher_GO_Q1_BP, topNodes = 28)
- print(subset(GO_results_Q1_BP, Significant >= 3))
- #Create a topGO Object for Molecular function
- GO_data_Q1_MF = new("topGOdata",
- ontology = "MF",
- allGenes = gene_list,
- annot = annFUN.gene2GO,
- gene2GO = gene2GO)
- #Run Fisher's Exact Test
- resultFisher_GO_Q1_MF = runTest(GO_data_Q1_MF, algorithm = "weight01", statistic = "fisher")
- print(resultFisher_GO_Q1_MF)
- #Retrieve Significant GO Terms represented by at least three genes in the list of DEG
- GO_results_Q1_MF = GenTable(GO_data_Q1_MF, resultFisher_GO_Q1_MF, topNodes = 9)
- print(GO_results_Q1_MF)
- print(subset(GO_results_Q1_MF, Significant >= 3))
- #Extraction of DEGs with significant GOs
- #Biological Process
- GO2genes_list_BP = genesInTerm(GO_data_Q1_BP)
- GO_signif_Q1_BP = subset(GO_results_Q1_BP, Significant >= 3)
- GO_signif_Q1_BP$Genes = sapply(GO_signif_Q1_BP$GO.ID, function(go_id) {
- genes = GO2genes_list_BP[[go_id]]
- paste(genes, collapse = ", ")
- genes = intersect(genes, rownames(DEG_Q1))
- })
- GO_signif_Q1_BP$Genes
- #Molecular function
- GO2genes_list_MF = genesInTerm(GO_data_Q1_MF)
- GO_signif_Q1_MF = subset(GO_results_Q1_MF, Significant >= 3)
- GO_signif_Q1_MF$Genes = sapply(GO_signif_Q1_MF$GO.ID, function(go_id) {
- genes = GO2genes_list_MF[[go_id]]
- paste(genes, collapse = ", ")
- genes = intersect(genes, rownames(DEG_Q1))
- })
- GO_signif_Q1_MF$Genes
- ##1.4. Produce Figure 1-----
- #Data preparation
- res_Q1_df <- as.data.frame(res_Q1)
- res_Q1_df <- res_Q1_df[!is.na(res_Q1_df$padj),]
- res_Q1_df$diffexpressed <- "No"
- res_Q1_df$diffexpressed[res_Q1_df$log2FoldChange > 0 & res_Q1_df$padj < 0.05] <- "Overexpressed with workers"
- res_Q1_df$diffexpressed[res_Q1_df$log2FoldChange < 0 & res_Q1_df$padj < 0.05] <- "Underexpressed with workers"
- res_Q1_df$Comparison <- ifelse(res_Q1_df$diffexpressed == "Overexpressed with workers", "Workers superior",
- ifelse(res_Q1_df$diffexpressed == "Underexpressed with workers", "Workers inferior", "No"))
- #Arrow Preparation
- y_arrow <- max(-log10(res_Q1_df$padj), na.rm = TRUE) * 1.05
- # Volcano plot
- Volcano_plot_final <- ggplot(res_Q1_df, aes(x = log2FoldChange, y = -log10(padj), col = Comparison)) +
- geom_point(size = 2, alpha = 0.8) +
- geom_hline(yintercept = -log10(0.05), color = "red", linetype = "dashed", size = 0.8) +
- geom_vline(xintercept = 0, color = "black", linetype = "dashed", size = 0.8) +
- annotate("segment", x = 0, xend = 3.5, y = y_arrow, yend = y_arrow,
- color = "#0072B2", size = 1) +
- annotate("text", x = 1.75, y = y_arrow + 0.4,
- label = "Overexpressed in the brain of queens \nprovided with workers", color = "#0072B2", size = 4) +
- annotate("segment", x = 0, xend = -3.5, y = y_arrow, yend = y_arrow,
- color = "darkgreen", size = 1) +
- annotate("text", x = -1.75, y = y_arrow + 0.4,
- label = "Overexpressed in the brain of queens \nkept without workers", color = "darkgreen", size = 4) +
- scale_color_manual(values = c("Workers superior" = "#0072B2",
- "Workers inferior" = "darkgreen",
- "No" = "grey70")) +
- scale_x_continuous(limits = c(-3.5, 3.5), breaks = seq(-3, 3, 1)) +
- labs(x = expression(log[2]~"fold change"), y = expression(-log[10]~"(adjusted p-value)")) + ##C1:Change p Value name as you wish
- theme_minimal(base_size = 12) +
- theme(
- legend.position = "none",
- axis.title = element_text(size = 14),
- axis.text = element_text(size = 10)
- )
- Volcano_plot_final
- #Barplot
- #Recombining the datasets
- GO_signif_Q1_BP$Category <- "Biological processes"
- GO_signif_Q1_MF$Category <- "Molecular functions"
- GO_signif_Q1_all <- rbind(GO_signif_Q1_BP, GO_signif_Q1_MF)
- GO_signif_Q1_all <- GO_signif_Q1_all %>%
- group_by(Category) %>%
- arrange(desc(Significant)) %>%
- ungroup() %>%
- mutate(Term = factor(Term, levels = rev(Term)))
- n_BP <- nrow(GO_signif_Q1_BP)
- n_all <- nrow(GO_signif_Q1_all)
- GO_signif_Q1_all <- GO_signif_Q1_all %>%
- rowwise() %>%
- mutate(
- FullTerm = Term(GOTERM[[GO.ID]]) %>% as.character()
- ) %>%
- ungroup()
- #Wrap for long names. Very useful
- GO_signif_Q1_all$FullTerm <- str_wrap(GO_signif_Q1_all$FullTerm, width = 30)
- GO_signif_Q1_all <- GO_signif_Q1_all %>%
- group_by(Category) %>%
- arrange(desc(Significant)) %>%
- ungroup() %>%
- mutate(FullTerm = factor(FullTerm, levels = rev(FullTerm)))
- GO_barplot <- ggplot(GO_signif_Q1_all, aes(x = Significant, y = FullTerm, fill = as.numeric(result1))) +
- geom_col() +
- scale_fill_gradient(low = "grey20", high = "grey90", name = "p-value") + #C1 Check p-value
- labs(x = "Number of genes in the list of DEG", y = NULL) +
- theme_classic() +
- theme(
- axis.text.y = element_text(size = 12),
- axis.text.x = element_text(size = 10),
- axis.title.x = element_text(size = 12)
- ) +
- geom_hline(yintercept = nrow(GO_signif_Q1_all %>% filter(Category == "Biological processes")) + 0.5, linewidth = 0.8) +
- annotate(
- "text",
- x = 9,
- y = nrow(GO_signif_Q1_all %>% filter(Category == "Biological processes")) - 0.1,
- label = "Biological processes",
- fontface = "bold",
- hjust = 0,
- size = 3
- ) +
- annotate(
- "text",
- x = 9,
- y = nrow(GO_signif_Q1_all %>% filter(Category == "Biological processes")) +1.1,
- label = "Molecular functions",
- fontface = "bold",
- hjust = 0,
- size = 3
- ) +
- scale_x_continuous(limits = c(0, max(GO_signif_Q1_all$Significant, 21)),breaks = seq(0,21,by = 3))
- GO_barplot
- Combined_plot <- ggarrange(
- Volcano_plot_final,
- GO_barplot,
- ncol = 2,
- widths = c(1.3, 1),
- labels = c("A", "B")
- )
- #Figure 1 Result
- Combined_plot
- #Export
- #ggsave(
- # filename = "Figure_1.svg",
- # plot = Combined_plot,
- # width = 14,
- # height = 7,
- # dpi = 600,
- # bg = "white",
- # device = "svg")
- #Part 2: Identification of genes of interests for the social regulation of queen brood care behavior-----
- ##2.1. List of genes of interest-----
- DEG_Q1_Genes_of_Interest=DEG_Q1
- DEG_Q1_Genes_of_Interest$Gene_name=rownames(DEG_Q1_Genes_of_Interest)
- Krh1=subset(DEG_Q1_Genes_of_Interest, Gene_name=="Lnig_g01448")
- dPDK1=subset(DEG_Q1_Genes_of_Interest, Gene_name=="Lnig_g11740")
- Insulin=subset(DEG_Q1_Genes_of_Interest, Gene_name=="Lnig_g17128")
- Juv_esterase=subset(DEG_Q1_Genes_of_Interest, Gene_name=="Lnig_g08195")
- E4=subset(DEG_Q1_Genes_of_Interest, Gene_name=="Lnig_g15862")
- Dsx=subset(DEG_Q1_Genes_of_Interest, Gene_name=="Lnig_g04508")
- Henna=subset(DEG_Q1_Genes_of_Interest, Gene_name=="Lnig_g13064")
- Prohormone=subset(DEG_Q1_Genes_of_Interest, Gene_name=="Lnig_g06899")
- GP9=subset(DEG_Q1_Genes_of_Interest, Gene_name=="gLnigOBP1")
- GR81= subset(DEG_Q1_Genes_of_Interest, Gene_name=="gLnigGR81")
- Tret1a=subset(DEG_Q1_Genes_of_Interest, Gene_name=="Lnig_g01559")
- Tret1b=subset(DEG_Q1_Genes_of_Interest, Gene_name=="Lnig_g11948")
- Tret1_2=subset(DEG_Q1_Genes_of_Interest, Gene_name=="Lnig_g10144")
- ##2.2. Produce Supplementary Figure 1 -----
- plot_info <- data.frame(
- gene_id = c("Lnig_g01448","Lnig_g11740","Lnig_g17128","Lnig_g08195",
- "Lnig_g15862","Lnig_g04508","Lnig_g13064",
- "Lnig_g06899","gLnigOBP1","gLnigGR81",
- "Lnig_g01559","Lnig_g11948","Lnig_g10144"),
- padj_key = c("Krh1","dPDK1","Insulin","JuvEsterase",
- "E4","Dsx","Henna",
- "Prohormone","GP9","GR81",
- "Tret1a","Tret1b","Tret1_2"),
- display_name = c("Kr-h1","PDK1","Insulin","Juvenile hormone esterase",
- "Esterase E4","Protein doublesex",
- "Protein henna","Prohormone-2",
- "Pheromone binding protein GP9",
- "GR81","Tret1a","Tret1b","Tret1-2 homolog"
- ),
- extra_desc = c("", "", "", "", "", "", "", "", "", "", "", "", ""),
- stringsAsFactors = FALSE
- )
- Genes_of_interest_Overexpressed_in_worker_presence= c("Lnig_g01448", "Lnig_g17128", "Lnig_g08195", "Lnig_g11948", "Lnig_g11740", "Lnig_g04508")
- Genes_of_interest_Overexpressed_in_worker_absence= c( "Lnig_g15862", "Lnig_g13064", "gLnigOBP1", "gLnigGR81", "Lnig_g01559", "Lnig_g10144", "Lnig_g06899")
- res_Q1_plot=as.data.frame(res_Q1)
- res_Q1_plot$gene=rownames(res_Q1_plot)
- res_Q1_plot$Interest=NA
- for (i in seq_len(nrow(res_Q1_plot))) {
- gene_name <- rownames(res_Q1_plot)[i]
- if(gene_name %in% Genes_of_interest_Overexpressed_in_worker_presence) {
- res_Q1_plot$Interest[i]="Genes of interest Overexpressed in worker presence"
- } else if (gene_name %in% Genes_of_interest_Overexpressed_in_worker_absence) {
- res_Q1_plot$Interest[i] = "Genes of interest Overexpressed in worker absence"
- }
- }
- res_Q1_plot <- res_Q1_plot %>%
- left_join(plot_info[, c("gene_id", "display_name")],
- by = c("gene" = "gene_id"))
- #Volcano plot with genes of interests
- Volcano_plot_Supplementary <- ggplot(data=res_Q1_plot, aes(x=log2FoldChange, y=-log10(padj), col=Interest)) +
- geom_point(size = 2, alpha = 0.8) +
- geom_hline(yintercept = -log10(0.05), color = "red", linetype = "dashed", size = 0.8) +
- geom_vline(xintercept = 0, color = "black", linetype = "dashed", size = 0.8) +
- geom_text_repel(data=res_Q1_plot[res_Q1_plot$padj < 0.05 & res_Q1_plot$Interest!="NA", ], aes(label=display_name),
- size=5, max.overlaps=15) +
- scale_color_manual(values=c("darkgreen","#0072B2"),na.value="lightgrey") +
- annotate("segment", x = 0, xend = 3.5, y = y_arrow, yend = y_arrow,
- color = "#0072B2", size = 1) +
- annotate("text", x = 1.75, y = y_arrow + 0.4,
- label = "Overexpressed in the brain of queens \nprovided with workers", color = "#0072B2", size = 4) +
- annotate("segment", x = 0, xend = -3.5, y = y_arrow, yend = y_arrow,
- color = "darkgreen", size = 1) +
- annotate("text", x = -1.75, y = y_arrow + 0.4,
- label = "Overexpressed in the brain of queens \nkept without workers", color = "darkgreen", size = 4) +
- scale_x_continuous(limits = c(-3.5, 3.5), breaks = seq(-3, 3, 1)) +
- labs(x = expression(log[2]~"fold change"), y = expression(-log[10]~"(adjusted p-value)")) +
- theme_minimal(base_size = 12) +
- theme(
- legend.position = "none",
- axis.title = element_text(size = 14),
- axis.text = element_text(size = 10)
- )
- Volcano_plot_Supplementary
- #ggsave(
- # filename = "Lasius_Supplementary_Figure_1.svg",
- # plot = Volcano_plot_Supplementary,
- # width = 12,
- # height = 7,
- # dpi = 600,
- # bg = "white",
- # device = "svg")
- ##2.3. Produce Figure 2-----
- padj_vals <- c(
- Krh1 = Krh1$padj,
- dPDK1 = dPDK1$padj,
- Insulin = Insulin$padj,
- JuvEsterase= Juv_esterase$padj,
- E4 = E4$padj,
- Dsx = Dsx$padj,
- GP9 = GP9$padj,
- GR81 = GR81$padj,
- Tret1a = Tret1a$padj,
- Tret1b = Tret1b$padj,
- Tret1_2 = Tret1_2$padj,
- Henna = Henna$padj,
- Prohormone = Prohormone$padj
- )
- worker_cols <- c("darkgreen","#0072B2")
- jitter_pt_size <- 3
- jitter_pt_colour <- "grey"
- jitter_pt_fill <- "grey"
- jitter_pt_shape <- 21
- mean_se_pt_size <- 2
- x_axis_txt_size <- 20
- y_axis_txt_size <- 20
- title_txt_size <- 20
- subtitle_txt_size<- 18
- axis_title_y_sz <- 20
- ncol_grid <- 3
- all_plots <- lapply(seq_len(nrow(plot_info)), function(i) {
- make_gene_plot(plot_info[i, ], i, ncol_grid = ncol_grid)
- })
- final_figure <- plot_grid(
- plotlist = all_plots,
- nrow = ceiling(length(all_plots) / ncol_grid),
- ncol = ncol_grid,
- labels = LETTERS[seq_along(all_plots)],
- label_size = 20,
- label_fontface = "bold",
- align = "hv"
- )
- final_figure
- #Export
- #ggsave(
- # filename = "Figure_2.svg",
- # plot = final_figure,
- # width = 50,
- # height = 75,
- # units = "cm",
- # device = "svg")
- #Part 3: Comparison of the genes of interest among queens with workers, without workers and with workers removed-----
- ##3.1. Load count table and metadata information------
- #Only the brain samples for experiment E11 are used in this analysis
- txi_with_without_removed_workers <- readRDS("txi_with_without_removed_workers.rds")
- ##3.2. Analysis of expression differences-----
- #Create dds
- dds_3.1=DESeqDataSetFromMatrix(countData = txi_with_without_removed_workers$counts,
- colData = txi_with_without_removed_workers$meta,
- design=~workers)
- #To only keep genes expressed in at least half of the samples,
- #we only keep rows at least 19 samples with a non-zero value
- dds50_3.1=dds_3.1[rowSums(counts(dds_3.1) >0)>= 19]
- #Normalized counts extraction
- dds_test_3.1=DESeq(dds50_3.1, test="LRT", reduced=~1)
- normalized_counts.3.1 <- counts(dds_test_3.1, normalized = TRUE)
- #Pivot longer the data frame
- normalized_counts_long.3.1 <- normalized_counts.3.1 %>%
- as.data.frame() %>%
- rownames_to_column(var = "gene") %>%
- pivot_longer(
- cols = -gene,
- names_to = "sample",
- values_to = "normalized_count"
- )
- normalized_counts_long.3.1 <- normalized_counts_long.3.1 %>%
- left_join(as.data.frame(txi_with_without_removed_workers$meta) %>% dplyr::select(sample, workers), by = "sample")
- #Comparison of the expression levels for each of the genes of interest
- ###Kr-h1
- #Subset Kr-h1 counts
- Krup.3.1=subset(normalized_counts_long.3.1, gene=="Lnig_g01448")
- #Model
- modK.3.1=lm(log(normalized_count+1)~workers, data=Krup.3.1)
- simulationOutput = simulateResiduals(fittedModel= modK.3.1, plot = T)
- #Results
- car::Anova(modK.3.1)
- emmeans(modK.3.1,pairwise~workers)
- ###PDK1
- #Subset the PDK1 counts
- dPDK1.3.1 =subset(normalized_counts_long.3.1, gene=="Lnig_g11740")
- #Model
- moddPDK1.3.1=lm(normalized_count~workers, data=dPDK1.3.1)
- simulationOutput = simulateResiduals(fittedModel= moddPDK1.3.1, plot = T)
- #Results
- car::Anova(moddPDK1.3.1)
- emmeans(moddPDK1.3.1,pairwise~workers)
- ###Insulin
- #Subset the Insulin counts
- Ins.3.1 =subset(normalized_counts_long.3.1, gene=="Lnig_g17128")
- #Model
- modIns.3.1=lm(normalized_count~workers, data=Ins.3.1)
- simulationOutput = simulateResiduals(fittedModel= modIns.3.1, plot = T)
- ##Results
- car::Anova(modIns.3.1)
- emmeans(modIns.3.1,pairwise~workers)
- ###Juvenile hormone esterase
- #Subset the Juvenile hormone esterase counts
- Carb.3.1 =subset(normalized_counts_long.3.1, gene=="Lnig_g08195")
- #Model
- modCarb.3.1=lm(normalized_count~workers, data=Carb.3.1)
- simulationOutput = simulateResiduals(fittedModel= modCarb.3.1, plot = T)
- #Results
- car::Anova(modCarb.3.1)
- emmeans(modCarb.3.1,pairwise~workers)
- ###Esterase E4
- #Subset the Esterase E4 counts
- E4.3.1 =subset(normalized_counts_long.3.1, gene=="Lnig_g15862")
- #Model
- modE4.3.1=lm(normalized_count~workers, data=E4.3.1)
- simulationOutput = simulateResiduals(fittedModel= modE4.3.1, plot = T)
- #Results
- car::Anova(modE4.3.1)
- emmeans(modE4.3.1,pairwise~workers)
- ###Protein doublesex
- #Subset the Doublesex counts
- Dbs.3.1 =subset(normalized_counts_long.3.1, gene=="Lnig_g04508")
- #Model
- modDbs.3.1=lm(normalized_count~workers, data=Dbs.3.1)
- simulationOutput = simulateResiduals(fittedModel= modDbs.3.1, plot = T)
- #Results
- car::Anova(modDbs.3.1)
- ###Protein henna
- #Subset the Tret1-2 homolog counts
- Henna.3.1=subset(normalized_counts_long.3.1, gene=="Lnig_g13064")
- #Model
- modHenna.3.1=lm(normalized_count~workers, data=Henna.3.1)
- simulationOutput = simulateResiduals(fittedModel= modHenna.3.1, plot = T)
- #Results
- car::Anova(modHenna.3.1)
- emmeans(modHenna.3.1,pairwise~workers)
- ###Prohormone-2
- #Subset the Prohormone-2 counts
- Pro.3.1 =subset(normalized_counts_long.3.1, gene=="Lnig_g06899")
- #Model
- modPro.3.1=lm(normalized_count~workers, data=Pro.3.1)
- simulationOutput = simulateResiduals(fittedModel= modPro.3.1, plot = T)
- #Results
- car::Anova(modPro.3.1)
- emmeans(modPro.3.1,pairwise~workers)
- ###Pheromone-binding protein Gp-9
- #Subset the GP9 counts
- GP9.3.1=subset(normalized_counts_long.3.1, gene=="gLnigOBP1")
- #Model
- modGP9.3.1=lm(normalized_count~workers, data=GP9.3.1)
- simulationOutput = simulateResiduals(fittedModel= modGP9.3.1, plot = T)
- #Results
- car::Anova(modGP9.3.1)
- emmeans(modGP9.3.1,pairwise~workers)
- ###GR81
- #Subset the GR81 counts
- GR81.3.1 =subset(normalized_counts_long.3.1, gene=="gLnigGR81")
- #Model
- modGR81.3.1=lm(normalized_count~workers, data=GR81.3.1)
- simulationOutput = simulateResiduals(fittedModel= modGR81.3.1, plot = T)
- #Results
- car::Anova(modGR81.3.1)
- emmeans(modGR81.3.1,pairwise~workers)
- ###Tret1a
- #Subset the Tret1a counts
- Tret1a.3.1 =subset(normalized_counts_long.3.1, gene=="Lnig_g01559")
- #Model
- modTret1a.3.1=lm(normalized_count~workers, data=Tret1a.3.1)
- simulationOutput = simulateResiduals(fittedModel= modTret1a.3.1, plot = T)
- #Results
- car::Anova(modTret1a.3.1)
- ###Tret1b
- #Subset the Tret1b counts
- Tret1b.3.1 =subset(normalized_counts_long.3.1, gene=="Lnig_g11948")
- #Model
- modTret1b.3.1=lm(normalized_count~workers, data=Tret1b.3.1)
- simulationOutput = simulateResiduals(fittedModel= modTret1b.3.1, plot = T)
- #Results
- car::Anova(modTret1b.3.1)
- emmeans(modTret1b.3.1,pairwise~workers)
- ###Tret1-2 homolog
- #Subset the Tret1-2 homolog counts
- Tret1_2.3.1=subset(normalized_counts_long.3.1, gene=="Lnig_g10144")
- #Model
- modTret1_2.3.1=lm(normalized_count~workers, data=Tret1_2.3.1)
- simulationOutput = simulateResiduals(fittedModel= modTret1_2.3.1, plot = T)
- #Results
- car::Anova(modTret1_2.3.1)
- emmeans(modTret1_2.3.1,pairwise~workers)
- ##3.3. Produce Supplementary Figure 2----------
- #data
- models <- list(
- Krh1 = modK.3.1,
- dPDK1 = moddPDK1.3.1,
- Insulin = modIns.3.1,
- JuvEsterase= modCarb.3.1,
- E4 = modE4.3.1,
- Dsx = modDbs.3.1,
- GP9 = modGP9.3.1,
- GR81 = modGR81.3.1,
- Tret1a = modTret1a.3.1,
- Tret1b = modTret1b.3.1,
- Tret1_2 = modTret1_2.3.1,
- Henna = modHenna.3.1,
- Prohormone = modPro.3.1
- )
- #Color of titles and means. I did it manually here. Recheck important
- title_pat <- gsub(" ", "", "brb brr rbb rrr b")
- title_vec <- strsplit(title_pat, "")[[1]]
- title_col <- ifelse(title_vec == "r", "darkgrey", "black")
- cb_palette <- c("darkgreen", "#0072B2", "#E69F00")
- padj_3.1 = list(
- Krh1 = car::Anova(modK.3.1)[["Pr(>F)"]][1],
- dPDK1 = car::Anova(moddPDK1.3.1)[["Pr(>F)"]][1],
- Insulin = car::Anova(modIns.3.1)[["Pr(>F)"]][1],
- JuvEsterase = car::Anova(modCarb.3.1)[["Pr(>F)"]][1],
- E4 = car::Anova(modE4.3.1)[["Pr(>F)"]][1],
- Dsx = car::Anova(modDbs.3.1)[["Pr(>F)"]][1],
- GP9 = car::Anova(modGP9.3.1)[["Pr(>F)"]][1],
- GR81 = car::Anova(modGR81.3.1)[["Pr(>F)"]][1],
- Tret1a = car::Anova(modTret1a.3.1)[["Pr(>F)"]][1],
- Tret1b = car::Anova(modTret1b.3.1)[["Pr(>F)"]][1],
- Tret1_2 = car::Anova(modTret1_2.3.1)[["Pr(>F)"]][1],
- Henna = car::Anova(modHenna.3.1)[["Pr(>F)"]][1],
- Prohormone = car::Anova(modPro.3.1)[["Pr(>F)"]][1])
- padj_vec_3 <- setNames(padj_3.1, names(padj_3.1))
- names(padj_vec_3)[names(padj_vec_3) == "Doublesex"] <- "Dsx"
- padj_vec_3 <- unlist(padj_vec_3, use.names = TRUE)
- #Letter build
- raw_cld_list <- vector("list", nrow(plot_info))
- for (i in seq_len(nrow(plot_info))) {
- padj_val <- padj_vec_3[plot_info$padj_key[i]]
- if (!is.na(padj_val) && padj_val < 0.05) {
- tryCatch({
- emm <- emmeans(models[[plot_info$padj_key[i]]], pairwise ~ workers)
- cld <- cld(emm)
- cld$.group <- toupper(trimws(cld$.group))
- num2letter <- function(s) {
- s <- gsub(" ", "", s)
- if (s == "") return("")
- digits <- strsplit(s, "")[[1]]
- letters <- sapply(digits,
- function(d) {
- if (d %in% as.character(1:26)) LETTERS[as.integer(d)] else d
- })
- paste0(letters, collapse = "")
- }
- cld$.group <- sapply(cld$.group, num2letter)
- raw_cld_list[[i]] <- data.frame(
- gene_id = plot_info$gene_id[i],
- workers = cld$workers,
- letter = cld$.group,
- stringsAsFactors = FALSE
- )
- }, error = function(e) {
- raw_cld_list[[i]] <<- NULL
- message("CLD failed for ", plot_info$gene_id[i], ": ", e$message)
- })
- } else {
- raw_cld_list[[i]] <- NULL
- }
- }
- cld_list <- raw_cld_list
- #Manual adjustments to make without workers group assignment always A
- cld_list[[1]]$letter <- c("C", "A", "B")
- cld_list[[5]]$letter <- c("B", "B", "A")
- cld_list[[7]]$letter <- c("B", "B", "A")
- cld_list[[8]]$letter <- c("B", "A", "A")
- cld_list[[10]]$letter <- c("B", "AB", "A")
- cld_list[[13]]$letter <- c("B", "A", "A")
- if (length(title_col) < nrow(plot_info))
- title_col <- rep(title_col, length.out = nrow(plot_info))
- all_plots <- lapply(seq_len(nrow(plot_info)), function(i) {
- make_q3_panel(plot_info[i, ], i,
- ncol_grid = 3,
- cld_df = cld_list[[i]])
- })
- final_figure <- plot_grid(
- plotlist = all_plots,
- nrow = 5,
- ncol = 3,
- labels = LETTERS,
- label_size = 20,
- label_fontface = "bold",
- align = "hv"
- )
- print(final_figure)
- #ggsave(
- # filename = "Supplementary_Figure_2.svg",
- # plot = final_figure,
- # width = 50,
- # height = 75,
- # units = "cm",
- # device = "svg"
- #)
- #Part 4: Comparison of the genes of interest among queens with workers, without workers and with workers separated-----
- ##4.1. Load count table and metadata information------
- #Only the brain samples for experiment E4 are used in this analysis
- txi_with_without_separated_workers <- readRDS("txi_with_without_separated_workers.rds")
- ##4.2. Analysis of expression differences-----
- #Create dds
- dds_3.2=DESeqDataSetFromMatrix(countData = txi_with_without_separated_workers$counts,
- colData=txi_with_without_separated_workers$meta,
- design=~workers)
- #To only keep genes expressed in at least half of the samples, we only keep rows at least 19 samples with a non-zero value
- dds50_3.2=dds_3.2[rowSums(counts(dds_3.2) >0)>= 19]
- #Normalized counts extraction
- dds_test_3.2=DESeq(dds50_3.2, test="LRT", reduced=~1)
- normalized_counts.3.2 = counts(dds_test_3.2, normalized = TRUE)
- #Pivot longer the dataframe
- normalized_counts_long.3.2 = normalized_counts.3.2 %>%
- as.data.frame() %>%
- rownames_to_column(var = "gene") %>%
- pivot_longer(
- cols = -gene,
- names_to = "sample",
- values_to = "normalized_count"
- )
- normalized_counts_long.3.2 = normalized_counts_long.3.2 %>%
- left_join(as.data.frame(txi_with_without_separated_workers$meta) %>% dplyr::select(sample, workers), by = "sample")
- ###Kr-h1
- #Subset kr-h1 counts
- Krup.3.2=subset(normalized_counts_long.3.2, gene=="Lnig_g01448")
- #Model
- modK.3.2=lm(normalized_count~workers, data=Krup.3.2)
- simulationOutput = simulateResiduals(fittedModel= modK.3.2, plot = T)
- #Results
- car::Anova(modK.3.2)
- emmeans(modK.3.2,pairwise~workers)
- ###PDK1
- #Subset the PDK1 counts
- dPDK1.3.2 =subset(normalized_counts_long.3.2, gene=="Lnig_g11740")
- #Model
- moddPDK1.3.2=lm(normalized_count~workers, data=dPDK1.3.2)
- simulationOutput = simulateResiduals(fittedModel= moddPDK1.3.2, plot = T)
- #Results
- car::Anova(moddPDK1.3.2)
- emmeans(moddPDK1.3.2,pairwise~workers)
- ###Insulin
- #Subset the Insulin counts
- Ins.3.2 =subset(normalized_counts_long.3.2, gene=="Lnig_g17128")
- #Model
- modIns.3.2=lm(normalized_count~workers, data=Ins.3.2)
- simulationOutput = simulateResiduals(fittedModel= modIns.3.2, plot = T)
- ##Results
- car::Anova(modIns.3.2)
- emmeans(modIns.3.2,pairwise~workers)
- ###Juvenile hormone esterase
- #Subset the Juvenile hormone esterase counts
- Carb.3.2 =subset(normalized_counts_long.3.2, gene=="Lnig_g08195")
- #Model
- modCarb.3.2=lm(normalized_count~workers, data=Carb.3.2)
- simulationOutput = simulateResiduals(fittedModel= modCarb.3.2, plot = T)
- #Results
- car::Anova(modCarb.3.2)
- emmeans(modCarb.3.2,pairwise~workers)
- ###Esterase E4
- #Subset the Esterase E4 counts
- E4.3.2 =subset(normalized_counts_long.3.2, gene=="Lnig_g15862")
- #Model
- modE4.3.2=lm(normalized_count~workers, data=E4.3.2)
- simulationOutput = simulateResiduals(fittedModel= modE4.3.2, plot = T)
- #Results
- car::Anova(modE4.3.2)
- ###Protein doublesex
- #Subset the Doublesex counts
- Dbs.3.2 =subset(normalized_counts_long.3.2, gene=="Lnig_g04508")
- #Model
- modDbs.3.2=lm(normalized_count~workers, data=Dbs.3.2)
- simulationOutput = simulateResiduals(fittedModel= modDbs.3.2, plot = T)
- #Results
- car::Anova(modDbs.3.2)
- emmeans(modDbs.3.2,pairwise~workers)
- ###Protein henna
- #Subset the Protein henna counts
- Henna.3.2 =subset(normalized_counts_long.3.2, gene=="Lnig_g13064")
- #Model
- modHenna.3.2=lm(log(normalized_count+1)~workers, data=Henna.3.2)
- simulationOutput = simulateResiduals(fittedModel= modHenna.3.2, plot = T)
- #Results
- car::Anova(modHenna.3.2)
- emmeans(modHenna.3.2,pairwise~workers)
- ###Prohormone-2
- #Subset the Prohormone-2 counts
- Pro.3.2 =subset(normalized_counts_long.3.2, gene=="Lnig_g06899")
- #Model
- modPro.3.2=lm(normalized_count~workers, data=Pro.3.2)
- simulationOutput = simulateResiduals(fittedModel= modPro.3.2, plot = T)
- #Results
- car::Anova(modPro.3.2)
- emmeans(modPro.3.2,pairwise~workers)
- ###Pheromone binding protein GP-9
- #Subset the GP9 counts
- GP9.3.2=subset(normalized_counts_long.3.2, gene=="gLnigOBP1")
- #Model
- modGP9.3.2=lm(normalized_count~workers, data=GP9.3.2)
- simulationOutput = simulateResiduals(fittedModel= modGP9.3.2, plot = T)
- #Results
- car::Anova(modGP9.3.2)
- ###GR81
- #Subset the GR81 counts
- GR81.3.2=subset(normalized_counts_long.3.2, gene=="gLnigGR81")
- #Model
- modGR81.3.2=lm(normalized_count~workers, data=GR81.3.2)
- simulationOutput = simulateResiduals(fittedModel= modGR81.3.2, plot = T)
- #Results
- car::Anova(modGR81.3.2)
- emmeans(modGR81.3.2,pairwise~workers)
- ###Tret1a
- #Subset the Tret1a counts
- Tret1a.3.2 =subset(normalized_counts_long.3.2, gene=="Lnig_g01559")
- #Model
- modTret1a.3.2=lm(normalized_count~workers, data=Tret1a.3.2)
- simulationOutput = simulateResiduals(fittedModel= modTret1a.3.2, plot = T)
- #Results
- car::Anova(modTret1a.3.2)
- emmeans(modTret1a.3.2,pairwise~workers)
- ###Tret1b
- #Subset the Tret1b counts
- Tret1b.3.2 =subset(normalized_counts_long.3.2, gene=="Lnig_g11948")
- #Model
- modTret1b.3.2=lm(log(normalized_count+1)~workers, data=Tret1b.3.2)
- simulationOutput = simulateResiduals(fittedModel= modTret1b.3.2, plot = T)
- #Results
- car::Anova(modTret1b.3.2)
- emmeans(modTret1b.3.2,pairwise~workers)
- ###Tret1-2 homolog
- #Subset the Tret1-2 homolog counts
- Tret1_2.3.2=subset(normalized_counts_long.3.2, gene=="Lnig_g10144")
- #Model
- modTret1_2.3.2=lm(normalized_count~workers, data=Tret1_2.3.2)
- simulationOutput = simulateResiduals(fittedModel= modTret1_2.3.2, plot = T)
- #Results
- car::Anova(modTret1_2.3.2)
- emmeans(modTret1_2.3.2, pairwise~workers)
- ##4.3. Produce Supplementary Figure 4-----
- #Again manually. Important to check
- title_pat <- gsub(" ", "", "bbb brb brr rbb b")
- title_vec <- strsplit(title_pat, "")[[1]]
- title_col <- ifelse(title_vec == "r", "darkgrey", "black")
- title_col <- rep(title_col, length.out = 13)
- cb_palette_4 <- c("darkgreen", "#0072B2", "purple")
- models_4 <- list(
- Krh1 = modK.3.2,
- dPDK1 = moddPDK1.3.2,
- Insulin = modIns.3.2,
- JuvEsterase = modCarb.3.2,
- E4 = modE4.3.2,
- Dsx = modDbs.3.2,
- Henna = modHenna.3.2,
- Prohormone = modPro.3.2,
- GP9 = modGP9.3.2,
- GR81 = modGR81.3.2,
- Tret1a = modTret1a.3.2,
- Tret1b = modTret1b.3.2,
- Tret1_2 = modTret1_2.3.2
- )
- padj_3.2 = list(
- Krh1 = car::Anova(modK.3.2)[["Pr(>F)"]][1],
- dPDK1 = car::Anova(moddPDK1.3.2)[["Pr(>F)"]][1],
- Insulin = car::Anova(modIns.3.2)[["Pr(>F)"]][1],
- JuvEsterase = car::Anova(modCarb.3.2)[["Pr(>F)"]][1],
- E4 = car::Anova(modE4.3.2)[["Pr(>F)"]][1],
- Dsx = car::Anova(modDbs.3.2)[["Pr(>F)"]][1],
- Henna = car::Anova(modHenna.3.2)[["Pr(>F)"]][1],
- Prohormone = car::Anova(modPro.3.2)[["Pr(>F)"]][1],
- GP9 = car::Anova(modGP9.3.2)[["Pr(>F)"]][1],
- GR81 = car::Anova(modGR81.3.2)[["Pr(>F)"]][1],
- Tret1a = car::Anova(modTret1a.3.2)[["Pr(>F)"]][1],
- Tret1b = car::Anova(modTret1b.3.2)[["Pr(>F)"]][1],
- Tret1_2 = car::Anova(modTret1_2.3.2)[["Pr(>F)"]][1])
- padj_vec_4 <- setNames(padj_3.2, names(padj_3.2))
- padj_vec_4 <- unlist(padj_vec_4, use.names = TRUE)
- #Letter build
- raw_cld_list_4 <- vector("list", nrow(plot_info))
- for (i in seq_len(nrow(plot_info))) {
- padj_val <- padj_vec_4[plot_info$padj_key[i] ]
- if (!is.na(padj_val) && padj_val < 0.05) {
- cld_tmp <- tryCatch({
- emm <- emmeans(models_4[[ plot_info$padj_key[i] ]], pairwise ~ workers)
- cld <- cld(emm)
- cld$.group <- toupper(trimws(cld$.group))
- num2letter <- function(s) {
- s <- gsub(" ", "", s)
- if (s == "") return("")
- digits <- strsplit(s, "")[[1]]
- letters <- sapply(digits,
- function(d) {
- if (d %in% as.character(1:26))
- LETTERS[as.integer(d)] else d
- })
- paste0(letters, collapse = "")
- }
- cld$.group <- sapply(cld$.group, num2letter)
- data.frame(
- gene_id = plot_info$gene_id[i],
- workers = cld$workers,
- letter = cld$.group,
- stringsAsFactors = FALSE
- )
- }, error = function(e) {
- message("CLD failed for ", plot_info$gene_id[i], ": ", e$message)
- NULL
- })
- raw_cld_list_4[[i]] <- if (!is.null(cld_tmp)) cld_tmp else NULL
- } else {
- raw_cld_list_4[[i]] <- NULL
- }
- }
- cld_list_4 <- raw_cld_list_4
- #Manual adjustments to make without workers group assigment always A
- cld_list_4[[7]]$letter <- c("B", "A", "A")
- cld_list_4[[8]]$letter <- c("B", "AB", "A")
- cld_list_4[[10]]$letter <- c("B", "AB", "A")
- cld_list_4[[11]]$letter <- c("A", "B", "B")
- cld_list_4[[13]]$letter <- c("B", "A", "A")
- if (length(title_col) < nrow(plot_info))
- title_col <- rep(title_col, length.out = nrow(plot_info))
- all_plots_4 <- lapply(seq_len(nrow(plot_info)), function(i) {
- make_q4_panel(plot_info[i, ], i,
- ncol_grid = 3,
- cld_df = cld_list_4[[i]])
- })
- final_figure_4 <- plot_grid(
- plotlist = all_plots_4,
- nrow = 5,
- ncol = 3,
- labels = LETTERS[1:13],
- label_size = 20,
- label_fontface = "bold",
- align = "hv"
- )
- print(final_figure_4)
- #ggsave(
- # filename = "Supplementary_Figure_4.svg",
- # plot = final_figure_4,
- # width = 50,
- # height = 75,
- # units = "cm",
- # device = "svg"
- #)
- ##4.4. Analysis of queen behavior and antennation through the wire mesh -----
- #Import data
- Antennation=read.table("data_queen_antennation_wire_mesh.txt", h=T, stringsAsFactors = T)
- Antennation_subject=subset(as.data.frame(txi_with_without_separated_workers$meta), workers=="separated_workers")
- Antennation_subject=sub("B$","",Antennation_subject$sample)
- Antennation=subset(Antennation, Subject %in% Antennation_subject)
- #Number of occurrence per behavior
- Antennation_counts <- Antennation %>%
- group_by(Subject , Behavior) %>%
- summarise(nb_occurrences = n(), .groups = "drop")
- All_queens <- data.frame(
- Subject = unique(Antennation_subject)
- )
- #Number of each queen behavior
- Antennation_all <- All_queens %>%
- left_join(Antennation_counts, by = "Subject") %>%
- mutate(nb_occurrences = ifelse(is.na(nb_occurrences), 0, nb_occurrences))
- #Plot Number of antennation through the wire mesh for each queen
- Antennation_Occurence <- ggplot(
- Antennation_all,
- aes(
- x = Subject,
- y = nb_occurrences,
- fill = Behavior
- )
- ) +
- geom_col() +
- labs(
- x = "Queen identity",
- y = "Number of occurrences"
- ) +
- theme_classic(base_size = 18) +
- scale_fill_viridis_d(
- option = "E",
- na.translate = FALSE,
- name=NULL,
- labels = c(
- "Number of times that queens made antennal contact with workers" = "Number of times that queens made antennal\ncontact with workers",
- "Number of times that queens passed their antennae through or above the wire mesh without touching a worker" = "Number of times that queens passed their antennae\nthrough or above the wire mesh without touching a worker"
- )
- ) +
- theme(
- plot.title = element_text(size = 20, face = "bold", hjust = 0.5),
- strip.text = element_text(size = 16, face = "bold"),
- panel.border = element_blank(),
- panel.grid.major = element_blank(),
- panel.grid.minor = element_blank(),
- axis.line = element_line(colour = "black"),
- legend.position = "top",
- legend.justification = "center",
- legend.direction = "horizontal"
- )
- print(Antennation_Occurence)
- ###Duration of antennal contacts with workers
- Duration=Antennation
- Duration$Antennation=NA
- #Creation of a new column with the duration of both antennation behaviors with the workers,
- #and 0 for all other behaviors
- Duration$Antennation <- ifelse(Duration$Behavior =="Number of times that queens made antennal contact with workers",
- as.numeric(Duration$Duration),0)
- #Addition of the E4_53 subject that did not perform any behavior
- Duration <- Duration %>%
- dplyr::bind_rows(data.frame(Subject = "E4_53",Antennation = 0)
- )
- Duration$Duration=as.numeric(Duration$Duration)
- #Creation of a dataframe with the total duration of antennation for each queen
- Duration_Both_Antennation <- All_queens %>%
- left_join(
- Duration %>%
- group_by(Subject)%>%
- summarise(
- Total_duration = sum(Duration, na.rm = TRUE),
- .groups = "drop"
- ),
- by = "Subject"
- )
- #Calculation of the mean and standard deviation of the d'antennation
- Duration_mean=subset(Duration_Both_Antennation, Total_duration >0)
- mean(Duration_mean$Total_duration)
- sd(Duration_mean$Total_duration)
- #Antennation duration plot
- Duration_plot <- ggplot(
- Duration_Both_Antennation,
- aes(x = Subject, y = Total_duration, fill = Subject)
- ) +
- geom_col(width = 0.7, fill="#00204DFF") +
- labs(
- x = "Queen identity",
- y = "Total duration of antennal contacts with workers (s)"
- ) +
- theme_classic(base_size = 18) +
- theme(
- axis.text.x = element_text(size = 14),
- plot.title = element_text(color = "#00204DFF", size = 14, face = "bold"),
- panel.border = element_blank(),
- panel.grid.major = element_blank(),
- panel.grid.minor = element_blank(),
- axis.line = element_line(colour = "black"),
- legend.position = "none"
- )
- print(Duration_plot)
- #Creation of a panel with both plots
- Antennation_2plots=ggarrange(Antennation_Occurence,Duration_plot, labels="AUTO")
- Antennation_2plots
- #Export
- #ggsave(
- # filename = "Supplementary_Figure_3.svg",
- # plot = Antennation_2plots,
- # width = 22,
- # height = 10,
- # dpi = 600,
- # bg = "white",
- # device = "svg")
- #Part 5: Comparison of the genes of interest between queens with and without larvae-----
- ##5.1. Load count table and metadata information------
- txi_with_without_larvae <- readRDS("txi_with_without_larvae.rds")
- ##5.2. Analysis of expression differences-----
- #Create dds
- dds_3.3=DESeqDataSetFromMatrix(countData = txi_with_without_larvae$counts,
- colData=txi_with_without_larvae$meta,
- design=~workers)
- #To only keep genes expressed in at least half of the samples, we only keep rows with at least 13 samples with a non-zero value
- dds50_3.3=dds_3.3[rowSums(counts(dds_3.3) >0)>= 13]
- #Normalized counts extraction
- dds_test_3.3=DESeq(dds50_3.3, test="LRT", reduced=~1)
- normalized_counts.3.3 = counts(dds_test_3.3, normalized = TRUE)
- #Pivot longer the dataframe
- normalized_counts_long.3.3 = normalized_counts.3.3 %>%
- as.data.frame() %>%
- rownames_to_column(var = "gene") %>%
- pivot_longer(
- cols = -gene,
- names_to = "sample",
- values_to = "normalized_count"
- )
- normalized_counts_long.3.3 = normalized_counts_long.3.3 %>%
- left_join(as.data.frame(txi_with_without_larvae$meta) %>% dplyr::select(sample, workers), by = "sample")
- ###Kr-h1
- #Subset Kr-h1 counts
- Krup.3.3=subset(normalized_counts_long.3.3, gene=="Lnig_g01448")
- #Model
- modK.3.3=lm(normalized_count~workers, data=Krup.3.3)
- simulationOutput = simulateResiduals(fittedModel= modK.3.3, plot = T)
- #Results
- car::Anova(modK.3.3)
- summary(modK.3.3)
- ###PDK1
- #Subset the dPDK1 counts
- dPDK1.3.3 =subset(normalized_counts_long.3.3, gene=="Lnig_g11740")
- #Model
- moddPDK1.3.3=lm(normalized_count~workers, data=dPDK1.3.3)
- simulationOutput = simulateResiduals(fittedModel= moddPDK1.3.3, plot = T)
- #Results
- car::Anova(moddPDK1.3.3)
- summary(moddPDK1.3.3)
- ###Insulin
- #Subset the Insulin counts
- Ins.3.3 =subset(normalized_counts_long.3.3, gene=="Lnig_g17128")
- #Model
- modIns.3.3=lm(normalized_count~workers,data=Ins.3.3)
- simulationOutput = simulateResiduals(fittedModel= modIns.3.3, plot = T)
- ##Results
- car::Anova(modIns.3.3)
- summary(modIns.3.3)
- ###Juvenile hormone esterase
- #Subset the Juvenile hormone esterase counts
- Carb.3.3 =subset(normalized_counts_long.3.3, gene=="Lnig_g08195")
- #Model
- modCarb.3.3=lm(normalized_count~workers, data=Carb.3.3)
- simulationOutput = simulateResiduals(fittedModel= modCarb.3.3, plot = T)
- #Results
- car::Anova(modCarb.3.3)
- summary(modCarb.3.3)
- ###Esterase E4
- #Subset the Esterase E4 counts
- E4.3.3 =subset(normalized_counts_long.3.3, gene=="Lnig_g15862")
- #Model
- modE4.3.3=lm(normalized_count~workers, data=E4.3.3)
- simulationOutput = simulateResiduals(fittedModel= modE4.3.3, plot = T)
- #Results
- car::Anova(modE4.3.3)
- summary(modE4.3.3)
- ###Doublesex
- #Subset the Doublesex counts
- Dbs.3.3 =subset(normalized_counts_long.3.3, gene=="Lnig_g04508")
- #Model
- modDbs.3.3=lm(normalized_count~workers, data=Dbs.3.3)
- simulationOutput = simulateResiduals(fittedModel= modDbs.3.3, plot = T)
- #Results
- car::Anova(modDbs.3.3)
- summary(modDbs.3.3)
- ###Protein henna
- #Subset the Protein henna counts
- Henna.3.3=subset(normalized_counts_long.3.3, gene=="Lnig_g13064")
- #Model
- modHenna.3.3=lm(normalized_count~workers, data=Henna.3.3)
- simulationOutput = simulateResiduals(fittedModel= modHenna.3.3, plot = T)
- #Results
- car::Anova(modHenna.3.3)
- summary(modHenna.3.3)
- ###Prohormone-2
- #Subset the Prohormone-2 counts
- Pro.3.3 =subset(normalized_counts_long.3.3, gene=="Lnig_g06899")
- #Model
- modPro.3.3=lm(normalized_count~workers, data=Pro.3.3)
- simulationOutput = simulateResiduals(fittedModel= modPro.3.3, plot = T)
- #Results
- car::Anova(modPro.3.3)
- summary(modPro.3.3)
- ###Pheromone binding protein GP-9
- #Subset the GP9 counts
- GP9.3.3=subset(normalized_counts_long.3.3, gene=="gLnigOBP1")
- #Model
- modGP9.3.3=lm(normalized_count~workers, data=GP9.3.3)
- simulationOutput = simulateResiduals(fittedModel= modGP9.3.3, plot = T)
- #Results
- car::Anova(modGP9.3.3)
- summary(modGP9.3.3)
- ### GR81
- #Subset the GR81 counts
- GR81.3.3=subset(normalized_counts_long.3.3, gene=="gLnigGR81")
- #Model
- modGR81.3.3=lm(normalized_count~workers, data=GR81.3.3)
- simulationOutput = simulateResiduals(fittedModel= modGR81.3.3, plot = T)
- #Results
- car::Anova(modGR81.3.3)
- summary(modGR81.3.3)
- ###Tret1a
- #Subset the Tret1a counts
- Tret1a.3.3 =subset(normalized_counts_long.3.3, gene=="Lnig_g01559")
- #Model
- modTret1a.3.3=lm(normalized_count~workers,data=Tret1a.3.3)
- simulationOutput = simulateResiduals(fittedModel= modTret1a.3.3, plot = T)
- #Results
- car::Anova(modTret1a.3.3)
- summary(modTret1a.3.3)
- ###Tret1b
- #Subset the Tret1b counts
- Tret1b.3.3 =subset(normalized_counts_long.3.3, gene=="Lnig_g11948")
- #Model
- modTret1b.3.3=lm(normalized_count~workers, data=Tret1b.3.3)
- simulationOutput = simulateResiduals(fittedModel= modTret1b.3.3, plot = T)
- #Results
- car::Anova(modTret1b.3.3)
- summary(modTret1b.3.3)
- ###Tret1-2 homolog
- #Subset the Tret1-2 counts
- Tret1_2.3.3=subset(normalized_counts_long.3.3, gene=="Lnig_g10144")
- #Model
- modTret1_2.3.3=lm(normalized_count~workers, data=Tret1_2.3.3)
- simulationOutput = simulateResiduals(fittedModel= modTret1_2.3.3, plot = T)
- #Results
- car::Anova(modTret1_2.3.3)
- summary(modTret1_2.3.3)
- ##5.3. Produce Supplementary Figure 5-----
- #Manual title colors
- title_pat <- gsub(" ", "", "bbb bbb bbb bbb b")
- title_vec <- strsplit(title_pat, "")[[1]]
- title_col <- ifelse(title_vec == "r", "darkgrey", "black")
- title_col <- rep(title_col, length.out = 13)
- cb_palette_5 <- c(without_larvae = "#46D3E9" ,with_larvae = "#D55E00")
- models_5 <- list(
- Krh1 = modK.3.3,
- dPDK1 = moddPDK1.3.3,
- Insulin = modIns.3.3,
- JHE = modCarb.3.3,
- E4 = modE4.3.3,
- Dsx = modDbs.3.3,
- GP9 = modGP9.3.3,
- GR81 = modGR81.3.3,
- Tret1a = modTret1a.3.3,
- Tret1b = modTret1b.3.3,
- Tret1_2 = modTret1_2.3.3,
- Henna = modHenna.3.3,
- Prohormone = modPro.3.3
- )
- padj_3.3 <- list(
- Krh1 = car::Anova(modK.3.3) [["Pr(>F)"]][1],
- dPDK1 = car::Anova(moddPDK1.3.3)[["Pr(>F)"]][1],
- Insulin = car::Anova(modIns.3.3)[["Pr(>F)"]][1],
- JuvEsterase = car::Anova(modCarb.3.3)[["Pr(>F)"]][1],
- E4 = car::Anova(modE4.3.3)[["Pr(>F)"]][1],
- Dsx = car::Anova(modDbs.3.3)[["Pr(>F)"]][1],
- GP9 = car::Anova(modGP9.3.3)[["Pr(>F)"]][1],
- GR81 = car::Anova(modGR81.3.3)[["Pr(>F)"]][1],
- Tret1a = car::Anova(modTret1a.3.3)[["Pr(>F)"]][1],
- Tret1b = car::Anova(modTret1b.3.3)[["Pr(>F)"]][1],
- Tret1_2 = car::Anova(modTret1_2.3.3)[["Pr(>F)"]][1],
- Henna = car::Anova(modHenna.3.3)[["Pr(>F)"]][1],
- Prohormone = car::Anova(modPro.3.3)[["Pr(>F)"]][1]
- )
- padj_vec_5 <- setNames(padj_3.3, names(padj_3.3))
- padj_vec_5 <- unlist(padj_vec_5, use.names = TRUE)
- all_plots_5 <- lapply(seq_len(nrow(plot_info)), function(i) {
- make_q5_panel(plot_info[i, ], i, ncol_grid = 3)
- })
- final_figure_5 <- plot_grid(
- plotlist = all_plots_5,
- nrow = 5,
- ncol = 3,
- labels = LETTERS[1:13],
- label_size = 20,
- label_fontface = "bold",
- align = "hv"
- )
- print(final_figure_5)
- #ggsave(
- # filename = "Supplementary_Figure_5.svg",
- # plot = final_figure_5,
- # width = 50,
- # height = 75,
- # units = "cm",
- # device = "svg"
- #)
- #Production of Figure 3-----
- #Addition of y axis label to plot D
- all_plots[[3]] <- all_plots[[3]] +
- ggplot2::ylab("Normalized read counts") +
- ggplot2::theme(axis.title.y = ggplot2::element_text(angle = 90,size = 20))
- figure3_plots <- c(
- all_plots[1], all_plots_4[1],
- all_plots_5[1],all_plots[3], all_plots_4[3],
- all_plots_5[3],all_plots[4], all_plots_4[4],
- all_plots_5[4],all_plots[13], all_plots_4[13],
- all_plots_5[13]
- )
- keep_y <- seq(1, length(figure3_plots), by = 3)
- figure3_plots_clean <- lapply(seq_along(figure3_plots), function(i) {
- if (!(i %in% keep_y)) {
- figure3_plots[[i]] +
- ggplot2::theme(axis.title.y = ggplot2::element_blank())
- } else {
- figure3_plots[[i]]
- }
- })
- figure3_grid <- cowplot::plot_grid(
- plotlist = figure3_plots_clean,
- nrow = 5,
- ncol = 3,
- labels = LETTERS,
- label_size = 20,
- label_fontface = "bold",
- align = "hv"
- )
- col_titles <- plot_grid(
- ggdraw() + draw_label("Experiment A", fontface = "bold", size = 30, x = 0.55),
- ggdraw() + draw_label("Experiment B", fontface = "bold", size = 30, x = 0.55),
- ggdraw() + draw_label("Experiment C", fontface = "bold", size = 30, x = 0.55),
- ncol = 3
- )
- figure3 <- plot_grid(
- col_titles,
- figure3_grid,
- ncol = 1,
- rel_heights = c(0.05, 0.95)
- )
- figure3
- #ggsave(
- # filename = "Figure_3.svg",
- # plot = figure3,
- # width = 50,
- # height = 75,
- #units = "cm",
- # device = "svg"
- #)
R script_Mol_Ecol_2026.R, no license · at the source
Overview
- Insect Biology Research Institute, UMR 7261, CNRS, University of Tours, Tours, France
- Institute of Organismic and Molecular Evolution, Johannes Gutenberg University, Mainz, Germany
Abstract
Insect societies are characterised by a reproductive division of labour between queens that monopolise egg production and workers that perform all non‐reproductive tasks. The queen specialisation in egg laying is typically considered to be constitutive and independent of environmental conditions, but this common assumption was recently challenged by the finding that the presence of workers both induces and maintains the queen specialisation in several species of ants. However, the molecular changes that translate worker presence into queen behavioural specialisation remain unknown. To investigate the transcriptomic basis of the socially regulated specialisation of ant queens, we produced 93 individual brain transcriptomes from queens of the black garden ant Lasius niger that were experimentally maintained in different social environments. Our transcriptomic analyses revealed that 123 genes were differentially expressed between the brains of queens maintained with and without workers. These genes were enriched for processes related to brain energy metabolism and neuronal plasticity and signalling. By investigating the response of selected genes of interest to further manipulations of the social environment, we identified four candidate genes that fully mirrored the queen behavioural changes. Specifically, their expression changes in response to worker presence were reversible and they did not respond to mere cues of the worker presence. These candidate genes included the transcription factor Krüppel‐homologue 1 and other genes in the juvenile hormone and insulin signalling pathways, both known to regulate multiple aspects of division of labour in social insects. By producing a robust, well‐replicated and well‐controlled investigation of the transcriptomic basis of the behavioural specialisation of ant queens, this study provides a better understanding of the emergence and maintenance of reproductive division of labour in insect societies.
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 9 matches between paragraphs and lines of code.
supp:PMC13724878/MEC-35-e70614-s003.zip
Availability: 1 check, the latest on 3 November 2026: the link answers (HTTP 200)
- 3 November 2026: the link answers (HTTP 200)
1 file
- R script_Mol_Ecol_2026.R, R, 1,888 lines, 9 matches
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;
- 9 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
No dataset and no data link were found in the paper.
Data Availability Statement
The code and input data for all analyses are provided in Data S1. The raw RNA‐seq sequences used in this study are publicly available from the NCBI BioProject PRJNA1548310.
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 2, 11 November 2026
- Publisher: n/a → Wiley
Version 1, 3 November 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 4 authors, 5 keywords, 9 MeSH terms, 2 funders, 125 references.
Cite
This paper
Le Lay, H. E., Bolder, M. F., Colgan, T. J., & Libbrecht, R. (2026). Brain Transcriptomic Changes Associated With the Socially Regulated Behavioural Specialisation of Ant Queens. Molecular ecology, 35(21), e70614. https://
BibTeX
@article{lelay2026brain,
author = {Le Lay, Hugo E and Bolder, Maximilian F and Colgan, Thomas J and Libbrecht, Romain},
title = {{Brain Transcriptomic Changes Associated With the Socially Regulated Behavioural Specialisation of Ant Queens}},
journal = {Molecular ecology},
year = {2026},
month = nov,
volume = {35},
number = {21},
pages = {e70614},
publisher = {Wiley},
issn = {0962-1083},
doi = {10.1111/
url = {https://
pmid = {42968400},
pmcid = {PMC13724878}
}
RIS
TY - JOUR
AU - Le Lay, Hugo E
AU - Bolder, Maximilian F
AU - Colgan, Thomas J
AU - Libbrecht, Romain
TI - Brain Transcriptomic Changes Associated With the Socially Regulated Behavioural Specialisation of Ant Queens
T2 - Molecular ecology
J2 - Mol Ecol
PY - 2026
DA - 2026/
VL - 35
IS - 21
SP - e70614
SN - 0962-1083
PB - Wiley
DO - 10.1111/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1111/
"type": "article-journal",
"title": "Brain Transcriptomic Changes Associated With the Socially Regulated Behavioural Specialisation of Ant Queens",
"container-title": "Molecular ecology",
"author": [
{
"family": "Le Lay",
"given": "Hugo E"
},
{
"family": "Bolder",
"given": "Maximilian F"
},
{
"family": "Colgan",
"given": "Thomas J"
},
{
"family": "Libbrecht",
"given": "Romain"
}
],
"container-title-short":
"volume": "35",
"issue": "21",
"page": "e70614",
"DOI": "10.1111/
"PMID": "42968400",
"PMCID": "PMC13724878",
"ISSN": "0962-1083",
"publisher": "Wiley",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
11,
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.1111/mec.70360 [code]
- Unmated Queens Show Worker-Like Behaviour and Gene Expression in Polygynous Colonies of the Ant Stigmatomma pallipes.Journal: Molecular ecologyIn common: other, genetics / omics, cellular / molecular, 16 references, 2 authors
- [2] doi:10.1038/s42003-023-05273-4 [code]
- Task-specific odorant receptor expression in worker antennae indicates that sensory filters regulate division of labor in ants.Journal: Communications biologyIn common: other, genetics / omics, cellular / molecular, 16 references, author Romain Libbrecht
- [3] doi:10.1371/journal.pbio.3002763 [code]
- An evolutionarily conserved pathway mediated by neuroparsin-A regulates reproductive plasticity in ants.Journal: PLoS biologyIn common: other, cellular / molecular, 12 references
- [4] doi:10.1242/jeb.246785
- Effects of microRNA-305 knockdown on brain gene expression associated with division of labor in honey bee colonies (Apis mellifera).Journal: The Journal of experimental biologyIn common: other, genetics / omics, cellular / molecular, 9 references
- [5] doi:10.1038/s41586-026-10747-6 [code]
- Ancient feeding-related neuropeptides regulate alloparenting in ants.Journal: NatureIn common: patchwork, ggpubr, ggplot2, 1 other tool, other, 7 references
- [6] 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: multcomp, emmeans, car, 7 other tools, genetics / omics, 2 references
- [7] doi:10.1038/s43587-025-00816-2 [code]
- Interleukin-12 signaling drives Alzheimer's disease pathology through disrupting neuronal and oligodendrocyte homeostasis.Journal: Nature agingIn common: multcomp, car, DESeq2, 6 other tools, cellular / molecular, 1 reference
- [8] doi:10.1111/gbb.70007 [code]
- The brain atlas of a subsocial bee reflects that of eusocial Hymenoptera.Journal: Genes, brain, and behaviorIn common: patchwork, cowplot, ggplot2, 1 other tool, other, genetics / omics, 4 references
- [9] doi:10.1371/journal.pone.0353990 [code]
- Positive mood enhances accessibility of unrelated concepts in the first language but not in the foreign language.Journal: PloS oneIn common: multcomp, emmeans, car, 5 other tools, 1 reference
- [10] doi:10.1002/aur.70042 [code]
- Multisensory Integration of Naturalistic Speech and Gestures in Autistic Adults.Journal: Autism research : official journal of the International Society for Autism ResearchIn common: multcomp, emmeans, car, 6 other tools
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 1 script, and 9 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:a85e082a1ab71f3d…
Add the badge to the code's README
If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.
Markdown
<!-- oscr-badge:start -->
[](https://openscicode.org/badge/doi/10.1111/mec.70614)
<!-- oscr-badge:end -->reStructuredText
.. oscr-badge:start
.. image:: https://openscicode.org/badge/doi/10.1111/mec.70614.svg
:target: https://openscicode.org/badge/doi/10.1111/mec.70614
:alt: OSCR
.. oscr-badge:endHTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1111/mec.70614"><img src="https://openscicode.org/badge/doi/10.1111/mec.70614.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge page.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.
Report a mismatch between the code and the paper · Report a code error (signed in)
Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.
Report a reproduction failure (signed in)
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
