Functional enrichment in Platt
Once you have per-gene pattern calls — from Reference DEGs or Perturbation DEGs — the next question is often at the level of programs rather than individual genes: is a cell state's differentially-expressed gene set enriched for a particular biological process, like proliferation, apoptosis, or a stress response? Platt wraps fgsea for this, at two granularities: rank-based GSEA within a single cell state, or over-representation analysis (ORA) across the whole graph at once.
Rank-based GSEA within a single cell state
Any table with a pattern_activity_score column — such as condensate_genes from the Reference DEGs page — can be handed to calc_gsea_enrichment_on_state_specific_genes(), which uses that score to rank the state's genes and runs fgsea::fgsea() against a gene set table you supply:
gene_patterns_within_state_graph- a table withgene_short_nameandpattern_activity_scorecolumns, e.g.condensate_genesgene_df- a gene set table withgene_short_nameandgs_namecolumns;msigdbris a convenient source for zebrafish GO/pathway gene sets, but any curated list works the same waysig_thresh-padjcutoff for the returned results, default0.1
library(msigdbr)
gene_sets = msigdbr(species = "Danio rerio", subcategory = "GO:BP") %>%
dplyr::distinct(gs_name, gene_short_name = gene_symbol)
condensate_gsea = calc_gsea_enrichment_on_state_specific_genes(
condensate_genes,
gene_sets,
sig_thresh = 0.1
)
The result is a standard fgsea output tibble — pathway, pval, padj, ES, NES, size, and the leading-edge gene list — already filtered down to padj < sig_thresh. A pathway with a large positive NES is enriched among the genes with the highest pattern_activity_score at this state (e.g. its most strongly activated/upregulated genes); a large negative NES is enriched among its most strongly deactivated/downregulated genes.
gene_df doesn't have to come from msigdbr — a handful of curated proliferation/apoptosis/stress/senescence gene sets, tested the same way, is what typically informs the fitness_label calls on the Phenotyping page.
Over-representation across the whole graph
For a graph-wide pass, calc_graph_overrep_genes() takes the same kind of nested DEG table compare_genes_over_graph() returns (see Reference DEGs) and computes ORA independently at every cell state:
ref_degs- a DEG table withcell_state,gene_short_name,gene_id, andinterpretationcolumns —pf_graph_degsfrom the Reference DEGs page works directly (its nestedgene_class_scorescolumn is unnested automatically)pathway_type-"GO:BP"or"GO:MF", forwarded tomsigdbrto build the gene set tablespecies- forwarded tomsigdbr, default"Danio rerio"
pf_graph_overrep = calc_graph_overrep_genes(pf_graph_degs, pathway_type = "GO:BP")
Under the hood, this collapses each gene's finer interpretation call (the same category names from Gene expression patterns) down to "Up", "Down", or "Maintained", then runs ORA (fgsea::fora()) separately for the up- and down-regulated gene sets at each state — "Maintained" genes aren't tested, since there's no direction of change to look for. The result is a nested tibble, one row per cell state:
pf_graph_overrep %>%
tidyr::unnest(overrep_pathways) %>%
dplyr::select(cell_state, interpretation_simple, pathway, padj)
| cell_state | interpretation_simple | pathway | padj |
|---|---|---|---|
| pectoral fin condensate | Up | GOBP_SKELETAL_SYSTEM_DEVELOPMENT | 0.004 |
| pectoral fin condensate | Up | GOBP_COLLAGEN_FIBRIL_ORGANIZATION | 0.017 |
| pectoral fin bud progenitor | Down | GOBP_CELL_DIFFERENTIATION | 0.031 |
padj is already filtered to the q_val_thresh default (0.05) inside calc_overrep_genes(), the per-state worker calc_graph_overrep_genes() calls internally. If you already have a plain gene list for one state rather than a full graph-wide DEG table, calc_overrep_genes() and calc_pathway_enrichment_on_state_specific_genes() (a thinner wrapper around clusterProfiler::enricher()) are the lower-level building blocks — most users will only need the graph-wide wrapper above.
Visualizing enrichment results
There's no dedicated plot_* wrapper for enrichment results yet, but the unnested tibble drops straight into ggplot2 — a dot plot with point size mapped to significance and color mapped to direction is a common way to scan results across many cell states at once:
pf_graph_overrep %>%
tidyr::unnest(overrep_pathways) %>%
dplyr::group_by(cell_state) %>%
dplyr::slice_min(padj, n = 5) %>%
ggplot(aes(x = cell_state, y = pathway, size = -log10(padj), color = interpretation_simple)) +
geom_point() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
For more on turning a handful of enrichment results into the fitness axes (proliferation, apoptosis, stress, senescence) used on a phenotype call, see the Phenotyping page — Platt doesn't yet package that specific mapping for you, so going from enrichment results to a single fitness_label is still a judgment call you make yourself.