EXPLORING THE EFFECT OF VIRAL INFECTION ON AT2-TO-AT1 TRANS-DIFFERENTIATION

Chika Ikpechukwu

2025-04-30


Overview

This project investigates how viral infection impacts the canonical alveolar type 2 (AT2) to alveolar type 1 (AT1) trans-differentiation process, a key mechanism in lung repair following injury. To explore this, RNA sequencing (RNA-seq) data from Bai et al.’s study on the role of mechanical breathing in modulating innate immune responses to viral infection was analyzed. The original researchers employed a stretchable microfluidic alveolus-on-a-chip model to co-culture primary human alveolar epithelial cells and pulmonary microvascular endothelial cells on opposite sides of an ECM-coated porous membrane. The chip was subjected to 5% cyclic strain at 0.25 Hz for 16 days to mimic physiological breathing. Epithelial cells were infected with the H3N2 influenza virus, and RNA-seq was performed to assess transcriptional changes under these dynamic conditions.

Bai et al. found that the application of breathing-like mechanical strain significantly reduced viral replication when compared to static controls. They further identified key mechano-sensitive pathways, including TRPV4 and RAGE, as mediators of this enhanced innate immune response. While the study demonstrated role of mechanical strain during viral infection, it did not investigate whether viral infection alters key alveolar epithelial repair processes—specifically, the trans-differentiation of AT2 to AT1 cells. This project builds on that gap by assessing differential expression of key AT2 and AT1 markers in H3N2 influenza infected versus uninfected AT2 cells (subjected to physiological breathing motions) to determine whether viral presence interferes with this critical regenerative pathway.

I hypothesized that viral infection significantly alters the AT2:AT1 cell ratio in the epithelium by significantly altering the expression of key AT2, AT1 and transitional markers’ expression levels. For the sake of this study 6 known AT2, AT1 and transition state markers’ expression will be analyzed in both H3N2 infected cells and non-infected cells. The markers used for this analysis are listed in Table 1.

Table 1: AT2, AT1 and Transitional Markers’ Analyzed

AT2 Markers AT1 Markers Transitional Markers
ABCA3 AGER KRT8
LAMP3 AQP5 CLDN4
NAPSA CAV1 SFN
SFTPB EMP2 CCN2
SFTPD HOPX ANKRD1
SFTPC RTKN2 KRT17

Data Acquisition and Processing

Bulk RNA-seq data from H3N2-infected and uninfected epithelial cells under physiological breathing conditions were downloaded from NCBI GEO (Accession #: GSE178266). The raw fastq files for the paired end reads were downloaded using the ‘fasterq-dump’ function in a UNIX environment. Table 2 shows the relevant attributes of the samples analyzed in this project.

Table 2: Sample Information

SRR IDs Sample Name Organism Treatment Read Type Sequencer
SRR14821206 Epi_control_rep_1 H. sapiens
  • 5% cyclic mechanical strain
  • No infection
Paired-end Illumina HiSeq 2500
SRR14821207 Epi_control_rep_2 H. sapiens
  • 5% cyclic mechanical strain
  • No infection
Paired-end Illumina HiSeq 2500
SRR14821208 Epi_control_rep_3 H. sapiens
  • 5% cyclic mechanical strain
  • No infection
Paired-end Illumina HiSeq 2500
SRR14821209 Epi_H3N2_rep_1 H. sapiens
  • 5% cyclic mechanical strain
  • H3N2 infection
Paired-end Illumina HiSeq 2500
SRR14821210 Epi_H3N2_rep_2 H. sapiens
  • 5% cyclic mechanical strain
  • H3N2 infection
Paired-end Illumina HiSeq 2500
SRR14821211 Epi_H3N2_rep_3 H. sapiens
  • 5% cyclic mechanical strain
  • H3N2 infection
Paired-end Illumina HiSeq 2500

Initial quality control checks revealed that the data quality was good besides the presence of some overly-represented sequences and adapter sequences. These artifacts were trimmed off using Trimmomatic v.0.39 before mapping the reads to the human genome (GRCh38) using STAR aligner v. 2.7. Gene count matrix for each sample was generated using HTSeq Count.

Gene Expression Analysis

Load Relevant Libraries

The following packages listed in this code chunk were loaded into the R environment using pacman package manager.

pacman::p_load(DESeq2, tidyverse, RColorBrewer, EnhancedVolcano, ggnewscale, knitr, patchwork, ggplotify, biomaRt, ggpubr, kableExtra)

Create dds object

Next the count matrices along with relevant metadata (Table 3) were imported into the R environment as a DESeqDataSet (dds) object using the ‘DESeqDataSetFromHTSeqCount’ function. Since the research question involves comparing differential expressed genes between H3N2 infect and non-infected cells, the condition was specified in the dds object creation step. Furthermore, the non-infected group was used as the reference for differentially expressed genes (DEGs) analysis. Lastly, only genes with a total sum of at least 10 reads count were used for DEG analysis. Then genes with total reads count less than 10 were exclude and the data was then normalized by the library size factors using the ‘estimateSizeFactors()’ fuction to correct for libriry size differences across the samples.

## Metadata File

GSE178266_metadata <- read_csv("GSE178266_metafile.csv") # read in metadata file as a dataframe
condition <- factor(GSE178266_metadata$condition) # specify as condition factor 



## Create dds object
dds <- DESeqDataSetFromHTSeqCount(sampleTable = GSE178266_metadata,
                                  directory = "counts/",
                                  design = ~ condition)
dds$condition <- relevel(dds$condition, ref = "no_infection") # set 'no_infection' group as the reference group

## Filter out features with overall low reads count
keep <- rowSums(counts(dds)) >= 10
dds <- dds[keep,]

# Normalizing dds by size factors
dds <- estimateSizeFactors(dds)
# 

kable(GSE178266_metadata, caption = "***Table 3: Samples Metadata***") # display meta data
Table 3: Samples Metadata
samplename filename condition replicate
no_infection_rep1 SRR14821206.gene_id.count.txt no_infection 1
no_infection_rep2 SRR14821207.gene_id.count.txt no_infection 2
no_infection_rep3 SRR14821208.gene_id.count.txt no_infection 3
H3N2_rep1 SRR14821209.gene_id.count.txt H3N2 1
H3N2_rep2 SRR14821210.gene_id.count.txt H3N2 2
H3N2_rep3 SRR14821211.gene_id.count.txt H3N2 3

Run DESeq

Differentially expression genes between the treatment and control group were identified using the ‘DESeq()’ function as shown in the code chunk below. DEGs were identified as genes with adjusted p-values less than 0.05 an absolute log2-fold-change greater than 1. Following this, a new classification column ‘diffexpressed’ was added to the result dataframe indicate whether each each gene is up-regulated, down-regulated or not significant. As shown on Table 4, 476 genes where upregulated while 485 genes were downregulated (total DEGs = 961) due to the viral infection.

dds <- DESeq(dds)

res <- results(dds, contrast=c('condition','H3N2', 'no_infection'))

resLfc <- lfcShrink(dds, coef = "condition_H3N2_vs_no_infection", res = res)
# plotMA(resLfc)
result <- resLfc[order(resLfc$padj), ]



# Combine DESeq Result with count data from dds
result_df <- merge(as.data.frame(result),
                 as.data.frame(counts(dds, normalized=TRUE)),
                 by="row.names",
                 sort=FALSE)

names(result_df)[1] <- "Gene_id" 


# Add a column to dataframe to specify up or down regulated or Not significant
result_df$diffexpressed <- "Not Significant"

#if log2FC > 1 and padj < 0.05 set as upregulated
result_df$diffexpressed[result_df$padj < 0.05 & result_df$log2FoldChange > 1] <- "Upregulated"

#if log2FC < -1 and padj < 0.05 set as downregulated
result_df$diffexpressed[result_df$padj < 0.05 & result_df$log2FoldChange < -1] <- "Downregulated"


DEG_count <- result_df |> 
  group_by(diffexpressed) |> 
  summarise(
    No_genes = n()
  )
kable(DEG_count, caption = "*Table 4: Number of DEGs*")
Table 4: Number of DEGs
diffexpressed No_genes
Downregulated 485
Not Significant 32003
Upregulated 476

Extract Genes of Interest (GOI) Results

Although 1306 genes were differentially expressed only 18 genes (shown in Table1 ) will be used in assessment of the hypothesis. This is because significant changes in key AT2, AT1 or transitional markers’ expression is indicative of the AT2-to-AT1 trans-differention. In order to accurately subset the DESeq results dataframe, the corresponding gene names for each Ensembl ID was added to the dataframe with the help of biomaRt package - a package that allows users to query Ensembl’s database directly from R. Note: the biomaRt package was used instead of ‘genekitr’ consistently returned errors.

After generating the corresponding gene names, a subset of the dataset including only the specified genes of interest was created. Table 5 shows the selected results.

# Remove the version from Ensembl gene IDs
result_df$Ensembl_id <- sub("\\.\\d+$", "", result_df$Gene_id)

# Extract the cleaned Ensembl IDs
ids <- result_df$Ensembl_id


# Connect to Ensembl repository
ensembl <- useMart("ensembl", dataset = "hsapiens_gene_ensembl")

# Get corresponding gene names for each gene ids.
gene_map <- getBM(attributes = c('ensembl_gene_id', 'hgnc_symbol'),
                  filters = 'ensembl_gene_id',
                  values = ids,
                  mart = ensembl)



# Specify relevant genes for analysis
AT1_Markers <- c("AGER", "AQP5", "HOPX", "CAV1", "RTKN2", "EMP2")
AT2_Markers <- c("SFTPC", "SFTPB", "SFTPD", "ABCA3", "NAPSA", "LAMP3")
Trans_Markers <- c("KRT8", "CLDN4", "SFN", "CCN2", "ANKRD1", "KRT17")
all_markers <- c(AT1_Markers, AT2_Markers, Trans_Markers)

# Only store the relevant genes (AT1, AT2 and Transitional genes)
select_genes_names <- gene_map |>
  filter(hgnc_symbol %in% all_markers) |>
   rename(
    Ensembl_id = ensembl_gene_id,
    symbol = hgnc_symbol
  )

all_gene_names <- gene_map |>
   rename(
    Ensembl_id = ensembl_gene_id,
    symbol = hgnc_symbol
  )

merged_all_df <- result_df %>%
  inner_join(all_gene_names, by = "Ensembl_id")


# Create a dataframe containing the DESeq results for the genes of interest
merged_df <- result_df %>%
  inner_join(select_genes_names, by = "Ensembl_id")

# Classify gene by gene type (AT1, AT2 or Transitional genes)
merged_df <- merged_df |>
  mutate(
    gene_class = case_when(
      symbol %in% AT1_Markers ~ "AT1",
      symbol %in% AT2_Markers ~ "AT2",
      symbol %in% Trans_Markers ~ "Transitional"

    )
  )

merged_df <- merged_df |> 
  arrange(gene_class, symbol)


# Display relevant results
kable(dplyr::select(merged_df,Ensembl_id, symbol, gene_class,baseMean, log2FoldChange, padj, diffexpressed), caption = "*Table 5: Genes of Interest DEQSeq Results*")
Table 5: Genes of Interest DEQSeq Results
Ensembl_id symbol gene_class baseMean log2FoldChange padj diffexpressed
ENSG00000204305 AGER AT1 46.658147 0.2045861 0.3813080 Not Significant
ENSG00000161798 AQP5 AT1 75.028627 0.4952810 0.0522861 Not Significant
ENSG00000105974 CAV1 AT1 9564.136923 0.5572171 0.0000000 Not Significant
ENSG00000213853 EMP2 AT1 600.725520 0.9132344 0.0000000 Not Significant
ENSG00000171476 HOPX AT1 8.141901 -0.0268827 0.8906798 Not Significant
ENSG00000182010 RTKN2 AT1 188.736330 0.3310409 0.0396731 Not Significant
ENSG00000167972 ABCA3 AT2 256.453601 -0.9576449 0.0000006 Not Significant
ENSG00000078081 LAMP3 AT2 1160.719376 0.5348979 0.0000475 Not Significant
ENSG00000131400 NAPSA AT2 42.923179 -0.3797794 0.1260648 Not Significant
ENSG00000168878 SFTPB AT2 15.823521 0.1126240 0.5962442 Not Significant
ENSG00000133661 SFTPD AT2 27.061988 0.5585833 0.0663541 Not Significant
ENSG00000148677 ANKRD1 Transitional 6739.879463 0.6953494 0.0000000 Not Significant
ENSG00000118523 CCN2 Transitional 221.241530 0.0595317 0.8011102 Not Significant
ENSG00000189143 CLDN4 Transitional 7779.068729 -0.3438340 0.0005450 Not Significant
ENSG00000128422 KRT17 Transitional 20265.239919 0.1837919 0.1772175 Not Significant
ENSG00000170421 KRT8 Transitional 30873.733806 0.2956786 0.0007427 Not Significant
ENSG00000175793 SFN Transitional 2990.560061 0.3912785 0.0029866 Not Significant

Visualizations

Principal component analysis (Figure 1) revealed a clear separation in gene expression profiles based on treatment condition, indicating substantial transcriptional differences between H3N2-infected and uninfected samples. To further explore the expression patterns of specific genes of interest (GOIs), boxplots were generated using ggplot2, displaying the mean normalized expression levels for each condition (Figure 3). These plots focus on three gene classes: AT2, AT1, and transitional markers.

Although differential expression analysis (Figure 2) did not identify any GOIs as significantly differentially expressed overall, several individual markers—namely ABCA3, LAMP3, CAV1, EMP2, RTKN2, ANKRD1, CLDN4, and KRT8—showed statistically significant differences between conditions. The absence of strong differential expression across all GOIs may be due to small effect sizes, as none of the genes exhibited large fold changes despite some reaching statistical significance.

Notably, the expression levels of most AT1 and transitional markers were lower in the H3N2-infected samples, suggesting that viral infection may impair the AT2-to-AT1 trans-differentiation process during alveolar repair.

In conclusion, H3N2 influenza infection appears to disrupt the AT2-to-AT1 trans-differentiation process by altering the expression of key AT1, AT2, and transitional state markers.

# 

######## FIGURE 1

### Principal components analysis
vstcounts <- vst(dds, blind=TRUE)
pcaData <- plotPCA(vstcounts, intgroup=c("condition"), returnData=TRUE)
percentVar <- round(100 * attr(pcaData, "percentVar"))

pca <-ggplot(pcaData, aes(PC1, PC2, color=condition, shape = condition)) +
  geom_point(size=4, alpha=0.8) + # adding transparency
  ylim(-10,10) + 
  xlab(paste0("PC1: ",percentVar[1],"% variance")) +
  ylab(paste0("PC2: ",percentVar[2],"% variance")) + 
  coord_fixed() + 
  ggtitle("Principal Component Analysis of Control and Infected Samples") + 
  scale_color_brewer(palette = "Set1") + 
  theme_classic() + 
  theme(legend.position = "right", 
        legend.title = element_text(size = 12, face = "bold",hjust = 0.5),
        legend.text = element_text(size = 12),
        plot.title = element_text(hjust=0.5, face = "bold"),
        axis.title.x = element_text(size = 14),   # x-axis label
        axis.title.y = element_text(size = 14),   # y-axis label
        axis.text.x  = element_text(size = 12),   # x-axis tick numbers
        axis.text.y  = element_text(size = 12)    # y-axis tick numbers
  )+
  
labs(caption = "Figure 1: Principal Component Analysis plot displaying the variance between all sample.\n Clustering was done by treatment conditon.") +
  theme(
    plot.caption = element_text(size = 11, hjust = 0, face = "italic")  
  )

print(pca)

##### FIGURE 2: VOLCANO PLOT of DEGs

select_volcano <- ggplot(merged_all_df) +
  geom_point(aes(x = log2FoldChange, y = -log10(padj),
                 color = diffexpressed,
                 alpha = 1),
             size = 2) +
  geom_text(data = subset(merged_all_df, symbol %in% all_markers), 
            aes(x = log2FoldChange, y = -log10(padj), 
            label = symbol),
            size = 3, vjust = -1, check_overlap = T) +
  
  # Add vertical dotted lines at x = -1 and x = 1
  geom_vline(xintercept = c(-1, 1), linetype = "dashed", color = "black", linewidth = 1) +

  theme_classic() +
  guides(alpha = "none") +     # Remove alpha legend
  # Custom colors for diffexpressed
  scale_color_manual(values = c("Downregulated" = "gray", "Upregulated" = "gray", "Not Significant" = "red")) +

  labs(color = "Legend") +
  theme(
    legend.title = element_text(hjust = 0.5)  # Center and bold the title
  ) +
  ggtitle("DEGs (Only Genes of Interest) H3N2 infected and no infection") +
  xlab("Log2 fold change") +
  ylab("-Log10(padj)") +
  theme(legend.position = "top",
        plot.title = element_text(size = rel(1.5), hjust = 0.5, face = "bold"),
        axis.title = element_text(size = rel(1.2)),
        axis.line = element_line(color = "black", size = 0.8)
        )+ # add x and y axis lines
  scale_x_continuous(limits = c(-5, 5)) +
labs(caption = "Figure 2: Volcano Plot Showing DEGs (only select genes) Between H3N2 Infected \n and Non-infected Cells. None of the key AT1, AT2 or Transitional cells were differentially \n expressed.") +
  theme(
    plot.caption = element_text(size = 11, hjust = 0, face = "italic")  
  )+
  coord_cartesian(ylim = c(0, 50), clip = "off")

print(select_volcano)

# Reshape the data to long format
df_long <- merged_df %>%
  pivot_longer(
    cols = starts_with(c("no_infection", "H3N2")),
    names_to = c("Condition", "Replicate"),
    names_pattern = "(.*)_(rep\\d+)",
    values_to = "Expression"
  )



## AT2 BOX PLOTS

AT2_boxplots <- ggplot(df_long |>
         filter(gene_class == "AT2"),
       aes(x = Condition, y = Expression, fill = Condition)) +
  geom_boxplot(width = 0.5, alpha = 0.7, outlier.shape = NA) +
  geom_jitter(width = 0.2, size = 1.5, alpha = 0.8) +
  facet_wrap(~ symbol, scales = "free_y", nrow = 1) +
  theme_minimal() +
  theme(
    strip.text = element_text(face = "bold", size = 10, margin = margin(b = 18)),
    axis.text.x = element_blank(),
    legend.position = "none",    # move legend to top for better space
    legend.title = element_blank(),   # remove unnecessary title
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    axis.line = element_line(color = "black", size = 0.8),  # add x and y axis lines
    plot.title = element_text(hjust = 0.5, face = "bold", size = 16)  # <== main title centered and bold

  ) +
  labs(
    title = "AT2 Markers",
    x = NULL,
    y = "Expression"
  ) +
  scale_fill_manual(
    values = c("no_infection" = "lightblue", "H3N2" = "salmon")
    # labels = c("No Infection", "H3N2")   # set legend labels nicely
  ) +
  stat_compare_means(
    method = "t.test",
    label = "p.signif",
    comparisons = list(c("no_infection", "H3N2")),
    hide.ns = TRUE,
    size = 6, fontface = "bold"
  ) + 
  coord_cartesian(clip = "off")


## AT1 BOX PLOTS

AT1_boxplots <- ggplot(df_long |>
         filter(gene_class == "AT1"),
       aes(x = Condition, y = Expression, fill = Condition)) +
  geom_boxplot(width = 0.5, alpha = 0.7, outlier.shape = NA) +
  geom_jitter(width = 0.2, size = 1.5, alpha = 0.8) +
  facet_wrap(~ symbol, scales = "free_y", nrow = 1) +
  theme_minimal() +
  theme(
    strip.text = element_text(face = "bold", size = 10, margin = margin(b = 18)),
    axis.text.x = element_blank(),
    legend.position = "none",    # move legend to top for better space
    legend.title = element_blank(),   # remove unnecessary title
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    axis.line = element_line(color = "black", size = 0.8),  # add x and y axis lines
    plot.title = element_text(hjust = 0.5, face = "bold", size = 16)  # <== main title centered and bold

  ) +
  labs(
    title = "AT1 Markers",
    x = NULL,
    y = "Expression"
  ) +
  scale_fill_manual(
    values = c("no_infection" = "lightblue", "H3N2" = "salmon"),
    labels = c("No Infection", "H3N2")   # set legend labels nicely
  ) +
  stat_compare_means(
    method = "t.test",
    label = "p.signif",
    comparisons = list(c("no_infection", "H3N2")),
    hide.ns = TRUE,
    size = 6, fontface = "bold"
  ) + 
  coord_cartesian(clip = "off")

## TRANSITIONAL BOX PLOTS

Trans_boxplots <- ggplot(df_long |>
         filter(gene_class == "Transitional"),
       aes(x = Condition, y = Expression, fill = Condition)) +
  geom_boxplot(width = 0.5, alpha = 0.7, outlier.shape = NA) +
  geom_jitter(width = 0.2, size = 1.5, alpha = 0.8) +
  facet_wrap(~ symbol, scales = "free_y", nrow = 1) +
  theme_minimal() +
  theme(
    strip.text = element_text(face = "bold", size = 10, margin = margin(b = 18)),
    axis.text.x = element_blank(),
    # axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom",    # move legend to top for better space
    legend.title = element_blank(),   # remove unnecessary title
    legend.text = element_text(size = 12),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    axis.line = element_line(color = "black", size = 0.8),  # add x and y axis lines
    plot.title = element_text(hjust = 0.5, face = "bold", size = 16)  # <== main title centered and bold

  ) +
  labs(
    title = "Transitional Markers",
    x = NULL,
    y = "Expression"
  ) +
  scale_fill_manual(
    values = c("no_infection" = "lightblue", "H3N2" = "salmon"),
    labels = c("No Infection", "H3N2")   # set legend labels nicely
  ) +
  stat_compare_means(
    method = "t.test",
    label = "p.signif",
    comparisons = list(c("no_infection", "H3N2")),
    hide.ns = TRUE,
    size = 6, fontface = "bold"
  ) + 
  coord_cartesian(clip = "off")
### COMBINE PLOTS (FIGURE 3)
combined_plots1 <- AT2_boxplots/AT1_boxplots/Trans_boxplots

combined_plots1 <- combined_plots1+
 plot_annotation(
    title = "Gene Expression Comparison H3N2 and No Infection",
    theme = theme(
      plot.title = element_text(size = 20, face = "bold", hjust = 0.5)  # center and bold the big title
    ),
    tag_levels = "a"  # <<< automatically adds (a), (b), (c) labels
  )+
  plot_annotation(caption = "Figure 3: Gene Expression Comparison According to Gene Type. Pairwise comparison was done using t-test \n(ns = P > 0.05;     * = P ≤ 0.05;     ** = P ≤ 0.01)" ,
                  theme = theme(plot.caption = element_text(size = 12, face = "italic", hjust =0))
                  )
print(combined_plots1)

sessionInfo()
## R version 4.4.3 (2025-02-28 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26100)
## 
## Matrix products: default
## 
## 
## locale:
## [1] LC_COLLATE=English_United States.utf8 
## [2] LC_CTYPE=English_United States.utf8   
## [3] LC_MONETARY=English_United States.utf8
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.utf8    
## 
## time zone: America/New_York
## tzcode source: internal
## 
## attached base packages:
## [1] stats4    stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
##  [1] kableExtra_1.4.0            ggpubr_0.6.0               
##  [3] biomaRt_2.62.1              ggplotify_0.1.2            
##  [5] patchwork_1.3.0             knitr_1.50                 
##  [7] ggnewscale_0.5.1            EnhancedVolcano_1.24.0     
##  [9] ggrepel_0.9.6               RColorBrewer_1.1-3         
## [11] lubridate_1.9.4             forcats_1.0.0              
## [13] stringr_1.5.1               dplyr_1.1.4                
## [15] purrr_1.0.4                 readr_2.1.5                
## [17] tidyr_1.3.1                 tibble_3.2.1               
## [19] ggplot2_3.5.2               tidyverse_2.0.0            
## [21] DESeq2_1.46.0               SummarizedExperiment_1.36.0
## [23] Biobase_2.66.0              MatrixGenerics_1.18.1      
## [25] matrixStats_1.5.0           GenomicRanges_1.58.0       
## [27] GenomeInfoDb_1.42.3         IRanges_2.40.1             
## [29] S4Vectors_0.44.0            BiocGenerics_0.52.0        
## 
## loaded via a namespace (and not attached):
##  [1] rstudioapi_0.17.1       jsonlite_2.0.0          magrittr_2.0.3         
##  [4] farver_2.1.2            rmarkdown_2.29          fs_1.6.5               
##  [7] zlibbioc_1.52.0         vctrs_0.6.5             memoise_2.0.1          
## [10] prettydoc_0.4.1         rstatix_0.7.2           htmltools_0.5.8.1      
## [13] S4Arrays_1.6.0          progress_1.2.3          curl_6.2.2             
## [16] broom_1.0.8             SparseArray_1.6.2       Formula_1.2-5          
## [19] gridGraphics_0.5-1      sass_0.4.9              bslib_0.9.0            
## [22] plyr_1.8.9              httr2_1.1.2             cachem_1.1.0           
## [25] lifecycle_1.0.4         pkgconfig_2.0.3         Matrix_1.7-3           
## [28] R6_2.6.1                fastmap_1.2.0           GenomeInfoDbData_1.2.13
## [31] digest_0.6.37           numDeriv_2016.8-1.1     colorspace_2.1-1       
## [34] AnnotationDbi_1.68.0    RSQLite_2.3.9           labeling_0.4.3         
## [37] filelock_1.0.3          timechange_0.3.0        httr_1.4.7             
## [40] abind_1.4-8             compiler_4.4.3          bit64_4.6.0-1          
## [43] withr_3.0.2             backports_1.5.0         BiocParallel_1.40.0    
## [46] carData_3.0-5           DBI_1.2.3               ggsignif_0.6.4         
## [49] MASS_7.3-65             rappdirs_0.3.3          DelayedArray_0.32.0    
## [52] tools_4.4.3             glue_1.8.0              grid_4.4.3             
## [55] generics_0.1.3          gtable_0.3.6            tzdb_0.5.0             
## [58] hms_1.1.3               xml2_1.3.8              car_3.1-3              
## [61] XVector_0.46.0          pillar_1.10.2           yulab.utils_0.2.0      
## [64] emdbook_1.3.13          vroom_1.6.5             BiocFileCache_2.14.0   
## [67] lattice_0.22-7          bit_4.6.0               tidyselect_1.2.1       
## [70] locfit_1.5-9.12         Biostrings_2.74.1       svglite_2.1.3          
## [73] xfun_0.52               stringi_1.8.7           UCSC.utils_1.2.0       
## [76] yaml_2.3.10             pacman_0.5.1            evaluate_1.0.3         
## [79] codetools_0.2-20        bbmle_1.0.25.1          cli_3.6.4              
## [82] systemfonts_1.2.2       munsell_0.5.1           jquerylib_0.1.4        
## [85] Rcpp_1.0.14             dbplyr_2.5.0            coda_0.19-4.1          
## [88] png_0.1-8               bdsmatrix_1.3-7         parallel_4.4.3         
## [91] blob_1.2.4              prettyunits_1.2.0       viridisLite_0.4.2      
## [94] mvtnorm_1.3-3           apeglm_1.28.0           scales_1.3.0           
## [97] crayon_1.5.3            rlang_1.1.5             KEGGREST_1.46.0