Omics data: Too many results, too many tables …

Omics data: Too many results, too many tables …

Omics data: Too many results, too many tables …

Omics data: Too many results, too many tables …

Omics data: Too many results, too many tables …

Problem amplified: Complex designs/Single-cell data …

Problem

  • Difficulty to manage, explore, contextualize and reproduce the results

Our solution

  • A new S4 object DeeDeeExperiment to structure and store DEA and FEA results in one place, based on the SingleCellExperiment object

Note

DeeDeeExperiment won’t do the analysis for you, it’s a container

Creating a dde object

# initialize DeeDeeExperiment with dds object and DESeq results (as a named list)
dde <- DeeDeeExperiment(sce = dds_macrophage,
                        de_results = list(
                          IFNg_vs_naive = IFNg_vs_naive,
                          Salm_vs_naive = Salm_vs_naive
                          ))

dde
class: DeeDeeExperiment 
dim: 1000 24 
metadata(7): tximetaInfo quantInfo ... txdbInfo version
assays(7): counts abundance ... H cooks
rownames(1000): ENSG00000164741 ENSG00000078808 ... ENSG00000273680
  ENSG00000073536
rowData names(58): gene_id SYMBOL ... Salm_vs_naive_pvalue
  Salm_vs_naive_padj
colnames(24): SAMEA103885102 SAMEA103885347 ... SAMEA103885308
  SAMEA103884949
colData names(15): names sample_id ... condition line
reducedDimNames(0):
mainExpName: NULL
altExpNames(0):
dea(2): IFNg_vs_naive, Salm_vs_naive 
fea(0): 

Note

Supported DE result types: DESeqResults, DGEExact, DGELRT, MArrayLM, or data.frame

Adding results to a dde object

DEA results

# add results from limma as a MArrayLM object
dde <- addDEA(dde, dea = de_limma)

dde
class: DeeDeeExperiment 
dim: 1000 24 
metadata(7): tximetaInfo quantInfo ... txdbInfo version
assays(7): counts abundance ... H cooks
rownames(1000): ENSG00000164741 ENSG00000078808 ... ENSG00000273680
  ENSG00000073536
rowData names(61): gene_id SYMBOL ... de_limma_pvalue de_limma_padj
colnames(24): SAMEA103885102 SAMEA103885347 ... SAMEA103885308
  SAMEA103884949
colData names(15): names sample_id ... condition line
reducedDimNames(0):
mainExpName: NULL
altExpNames(0):
dea(3): IFNg_vs_naive, Salm_vs_naive, de_limma 
fea(0): 
# inspect the columns of the rowData
tail(names(rowData(dde)))
[1] "Salm_vs_naive_log2FoldChange" "Salm_vs_naive_pvalue"        
[3] "Salm_vs_naive_padj"           "de_limma_log2FoldChange"     
[5] "de_limma_pvalue"              "de_limma_padj"               

Adding results to a dde object

FEA results

→ Can be added to a dde object using the addFEA() method.

# add FEA results as a named list
dde <- addFEA(dde,
              fea = list(IFNg_vs_naive = topGO_results_list$ifng_vs_naive))

# add FEA results as a single object
dde <- addFEA(dde, fea = gost_res$result)

# add FEA results and specify the FEA tool
dde <- addFEA(dde, fea = clusterPro_res, fea_tool = "clusterProfiler")

FEA results formats that are supported natively within DeeDeeExperiment

supported_fea_formats()
        Format         Package
1   data.frame           topGO
2 enrichResult clusterProfiler
3   gseaResult clusterProfiler
4  fgseaResult           fgsea
5   data.frame      gprofiler2
6   data.frame         enrichR
7   data.frame           DAVID
8   data.frame       GeneTonic

Linking DE and FE Analysis in a dde object





dde <- linkDEAandFEA(dde,
                     dea_name = "IFNg_vs_naive",
                     fea_name = c("IFNg_vs_naive", "gost_res$result"))
✔ Assigning DEA: "IFNg_vs_naive" to FEA "IFNg_vs_naive"
✔ Assigning DEA: "IFNg_vs_naive" to FEA "gost_res$result"

Adding contextual information





dde <- addScenarioInfo(dde,
                       dea_name = "IFNg_vs_naive",
                       info = "This results contains the output of a Differential Expression Analysis performed on data from the `macrophage` package, more precisely contrasting the counts from naive macrophage to those associated with IFNg."
)
  • Document experimental setup for clarity & reproducibility
  • Clarify comparisons between conditions
  • Provide extra context that can assist interpretation (e.g. by LLM)

Summary of a dde object

Set FDR threshold

# specify FDR threshold for subsetting DE genes based on adjusted p-values
summary(dde,
        FDR = 0.01)
DE Results Summary:
      DEA_name  Up Down  FDR
 IFNg_vs_naive  30   15 0.01
 Salm_vs_naive  80   29 0.01
      de_limma 203  244 0.01
 same_contrast 203  244 0.01

FE Results Summary:
            FEA_Name     Linked_DE         FE_Type Term_Number
       IFNg_vs_naive IFNg_vs_naive           topGO         955
     gost_res$result IFNg_vs_naive       gProfiler        2095
       ifng_vs_naive             . clusterProfiler          20
 salmonella_vs_naive             . clusterProfiler          11

Summary of a dde object

Display scenario information

# show contextual information, if available
summary(dde,
        show_scenario_info = TRUE)
DE Results Summary:
      DEA_name  Up Down  FDR
 IFNg_vs_naive  36   17 0.05
 Salm_vs_naive  90   34 0.05
      de_limma 265  303 0.05
 same_contrast 265  303 0.05

FE Results Summary:
            FEA_Name     Linked_DE         FE_Type Term_Number
       IFNg_vs_naive IFNg_vs_naive           topGO         955
     gost_res$result IFNg_vs_naive       gProfiler        2095
       ifng_vs_naive             . clusterProfiler          20
 salmonella_vs_naive             . clusterProfiler          11

Scenario Info:
 - IFNg_vs_naive :
 This results contains the output of a Differential Expression Analysis
  performed on data from the `macrophage` package, more precisely contrasting
  the counts from naive macrophage to those associated with IFNg. 
 

No scenario info for: Salm_vs_naive, de_limma, same_contrast 

Accessing results stored in a dde object

Accessing DEA results, by DEA name

# access specific DEA by name, in minimal format
knitr::kable(head(getDEA(dde,
                         dea_name = "Salm_vs_naive")))
Salm_vs_naive_log2FoldChange Salm_vs_naive_pvalue Salm_vs_naive_padj
ENSG00000164741 0.0114691 0.9996325 1.0000000
ENSG00000078808 0.7893601 0.9975592 1.0000000
ENSG00000251034 1.1881497 0.2269175 0.9820422
ENSG00000162676 0.4420821 0.8432117 1.0000000
ENSG00000170356 -0.6249201 0.7269723 1.0000000
ENSG00000204257 -0.7293810 0.8838883 1.0000000

Accessing results stored in a dde object

Accessing DEA results, as a list

# get dea results as a list, (default: minimal format)
lapply(getDEAList(dde), head)
$IFNg_vs_naive
                log2FoldChange       pvalue        padj
ENSG00000164741     0.22914866 9.805414e-01 1.00000e+00
ENSG00000078808    -0.01153364 1.000000e+00 1.00000e+00
ENSG00000251034    -0.11670132 9.338990e-01 1.00000e+00
ENSG00000162676     0.26914813 9.008170e-01 1.00000e+00
ENSG00000170356    -0.12786371 9.728148e-01 1.00000e+00
ENSG00000204257     4.05502439 1.672976e-56 8.36488e-54

$Salm_vs_naive
                log2FoldChange    pvalue      padj
ENSG00000164741      0.0114691 0.9996325 1.0000000
ENSG00000078808      0.7893601 0.9975592 1.0000000
ENSG00000251034      1.1881497 0.2269175 0.9820422
ENSG00000162676      0.4420821 0.8432117 1.0000000
ENSG00000170356     -0.6249201 0.7269723 1.0000000
ENSG00000204257     -0.7293810 0.8838883 1.0000000

$de_limma
                log2FoldChange       pvalue         padj
ENSG00000164741    -0.07694397 8.044824e-01 8.540153e-01
ENSG00000078808     0.78155238 1.672966e-08 3.510702e-07
ENSG00000251034     1.32914271 1.704072e-02 3.215229e-02
ENSG00000162676     0.65022935 1.042612e-01 1.546902e-01
ENSG00000170356    -0.35191649 4.004132e-01 4.877139e-01
ENSG00000204257    -0.79077889 2.294410e-03 5.721721e-03

$same_contrast
                log2FoldChange       pvalue         padj
ENSG00000164741    -0.07694397 8.044824e-01 8.540153e-01
ENSG00000078808     0.78155238 1.672966e-08 3.510702e-07
ENSG00000251034     1.32914271 1.704072e-02 3.215229e-02
ENSG00000162676     0.65022935 1.042612e-01 1.546902e-01
ENSG00000170356    -0.35191649 4.004132e-01 4.877139e-01
ENSG00000204257    -0.79077889 2.294410e-03 5.721721e-03

Accessing FEA results

getFEA() directly accesses specific FEA results.

getFEAList() returns all FEAs stored in a dde object. Optionally, if dea_name is set, it returns all FEAs linked to a specific DEA.

Other operations …

Renaming results in a dde object

Renaming DEA results



# rename dea, one element
dde <- renameDEA(dde,
                 old_name = "de_limma",
                 new_name = "ifng_vs_naive_&_salm_vs_naive")
✔ Renamed DEA entries: "de_limma" to "ifng_vs_naive_&_salm_vs_naive"
# multiple entries at once
dde <- renameDEA(dde,
                 old_name = c("same_contrast", "Salm_vs_naive"),
                 new_name = c("same_contrast_new", "Salm_vs_naive_new")
                 )
✔ Renamed DEA entries: "same_contrast" and "Salm_vs_naive" to "same_contrast_new" and "Salm_vs_naive_new"

Tip

To rename FEAs stored in a dde object, use renameFEA()

Removing results in a dde object

Removing DEA results



# removing dea
dde <- removeDEA(dde,
                 c("ifng_vs_naive_&_salm_vs_naive",
                   "same_contrast_new",
                   "Salm_vs_naive_new"))

Tip

To remove FEAs stored in a dde object, use removeFEA()

Single-cell in practice

Single-cell in practice (muscat::pbDS()DeeDeeExperiment)

# create res, a list to hold pseudobulk DE results for all contrasts
for (i in names(contrast)) {
  cat("Contrast: ", i,"\n")
  res <- pbDS(pb,
              design = mm,
              contrast = contrast[[i]],
              verbose = TRUE,
              BPPARAM = BiocParallel::MulticoreParam(6))
  
  results_list[[i]] <- res
}

# extract contrast
contrast_vtp_DMSO <- res$table$`VTP-DMSO`

# renaming columns
for (cell in names(contrast_vtp_DMSO)) {
  contrast_vtp_DMSO[[cell]] <-
  contrast_vtp_DMSO[[cell]] |>
  dplyr::rename(log2FoldChange = logFC,
                pvalue = p_val,
                padj = p_adj.loc)
  
  rownames(contrast_vtp_DMSO[[cell]]) <- contrast_vtp_DMSO[[cell]]$gene
}

# optional: update de + enrich list names
new_names <- c(
  "NK1 A+B" = "NK1_A_B",
  "NK1 C" = "NK1_C",
  "NK2" = "NK2",
  "NK3" = "NK3" ,
  "NKint" = "NKint"
)
names(contrast_vtp_DMSO) <- new_names[names(contrast_vtp_DMSO)]
names(func_res) <- new_names[names(func_res)]

# create dde object
dde <- DeeDeeExperiment(sce_NKcells, # sce object
                        de_results = contrast_vtp_DMSO, # DEA results
                        enrich_results = func_res # FEA results
                        )

Downstream operations with DeeDeeExperiment objects

DeeDeeExperiment objects can be used with other Bioconductor tools like iSEE & GeneTonic, or anything that works for a SCE object




DeeDeeExperiment is available on Bioconductor

https://bioconductor.org/packages/DeeDeeExperiment

Thank you :)


  • Bioinformatics group @IMBEI
  • Bioconductor community, developers-forum