NEWS
debrowser 1.41.2
Bug fixes
- Dropped the
sodium dependency, which broke R CMD check on the
Bioconductor Linux builder (nebbiolo2 has no libsodium, so the check failed
with "Package suggested but not available: 'sodium'" before running any other
stage). Auth crypto now uses scrypt and openssl — both already Imports:
of shinymanager, and both present on every Bioconductor builder.
- Password hashing moved from libsodium argon2id to
scrypt::hashPassword(),
the same primitive shinymanager itself stores.
- Per-user AI key encryption moved from libsodium secretbox to AES-256-GCM
with an explicit encrypt-then-MAC HMAC-SHA256 tag. R's
openssl package
neither emits nor verifies a GCM tag, so authentication is applied
explicitly; encryption and MAC subkeys are domain-separated.
- Existing password hashes and stored AI keys are not readable across this
change — see the migration note below.
Migration
- Password hashes and encrypted per-user AI keys written by 1.41.1 or earlier
use libsodium formats and cannot be read by 1.41.2. Any user database created
during D2 development must be re-created: users need to reset their passwords
and re-enter their AI provider keys.
debrowser 1.41.1
Documentation overhaul
- Rewrote the user-guide vignette (
vignettes/DEBrowser.Rmd) around the
modernized six-step Data Prep wizard and the current top-level tabs (Main
Plots, QC Plots, Concordance, Enrichment, Tables). Added coverage for the
features the old guide missed — batch-correction QC, cross-contrast
concordance, GO/KEGG + GSEA enrichment, reproducibility exports (R / R
Markdown / Jupyter / methods paragraph), bookmarking & sharing, theming and
keyboard shortcuts, and the optional AI interpretation panel.
- Kept the package small. The full illustrated user guide — with all
screenshots and worked examples — lives outside the package at
https://debrowser.readthedocs.io (the
UMMS-Biocore/debrowser-docs repo, served by Read the Docs). The vignette is a
concise, image-free reference that links there, and the README references the
same externally hosted screenshots, so no images are bundled in the package
tarball.
- Rewrote
README.md to mirror the modern walkthrough at a shorter
altitude and point to the online guide.
- Removed the unused
fontawesome and RColorBrewer entries from Imports
(icons come via shiny::icon(); no brewer.pal/RColorBrewer:: usage),
clearing the R CMD check "declared Imports should be used" note.
UI design-system consolidation (docs/design plans §1–§6)
- Grid/layout: collapsed four grid idioms to one primitive
(
bslib::layout_columns(col_widths=)) and two card systems to one
wrapper (de_card(), now with a class= passthrough) across every
panel; retired layout_column_wrap, hand-rolled display:grid, and
ragged rows. Spacing comes from a --de-space-* scale and plot heights
from de_plot_h(). Added tools/check-grid.sh to lock the standard in.
- Color/contrast: raised light/dark muted text and introduced
theme-resolved
--de-accent-ink (accent-as-text) + --de-ink-on-accent
tokens for WCAG-AA contrast; --de-cyan is now fill-only.
- Icons: Font Awesome only, via
shiny::icon(). Repaired app-wide FA
webfont rendering (the Inter UI font was clobbering glyphs), consolidated
ad-hoc glyphs, and wired the favicon.
- Loading/motion: replaced the 1.1 MB boot gif with a CSS conic ring;
added stepwise
withProgress detail to the DE run; added
--de-transition, :focus-visible rings, prefers-reduced-motion, and
cursor:not-allowed affordances; removed the dead getLoadingMsg
overlay and its orphan gifs.
- Handoff: added
de_style_guide() + inst/extdata/www/style-guide.html
(a component gallery in both themes that doubles as a pixel-regression
baseline) and DESIGN.md, the contributor design contract.
Phase A1 — foundation modernization
- Bumped minimum R version to 4.2 and
RoxygenNote to 7.3.x.
- Added
lintr and styler configs; one-time formatting pass.
- Added GitHub Actions for R-CMD-check (R-release + R-devel),
BiocCheck, lintr, and
covr coverage (codecov).
- Extended
.Rbuildignore for docs, CI, lint, and dev configs.
- Removed stale empty
viafoundry_errors.log from the repo.
Phase A2 — test scaffolding + golden snapshots
- Migrated
tests/test-*.R to the testthat 3e layout under
tests/testthat/, with shared helpers in helper-debrowser.R.
- Added golden snapshot tests for DESeq2, edgeR, limma,
getNormalizedMatrix(), and PCA coordinates on the demo data —
these are the safety net for Phase A3+ refactors.
- Added a
shinytest2 smoke-test scaffold (CI-skipped until A4
stabilises module IDs).
- Fixed silent Treat/Control inversion in the migrated DESeq2 test.
Phase A3a — pure analytic core (DE + normalize + filter)
- Added
R/fct_de_methods.R with run_deseq2(), run_edger(),
run_limma(), run_de() — pure functions taking structured
(named-list) params instead of legacy comma-string params. No Shiny
dependency.
- Added
R/fct_normalize.R with normalize_counts() and pure
apply_batch_correction() (Combat / CombatSeq / Harman). Batch /
treatment column names are now arguments instead of input$ lookups.
- Added
R/fct_filter.R with filter_low_counts() (max / mean / cpm).
- Added
R/utils_validate.R with de_error() — structured stop()
raising classed conditions so callers dispatch on class, not message
text.
- Legacy
runDE(), runDESeq2(), runEdgeR(), runLimma(),
getNormalizedMatrix(), correctCombat(), correctHarman() are now
thin shims that translate input/comma-string params and delegate.
Their signatures are unchanged so existing callers and scripts keep
working.
- Fixed silent "Repeated column names found in count matrix" warning
in the limma path (legacy code set all column names to factor levels;
removing it does not affect results).
debrowserlowcountfilter module's filter observer shrinks from ~20
lines to 9 by delegating to filter_low_counts().
Phase A3b — pure data-prep functions
- Added
R/fct_prep_data.R with apply_de_filters(), get_most_varied(),
select_dataset(), search_geneset(), merge_comparisons(),
apply_merged_filters(), get_table_data() — pure functions that take
a structured filter-params list.
- Added
filter_params_from_input() in utils_validate.R to centralise
the Shiny-input → pure-fn-params field-name mapping (e.g. input$padj
→ params$padj_cutoff, input$genesetarea → params$geneset_area).
- Legacy
applyFilters(), getMostVariedList(), getSelectedDatasetInput(),
getSearchData(), getMergedComparison(), applyFiltersToMergedComparison(),
getDataForTables() are now thin shims that delegate to
R/fct_prep_data.R. Public signatures unchanged.
- New golden snapshot locks the (Up=551, Down=864, NS=13941) row-count
distribution on the demo DE result with default cutoffs (padj 0.05,
fold 2) — catches regressions in cutoff logic or normalization.
Phase A4a + A4c — Shiny API modernization
- Migrated all 13 modules from the deprecated
callModule() API to
moduleServer() (Shiny 1.5+ idiom): debrowserdataload,
debrowserlowcountfilter, debrowserbatcheffect, debrowserhistogram,
debrowserpcaplot, debrowserIQRplot, debrowserdensityplot,
debrowserall2all, debrowserheatmap, debrowsermainplot,
debrowserbarmainplot, debrowserboxmainplot, debrowserdeanalysis.
Public function signatures changed from (input, output, session, …)
to (id, …) to match the modern Shiny convention.
- Removed the
library("debrowser") self-import inside deUI() —
was a no-op at best and a side-effect at worst.
- Replaced the runtime
installpack() / loadpack() package-loading
helpers with standard requireNamespace(pkg, quietly = TRUE) checks
in R/GOterm.R. Deleted R/installpack.R and its exported functions
(installpack, loadpack).
- Dropped the unused
aes_string import (deprecated in ggplot2 3.0).
condSelect.R is deliberately left untouched — full rewrite folded
into Phase B2 alongside the three-stage-shell wizard redesign.
Phase A5 — slim dependencies
- Moved seven rarely-used packages from
Imports: to Suggests: so a
fresh install pulls a smaller dependency graph: Harman, pathview,
org.Mm.eg.db, apeglm, ashr, enrichplot, DOSE.
- Added
require_pkg(pkg, feature) helper in R/utils_validate.R
that raises a debrowser_error of class missing_suggested_pkg
with the install command when a Suggested package is needed but
unavailable.
- Gated every direct call site:
Harman::harman() / Harman::reconstructData() — harman_correct()
DESeq2::lfcShrink(type="apeglm"/"ashr") — run_deseq2()
enrichplot::dotplot() / enrichplot::gseaplot() — gopanel.R,
GOterm.R::compareClust, server.R GSEA render path
DOSE::enrichDO() — getEnrichDO() (the compareCluster(fun = "enrichDO")
branch in compareClust() keeps its existing in-place requireNamespace
gate)
pathview::pathview() — already gated in drawKEGG(); now namespaced
- Stripped the corresponding
@import / @importFrom lines from
R/server.R and R/GOterm.R; NAMESPACE no longer pulls these
packages at load time.
Phase B1 — bslib chrome + theme swap
- Replaced
shinydashboard::dashboardPage shell with bslib::page_navbar
and per-tab bslib::layout_sidebar. Top navbar now hosts five sections
(Data Prep / Main Plots / QC Plots / GO Term / Tables) plus a
light/dark toggle (bslib::input_dark_mode).
- Theme: Slate (
#0f172a) navbar + OK-blue (#0369a1) primary,
Bootstrap 5, Inter typography. New de_theme() helper.
- Migrated all 22
shinydashboard::box() call sites to bslib::card
via a new de_card() helper (with optional download button in the
header). Wide layout containers use raw bslib::card; narrow widget
cards use de_card.
- DE Filter (cutoff + comparison-selector controls) moved from the
sidebar into a card at the top of the DE Analysis wizard panel.
- Migrated all 24
shinydashboard::menuItem() collapsible widget
containers to bslib::accordion + bslib::accordion_panel (in
R/IQR.R, R/barmain.R, R/all2all.R, R/density.R, R/boxmain.R,
R/plotSize.R, R/mainScatter.R, R/heatmap.R, R/uifuncs.R).
- Replaced
getTabUpdateJS()'s shinydashboard .sidebar-menu jQuery
with server-side bslib::nav_show/nav_hide observers in deServer.
Same trigger button ids, same behavior.
togglePanels() body rewritten to bslib::nav_show/nav_hide/
nav_select. Function signature unchanged — all callers untouched.
- The standalone heatmap app (
startHeatmap()) shell heatmapUI()
also migrated to bslib::page_navbar with the same Slate + OK-blue
theme; controls now live in the Heatmap tab's layout_sidebar.
de_card() defaults to full_screen = FALSE to avoid bslib's
expand-overlay interfering with htmlwidget click handlers.
- CSS file
shinydashboard_additional.css audited and renamed to
debrowser.css; shrunk from 145 to ~30 lines of app-specific
positioning rules.
- Dropped
shinydashboard from Imports. Added bslib (>= 0.7.0).
Added explicit @importFrom shiny tagList req to compensate for
symbols previously pulled through shinydashboard's dependency chain.
- Dark-mode plot theming (plotly/heatmaply/ggplot color flips) deferred
to Phase B6.
Phase B2.5 — Comparison Selection wizard rewrite
- Rewrote
R/condSelect.R (≈900 LOC monolith) into three focused files:
R/fct_condselect.R (pure helpers + validation predicates),
R/mod_condselect.R (condSelectUI + condSelectServer module), and
R/prep_data_container.R (the DE runner with a structured signature).
- New module API:
condSelectUI(id) and condSelectServer(id, data, metadata).
Returns list(n_comparisons, start_de, is_ready, comparisons_spec).
prepDataContainer() signature changed from
(data, counter, input, meta) to (data, metadata, comparisons_spec).
The leaky condselect$input boundary in R/server.R is gone.
- UX: single-comparison default with "Add another comparison" footer for
multi-comparison; editable per-side Treatment/Control labels with metadata-
driven defaults; reference-word direction heuristic
(
control|ctrl|wt|wildtype|...) with always-visible swap button;
per-method advanced settings + covariates collapsed by default;
inline non-toast validation messages (.text-warning / .text-danger).
- Internal
conds codes ("Cond1"/"Cond2") preserved so
R/fct_de_methods.R, R/fct_prep_data.R, R/deprogs.R, R/barmain.R,
and downstream plotting need no changes.
- Removed exports (no known external callers):
debrowsercondselect,
debrowsercondselectServer, selectedInput, getSelectInputBox,
getMetaSelector, getGroupSelector, getConditionSelector,
getConditionSelectorFromMeta, getMethodDetails, getCovariateDetails,
selectConditions, get_conditions_given_selection, getSampleNames.
- New tests:
test-condselect-helpers.R (helpers), test-condselect-validation.R
(predicates), test-prepdatacontainer.R (prep_comparison_inputs purity).
Total +73 assertions (126 → 199 PASS).
Phase B3 — Sane defaults harmonization
- Switched DE cutoff input from fold-change to |log2FC| convention.
The cutoff numeric inputs are now labelled
padj <= and |log2FC| >=.
- Added
[ Strict ] [ Standard ] preset buttons above the DE cutoff
inputs. Strict (padj 0.01, |log2FC| 1) is the default; Standard is
(padj 0.05, |log2FC| 1). Manual edits clear the preset highlight
unless the new pair matches a preset exactly.
- Cutoff inputs (DE padj, DE |log2FC|, GO p.adjust) are now
numericInput with bounds + native validation, replacing
textInput widgets that silently produced NaN downstream when
users typed non-numeric values.
- New helper module
R/fct_cutoffs.R owns the single source of
truth for default values and preset definitions:
default_cutoffs(), cutoff_presets(), match_preset(),
log2fc_to_fold(), fold_to_log2fc(),
install_cutoff_preset_observers(). The hardcoded fallback in
generateTestData() now reads from default_cutoffs().
- Internal-only Shiny input rename:
input$foldChange -> input$log2fc_cutoff.
Public cutOffSelectionUI API is unchanged; new exported
companion cutOffSelectionServer(id) wires preset observers
for the namespaced widget.
Phase E3.B — Rich report generation + Jupyter + view-in-tab
- Export dropdown gains three new items, bringing the total to six:
- Rmd source -- downloads the raw
.Rmd body (no render).
- View HTML in tab -- renders the Rmd to a tempdir, registers it
as a Shiny resource path, and opens the rendered HTML in a new
browser tab via
Shiny.addCustomMessageHandler('debrowser_open_tab',...).
- Jupyter notebook -- downloads the same content as a
.ipynb
file with R-kernel (ir) code cells; opens directly in JupyterLab.
The pre-existing Rmd -> HTML item is renamed to plain HTML
(it always meant "render and download"); the new View HTML in tab
is the in-browser counterpart.
emit_rmd() now produces a manuscript-style report mirroring a
reference Rmd contributed by a user (Haania mouse PA/DMSO study).
YAML uses code_folding: hide so chunks are collapsible in the
rendered HTML; setup chunk runs eval = TRUE so the report includes
actual plots when rendered. New sections (in order):
- Library + helper-source chunks
## Methods (paragraph from Phase E9's methods_paragraph())
## Pipeline -- load, filter, batch, DE per comparison
## Sample Info -- DT::datatable of metadata
## Quality Control {.tabset} -- Count distribution / All2All /
PCA + Scree (all on the all-detected-genes matrix)
## DESeq Analysis {.tabset} -- one tab per comparison with
sub-tabs Results / Volcano / MA / Heatmap
## Enrichment (when configured)
## Session Info {.tabset} -- Hide / Show
- New pure helpers in
R/fct_export_session.R: emit_ipynb(blocks)
parses emit_rmd() output and converts to .ipynb JSON cells.
- New file:
inst/templates/report_helpers.R (~534 lines) bundling
the report's plotting functions (count_distribution, all2all,
run_pca, pca_plot, scree_plot, volcano_plot, ma_plot,
heatmap_plot, getNormalizedMatrix, post_processing,
add_alias, add_highlights, call_significance). The emitted
Rmd / Jupyter / .R all source() this file from the installed
package so report styling stays in one place.
state_react() (in R/server.R) now surfaces full_counts (the
filter+batch-corrected matrix on all detected genes) and metadata
(the sample-info table) so the QC and Sample Info sections can
reference the same data DEBrowser sees.
Phase E12.B — AI interpretation: presets + mount points
- AI interpretation panel widened from
fgseaGSEA-only to all 6
Enrichment modes (enrichGO, enrichKEGG, enrichDO,
enrichPathway, compareCluster, fgseaGSEA). One mount, one
preset (summarize_geneset) works across all modes via per-mode
payload adapters.
- New AI panel on the DE Analysis tab (per-comparison, below the
results table). Presets:
summarize_geneset, suggest_followup,
draft_methods. Privacy default for this mount: + Stats.
- New AI panel on the Comparison Concordance tab (below the
summary card). Presets:
reconcile_enrichments, suggest_followup,
draft_methods. In-card pathway picker surfaces when one or more
pathways are enriched in two or more comparisons; selecting one
triggers cross-comparison fgsea so the prompt sees real NES rows.
- New presets in
inst/templates/:
ai_reconcile_enrichments.md — explains a pathway's divergent
NES across multiple comparisons.
ai_suggest_followup.md — two-section response: bioinformatic
next-analyses + wet-lab next-experiments.
ai_draft_methods.md — journal-style polish of E9's
deterministic Methods paragraph. Cannot add or remove facts.
- Sanitized markdown response rendering via
commonmark + xml2
(replaces v1's plain <pre>). Strict allow-list: headings, bold,
italic, lists, code, blockquote, hr. Links rendered as plain text
(no hallucinated URLs are clickable). Images and scripts stripped.
- Privacy modes adapted per payload shape:
de_table and
concordance default to + Stats; the draft_methods preset
hides the radio entirely (no genes / stats in payload).
- No new Imports.
commonmark + xml2 added to Suggests (both
already transitively present via rmarkdown / httr2).
- Streaming responses still deferred.
Phase E12.A — AI interpretation foundation
- New top-right Settings dropdown in the navbar with an AI
configuration modal: master switch (off by default), provider
picker (Anthropic / OpenAI / Ollama), dynamic model lookup via
ellmer::models_*, encrypted API-key storage via the OS keychain
(keyring package), and a default privacy mode setting.
- New AI interpretation card on the Enrichment tab below the
Leading Edge card. Renders only when the master switch is on, a
provider is configured, and (for non-Ollama providers) an API key
is present. v1 ships one question preset: "Summarize this gene
set's biology", attached to the currently-selected fgsea pathway's
leading-edge genes.
- Privacy modes per call (default: Symbols only):
- Symbols only -- gene symbols of the leading edge.
- + Stats -- also log2FoldChange and adjusted p-value per gene.
- + Stats + Enrichment -- also the term name, p-value, and
overlap count of the selected pathway.
A "What will be sent?" disclosure shows the literal prompt body
(live preview) and a character count before the user clicks Ask.
- New exported helpers in pure files:
ai_interpret(question, payload, privacy_mode, provider_chat, top_n, template_dir) (R/fct_ai_interpret.R),
list_models(provider, api_key) and ai_chat(provider, model, api_key)
(R/fct_ai_providers.R). Internal helpers cover settings I/O and
encrypted key storage (R/fct_ai_settings.R).
- New error class hierarchy:
ai_error extends simpleError; subclasses
ai_no_key, ai_rate_limit, ai_network, ai_invalid_response,
ai_disabled. The Shiny module maps each subclass to a friendly
notification with a recovery hint.
- LLM responses are rendered as plain preformatted text (
tags$pre);
no markdown parsing, no HTML execution, no automatic link
traversal -- defense against untrusted-content patterns in model
output.
- Three new Suggests gated via
require_pkg: ellmer (>= 0.1.0),
whisker, keyring. R CMD check passes with all three uninstalled
-- the AI features are gracefully unavailable in that case.
- AI is disabled by default. No network calls happen unless the
user explicitly enables AI features and configures a provider.
- Phase E12.B will extend with the remaining 3 question presets
(reconcile enrichments, suggest follow-up experiments, draft methods
narrative) and 2 mount points (DE Analysis tab results, Comparison
Concordance summary).
Phase E9 — Methods-paragraph autogen
- Phase E3's Export dropdown now emits a single manuscript-ready methods
paragraph (~150-250 words) with inline citations and version stamps,
replacing the previous per-step bullet list. The paragraph appears
in three places:
- At the top of the exported
.R script as a wrapped comment block.
- In the rendered
.Rmd -> HTML report's "## Methods" section.
- In a new Copy methods text Export menu item that opens a modal
with the paragraph in selectable preformatted text plus a
"Download as .txt" button.
- New exported
methods_paragraph(blocks) function (in
R/fct_methods_text.R); upgraded internal methods_sentences()
helper now produces citation-rich, version-stamped per-step
sentences. Both functions are pure (no Shiny dependency) and
consume the build_session_blocks() output from Phase E3.
- New internal
.method_refs registry maps method keys to
list(name, version_pkg, cite) for nine entries: DEBrowser,
DESeq2, edgeR, limma, ComBat, ComBat-seq, Harman, fgsea, MSigDB.
Citations are inline "(Author et al., YEAR)" plain text.
- Soft fallback when a cited package is not installed: citation
reads "(version unknown)" and a deduplicated
showNotification
warns the user. Methods text export never errors on a missing
version lookup.
Phase E3 — Reproducibility export
- New top-right Export dropdown in the navbar with two items:
- R script -- downloads a runnable
.R script that reproduces the
full analytical pipeline (data load -> low-count filter -> batch
correction -> DE per comparison -> GSEA if loaded). Calls only
already-exported pure helpers (filter_low_counts,
apply_batch_correction, run_de, run_gsea, msigdb_pathways),
so the script has no Shiny dependency. Sets per-comparison deN
variables in the workspace, writes per-comparison TSVs to
./debrowser_results/, and prints sessionInfo() at the end.
- Rmd -> HTML -- renders a self-contained HTML report with the
same pipeline as code chunks (
eval = FALSE by default) plus an
auto-generated Methods paragraph. Gated on the rmarkdown package
being installed; falls back to raw .Rmd download if pandoc fails.
- New pure helpers in
R/fct_export_session.R: build_session_blocks(),
emit_r_script(), emit_rmd(), sanitize_label(). New
R/fct_methods_text.R::methods_sentences() produces the per-step
prose consumed by both emitters; Phase E9 will upgrade it to a
citation-rich paragraph generator.
enrichmentGmtServer() return is now list(pathways, state) instead
of just the pathways reactive (additive; consumers extend the
destructure).
- Both export items are gated by a "Run a DE analysis before exporting"
notification until DE has been run.
- Frozen
sessionInfo() of the export-time R session is embedded in
the .R script header for audit reproducibility; live sessionInfo()
is also called at script end.
- Comparison labels with collisions get
_2, _3 suffixes in TSV
filenames; unsafe characters in labels are replaced with underscores.
Phase E11 — Comparison Concordance tab (top-level)
- New top-level Comparison Concordance tab between QC Plots and Enrichment.
Auto-shown when the user has set up two or more comparisons in CondSelect; hidden for
single-comparison sessions. Compares the user's existing comparisons against each other
(no DE re-running — reads
dc()[[i]]$init_data produced by the main DE pipeline).
- Five cards driven by live
padj / lfc cutoffs:
- DEG bar (up red rightward / down blue leftward, ordered by total DEG count)
- Pairwise DEG count heatmap (symmetric
groups x groups matrix)
- UpSet plot of significant-gene-set overlap across comparisons
- Pairwise log2FC scatter with Spearman correlation
- Pairwise concordance summary table (DT)
- New pure helpers in
R/fct_method_concordance.R: concordance_sets(),
concordance_summary(), plot_method_upset(), plot_method_scatter(),
comparison_labels(), de_direction_summary(), plot_de_direction_bar(),
plot_de_pairwise_heatmap(), plus run_de_methods() for programmatic use.
UpSetR added to Suggests (gated via require_pkg("UpSetR")).
Phase E2.5 — Consolidated Enrichment tab
- The previously-separate GO Term and Enrichment tabs are
now a single Enrichment tab. The legacy GO Term modes
(enrichGO / enrichKEGG / Disease / compareClusters / GSEA via
clusterProfiler::gseGO) and the new fgsea-based GSEA share one
top-level tab. The standalone Enrichment tab introduced in E1
has been removed; its content is folded in here.
- New radio choice "GSEA (fgsea / .gmt or MSigDB)" under the
Enrichment-method picker. Selecting it reveals the GMT/MSigDB
picker and Advanced controls (min/max set size, permutations,
seed) inside the same sidebar that hosts the legacy GO Term
options.
- Both render styles coexist via conditional panels: the legacy
modes keep their plot+table tabset; the fgsea mode renders
results table + enrichment plot + leading edge cards plus a
multi-comparison NES heatmap when more than one comparison is
loaded — same widgets the standalone Enrichment tab used.
enrichmentUI() / enrichmentServer() (the standalone-tab
module pair from E1) remain exported as a public API for users
who want to embed the enrichment tab elsewhere; the consolidated
panel reuses the smaller enrichmentGmtServer() and
enrichmentNesHeatmapServer() building blocks directly.
togglePanels() reverts from a 0..5 loop with backwards-compat
rule to a clean 0..4 loop, since panel5 no longer exists.
Phase E2 — MSigDB integration (gene-set source picker)
- The Enrichment tab's gene-set picker now offers MSigDB as a
sibling source to manual
.gmt upload. Pick a species (the 20
species msigdbr ships, including human, mouse, rat, fly, yeast,
zebrafish, C. elegans, and more), a top-level collection
(Hallmark, Curated, Ontology, Cell type, ...), and an optional
subcollection (e.g. CP:KEGG, GO:BP). Click "Load gene sets"
to pull the named-list of pathways into the running GSEA session.
- New pure helper
msigdb_pathways(species, collection, subcollection) in R/fct_gsea.R wraps msigdbr::msigdbr() and
reshapes its long-format tibble into the same named-list-of-
character-vectors shape gmt_to_pathways() returns, so all
downstream code (run_gsea, NES heatmap, leading edge) is
source-agnostic. Errors from msigdbr (unknown species, unknown
collection, empty result) are normalized to the
empty_input classed condition.
msigdbr added to Suggests (~50MB local install but no
install-time network — Bioc-friendly). Calls go through
require_pkg("msigdbr") with the install command for users who
don't have it.
- Per-session in-module cache keyed on
(species, collection, subcollection) so re-clicking "Load" with
the same inputs is instant.
- The GO Term tab is unchanged in this release; folding ORA into
the Enrichment tab as the second method is deferred to E2.5.
Phase E1 — Enrichment tab (GSEA via fgsea)
- New top-level Enrichment tab next to GO Term, driven by
ranked-list Gene Set Enrichment Analysis. Pre-DE the tab is
hidden; once DE has run, paste a
.gmt file (or use the bundled
inst/extdata/test-gmt/hallmark-mini.gmt fixture) and the
results table populates with NES, padj, leading edge.
- When more than one comparison is loaded, the NES heatmap card
appears below the results, plotting NES across pathways x
comparisons (significance stars, axis flip, padj cutoff slider).
- New pure helpers in
R/fct_gsea.R (@export):
gmt_to_pathways(path) (fgsea-gated wrapper around
fgsea::gmtPathways), run_gsea(de_table, pathways, ...) (DE
table -> tidy enrichment data.frame), and
nes_heatmap_data(results_by_comparison, sig_only, sig_threshold)
(long-format reshape for the heatmap).
- New Shiny modules in
R/mod_enrichment.R,
R/mod_enrichment_gmt.R, R/mod_enrichment_nes_heatmap.R. The
GMT picker is the integration point Phase E2 will use to add
MSigDB as a sibling source; the NES heatmap module is the same
widget Phase E11 will reuse for cross-method comparison.
fgsea added to Suggests (Bioconductor); calls go through
require_pkg("fgsea") so users without it installed see the
install command instead of a stack trace.
- Reference architecture (gsea_analysis shape, NES heatmap card,
GMT picker layout) adapted from
https://github.com/nephantes/gsea-explorer (Via Scientific) —
re-implemented against this package's pure-helper conventions.
Phase E4 — Sample QC dashboard (always-on cards)
- QC Plots tab now exposes four new cards for raw-count
sample inspection: Library Depth (per-sample total
counts, with >2-SD outlier flag), Feature Detection
Rate (% of features with non-zero counts per sample),
Mitochondrial Read % (sum of
^MT-/^mt-/Mt- rows
per sample, with empty-state when no MT genes are
detected), and Sample Distance Heatmap (clustered
Euclidean distance on VST-transformed counts).
- New
R/fct_qc.R exports the underlying pure helpers
(library_depth_summary, detection_rate,
mt_pct_per_sample, sample_distance_matrix,
flag_outliers_2sd) so they can be reused outside the
Shiny app.
- New Mapping / rRNA Stats card ships as an empty-state
stub describing the optional sidecar TSV format
(
sample, mapped_pct, rRNA_pct); the upload handler
itself lands in a follow-up.
- Cards consume post-filter, post-batch, pre-normalize
counts via
batch()$BatchEffect()$count so library-size
metrics report the correct raw values.
- Three additional post-DE cards (Dispersion, Size factors,
Cook's outlier flag) are deferred to a follow-up phase
pending DESeq2
dds retention through prepDataContainer.
Phase E4.5 — Post-DE QC cards + dds retention
run_deseq2() gains a return_dds = FALSE argument; when
TRUE it returns list(res, dds) so the fitted DESeqDataSet
is recoverable for downstream QC. Threaded through
runDESeq2(), runDE(), debrowserdeanalysis(), and
prepDataContainer() (which now stashes a dds slot per
comparison alongside init_data). Default behaviour is
unchanged so existing callers (generateTestData,
per-method tests) keep their data.frame contract.
- QC Plots tab adds three post-DE cards driven by the active
comparison's
dds: Dispersion Estimates (DESeq2
plotDispEsts of gene-wise / fitted / shrunken values),
Size Factors vs Library Size (scaled bars per sample
with Spearman ρ in the subtitle), and Cook's Outlier
Counts (per-sample count of high-Cook genes vs the
vignette threshold 4 / (n_samples - n_params)).
- New pure helpers in
R/fct_qc.R:
size_factor_library_summary(dds) and
cooks_outlier_summary(dds, threshold = NULL). The
Spearman correlation and active threshold are attached as
attributes on the returned data.frame.
- Cards render a friendly empty-state alert when no fitted
DESeqDataSet is available (pre-DE, or non-DESeq2 method).
- QC sidebar's "Select Columns" checkboxes now also drive cards
1-4 (Library Depth, Detection Rate, MT %, Sample Distance) and
cards 6-7 (Size Factors, Cook's): unchecking a sample hides
its bar/row across every per-sample card. Card 5 (Dispersion)
is gene-level so column selection has no effect there. New
pure helpers
qc_keep_cols(counts, selected) and
qc_keep_meta_rows(meta, selected) in R/fct_qc.R.
Phase B4 — Friendly errors
- User-facing error messages now follow a consistent "what went wrong + what to do" format with correct severity (red blocks, yellow warns, green/blue empty-result).
- Replaced raw R diagnostics in file-upload errors (separator mismatch, duplicate gene IDs, column/metadata mismatch).
- Empty enrichment results no longer display as red errors — they were a category bug.
- Six hand-rolled "Please install " messages in GO/KEGG paths collapsed into the existing
require_pkg() helper.
- No behavior change beyond message text and notification persistence.
Phase B3.5 — Sane defaults follow-up
- DESeq2 default test changed from
Wald to LRT, harmonizing the
pure-helper, parser fallback, test-data, and (where applicable)
help text with the UI default already in place.
- DESeq2 LFC shrinkage now defaults to
apeglm. Install via
BiocManager::install("apeglm") if not already available; a
friendly install message surfaces on first DE run otherwise.
apeglm remains in Suggests, not Imports.
- Low-count filter auto-applies on data load (method = Max,
cutoff = 10 — the previous default values, now applied without
a Filter click). Click Filter with a different cutoff/method to
override, or set cutoff = 0 to restore the unfiltered counts.
User-visible
- Raised
startDEBrowser() upload limit from 30 MB to 90 MB.