Skip to content

Add diffexp and diffadb projections to plot_features (#26)#27

Merged
Arshammik merged 2 commits into
mainfrom
feat/issue-26-diffexp-projection
Jun 9, 2026
Merged

Add diffexp and diffadb projections to plot_features (#26)#27
Arshammik merged 2 commits into
mainfrom
feat/issue-26-diffexp-projection

Conversation

@Arshammik

@Arshammik Arshammik commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Implements the feature requested in #26: visualize differential expression (and, symmetrically, differential pathway activity) with plot_features() by exposing them as projection types.

plot_features() gains two new projection values, both driven by a user contrast:

  • projection = "diffexp" — per-cell differential expression for selected genes (optional include_O = TRUE to add the global offset effect). The efficient path evaluates only the selected gene rows and never materialises the full J x N matrix.
  • projection = "diffadb" — per-cell differential pathway activity for selected pathways (requires a gene-level prior C).

Also adds the public accessor model$diffADB(contrast) (returns num_pathways x N).

Design

Every GEDI projection has the form Loadings · DB: ZDB uses Z, ADB uses C.rotation·A, and diffExp uses the differential gene loadings diffQ_Z = [Rk·(H.rotation·contrast)]. diffadb is the missing symmetric member.

Because solve_A() fits A linearly from Z (A = (CᵀC + λI)⁻¹ CᵀZ, λ = 1/S_A), ADB is a fixed linear map of the gene loadings. diffADB is therefore defined as the exact differential of ADB:

diffADB = ADB(Z + diffQ_Z) - ADB(Z) = C.rotation · solve_A(diffQ_Z) · DB

It applies the same solve_A shrinkage operator, so model$diffADB() stays on the same scale as model$projections$ADB (rather than being off by 1 + 1/S_A).

Changes

  • New getDiffADB_cpp kernel (src/gedi_differential.cpp); compute_diffADB wrapper and model$diffADB() method; plot_features() wiring for diffexp/diffadb.
  • Prior matrices are coerced to dense double before mapping into Eigen, so an integer or sparse C (e.g. a 0/1 membership matrix) is handled.
  • NEWS.md entry; regenerated man/, RcppExports.

Testing

  • testthat: 134/134 pass, 0 fail/warn/skip, no regressions. Includes numerical math-invariant checks: solve_A identity, diffADB == ADB(Z+ΔQ) − ADB(Z), a shrinkage-scale regression guard, contrast linearity, and plot-value correctness (efficient path == full matrix).
  • R CMD check: 0 errors, 0 warnings, 3 NOTES — all pre-existing/environmental (uninstalled optional glmnet, cluster clock, -march compile flag); none introduced by this PR.

Arshammik added 2 commits June 9, 2026 16:46
Allow plot_features() to visualize differential expression and
differential pathway activity as projection types, as requested in #26.

- plot_features() gains projection = "diffexp" (per-cell differential
  expression for selected genes, with optional include_O) and "diffadb"
  (per-cell differential pathway activity for selected pathways), both
  driven by a user `contrast`. The diffexp path evaluates only the
  selected gene rows and never materialises the full J x N matrix.
- New getDiffADB_cpp kernel and model$diffADB(contrast) method. diffADB
  is the exact differential of ADB (i.e. ADB(Z + dQ) - ADB(Z)): it
  applies the same solve_A shrinkage operator, so it stays on the same
  scale as model$projections$ADB.
- Coerce prior matrices to dense double before mapping into Eigen so an
  integer or sparse C prior (e.g. a 0/1 membership matrix) is handled.
- Tests: API and edge-case coverage plus numerical math-invariant checks
  (solve_A identity, diffADB == differential of ADB, contrast linearity,
  plot-value correctness). Full testthat suite: 134 passing.
@Arshammik Arshammik merged commit 6abe676 into main Jun 9, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant