--- title: > The `DeeDeeExperiment` User's Guide author: - name: Najla Abassi affiliation: - Institute of Medical Biostatistics, Epidemiology and Informatics (IMBEI), Mainz email: abassina@uni-mainz.de - name: Lea Rothörl affiliation: - Institute of Medical Biostatistics, Epidemiology and Informatics (IMBEI), Mainz - name: Federico Marini affiliation: - Institute of Medical Biostatistics, Epidemiology and Informatics (IMBEI), Mainz - Research Center for Immunotherapy (FZI), Mainz email: marinif@uni-mainz.de date: "`r BiocStyle::doc_date()`" package: "`r BiocStyle::pkg_ver('DeeDeeExperiment')`" output: BiocStyle::html_document: toc: true toc_float: true code_folding: show code_download: yes vignette: > %\VignetteIndexEntry{The DeeDeeExperiment User's Guide} %\VignetteEncoding{UTF-8} %\VignettePackage{DeeDeeExperiment} %\VignetteKeywords{GeneExpression, RNASeq, Sequencing, Pathways, Infrastructure} %\VignetteEngine{knitr::rmarkdown} editor_options: chunk_output_type: console bibliography: DeeDeeExperiment_bibliography.bib --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", error = FALSE, warning = FALSE, eval = TRUE, message = FALSE ) ``` # Introduction {#introduction} ## Why do we need a new class? Differential expression analysis (DEA) and functional enrichment analysis (FEA) are core steps in transcriptomic workflows, helping researchers detect and interpret biological differences between conditions. However, as the number of conditions (defined by complex experimental designs) and analysis tools increases, managing the outputs of these analyses across multiple contrasts becomes increasingly overwhelming. This challenge is further amplified in single-cell RNA-seq, where pseudo-bulk analyses generate numerous results tables across cell types and contrasts, making it challenging to organize, explore, and reproduce findings, even for experienced users. To address these issues, we introduce the `r BiocStyle::Biocpkg("DeeDeeExperiment")` class, an S4 object that extends the widely adopted `SingleCellExperiment` class in Bioconductor. `DeeDeeExperiment` provides a structured and consistent framework for integrating DEA and FEA results alongside core expression data and metadata. By centralizing these results in a single container, `DeeDeeExperiment` enables users to retrieve, explore, and manage their analysis results more efficiently across multiple contrasts. This vignette introduces the class structure, demonstrates how to create and work with `DeeDeeExperiment` objects, and walks through a typical RNA-seq workflow using the class. ## Anatomy of DeeDeeExperiment The `DeeDeeExperiment` class inherits from the core Bioconductor `SingleCellExperiment` object. This means it inherits all the slots, methods, and compatibility with tools built for `SingleCellExperiment`, while introducing additional components to streamline downstream analysis. ![](DeeDeeExperiment_Anatomy_02.png){width=100%} Specifically, `DeeDeeExperiment` has two new slots: - `dea` : a list that stores results from differential expression analysis (DEA), along with relevant metadata. This includes: - The used False Discovery Rate (FDR) and log2 fold change (LFC) thresholds (if specified). - Meta info related to both the LFC and p-value. - The package used to generate the DE results (e.g. `r BiocStyle::Biocpkg("DEseq2")`, `r BiocStyle::Biocpkg("edgeR")` or `r BiocStyle::Biocpkg("limma")`). - A copy of the original DE result object. The main columns to use in DEA in addition to the feature identifier (`log2FoldChange`, `pvalue`, and `padj`) are also stored in the `rowData` of the `DeeDeeExperiment` object. - `fea` : a list that stores results from functional enrichment analysis (FEA), along with relevant metadata. This includes: - The name of the associated DEA contrast. - The FEA name. - A `GeneTonicList`-compatible set of `shaken_results` (ready to be used in `r BiocStyle::Biocpkg("GeneTonic")`). - The enrichment tool used to generate the results (e.g. `topGO`, `clusterProfiler...`). - A copy of the original enrichment result object. ## Creating a `DeeDeeExperiment` object In order to create a `DeeDeeExperiment` object, at least one of the following inputs are required: - `sce`: A `SingleCellExperiment` object, that will be used as a scaffold to store the DE related information. - `de_results`: A named list of DE results, in any of the formats supported by the package (currently results from `DESeq2`, `edgeR`, or `limma`). - `enrich_results`: A named list of FE results, as `data.frame` generated by one of the following packages (currently `topGO`, `clusterProfiler`, `enrichR`, `gProfiler`, `fgsea`, `gsea`, `DAVID`, and output of `GeneTonic` shakers) ```{r create_dde, eval = FALSE} # do not run dde <- DeeDeeExperiment( sce = sce, # sce is a SingleCellExperiment object # de_results is a named list of de results de_results = de_results, # enrich_res is a named list of enrichment results enrich_results = enrich_results ) ``` # Getting started {#gettingstarted} To install this package, start R and enter: ```{r install, eval = FALSE} if (!requireNamespace("BiocManager", quietly = TRUE)) { install.packages("BiocManager") } BiocManager::install("DeeDeeExperiment") ``` Once installed, the package can be loaded and attached to your current workspace as follows: ```{r loadlib} library("DeeDeeExperiment") ``` # `DeeDeeExperiment` on the `macrophage` dataset In the remainder of this vignette, we will illustrate the main features of `r BiocStyle::Biocpkg("DeeDeeExperiment")` on a publicly available dataset from Alasoo, et al. "Shared genetic effects on chromatin and gene expression indicate a role for enhancer priming in immune response", published in Nature Genetics, January 2018 [@Alasoo2018] [doi:10.1038/s41588-018-0046-7](https://doi.org/10.1038/s41588-018-0046-7). The data is made available via the `r BiocStyle::Biocpkg("macrophage")` Bioconductor package, which contains the files output from the Salmon quantification (version 0.12.0, with GENCODE v29 reference), as well as the values summarized at the gene level, which we will use to exemplify. In the `macrophage` experimental setting, the samples are available from 6 different donors, in 4 different conditions (naive, treated with Interferon gamma, with SL1344, or with a combination of Interferon gamma and SL1344). Let's start by loading all the necessary packages: ```{r loadlibraries} library("DeeDeeExperiment") library("macrophage") library("DESeq2") library("edgeR") library("DEFormats") ``` We will demonstrate how `DeeDeeExperiment` fits into a regular bulk RNA-seq data analysis workflow. For this we will start by processing the data and setting up the design for the Differential Expression Analysis (DEA). ```{r load_data} # load data data(gse, package = "macrophage") ``` If you already have your differential expression results and want to skip the DEA workflow examples, you can jump directly to the section [4 Creating DeeDeeExperiment the DeeDee way](#creating_deedeeexperiment_the_deedee_way) - otherwise, you can follow along in the subsequent sections where we will showcase how the typical objects from each DE framework will seamlessly fit into a `DeeDeeExperiment` object. The remainder of this vignette assumes some knowledge of Differential Expression Analysis workflows. If you want some excellent introductions to this topic, you can refer to [@Love2016] and [@Law2018] - Otherwise, you can check [@Ludt2022] for a comprehensive overview of these workflows, as well as the usage of tools such as `GeneTonic` or `pcaExproler` for interactive exploration. ## DEA: DESeq2 framework Below we will demonstrate an example on how to generate DE results with `DESeq2` ```{r dds_setup} # set up design dds_macrophage <- DESeqDataSet(gse, design = ~ line + condition) rownames(dds_macrophage) <- substr(rownames(dds_macrophage), 1, 15) keep <- rowSums(counts(dds_macrophage) >= 10) >= 6 dds_macrophage <- dds_macrophage[keep, ] ``` For the sake of demonstration, we will further subset the dataset for faster processing ```{r dds_subset} # set seed for reproducibility set.seed(42) # sample randomly for 1k genes to speed up the processing selected_genes <- sample(rownames(dds_macrophage), 1000) dds_macrophage <- dds_macrophage[selected_genes, ] ``` We then run the main `DESeq()` function and check the `resultsNames` being generated ```{r dds_macrophage} dds_macrophage # run DESeq dds_macrophage <- DESeq(dds_macrophage) # contrasts resultsNames(dds_macrophage) ``` Let's extract the DE results for each contrast. We will only use two contrasts ```{r extract_de_results} FDR <- 0.05 # IFNg_vs_naive IFNg_vs_naive <- results(dds_macrophage, name = "condition_IFNg_vs_naive", lfcThreshold = 1, alpha = FDR ) IFNg_vs_naive <- lfcShrink(dds_macrophage, coef = "condition_IFNg_vs_naive", res = IFNg_vs_naive, type = "apeglm" ) # Salm_vs_naive Salm_vs_naive <- results(dds_macrophage, name = "condition_SL1344_vs_naive", lfcThreshold = 1, alpha = FDR ) Salm_vs_naive <- lfcShrink(dds_macrophage, coef = "condition_SL1344_vs_naive", res = Salm_vs_naive, type = "apeglm" ) head(IFNg_vs_naive) head(Salm_vs_naive) ``` We now have two `DESeqResults` objects: `IFNg_vs_naive` and `Salm_vs_naive`, ready to be integrated into a `DeeDeeExperiment` object. ## DEA: limma framework Not working with `DESeq2`? No problem. `DeeDeeExperiment` is method-agnostic and easily integrates results from other frameworks like `limma`. In this section, we will walk through a typical `limma` workflow to generate DE results. For demonstration purposes, we convert the filtered `dds_macrophage` as input for `limma`, using the `as.DGEList()` function from the `DEFormats` package. ```{r dds_to_dge} # create DGE list dge <- DEFormats::as.DGEList(dds_macrophage) ``` We then normalize and voom-transform the expression values, before running the `lmFit()` function: ```{r limmarun} # normalize the counts dge <- calcNormFactors(dge) # create design for DE design <- model.matrix(~ line + group, data = dge$samples) # transform counts into logCPM v <- voom(dge, design) # fitting linear models using weighted least squares for each gene fit <- lmFit(v, design) ``` We define here as usual the contrast matrix: ```{r limma_contrasts} # available comparisons colnames(design) # setup comparisons contrast_matrix <- makeContrasts( IFNg_vs_Naive = groupIFNg, Salm_vs_Naive = groupSL1344, levels = design ) ``` We then extract the results by applying the `contrasts.fit` function, followed by the empirical Bayes moderation as it follows: ```{r ebayes} # apply contrast fit2 <- contrasts.fit(fit, contrast_matrix) # empirical Bayes moderation of standard errors fit2 <- eBayes(fit2) de_limma <- fit2 # MArrayLM object ``` We show here the top 10 DE genes, as detected in the contrast `IFNg_vs_Naive` ```{r topTable} # show top 10 genes, first columns topTable(de_limma, coef = "IFNg_vs_Naive", number = 10)[, 1:7] ``` We now have a `MArrayLM` object: `de_limma`, ready to be integrated into a `DeeDeeExperiment` object. ## DEA: edgeR framework Below we will walk you through a typical `edgeR` pipeline to produce DE results ready for integration in `DeeDeeExperiment`. We reuse the normalized `DGEList` and design matrix from the previous `limma` workflow (again, created via `DEFormats::as.DGEList()`): ```{r glmfit} dge <- DEFormats::as.DGEList(dds_macrophage) # estimate dispersion dge <- estimateDisp(dge, design) # perform likelihood ratio test fit <- glmFit(dge, design) ``` Here as well, we define the contrasts of interest: ```{r edgeR_contrasts} # available comparisons colnames(design) # setup comparisons contrast_matrix <- makeContrasts( IFNg_vs_Naive = groupIFNg, Salm_vs_Naive = groupSL1344, levels = design ) ``` ... and. we create the `DGELRT` objects to store the DE results as follows: ```{r dge_lrt} # DGELRT objects dge_lrt_IFNg_vs_naive <- glmLRT(fit, contrast = contrast_matrix[, "IFNg_vs_Naive"]) dge_lrt_Salm_vs_naive <- glmLRT(fit, contrast = contrast_matrix[, "Salm_vs_Naive"]) ``` The top 10 DE genes computed within the edgeR framework can be shown as in this chunk: ```{r topTag1} # show top 10 genes, first few columns topTags(dge_lrt_IFNg_vs_naive, n = 10)[, 1:7] ``` For the sake of demonstrating that `DeeDeeExperiment` can handle the different objects from the `edgeR` framework, we also compute some results with the `exactTest()` approach. ```{r dge_exact} # perform exact test # exact test doesn't handle multi factor models, so we have to subset # IFNg vs naive keep_samples <- dge$samples$group %in% c("naive", "IFNg") dge_sub <- dge[, keep_samples] # droplevel group <- droplevels(dge_sub$samples$group) dge_sub$samples$group <- group # recalculate normalization and dispersion dge_sub <- calcNormFactors(dge_sub) dge_sub <- estimateDisp(dge_sub, design = model.matrix(~group)) # exact test # DGEExact object dge_exact_IFNg_vs_naive <- exactTest(dge_sub, pair = c("naive", "IFNg")) # SL1344 vs naive keep_samples <- dge$samples$group %in% c("naive", "SL1344") dge_sub <- dge[, keep_samples] # droplevel group <- droplevels(dge_sub$samples$group) dge_sub$samples$group <- group # recalculate normalization and dispersion dge_sub <- calcNormFactors(dge_sub) dge_sub <- estimateDisp(dge_sub, design = model.matrix(~group)) # exact test dge_exact_Salm_vs_naive <- exactTest(dge_sub, pair = c("naive", "SL1344")) ``` Again, the top 10 DE genes in the `dge_exact_Salm_vs_naive` object can be shown with ```{r topTag_2} topTags(dge_exact_Salm_vs_naive, n = 10)[, 1:7] ``` We now have two `DGELRT` & two `DGEExact` objects: `dge_lrt_IFNg_vs_naive`, `dge_lrt_Salm_vs_naive` & `dge_exact_IFNg_vs_naive`, `dge_exact_Salm_vs_naive` respectively, ready to be integrated into a `DeeDeeExperiment` object. For demonstration purposes, we will use precomputed FEA results generated with `run_topGO()` (a practical wrapper provided by the `mosdef` package), and with the `gost()` function from `gprofiler2` package. ```{r load_FEAs} # load Functional Enrichment Analysis results examples data("topGO_results_list", package = "DeeDeeExperiment") data("gost_res", package = "DeeDeeExperiment") data("clusterPro_res", package = "DeeDeeExperiment") ``` The enrichment results can be displayed in a summary way with these commands: ```{r topGO} # ifng vs naive head(topGO_results_list$ifng_vs_naive) ``` ```{r gost} # salmonella vs naive head(gost_res$result) ``` ```{r clusterPro} # ifng vs naive head(clusterPro_res$ifng_vs_naive) ``` To check which formats of Functional Enrichment Analysis (FEA) results are supported natively within `DeeDeeExperiment`, simply run the following command: ```{r fea_formats} DeeDeeExperiment::supported_fea_formats() ``` By now, we collected DEA results from three different frameworks and generated multiple FEA results. Each result has its own structure, columns, metadata, ... Managing and exploring this growing stack of outputs can quickly become overwhelming. So let’s now see how `DeeDeeExperiment` brings all these pieces together. # Creating `DeeDeeExperiment` the DeeDee way {#creating_deedeeexperiment_the_deedee_way} In the following example we construct the dde object using a `dds` object and **named list** of DE results ```{r construct_dde} # 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 ``` You can see from the summary overview that the information on the two `dea` has been added to the original object. ## Adding results to a `dde` object ### Adding DEA results Additional DE results can be added using the `addDEA()` method. These results are stored in both the `dea` slot and in the `rowData`. We can also add results as individual element of class `DESeqResults`, `MArrayLM`, `DGEExact` or `DGELRT`. ```{r addDEA} # add a named list of results from edgeR dde <- addDEA(dde, dea = list( dge_exact_IFNg_vs_naive = dge_exact_IFNg_vs_naive, dge_lrt_IFNg_vs_naive = dge_lrt_IFNg_vs_naive )) # add results from limma as a MArrayLM object dde <- addDEA(dde, dea = de_limma) dde # inspect the columns of the rowData names(rowData(dde)) ``` The `dde` object now contains 5 DEAs in its `dea` slot. The `rowData` also includes a record of the `log2FoldChange`, `pvalue`, and `padj` values for each contrast. It is possible to overwrite the results, when the argument `force` is set to `TRUE` ```{r addDEA_force} dde <- addDEA(dde, dea = list(same_contrast = dge_lrt_Salm_vs_naive)) # overwrite results with the same name # e.g. if the content of the same object has changed dde <- addDEA(dde, dea = list(same_contrast = dge_exact_Salm_vs_naive), force = TRUE) dde ``` ### Adding FEA results FEA results can be added to a `dde` object using the `addFEA()` method. These results are stored in the `fea` slot. If the `fea_tool` argument was not specified, the internal function used to generate the standardized format of FEA result is automatically detected - this should work in most cases, but it can be beneficial to explicitly specify the `fea_tool` used, also for simple bookkeeping reasons. ```{r addFEA} # 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") dde ``` ## Linking DE and FE Analysis in a `dde` object Once DE and FE results have been added, FEAs can be linked to specific DE contrasts using the `linkDEAandFEA()` method. This maintains a clear association between the analyses and helps document it within the `dde` object. ```{r link_fea} dde <- linkDEAandFEA(dde, dea_name = "Salm_vs_naive", fea_name = c("salmonella_vs_naive", "gost_res$result") ) ``` This is then directly visible in the object summary, provided with the dedicated `summary()` method: ```{r summary-linked} summary(dde) ``` ## Adding contextual information It is possible to add context to specific DEA results that are stored in a `dde` object using the `addScenarioInfo()` method. This information can help document the experimental setup, clarify comparisons, or maybe provided as additional element to a large language model that can benefit of the extra bits to assist in the interpretation. ```{r addScenarioInfo} 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." ) ``` ## Summary of a `dde` object All results stored in a `dde` object can be easily inspected with the `summary()` method ```{r summary_mini} # minimal summary summary(dde) ``` It is possible to customize the output of `summary()` using optional arguments. For example, the `FDR` threshold can be adjusted to display the number of up- and downregulated genes for each comparison. ```{r summary_fdr} # specify FDR threshold for subsetting DE genes based on adjusted p-values summary(dde, FDR = 0.01) ``` It is also possible to include any scenario information associated with each DEA by setting `show_scenario_info = TRUE` ```{r summary_show_scenario} # show contextual information, if available summary(dde, show_scenario_info = TRUE) ``` ## Renaming results in a `dde` object Specific results can be renamed after being added using the `renameDEA()` and `renameFEA()` methods. The corresponding column names in the `rowData` will be updated accordingly. ```{r rename} # rename dea, one element dde <- renameDEA(dde, old_name = "de_limma", new_name = "ifng_vs_naive_&_salm_vs_naive" ) # multiple entries at once dde <- renameDEA(dde, old_name = c("dge_exact_IFNg_vs_naive", "dge_lrt_IFNg_vs_naive"), new_name = c("exact_IFNg_vs_naive", "lrt_IFNg_vs_naive") ) # rename fea dde <- renameFEA(dde, old_name = "gost_res$result", new_name = "salm_vs_naive" ) ``` ## Removing results in a `dde` object The method `removeDEA()` and `removeFEA()` can be used to delete results from a `dde` object. ```{r remove} # removing dea dde <- removeDEA(dde, c( "ifng_vs_naive_&_salm_vs_naive", "exact_IFNg_vs_naive", "dge_Salm_vs_naive" )) # removing fea dde <- removeFEA(dde, c("salmonella_vs_naive")) dde ``` ## Accessing results stored in a `dde` object Several accessor methods are available to retrieve DEA and FEA results stored within a `dde` object. `getDEANames()` and `getFEANames()` are the methods to quickly retrieve the names of available DEAs and FEAs ```{r names} # get DEA names getDEANames(dde) # get FEA names getFEANames(dde) ``` It is possible to directly access specific DEA results either in their original format or in minimal format. Use `format = "original"` to retrieve results in the same class as originally provided (e.g., `DESeqResults`, `MArrayLM`...). ```{r get_dea_res} # access the 1st DEA if dea_name is not specified (default: minimal format) getDEA(dde) |> head() # access the 1st DEA, in original format getDEA(dde, format = "original") |> head() # access specific DEA by name, in original format getDEA(dde, dea_name = "lrt_IFNg_vs_naive", format = "original" ) |> head() # access specific DEA by name (default: minimal format) getDEA(dde, dea_name = "lrt_IFNg_vs_naive") |> head() ``` `getDEAList()` retrieves all available DEAs stored in a dde object as a list. ```{r getDEAList} # get dea results as a list, (default: minimal format) lapply(getDEAList(dde), head) ``` The next command can be quite verbose in its output, but it gives full access to the original objects provided when creating and updating the `dde` container. ```{r getDEAList-original, eval = FALSE} # get dea results as a list, in original format lapply(getDEAList(dde, format = "original"), head) ``` `getDEAInfo()` returns the whole content of the `dea` slot, including the DEA tables and their associated metadata - the following chunk is left unevaluated for clarity as its output can be very verbose. ```{r getDEAInfo, eval = FALSE} # extra info getDEAInfo(dde) ``` It is easy, still, to retrieve some specific set of information, such as the `package` used for a specific `dea_name`: ```{r dea_info_specific} # retrieve specific information like the package name used for specific dea dea_name <- "Salm_vs_naive" getDEAInfo(dde)[[dea_name]][["package"]] ``` `getFEA()` directly accesses specific FEA results either in their original format or in minimal format ```{r get_fea_res} # access the 1st FEA, (default: minimal format) getFEA(dde) |> head() # access the 1st FEA, in original format getFEA(dde, format = "original") |> head() # access specific FEA by name getFEA(dde, fea_name = "ifng_vs_naive") |> head() # access specific FEA by name, in original format getFEA(dde, fea_name = "ifng_vs_naive", format = "original") |> head() ``` Similarly to `getDEAList()`, `getFEAList()` returns all FEAs stored in a `dde` object. Optionally, if `dea_name` is set, it returns all FEAs linked to a specific DEA. This is illustrated in the following chunk ```{r getFEAList} # get fea results as a list (default: minimal format) lapply(getFEAList(dde), head) # get all FEAs for this de_name, in original format lapply(getFEAList(dde, dea_name = "IFNg_vs_naive", format = "original"), head) ``` `getFEAInfo()` returns the whole content of the `fea` slot, including the FEA tables and their associated metadata. Again, the following chunk is left unevaluated for clarity as its output can be very verbose: ```{r getFEAInfo, eval = FALSE} # extra info getFEAInfo(dde) ``` Yet, specific set of information, such as the `fe_tool` used for a specific `fea_name` (here, "ifng_vs_naive") can be easily retrieved with: ```{r fea_info_specific} # the tool used to perform the FEA getFEAInfo(dde)[["ifng_vs_naive"]][["fe_tool"]] ``` # Downstream operations with `DeeDeeExperiment` objects Since `DeeDeeExperiment` inherits from the `SingleCellExperiment` class, it can be seamlessly used with other Bioconductor tools such as `iSEE` or `GeneTonic`, or many more. With the `dde` object now containing all key elements of your analysis, from the counts to enrichment results, metadata, and scenario details, you can save it and plug it into these tools for interactive exploration and visualization. ```{r save, eval = FALSE} saveRDS(dde, "dde_macrophage.RDS") ``` To explore the `dde` object within `iSEE`, simply run these lines of code: ```{r runiSEE, eval = FALSE} library("iSEE") iSEE::iSEE(dde) ``` Similarly, to see more on `dde` within `GeneTonic`, you can run the following chunk: ```{r runGeneTonic, eval = FALSE} library("GeneTonic") my_dde <- dde res_de <- getDEA(my_dde, dea_name = "IFNg_vs_naive", format = "original") res_enrich <- getFEA(my_dde, fea_name = "ifng_vs_naive") annotation_object <- mosdef::get_annotation_orgdb(dds_macrophage, "org.Hs.eg.db", "ENSEMBL") GeneTonic::GeneTonic( dds = dds_macrophage, res_de = res_de, res_enrich = res_enrich, annotation_obj = annotation_object, project_id = "GeneTonic_with_DeeDee" ) ``` Of course, these packages need to be installed as usual on the same machine via `BiocManager::install()`. # FAQs *Do I need to process/filter my DE results before adding them to a `dde` object?* → `DeeDeeExperiment` is just a container, it does not alter your results. Any filtering or DEG selection should be done beforehand, giving you full control over how your analysis is conducted. *What happens if I forget to name my DE or FE result when adding it?* → If no name is provided, `DeeDeeExperiment` will attempt to assign a default one, which is the variable name in the current environment. However, it's strongly recommended to name each result clearly. *I am using a different enrichment analysis tool, and this is currently not supported by DeeDeeExperiment, what can I do?* → The quick-and-easy option would be to rename the output of the tabular format from this tool into the format expected by `DeeDeeExperiment` (which is the same adopted by `GeneTonic`). If you think a conversion function would be useful to yourself and many other users, feel free to submit a pull request within the `DeeDeeExperiment` Github repository (https://github.com/imbeimainz/DeeDeeExperiment/pulls)! # Session info {.unnumbered .smaller} ```{r sessioinfo} sessionInfo() ``` # References {.unnumbered}