| Title: | Stage-Aware PDAC Atlas and Prospectively Frozen Tissue-to-Serum Biomarker Audit Framework |
|---|---|
| Description: | pdactrace implements a transparent, deterministic claim-audit framework for stage-aware pancreatic ductal adenocarcinoma (PDAC) tissue-to-blood biomarker evidence. It integrates per-stage trajectory matching across bulk RNA-seq, tissue proteomics, single-cell origin, serum proteomics, and pancreatitis context, with explicit anchor-enrichment evaluation against a curated external reference set. The framework comprises a 12-template competitive trajectory catalog, a 3-axis + 2-gate reference score, an Evidence Math layer, TRACE-D tissue-to-serum directional evidence concordance, claim-tier classification, and weight-robustness and Pareto support audits. A prespecification layer supports freezing candidate scores, directions and a decision rule under a content hash before outcome labels are opened, with a distinct inconclusive terminal state when a frozen gate fails. Scope is deliberately PDAC-specific: the bundled atlas, the anchor reference set and every validated claim are PDAC, and no result is claimed for any other disease. Separately, no supervised classifier is trained or shipped, because validated non-circular early-detection ground truth is unavailable in PDAC. |
| Authors: | Jibeom Ko [aut, cre] (ORCID: <https://orcid.org/0009-0002-8630-1973>) |
| Maintainer: | Jibeom Ko <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.99.25 |
| Built: | 2026-09-28 15:49:32 UTC |
| Source: | https://github.com/BiocStaging/pdactrace |
Central message: PDAC tissue biomarker is not always a serum-up biomarker - tissue-derived candidates can preserve, invert, or decouple when projected into serum.
pdactrace integrates public PDAC multi-omics data - bulk RNA-seq, tissue proteomics, scRNA cell origin, serum proteomics, and pancreatitis context - under a 12-template competitive trajectory framework (Normal -> Early -> Mid -> Late) where genes compete against 11 alternative shapes (Early × 4 + Mid × 4 + Late × 2 + Monotonic × 2) and only Early-onset best-matches are surfaced as resectable-stage candidates. The current release adds a **3-axis
2-gate audit framework** (v0.3.0) and a user-data extension API + per-stage Wald padj (v0.4.0).
Each gene's z-scored 4-point N/E/M/L trajectory is matched against
12 pre-declared templates by Pearson-rho argmax. A template call is
retained only when the best-match rho passes rho_cutoff
(0.85 by default in classify_trajectory()). Only the 4
Early-onset best-matches are surfaced in
pdactrace_reference$rna_pattern:
Early_Burst_Up - Normal low -> Early up -> sustained
Early_Loss_Down - Normal high -> Early down -> sustained
Early_Peak - Early peak -> Mid/Late decline
Early_Trough - Early trough -> Mid/Late recovery
Non-Early best-matches (Mid × 4 / Late × 2 / Monotonic × 2) are
excluded from the surface but flagged via
excluded_mid_pattern, excluded_late_pattern,
excluded_monotonic_pattern for transparent provenance. Including
the 8 non-Early templates in the matching step is the v0.4.0
design discipline: a gene must beat 11 alternatives before being
surfaced — this widens the negative-evidence pool and correctly
demotes leaky candidates (e.g., GAPDH, CDH13 → Monotonic_Up).
query_gene() - single-gene full evidence dump
query_panel() - multi-gene join
list_candidates() - criterion-based candidate filter
summarize_gene_evidence() - human-readable text summary
plot_gene_evidence() - multi-panel composite figure
fit_stage_de() - DESeq2 LRT wrapper for stage-aware DE
classify_trajectory() - best-match against the 12-template catalog
score_trajectory() - gene-level rho vector vs all 12 templates
align_patient_profile() - sample-level alignment of a single patient's
log2(tumor/normal) profile against the atlas's stage-trajectory axes
(rho-style readout, not a stage prediction; v0.4.1)
trace_filters() - phase60 7-step filter audit + class route
plot_filter_trace() - pass/fail step bar across genes
plot_panel_heatmap() - gene x evidence comparison heatmap
plot_candidate_landscape() - tissue x serum scatter, Class A/B colored
translation_class == "B" is treated as a rare, manually
curated failure mode of tissue-to-serum translation, not a
predicted class. Even in v0.2.0+, Class B will be flagged via
nearest-reference evidence rather than predicted.
Ko J. pdactrace: a queryable stage-aware PDAC tissue-to-serum biomarker reference atlas. (2026)
Maintainer: Jibeom Ko [email protected] (ORCID)
Useful links:
Reports how a single patient's tumor-vs-matched-normal log2 fold-change profile aligns with the frozen pdactrace atlas's stage-trajectory axes (Early / Mid / Late), expressed as a Pearson correlation against each cohort-adjusted stage-effect vector and a complementary audit-weighted vote share. The result is an alignment readout, not a stage prediction. No supervised model has been fit — the atlas is frozen and the function is deterministic given (input, atlas).
align_patient_profile( rna_logfc, prot_logfc = NULL, weight_by = c("audit_score", "uniform"), min_audit_score = 0.3, top_n_genes = 500L, gene_selection = c("highest_audit", "highest_abs_beta"), min_genes = 50L, layer_combine = c("separate", "rna_only"), reference = NULL ) align_patient(...)align_patient_profile( rna_logfc, prot_logfc = NULL, weight_by = c("audit_score", "uniform"), min_audit_score = 0.3, top_n_genes = 500L, gene_selection = c("highest_audit", "highest_abs_beta"), min_genes = 50L, layer_combine = c("separate", "rna_only"), reference = NULL ) align_patient(...)
rna_logfc |
Named numeric vector. Names are HGNC gene symbols; values are log2(patient_tumor / matched_normal). Missing values are dropped. Required. |
prot_logfc |
Optional named numeric vector with the same format
for the protein layer. When supplied, returns a categorical
concordance table in |
weight_by |
Per-gene weight in both rho and vote_share. One of
|
min_audit_score |
Minimum atlas |
top_n_genes |
Optional integer. Cap genes used at the top N by
|
gene_selection |
If |
min_genes |
Warn-only floor. If the number of overlapping genes is below this (default 50), a warning is issued. The function hard-errors below 10 (rho is meaningless on so few points). |
layer_combine |
Either |
reference |
Optional atlas data.table override (advanced; for
testability). Default |
... |
Forwarded to |
Two complementary signals are reported, never collapsed into one decision:
cor_to_stage_axis
Audit-weighted Pearson rho between
the patient's per-gene log2FC vector and each of the three stage
axes rna_beta_E, rna_beta_M, rna_beta_L (with Fisher-z 95% CI).
Invariant to per-patient global shifts (library-size / age / FFPE
drift). Has a closed-form null distribution.
vote_share
Audit-weighted fraction of genes whose closest atlas β is each stage's β. Less rigorous but interpretable for non-statistical readers; surfaces disagreement-with-rho as a diagnostic.
Misalignment with all three stage axes is a legitimate output and does
not imply Normal — it indicates the patient does not resemble any of the
atlas's PDAC stage profiles. Limitations: rho is unstable below ~50
overlapping genes; the protein layer reports only categorical
concordance because the atlas does not carry per-stage numeric protein
effect sizes (use layer_combine = "rna_only" to skip the protein arm).
A list of class pdactrace_patient_alignment with elements
$rna (4-row data.table with stage / rho / CI / vote_share / weighted
distance / n_genes_used), $prot (data.table or NULL), $summary
(one-line character), and $attrs (named list of parameters and
provenance metadata).
# Synthetic Late-stage patient profile set.seed(7) ref <- pdactrace:::.get_reference() pool <- ref[!is.na(rna_beta_L) & audit_score >= 0.3][seq_len(300)] patient <- setNames( pool$rna_beta_L + rnorm(nrow(pool), sd = 0.3), pool$gene_symbol) aln <- align_patient_profile(patient, top_n_genes = 200) print(aln) aln$rna# Synthetic Late-stage patient profile set.seed(7) ref <- pdactrace:::.get_reference() pool <- ref[!is.na(rna_beta_L) & audit_score >= 0.3][seq_len(300)] patient <- setNames( pool$rna_beta_L + rnorm(nrow(pool), sd = 0.3), pool$gene_symbol) aln <- align_patient_profile(patient, top_n_genes = 200) print(aln) aln$rna
Returns a SummarizedExperiment view of the bundled v0.4.0 atlas
in which the four stage-effect coefficient columns
(rna_beta_N, rna_beta_E, rna_beta_M, rna_beta_L) become a
4-column assay, the standard errors rna_lfcSE_E/M/L (with NA
for the Normal reference column) become a parallel assay, and
all of the per-gene metadata (audit components, RNA / protein
trajectory pattern, translation class, scRNA cell origin, serum
direction, meta-analysis I2, etc.) goes into rowData(). The
colData() carries one row per stage with a reference_level
flag for the Normal column.
as_summarized_experiment(reference = NULL)as_summarized_experiment(reference = NULL)
reference |
Optional override of the bundled
|
Intended use: Bioconductor-native consumption of the atlas with
assay(), rowData(), subsetByOverlaps() (when paired with
a separate ranges object), and downstream tooling that expects
the SE container — without forcing a one-time mass conversion of
the bundled object (which remains a data.table for fast
query-based use cases).
A SummarizedExperiment with:
2 assays — rna_beta (10,113 genes by 4 stages) and
rna_lfcSE (same shape; NA in the Normal column).
colData — 4 rows: stage = c("Normal", "Early", "Mid", "Late"),
reference_level = c(TRUE, FALSE, FALSE, FALSE).
rowData — every non-stage-axis column of the bundled atlas
(~109 columns: identifiers, audit components, trajectory
pattern calls, meta-analysis summaries, etc.).
metadata — list(atlas_version, build_date, n_cohorts, ...).
se <- as_summarized_experiment() dim(se) SummarizedExperiment::assayNames(se) if (requireNamespace("SummarizedExperiment", quietly = TRUE)) { se <- as_summarized_experiment() se SummarizedExperiment::assay(se, "rna_beta")[1:3, ] head(SummarizedExperiment::rowData(se)) }se <- as_summarized_experiment() dim(se) SummarizedExperiment::assayNames(se) if (requireNamespace("SummarizedExperiment", quietly = TRUE)) { se <- as_summarized_experiment() se SummarizedExperiment::assay(se, "rna_beta")[1:3, ] head(SummarizedExperiment::rowData(se)) }
Combines optional per-layer user inputs into a single per-gene
evidence data.table whose column schema is the subset of the
bundled pdactrace_reference atlas that
compute_audit_score(evidence = ...) consumes. Layers the user
does not supply are filled with NA; the downstream feature
constructor in .audit_compute_features() is NA-tolerant and
degrades gracefully (a layer absent → that layer contributes
zero to evidence_strength; cross-layer concordance falls to
the available pair; etc.).
assemble_user_evidence( rna_fit = NULL, prot_fit = NULL, scrna_summary = NULL, serum_summary = NULL, signal_peptide = NULL, cross_cohort_agreement = NULL, max_I2 = NULL )assemble_user_evidence( rna_fit = NULL, prot_fit = NULL, scrna_summary = NULL, serum_summary = NULL, signal_peptide = NULL, cross_cohort_agreement = NULL, max_I2 = NULL )
rna_fit |
Optional output of |
prot_fit |
Optional output of |
scrna_summary |
Optional data.table with |
serum_summary |
Optional data.table with |
signal_peptide |
Optional character vector of gene symbols
that carry a signal peptide (UniProt SP-positive). Genes outside
this set are flagged |
cross_cohort_agreement |
Optional named numeric vector,
names = gene symbols, values in |
max_I2 |
Optional named numeric vector, names = gene
symbols, values are max meta-analysis I². When |
A data.table with the column schema consumed by
compute_audit_score(evidence = ...).
rna_fit <- data.table::data.table( gene_symbol = c("FAKE_UP", "FAKE_DOWN"), rna_pattern = c("Early_Burst_Up", "Early_Loss_Down"), rna_pattern_rho = c(0.95, 0.92), lrt_padj = c(1e-4, 1e-3)) ev <- assemble_user_evidence(rna_fit = rna_fit) compute_audit_score(evidence = ev)rna_fit <- data.table::data.table( gene_symbol = c("FAKE_UP", "FAKE_DOWN"), rna_pattern = c("Early_Burst_Up", "Early_Loss_Down"), rna_pattern_rho = c(0.95, 0.92), lrt_padj = c(1e-4, 1e-3)) ev <- assemble_user_evidence(rna_fit = rna_fit) compute_audit_score(evidence = ev)
Version, snapshot, source-script, and build metadata for the bundled pdactrace reference atlas.
atlas_metadataatlas_metadata
A named list.
Returns a named list summarising where the bundled atlas came from: package version, atlas snapshot date, the manuscript monorepo URL, both Zenodo concept DOIs (the package archive and the manuscript-monorepo archive), and the cohort count. Designed as a one-call provenance dossier for reviewers and citing authors.
atlas_provenance()atlas_provenance()
Named list with fields package_version, atlas_version,
build_date, n_cohorts, package_repo, manuscript_repo,
package_doi, manuscript_doi, and data_layers. Missing
metadata fields are returned as NA_character_.
atlas_provenance() atlas_provenance()$package_doiatlas_provenance() atlas_provenance()$package_doi
build_evidence_graph() exposes the audit-score evidence as a small
node/edge graph. It is intentionally descriptive: pdactrace v0.3.0 does
not train a graph neural network, and the graph is used to make the
hand-engineered evidence aggregation auditable.
build_evidence_graph(gene_symbol)build_evidence_graph(gene_symbol)
gene_symbol |
HGNC gene symbol. |
A list with nodes, edges, and score data.tables, or NULL
invisibly if the gene is not in the atlas.
g <- build_evidence_graph("LTBP1") head(g$nodes) g$scoreg <- build_evidence_graph("LTBP1") head(g$nodes) g$score
Combines v0.2 tier, v0.3 score, uncertainty, anchor provenance, and artifact/rescue calls for manuscript case-study panels.
case_study(genes)case_study(genes)
genes |
Character vector of HGNC gene symbols. |
A data.table with one row per matched gene.
case_study(c("THBS2", "LTBP1", "ALB", "GAPDH"))case_study(c("THBS2", "LTBP1", "ALB", "GAPDH"))
classify_claim_tier() separates evidence strength from claim
strength. A gene can have strong stage-aware tissue evidence while
still receiving a conservative blood-biomarker claim such as
translation_unknown or confounded.
classify_claim_tier( atlas = NULL, genes = NULL, tau_tissue = 0.5, tau_serum = 0.1 )classify_claim_tier( atlas = NULL, genes = NULL, tau_tissue = 0.5, tau_serum = 0.1 )
atlas |
Optional atlas-like data table. Defaults to the bundled
|
genes |
Optional character vector of genes to return. Ranking and thresholds are computed on the supplied atlas, then filtered. |
tau_tissue |
Minimum absolute tissue effect used by
|
tau_serum |
Minimum absolute serum log2 fold-change used by
|
A data.table with one row per gene and claim audit columns.
classify_claim_tier(genes = c("LGALS3BP", "LTBP1", "ALB", "GAPDH"))classify_claim_tier(genes = c("LGALS3BP", "LTBP1", "ALB", "GAPDH"))
Protein-side wrapper of classify_trajectory(): takes the output of
fit_stage_de_protein(), runs the same shared template-matching
engine (12 templates: Early x 4 + Mid x 4 + Late x 2 + Monotonic x 2),
and renames the output column rna_pattern to prot_pattern so
assemble_user_evidence() can consume both layers without colliding
on column names. As with the RNA side, the atlas surface restricts
visible prot_pattern calls to Early x 4; non-Early best-matches are
recorded internally but not surfaced.
classify_protein_trajectory(fit, rho_cutoff = 0.85, sig_only = TRUE) classify_prot_trajectory(...)classify_protein_trajectory(fit, rho_cutoff = 0.85, sig_only = TRUE) classify_prot_trajectory(...)
fit |
A |
rho_cutoff |
Numeric. Minimum Pearson rho for assignment.
Default 0.85. The bundled protein layer (phase34) was built with a
cutoff of 0.75; pass |
sig_only |
Logical. If |
... |
Forwarded to |
A data.table with columns gene_symbol, prot_pattern,
prot_pattern_rho, prot_pattern_rho_runner_up. The remaining
columns of the input fit are preserved.
prot_fit <- data.table::data.table( gene_symbol = c("P1", "P2"), beta_N = 0, beta_E = c(2, -2), beta_M = c(0.5, -0.5), beta_L = 0, lrt_padj = c(0.01, 0.02), lrt_significant = TRUE) classify_protein_trajectory(prot_fit, sig_only = FALSE) if (requireNamespace("limma", quietly = TRUE)) { data(toy_protein) data(toy_coldata) prot_fit <- fit_stage_de_protein(toy_protein, toy_coldata$stage, toy_coldata$cohort) prot_pat <- classify_protein_trajectory(prot_fit) }prot_fit <- data.table::data.table( gene_symbol = c("P1", "P2"), beta_N = 0, beta_E = c(2, -2), beta_M = c(0.5, -0.5), beta_L = 0, lrt_padj = c(0.01, 0.02), lrt_significant = TRUE) classify_protein_trajectory(prot_fit, sig_only = FALSE) if (requireNamespace("limma", quietly = TRUE)) { data(toy_protein) data(toy_coldata) prot_fit <- fit_stage_de_protein(toy_protein, toy_coldata$stage, toy_coldata$cohort) prot_pat <- classify_protein_trajectory(prot_fit) }
Takes the output of fit_stage_de() and matches each LRT-significant
gene's z-scored 4-point profile (beta_N, beta_E, beta_M, beta_L) against
the canonical 12-template catalog (Early × 4 + Mid × 4 + Late × 2 +
Monotonic × 2; v0.4.0). The best-match template is assigned if
rho >= rho_cutoff. The atlas surface (rna_pattern in
pdactrace_reference) restricts visible calls to Early × 4 only —
Mid / Late / Monotonic best-matches are recorded internally but flagged
via excluded_*_pattern columns rather than surfaced. Including the 8
non-Early templates in the matching step is a deliberate design choice
for honest competition: a gene must beat 11 alternatives before it is
surfaced as Early.
classify_trajectory(fit, rho_cutoff = 0.85, sig_only = TRUE)classify_trajectory(fit, rho_cutoff = 0.85, sig_only = TRUE)
fit |
A |
rho_cutoff |
Numeric. Minimum Pearson rho for assignment.
Default 0.85. The bundled |
sig_only |
Logical. If |
A data.table with the input plus columns:
rna_pattern - character: best 12-template match or NA. Note:
this returns the raw best-match label (any of the 12 templates).
The atlas-surfaced version in pdactrace_reference$rna_pattern
is filtered to Early × 4 only; non-Early calls are flagged via
excluded_mid_pattern / excluded_late_pattern /
excluded_monotonic_pattern.
rna_pattern_rho - numeric: Pearson rho with best template
rna_pattern_rho_runner_up - second-best rho (gap detection)
fit <- data.table::data.table( gene_symbol = c("G1", "G2"), beta_N = 0, beta_E = c(2, -2), beta_M = c(0.5, -0.5), beta_L = 0, lrt_padj = c(0.01, 0.02), lrt_significant = TRUE) classify_trajectory(fit, sig_only = FALSE) if (requireNamespace("DESeq2", quietly = TRUE)) { data(toy_counts) data(toy_coldata) fit <- fit_stage_de(toy_counts, toy_coldata$stage, toy_coldata$cohort) pat <- classify_trajectory(fit, rho_cutoff = 0.85) table(pat$rna_pattern) }fit <- data.table::data.table( gene_symbol = c("G1", "G2"), beta_N = 0, beta_E = c(2, -2), beta_M = c(0.5, -0.5), beta_L = 0, lrt_padj = c(0.01, 0.02), lrt_significant = TRUE) classify_trajectory(fit, sig_only = FALSE) if (requireNamespace("DESeq2", quietly = TRUE)) { data(toy_counts) data(toy_coldata) fit <- fit_stage_de(toy_counts, toy_coldata$stage, toy_coldata$cohort) pat <- classify_trajectory(fit, rho_cutoff = 0.85) table(pat$rna_pattern) }
Returns a single data.table row-per-gene with the columns most
useful for panel-design discussion: audit class + score, RNA and
protein trajectory pattern, translation class, dominant scRNA cell
origin, serum-detectability flags, and a redundancy hint based on
shared cell origin and shared RNA pattern. The result is sorted by
audit_score (descending) so the strongest candidates surface
first.
compare_candidates(gene_symbols)compare_candidates(gene_symbols)
gene_symbols |
Character vector of HGNC gene symbols (length >= 2; length-1 input is allowed but the comparison is trivial). |
Input genes that are not in the bundled atlas are returned with
audit_class = NA, so the call never fails on stray symbols — the
returned table makes the gap explicit.
A data.table (one row per gene) with columns:
gene_symbol, audit_class, audit_score
rna_pattern, prot_pattern, translation_class
cell_origin_top, serum_detected,
serum_log2fc_PDAC_vs_HC
max_I2_meta, redundancy_with — the latter lists other genes
in the input set that share rna_pattern and cell_origin_top
(semicolon-separated, "" if none).
compare_candidates(c("LGALS3BP", "LTBP1", "SERPINA1", "ALB", "GAPDH"))compare_candidates(c("LGALS3BP", "LTBP1", "SERPINA1", "ALB", "GAPDH"))
Calls evidence_math() for each input gene and pivots the
per-axis lists into a tidy data.table. Useful for assembling
the "candidate vs. competitors" comparison tables that show up
in the manuscript and in report_gene() output.
compare_genes(gene_symbols, axes = NULL, wide = FALSE, reference = NULL)compare_genes(gene_symbols, axes = NULL, wide = FALSE, reference = NULL)
gene_symbols |
Character vector of HGNC gene symbols. |
axes |
Optional character vector to filter the axis set
reported. Defaults to all axes from |
wide |
Logical. If |
reference |
Optional |
By default returns a long table with one row per
(gene x axis x metric) tuple — friendly to data.table::dcast()
if you need a custom wide layout. Set wide = TRUE for the
convenience pivot to one row per gene with metric columns
(axis.metric, e.g. trajectory_fit.delta_rho).
Note: this function reports the math evidence per axis. For
the audit-score-driven candidate ranking with redundancy
grouping, see compare_candidates() (different layer, same
atlas).
A data.table. Long form columns: gene, axis,
metric, value (character; numerics formatted to 4 sig
figs to keep the table renderable). Wide form: gene
followed by axis.metric columns.
evidence_math(), explain_gene(),
compare_candidates().
compare_genes(c("LGALS3BP", "LTBP1", "TIMP1")) compare_genes(c("LGALS3BP", "LTBP1"), axes = c("trajectory_fit", "rna_protein_coupling"), wide = TRUE)compare_genes(c("LGALS3BP", "LTBP1", "TIMP1")) compare_genes(c("LGALS3BP", "LTBP1"), axes = c("trajectory_fit", "rna_protein_coupling"), wide = TRUE)
Aggregates the seven implementation features into three transparent
evidence axes (evidence_strength, biological_coherence,
translational_relevance) and applies two pre-specified reliability
gates (leakage_gate, heterogeneity_gate), then rescales by the
largest gated score in the scored table:
audit_score = positive_score * leakage_gate * heterogeneity_gate / max(...).
The score is therefore relative to the best-scoring gene of the table
it is computed on (the bundled atlas by default, or evidence).
Each gene receives one of five audit_class labels. Gates take
precedence over the score: excluded (leakage gate 0), penalized
(leakage gate below 1), supported_uncertain (heterogeneity gate
below 1), and otherwise high_confidence (score >= 0.5),
supported_uncertain (>= 0.3) or low.
compute_audit_score(gene_symbol = NULL, evidence = NULL)compute_audit_score(gene_symbol = NULL, evidence = NULL)
gene_symbol |
Optional character vector of HGNC gene symbols.
When |
evidence |
Optional user-supplied evidence table (e.g.,
produced by |
This is not a supervised biomarker predictor; the formula is
pre-specified and external anchors are used only post-freeze for
enrichment evaluation. The seven implementation features are kept as
supplementary detail; see extract_graph_features().
A data.table with evidence_strength,
biological_coherence, translational_relevance,
leakage_gate, heterogeneity_gate, positive_score,
audit_score (rescaled to the table maximum), and audit_class.
compute_audit_score(c("LGALS3BP", "LTBP1", "ALB", "GAPDH"))compute_audit_score(c("LGALS3BP", "LTBP1", "ALB", "GAPDH"))
Convenience wrapper around compute_pareto_layers() that converts
numeric layers into manuscript-facing evidence classes.
compute_pareto_class(atlas = NULL, genes = NULL, top_n = 2000L)compute_pareto_class(atlas = NULL, genes = NULL, top_n = 2000L)
atlas |
Optional atlas-like data table. |
genes |
Optional genes to return. |
top_n |
Candidate pool size passed to |
A data.table with Pareto layer, rank, and class.
compute_pareto_class(genes = c("LGALS3BP", "LTBP1"), top_n = 200)compute_pareto_class(genes = c("LGALS3BP", "LTBP1"), top_n = 200)
compute_pareto_layers() implements layered non-dominated sorting on
audit_evidence_strength, audit_biological_coherence, and
audit_translational_relevance. The two reliability gates
(audit_leakage_gate, audit_heterogeneity_gate) are applied as a
hard pre-filter rather than as weights, mirroring the
"axes graded, gates reliability filter" structure of the frozen 3+2
audit framework. Ranking is layer-first, with crowding distance
(NSGA-II convention) as a within-layer tiebreaker and the frozen
deterministic audit_score as a final deterministic tiebreaker.
compute_pareto_layers( atlas = NULL, axes = c("audit_evidence_strength", "audit_biological_coherence", "audit_translational_relevance"), gate_cols = c("audit_leakage_gate", "audit_heterogeneity_gate"), score_col = "audit_score", gate_filter = TRUE, top_n = 2000L )compute_pareto_layers( atlas = NULL, axes = c("audit_evidence_strength", "audit_biological_coherence", "audit_translational_relevance"), gate_cols = c("audit_leakage_gate", "audit_heterogeneity_gate"), score_col = "audit_score", gate_filter = TRUE, top_n = 2000L )
atlas |
Optional user-supplied atlas (defaults to the bundled
|
axes |
Character(3) of the axis column names. Defaults to the three frozen axes. |
gate_cols |
Character(2) of the gate column names. Defaults to
|
score_col |
Column used both to restrict the candidate pool to
the top |
gate_filter |
Logical; when |
top_n |
Integer; restrict the Pareto candidate pool to the top
|
This function is complementary to compute_audit_score() and does
not modify the frozen weighted formula. Use it when reviewers ask
whether the audit ranking is driven by the scalar weights
0.40 / 0.35 / 0.25 — Pareto layers expose a weight-free alternative.
A data.table with one row per gene in atlas and the
columns pareto_layer (integer; NA for excluded genes),
crowding_distance (numeric; Inf for boundary points,
NA for excluded), pareto_rank (integer 1..N within the
candidate pool, NA for excluded), and pareto_excluded_by_gate
(logical).
head(compute_pareto_layers(top_n = 200L))head(compute_pareto_layers(top_n = 200L))
compute_trace_d() deterministically types each gene by the direction
concordance between tissue (RNA + Protein) and serum evidence, with
an explicit pancreatitis-specificity annotation that separates
PDAC-specific signal from shared-inflammation signal. The four
classes ("A" direction-preserved, "B" direction-inverted, "C"
decoupled, NA insufficient tissue evidence) coexist with the
legacy translation_class column rather than replacing it
(back-compatible).
compute_trace_d( atlas = NULL, tau_tissue = 0.5, tau_serum = 0.1, weights = c(tissue = 0.5, serum = 0.3, specificity = 0.2), legacy_translation = c("strict", "fallback") )compute_trace_d( atlas = NULL, tau_tissue = 0.5, tau_serum = 0.1, weights = c(tissue = 0.5, serum = 0.3, specificity = 0.2), legacy_translation = c("strict", "fallback") )
atlas |
Optional atlas (defaults to the bundled
|
tau_tissue |
Numeric; minimum |
tau_serum |
Numeric; minimum |
weights |
Named numeric vector of length 3 summing to 1
(tissue, serum, specificity components of |
legacy_translation |
One of |
This is one of two domain-specific audit algorithms introduced in
pdactrace v0.99.19; see compute_pareto_layers() for Algorithm 2.
Neither algorithm introduces new statistical machinery — the
contribution is the domain-specific combination of direction
consensus, magnitude thresholds, and pancreatitis-specificity
annotation packaged as a deterministic, reproducible audit layer.
Pancreatitis-specificity is annotation only by design: a
Class A candidate flagged shared_inflammation is not demoted —
downstream consumers apply stricter filters via
list_candidates() if required.
A data.table with one row per gene in atlas and the
columns tracd_tissue_dir, tracd_serum_dir, tracd_class,
tracd_confidence, tracd_pancreatitis_overlap_score,
tracd_pancreatitis_specificity, tracd_tissue_weight,
tracd_decision_path.
head(compute_trace_d()) compute_trace_d()[gene_symbol %in% c("LGALS3BP", "LTBP1", "GAPDH")]head(compute_trace_d()) compute_trace_d()[gene_symbol %in% c("LGALS3BP", "LTBP1", "GAPDH")]
Built-in 12 hypothesis-driven trajectory templates used by
classify_trajectory() and score_trajectory():
Early × 4 (Burst_Up, Loss_Down, Peak, Trough) + Mid × 4
(Plateau_Up, Plateau_Down, Peak, Trough) + Late × 2 (Burst_Up,
Loss_Down) + Monotonic × 2 (Up, Down). The atlas surface
(pdactrace_reference$rna_pattern) restricts visible best-match
calls to Early × 4 only — non-Early calls are flagged via
excluded_*_pattern columns. See ?early_pattern_names,
?mid_pattern_names_excluded for membership lists.
default_templatesdefault_templates
A named list of length 12, each element a numeric vector of length 4 (z-scored expected values across stages Normal / Early / Mid / Late).
The bundled inst/extdata carries the six small downstream phase
tables (phase2c / phase29 / phase42 / phase60 / phase77 / phase80)
but not the two large upstream fits — phase33_deseq2_coef_12template.csv
(~2.6 MB RNA fit) and phase34_protein_pooled_12template.csv
(~0.9 MB protein fit) — to keep the software tarball small. Both
are gene-level summary statistics and live in data-raw/ of the
public source repository, github.com/jibeomko/pdactrace. This
helper fetches them on demand via raw GitHub URLs and caches them
locally with BiocFileCache::BiocFileCache().
download_phase_csvs( target = c("both", "phase33", "phase34"), ref = "main", cache = NULL, verbose = TRUE )download_phase_csvs( target = c("both", "phase33", "phase34"), ref = "main", cache = NULL, verbose = TRUE )
target |
Optional character. Either |
ref |
Git ref (branch / tag / commit) on
|
cache |
A BiocFileCache::BiocFileCache object. Default uses the user's standard cache. |
verbose |
Logical. If |
A git checkout does not need this helper: data-raw/build_reference.R
and data-raw/build_protein_betas.R read both files from data-raw/
directly.
Invisibly, a named character vector mapping the requested
target value(s) to the absolute cached file path(s).
args(download_phase_csvs) # Pull both upstream CSVs once; subsequent calls hit the cache: paths <- download_phase_csvs("both") # ... and feed them to the build chain: p33 <- data.table::fread(paths[["phase33"]])args(download_phase_csvs) # Pull both upstream CSVs once; subsequent calls hit the cache: paths <- download_phase_csvs("both") # ... and feed them to the build chain: p33 <- data.table::fread(paths[["phase33"]])
The 4 patterns surfaced by pdactrace_reference$rna_pattern. Under
v0.4.0 the trajectory classifier matches against 12 templates total
(Early × 4 + Mid × 4 + Late × 2 + Monotonic × 2) but only Early-onset
best-matches are surfaced — non-Early best-matches are flagged via
excluded_mid_pattern, excluded_late_pattern,
excluded_monotonic_pattern.
early_pattern_names() early_patterns()early_pattern_names() early_patterns()
character(4)
early_pattern_names() early_patterns() # short aliasearly_pattern_names() early_patterns() # short alias
External anchors are used only for evaluation. They are not used by the frozen v0.3.0 scoring rule.
evaluate_anchor_enrichment( top_n = c(50, 100, 200, 500, 1000), tier = c("primary", "secondary", "exploratory", "all"), score_col = c("audit_score", "audit_score_median", "pareto_rank", "pareto_stability_top1", "tracd_confidence"), evidence = NULL, anchors = NULL ) anchor_enrichment(...)evaluate_anchor_enrichment( top_n = c(50, 100, 200, 500, 1000), tier = c("primary", "secondary", "exploratory", "all"), score_col = c("audit_score", "audit_score_median", "pareto_rank", "pareto_stability_top1", "tracd_confidence"), evidence = NULL, anchors = NULL ) anchor_enrichment(...)
top_n |
Integer vector of top-N cutoffs. |
tier |
Anchor tier: |
score_col |
Ranking column. Defaults to deterministic |
evidence |
Optional user-supplied evidence table (see
|
anchors |
Optional user-supplied anchor table with columns
|
... |
Forwarded to |
A data.table with hypergeometric enrichment results.
evaluate_anchor_enrichment(top_n = 100, tier = "secondary")evaluate_anchor_enrichment(top_n = 100, tier = "secondary")
evaluate_pareto_stability() recomputes the Pareto layer assignment
across n_draws Monte Carlo perturbations of the underlying
evidence (pattern-correlation rho, cohort agreement, and
between-cohort I^2), using the same perturbation kernel as
propagate_uncertainty(). For each gene it returns the proportion
of draws in which the gene appears in Pareto layer 1 of the
gate-passing candidate pool. This quantifies axis-agnostic ranking
robustness — a complement to the score-space CI returned by
propagate_uncertainty().
evaluate_pareto_stability( atlas = NULL, n_draws = 1000L, axes = c("audit_evidence_strength", "audit_biological_coherence", "audit_translational_relevance"), gate_cols = c("audit_leakage_gate", "audit_heterogeneity_gate"), score_col = "audit_score", top_n = 2000L, seed = 20250506L )evaluate_pareto_stability( atlas = NULL, n_draws = 1000L, axes = c("audit_evidence_strength", "audit_biological_coherence", "audit_translational_relevance"), gate_cols = c("audit_leakage_gate", "audit_heterogeneity_gate"), score_col = "audit_score", top_n = 2000L, seed = 20250506L )
atlas |
Optional atlas (see |
n_draws |
Integer number of Monte Carlo draws. Defaults to
|
axes |
Character(3) axis columns; see |
gate_cols |
Character(2) gate columns. |
score_col |
Column used to restrict the candidate pool to the
top |
top_n |
Integer pool size; see |
seed |
Random seed. |
This function is the MC analogue of compute_pareto_layers(); it
does not modify the frozen audit score in any draw.
A data.table with one row per gene in atlas, with columns
pareto_layer_median, pareto_stability_top1,
pareto_layer_lo95, pareto_layer_hi95,
pareto_top10_pct_stability. Genes outside the gate-passing pool
in every draw receive NA median/CI but a stability of 0.
head(evaluate_pareto_stability(n_draws = 10L, top_n = 50L)) evaluate_pareto_stability(n_draws = 50L)head(evaluate_pareto_stability(n_draws = 10L, top_n = 50L)) evaluate_pareto_stability(n_draws = 50L)
Returns the underlying numerical evidence values that fed the
frozen v0.3.0 audit decisions, organised by axis. This is the
canonical machine-readable form sitting between the plain-English
phase-tag layer (format_provenance()) and the audit-score
decomposition (explain_score()). The point is to expose
what the math actually says – not just labels, not just a
composite score.
evidence_math(gene_symbol, reference = NULL)evidence_math(gene_symbol, reference = NULL)
gene_symbol |
HGNC gene symbol (length-1 character). |
reference |
Optional |
Every value reported here is either read directly from
pdactrace_reference (or pdactrace_protein_betas for the
protein side) or derived by a single named arithmetic operation
on those columns. No new fitting, no recomputation. The function
name evidence_math reflects that it is the mathematical view
of the same evidence captured by the verbose / provenance text
layers.
Invisibly, a list with one element per axis (named-list
of named scalars). Suitable for str() / programmatic use.
The full 12-rho vector for non-Early best-match genes can be
recovered with score_trajectory() using the bundled fit.
trajectory_fitBest 12-template Pearson rho, runner-up
rho, and the specificity margin delta_rho = rho_best - rho_runner_up. A delta_rho above ~0.10 indicates clean
template specificity (the gene's profile is closer to its
matched template than to any other).
effect_magnitudeEuclidean norm and max-absolute of the
per-stage beta vector, on both RNA and protein sides. The
norm uses the 3-vector (beta_E, beta_M, beta_L) because
beta_N = 0 is a reference-level constant by DESeq2 / limma
convention, not a measured effect.
cohort_consistencyStouffer Z, BH-adjusted p, fraction of contributing cohorts agreeing with the meta sign, and the maximum heterogeneity I-squared across the three contrasts N-vs-E, M-vs-E, L-vs-E (which feeds the heterogeneity gate).
rna_protein_couplingCosine similarity between the
RNA and tissue-protein beta vectors over (E, M, L).
+1 means same template + same direction; -1 means
opposite. Reported alongside the categorical prot_tier
and the boolean rnaprot_concordant flag.
serum_bridgeTranslation class A / B / C
(A = same-direction RNA<->serum, B = opposite, C =
decoupled), serum log2 fold-changes against healthy and
pancreatitis cohorts, number of detected cohorts, and the
phase77_strict membership flag.
cell_specificityTop scRNA cell of origin and the Yanai et al. tau index. tau approaches 1 when expression is concentrated in one cell type.
filter_survivalThe 7-step phase60 audit as a count of passed steps plus a per-step boolean vector (signal_peptide, serum_measurable, serum_significant, pancreatitis_pdac, pancreatitis_hc, direction_match, final).
clinical_roleWhether the gene was screened in the phase29 resectable-marker shortlist and whether it is a member of the predeclared serum panel.
explain_gene() for the formatted text view, and
compare_genes() for a multi-gene tidy table.
m <- evidence_math("LGALS3BP") m$trajectory_fit m$rna_protein_coupling$cosine m$filter_survival$passedm <- evidence_math("LGALS3BP") m$trajectory_fit m$rna_protein_coupling$cosine m$filter_survival$passed
User-facing text formatter that wraps the two evidence layers
already in the package: format_provenance() (plain-English
phase-tag rollup) and evidence_math() (per-axis mathematical
values). Mirrors explain_score() in pattern: prints to console
when verbose = TRUE, returns the underlying structured data
invisibly either way.
explain_gene( gene_symbol, view = c("evidence", "math", "both"), verbose = TRUE, reference = NULL )explain_gene( gene_symbol, view = c("evidence", "math", "both"), verbose = TRUE, reference = NULL )
gene_symbol |
HGNC gene symbol (length-1 character). |
view |
One of |
verbose |
Logical. If |
reference |
Optional |
Three views are supported:
"evidence"Plain-English provenance summary only –
same content format_provenance() produces, plus the
gene's audit_class headline.
"math"Per-axis Evidence Math output – eight axes (trajectory_fit, effect_magnitude, cohort_consistency, rna_protein_coupling, serum_bridge, cell_specificity, filter_survival, clinical_role).
"both"Both, separated by a horizontal rule.
Per-axis printing is the load-bearing design choice: it keeps the output interpretable rather than hiding the evidence behind a single composite score.
Invisibly, a list with elements gene, view,
provenance (length-1 character or NA), and math (list-of-
axes from evidence_math() or NULL).
evidence_math(), format_provenance(),
explain_score().
explain_gene("LGALS3BP", view = "math", verbose = FALSE) explain_gene("LTBP1", view = "evidence", verbose = FALSE) explain_gene("LTBP1", view = "both", verbose = FALSE)explain_gene("LGALS3BP", view = "math", verbose = FALSE) explain_gene("LTBP1", view = "evidence", verbose = FALSE) explain_gene("LTBP1", view = "both", verbose = FALSE)
Returns a transparent breakdown of how the frozen v0.3.0 audit rule
arrived at one gene's audit_score and audit_class. The point is
to make the score auditable in plain English: "LTBP1 lands in
supported_uncertain because its heterogeneity_gate = 0.7 —
the cohort-level meta-analysis I2 exceeds 70% on at least one
contrast."
explain_score(gene_symbol, verbose = TRUE)explain_score(gene_symbol, verbose = TRUE)
gene_symbol |
HGNC gene symbol (length-1 character). |
verbose |
Logical. If |
The audit rule is a frozen weighted sum:
positive_score = 0.40 * evidence_strength
+ 0.35 * biological_coherence
+ 0.25 * translational_relevance
audit_score = positive_score * leakage_gate * heterogeneity_gate
/ max over the atlas of the same product
This function reports each component, the gate state, the audit
label that the gate transitions trigger, and a short prose
explanation derived from those numbers. It does NOT recompute any
new evidence — it reads the bundled atlas and presents what the
frozen rule already produced. Verbose dispatch is intended for
interactive console use; the underlying data.table is also
returned for programmatic use.
Invisibly returns a list with elements:
gene — the resolved HGNC symbol.
audit_class, audit_score, positive_score — top-line scalars.
axes — data.table (3 rows): name, weight, value, contribution.
gates — data.table (2 rows): name, value, triggered_by.
explanation — character(1), one-paragraph rationale.
explain_score("LGALS3BP") explain_score("LTBP1") explain_score("GAPDH")explain_score("LGALS3BP") explain_score("LTBP1") explain_score("GAPDH")
pdactrace_user_model via its top contributing featuresPrints (and invisibly returns) the top-N positive and top-N negative coefficients of the fitted elastic-net model, with feature names and signed coefficient values. This is the user-facing rationale for the supervised score: which evidence axes pushed the user's positive set up.
explain_user_evidence_model(model, top_n = 10L, verbose = TRUE)explain_user_evidence_model(model, top_n = 10L, verbose = TRUE)
model |
A |
top_n |
Number of positive AND number of negative
coefficients to surface. Default |
verbose |
Logical. If |
Invisibly, a list with top_pos, top_neg,
cv_auc_mean, cv_auc_sd, lambda_min, n_features,
n_train, n_positives.
model_card() for the full reviewer-facing card.
if (requireNamespace("glmnet", quietly = TRUE)) { set.seed(1) feats <- data.frame(gene_symbol = paste0("G", seq_len(30)), x1 = rnorm(30), x2 = rnorm(30)) y <- rep(c(0L, 1L), each = 15) fit <- fit_user_evidence_model(feats, y, nfolds = 3L) explain_user_evidence_model(fit, top_n = 2, verbose = FALSE) } feats <- make_evidence_features(scale = "z", drop_na_rows = TRUE) y <- as.integer(feats$gene_symbol %in% c("LGALS3BP", "TIMP1", "LRG1")) fit <- fit_user_evidence_model(feats, y) explain_user_evidence_model(fit, top_n = 5)if (requireNamespace("glmnet", quietly = TRUE)) { set.seed(1) feats <- data.frame(gene_symbol = paste0("G", seq_len(30)), x1 = rnorm(30), x2 = rnorm(30)) y <- rep(c(0L, 1L), each = 15) fit <- fit_user_evidence_model(feats, y, nfolds = 3L) explain_user_evidence_model(fit, top_n = 2, verbose = FALSE) } feats <- make_evidence_features(scale = "z", drop_na_rows = TRUE) y <- as.integer(feats$gene_symbol %in% c("LGALS3BP", "TIMP1", "LRG1")) fit <- fit_user_evidence_model(feats, y) explain_user_evidence_model(fit, top_n = 5)
Returns the frozen v0.3.0 audit feature components used by
compute_audit_score(). These are deterministic summaries of the
evidence graph, not learned embeddings.
extract_graph_features(gene_symbol)extract_graph_features(gene_symbol)
gene_symbol |
Character vector of HGNC gene symbols. |
A data.table with one row per matched gene.
extract_graph_features(c("LGALS3BP", "LTBP1", "GAPDH"))extract_graph_features(c("LGALS3BP", "LTBP1", "GAPDH"))
Wraps the phase33 canonical pipeline: dataset + stage_group
fixed-effect model on raw counts, LRT against ~ dataset reduced
model, return per-gene coefficients (beta_E, beta_M, beta_L vs Normal) +
BH-adjusted LRT padj.
fit_stage_de(object, ...) ## S4 method for signature 'ANY' fit_stage_de(object, stage, cohort = NULL, min_count = 10, padj_cutoff = 0.05) ## S4 method for signature 'SummarizedExperiment' fit_stage_de( object, stage_col, cohort_col = NULL, assay_name = "counts", min_count = 10, padj_cutoff = 0.05 )fit_stage_de(object, ...) ## S4 method for signature 'ANY' fit_stage_de(object, stage, cohort = NULL, min_count = 10, padj_cutoff = 0.05) ## S4 method for signature 'SummarizedExperiment' fit_stage_de( object, stage_col, cohort_col = NULL, assay_name = "counts", min_count = 10, padj_cutoff = 0.05 )
object |
Either a count matrix/data.frame (genes by samples,
rownames = gene symbols) or a |
... |
Method-specific arguments — see Details for the matrix and SummarizedExperiment interfaces. |
stage |
(matrix/data.frame interface) Character or factor
vector of stage labels per sample. Required levels: at minimum
|
cohort |
(matrix/data.frame interface) Optional character /
factor vector of dataset/cohort labels per sample. Used as a fixed
effect to absorb cohort-level technical variance. If only one
cohort, omit (default |
min_count |
Numeric. Pre-filter: genes with row sum below
|
padj_cutoff |
Numeric. BH-adjusted LRT padj cutoff for "stage-progressive" gene set. Default 0.05. |
stage_col |
(SummarizedExperiment interface) Name of the
column in |
cohort_col |
(SummarizedExperiment interface) Optional name
of the column in |
assay_name |
(SummarizedExperiment interface) Name of the
assay slot to pull as the count matrix. Default |
Two interfaces are supported via S4 method dispatch on object:
Matrix interface (the default): fit_stage_de(counts, stage, cohort). counts is a numeric matrix or data.frame with genes on
rows and samples on columns; stage and cohort are vectors of
length ncol(counts). This is the original v0.99.1 signature and
is preserved unchanged for backwards compatibility.
SummarizedExperiment interface (new in v0.99.2):
fit_stage_de(se, stage_col = "stage", cohort_col = "cohort").
The count matrix is pulled from assay(se, assay_name) and the
stage / cohort vectors are pulled from colData(se). This is the
Bioconductor-native entry point.
A data.table with one row per gene and columns:
gene_symbol, beta_N, beta_E, beta_M, beta_L, lrt_padj,
lrt_significant (logical, padj < cutoff), and lfcSE_*.
data(toy_counts) data(toy_coldata) if (requireNamespace("DESeq2", quietly = TRUE)) { fit <- fit_stage_de(toy_counts, toy_coldata$stage, toy_coldata$cohort) head(fit) } # SummarizedExperiment interface (Bioconductor-native): if (requireNamespace("DESeq2", quietly = TRUE)) { library(SummarizedExperiment) se <- SummarizedExperiment( assays = list(counts = toy_counts), colData = DataFrame(stage = toy_coldata$stage, cohort = toy_coldata$cohort)) fit <- fit_stage_de(se, stage_col = "stage", cohort_col = "cohort") pat <- classify_trajectory(fit) }data(toy_counts) data(toy_coldata) if (requireNamespace("DESeq2", quietly = TRUE)) { fit <- fit_stage_de(toy_counts, toy_coldata$stage, toy_coldata$cohort) head(fit) } # SummarizedExperiment interface (Bioconductor-native): if (requireNamespace("DESeq2", quietly = TRUE)) { library(SummarizedExperiment) se <- SummarizedExperiment( assays = list(counts = toy_counts), colData = DataFrame(stage = toy_coldata$stage, cohort = toy_coldata$cohort)) fit <- fit_stage_de(se, stage_col = "stage", cohort_col = "cohort") pat <- classify_trajectory(fit) }
Wraps the phase34 canonical pipeline: cohort + stage_group
fixed-effect model on log-transformed protein intensities, returning
per-gene contrasts (beta_E, beta_M, beta_L vs Normal) plus
BH-adjusted F-test padj on the stage_group main effect.
fit_stage_de_protein(object, ...) ## S4 method for signature 'ANY' fit_stage_de_protein( object, stage, cohort = NULL, min_nonNA = 10, padj_cutoff = 0.05 ) ## S4 method for signature 'SummarizedExperiment' fit_stage_de_protein( object, stage_col, cohort_col = NULL, assay_name = "intensity", min_nonNA = 10, padj_cutoff = 0.05 )fit_stage_de_protein(object, ...) ## S4 method for signature 'ANY' fit_stage_de_protein( object, stage, cohort = NULL, min_nonNA = 10, padj_cutoff = 0.05 ) ## S4 method for signature 'SummarizedExperiment' fit_stage_de_protein( object, stage_col, cohort_col = NULL, assay_name = "intensity", min_nonNA = 10, padj_cutoff = 0.05 )
object |
Either a numeric intensity matrix/data.frame
(genes by samples; rownames = gene symbols; values are log2
intensities) or a |
... |
Method-specific arguments — see the matrix and SummarizedExperiment interfaces below. |
stage |
(matrix/data.frame interface) Character or factor
vector of stage labels per sample. Required levels: at minimum
|
cohort |
(matrix/data.frame interface) Optional character /
factor vector of dataset/cohort labels per sample. |
min_nonNA |
Numeric. Pre-filter: rows with fewer than this many non-NA samples are dropped. Default 10. |
padj_cutoff |
Numeric. BH-adjusted F-test padj cutoff for "stage-progressive" gene set. Default 0.05. |
stage_col |
(SummarizedExperiment interface) Name of the
column in |
cohort_col |
(SummarizedExperiment interface) Optional name
of the column in |
assay_name |
(SummarizedExperiment interface) Name of the
assay slot to pull as the intensity matrix. Default |
Designed to be the protein-side parallel of fit_stage_de(), so
downstream classify_trajectory() / assemble_user_evidence() can
consume both layers symmetrically. Two interfaces are supported via
S4 dispatch: a numeric matrix / data.frame (the original v0.99.1
signature) or a SummarizedExperiment (new in v0.99.2; the
Bioconductor-native entry point).
A data.table with the same column schema as
fit_stage_de(): gene_symbol, beta_N, beta_E, beta_M, beta_L, lfcSE_E, lfcSE_M, lfcSE_L, lrt_padj, lrt_significant.
data(toy_protein) data(toy_coldata) if (requireNamespace("limma", quietly = TRUE)) { prot_fit <- fit_stage_de_protein(toy_protein, toy_coldata$stage, toy_coldata$cohort) head(prot_fit) } # SummarizedExperiment interface: if (requireNamespace("limma", quietly = TRUE)) { library(SummarizedExperiment) se <- SummarizedExperiment( assays = list(intensity = toy_protein), colData = DataFrame(stage = toy_coldata$stage, cohort = toy_coldata$cohort)) prot_fit <- fit_stage_de_protein( se, stage_col = "stage", cohort_col = "cohort", assay_name = "intensity") }data(toy_protein) data(toy_coldata) if (requireNamespace("limma", quietly = TRUE)) { prot_fit <- fit_stage_de_protein(toy_protein, toy_coldata$stage, toy_coldata$cohort) head(prot_fit) } # SummarizedExperiment interface: if (requireNamespace("limma", quietly = TRUE)) { library(SummarizedExperiment) se <- SummarizedExperiment( assays = list(intensity = toy_protein), colData = DataFrame(stage = toy_coldata$stage, cohort = toy_coldata$cohort)) prot_fit <- fit_stage_de_protein( se, stage_col = "stage", cohort_col = "cohort", assay_name = "intensity") }
Wraps glmnet::cv.glmnet(family = "binomial") to fit a sparse
logistic model that ranks genes by feature-space evidence. The
fit is owned entirely by the user: labels must be supplied
explicitly. The package ships no pretrained model – this is a
deliberate constraint for PDAC biomarker discovery, where
validated non-circular ground truth is unavailable.
fit_user_evidence_model( features, labels, method = "elastic_net", alpha = 0.5, nfolds = 10L, weights = NULL, seed = 1L )fit_user_evidence_model( features, labels, method = "elastic_net", alpha = 0.5, nfolds = 10L, weights = NULL, seed = 1L )
features |
|
labels |
Integer / logical vector of length |
method |
Currently only |
alpha |
Elastic-net mixing parameter in |
nfolds |
Number of CV folds. Default |
weights |
Optional per-row observation weights passed
through to |
seed |
Integer RNG seed for reproducibility. Default |
Use case: a user has their own positive set (e.g. their lab's validated panel) and wants a continuous prioritisation score across the rest of the atlas, with feature-level interpretability that survives Bioconductor review.
An S3 object of class pdactrace_user_model (a list)
with elements: cvfit (the underlying cv.glmnet object),
coef_table (data.table: feature, coef_value),
lambda_min, lambda_1se, cv_auc_mean, cv_auc_sd,
n_train, n_features, n_positives, top_pos,
top_neg, alpha, seed, method, feature_set_version,
card.
RNG is scoped via withr::local_seed() inside the fit. Two
calls with the same (features, labels, alpha, nfolds, seed)
produce byte-identical models.
10-fold CV by glmnet::cv.glmnet() over the lambda path; AUC
is recomputed per fold for the model card. Class imbalance is
not reweighted by default (use the weights arg if needed).
predict_user_evidence_model(),
explain_user_evidence_model(), model_card(),
make_evidence_features().
if (requireNamespace("glmnet", quietly = TRUE)) { set.seed(1) feats <- data.frame(gene_symbol = paste0("G", seq_len(30)), x1 = rnorm(30), x2 = rnorm(30)) y <- rep(c(0L, 1L), each = 15) fit_user_evidence_model(feats, y, nfolds = 3L) } if (requireNamespace("glmnet", quietly = TRUE)) { feats <- make_evidence_features(scale = "z", drop_na_rows = TRUE) y <- as.integer(feats$gene_symbol %in% c("LGALS3BP", "TIMP1", "LRG1")) fit <- fit_user_evidence_model(feats, y) explain_user_evidence_model(fit, top_n = 5) }if (requireNamespace("glmnet", quietly = TRUE)) { set.seed(1) feats <- data.frame(gene_symbol = paste0("G", seq_len(30)), x1 = rnorm(30), x2 = rnorm(30)) y <- rep(c(0L, 1L), each = 15) fit_user_evidence_model(feats, y, nfolds = 3L) } if (requireNamespace("glmnet", quietly = TRUE)) { feats <- make_evidence_features(scale = "z", drop_na_rows = TRUE) y <- as.integer(feats$gene_symbol %in% c("LGALS3BP", "TIMP1", "LRG1")) fit <- fit_user_evidence_model(feats, y) explain_user_evidence_model(fit, top_n = 5) }
Maps the internal phase33, phase34, stouffer_consistency, ...
provenance tags carried in pdactrace_reference$provenance onto
plain-English evidence-source labels. The phase tags remain the
canonical IDs for reproducibility (they correspond to the numbered
analysis scripts in the companion manuscript-monorepo) but the
user-facing print path now leads with the labels and folds the raw
tag list into a Technical: footer.
format_provenance(provenance, style = c("compact", "verbose", "raw"))format_provenance(provenance, style = c("compact", "verbose", "raw"))
provenance |
Character of length 1 or longer. Either a
comma-separated phase string (e.g. |
style |
One of:
|
Intended for internal use by query_gene(),
query_gene_detailed(), and summarize_gene_evidence() —
exported so end users who consume the raw provenance column can
relabel it the same way.
Character of length 1.
format_provenance("phase33,phase34,phase60", style = "compact") format_provenance("phase33,phase34,phase60", style = "verbose") format_provenance("phase33,phase34,phase60", style = "raw")format_provenance("phase33,phase34,phase60", style = "compact") format_provenance("phase33,phase34,phase60", style = "verbose") format_provenance("phase33,phase34,phase60", style = "raw")
Returns the bundled atlas_metadata list with version, snapshot
date, scope description, cohort tables, and source CSV provenance.
list_atlas_metadata()list_atlas_metadata()
Named list. See ?atlas_metadata for structure.
meta <- list_atlas_metadata() meta$version meta$source_csvsmeta <- list_atlas_metadata() meta$version meta$source_csvs
Multi-parameter filter on the pdactrace reference atlas. Pass NULL
(default) for any parameter to leave it unconstrained. Returns a
ranked data.table with key evidence columns.
list_candidates( onset = NULL, tissue_direction = NULL, pattern = NULL, translation_class = NULL, serum_detected = NULL, signal_peptide = NULL, panel_member = NULL, resectable_marker = NULL, phase77_strict = NULL, min_audit_class = c("ALL", "high_confidence", "supported_uncertain", "penalized", "low", "excluded"), top_n = NULL )list_candidates( onset = NULL, tissue_direction = NULL, pattern = NULL, translation_class = NULL, serum_detected = NULL, signal_peptide = NULL, panel_member = NULL, resectable_marker = NULL, phase77_strict = NULL, min_audit_class = c("ALL", "high_confidence", "supported_uncertain", "penalized", "low", "excluded"), top_n = NULL )
onset |
Character. |
tissue_direction |
Character. |
pattern |
Character vector. Specific 4-Early pattern names
(e.g., |
translation_class |
Character. One of |
serum_detected |
Logical. Restrict to genes detected (or not)
in any serum cohort. |
signal_peptide |
Logical. Filter on |
panel_member |
Logical. Member of LTBP1+SERPINA1 / hybrid
panels. |
resectable_marker |
Logical. Member of phase29 25 markers (19
in atlas). |
phase77_strict |
Logical. Member of 22 strict tissue+serum
convergent candidates. |
min_audit_class |
Minimum |
top_n |
Optional integer. Return top N rows ranked by
|
data.table with gene_symbol, key evidence columns, and
provenance.
list_candidates(onset = "Early", tissue_direction = "Up") list_candidates(translation_class = "inverse") list_candidates(translation_class = "concordant", serum_detected = TRUE, signal_peptide = TRUE, top_n = 20)list_candidates(onset = "Early", tissue_direction = "Up") list_candidates(translation_class = "inverse") list_candidates(translation_class = "concordant", serum_detected = TRUE, signal_peptide = TRUE, top_n = 20)
Returns the bundled pdactrace_data_sources table — one row per
public dataset (GEO / PRIDE / PDC / ICGC / GTEx / MassIVE / SRA)
that was used to populate the v0.99.x reference atlas. Designed so
a Bioconductor reviewer or end user can answer "where does this
data come from?" programmatically rather than by chasing prose in
the manuscript.
list_data_sources(layer = NULL)list_data_sources(layer = NULL)
layer |
Optional character vector to filter by data layer:
one or more of |
A data.table with columns:
accession — public identifier (GEO ID, PXD, etc.)
layer — RNA / Protein / scRNA / Serum / ...
source_type — repository name (GEO / PRIDE / PDC / ...)
used_for — short role description
citation — primary publication citation when available
url — direct repository URL
head(list_data_sources()) list_data_sources(layer = "Serum") nrow(list_data_sources())head(list_data_sources()) list_data_sources(layer = "Serum") nrow(list_data_sources())
Returns a wide numeric data.table (genes by features) suitable
for off-the-shelf supervised or descriptive modelling. Computes
the same arithmetic that evidence_math() exposes per-axis, but
as a single tabular shape so callers can hand it directly to
glmnet::cv.glmnet(), ranger::ranger(), scikit-learn, etc.
make_evidence_features( genes = NULL, reference = NULL, protein_betas = NULL, scale = c("none", "z", "robust"), impute = c("none", "mean", "zero"), drop_na_rows = FALSE )make_evidence_features( genes = NULL, reference = NULL, protein_betas = NULL, scale = c("none", "z", "robust"), impute = c("none", "mean", "zero"), drop_na_rows = FALSE )
genes |
Optional character vector of gene symbols. |
reference |
Optional |
protein_betas |
Optional |
scale |
One of |
impute |
One of |
drop_na_rows |
Logical. If |
Feature columns are deterministic functions of the bundled pdactrace_reference and pdactrace_protein_betas objects; no new fitting is performed. The full column list is grouped below by evidence axis.
A data.table keyed on gene_symbol with one row per
gene and one column per feature.
trajectory_rho_best,
trajectory_delta_rho (= rho_best - rho_runner_up).
rna_beta_norm
(= sqrt(sum(rna_beta_E,M,L^2))), rna_beta_max_abs,
prot_beta_norm, prot_beta_max_abs.
cohort_agreement,
stouffer_abs_z, stouffer_neglog10_fdr,
max_meta_I2.
rna_protein_cosine
(cosine of (E,M,L) beta vectors),
rna_protein_concordant (0/1),
prot_pattern_rho.
serum_detected (0/1),
serum_abs_log2fc, serum_n_cohorts_detected,
phase77_strict (0/1).
cell_specificity_tau,
filter_pass_fraction (passed / 7).
leakage_housekeeping (0/1),
leakage_plasma_high_abundance (0/1).
Plus one identifier column (gene_symbol). Logical inputs are
coerced to integer 0/1 so the resulting frame is uniformly
numeric except for the key.
scale = "z" standardizes each feature column to mean 0, sd 1
over the complete-case subset (NAs are preserved as NA and
do not contribute to the moment estimates). scale = "robust"
uses median / MAD instead. scale = "none" (default) returns
raw values.
Genes missing from pdactrace_protein_betas get NA for the
protein-side columns (prot_beta_*, rna_protein_cosine,
prot_pattern_rho). Genes with NA rna_pattern (no Early
best-match on the atlas surface) get NA for
trajectory_rho_best and trajectory_delta_rho. Set
drop_na_rows = TRUE to keep only complete-case rows; default
FALSE preserves the full atlas row count.
evidence_math() for the per-axis nested-list view,
score_anchor_similarity() for descriptive feature-space
scoring against bundled anchors, fit_user_evidence_model()
for the user-supplied supervised wrapper.
feats <- make_evidence_features() dim(feats) head(feats) z <- make_evidence_features(scale = "z", drop_na_rows = TRUE) summary(z[, -1L])feats <- make_evidence_features() dim(feats) head(feats) z <- make_evidence_features(scale = "z", drop_na_rows = TRUE) summary(z[, -1L])
Cohort-level and random-effects meta-analysis summaries used to populate
v0.2.0 meta-analysis and tier columns in pdactrace_reference.
meta_analysismeta_analysis
A data.frame with one row per gene and meta-analysis summary columns.
Returned for transparency. These patterns are not surfaced in
pdactrace_reference$rna_pattern; genes whose canonical phase33
4-Early-pattern call falls in this set will have rna_pattern = NA
and excluded_mid_pattern = TRUE.
mid_pattern_names_excluded() mid_patterns()mid_pattern_names_excluded() mid_patterns()
character(4)
mid_pattern_names_excluded() mid_patterns() # short aliasmid_pattern_names_excluded() mid_patterns() # short alias
Single point of documentation reviewers can audit when a
descriptive (score_anchor_similarity()) or supervised
(fit_user_evidence_model()) score is in use. Returns a
structured list and prints a multi-line summary to the console.
model_card( source = c("anchor_similarity", "user_model"), model = NULL, verbose = TRUE )model_card( source = c("anchor_similarity", "user_model"), model = NULL, verbose = TRUE )
source |
One of |
model |
Optional |
verbose |
Logical. If |
Two sources are supported:
"anchor_similarity"The descriptive layer. No labels
are used to train a predictor; the bundled
pdactrace_external_anchors table is used only to
define a reference centroid in the z-scored feature space.
Always available, no model argument needed.
"user_model"The user-supplied supervised fit
produced by fit_user_evidence_model(). Pass the fit
object via model = ....
The package ships no pretrained predictor. This deliberate constraint is the central defense against the "what was the training label?" reviewer question for PDAC biomarker discovery, where validated non-circular ground truth is not available.
Invisibly, a list with at least: source,
feature_set_version, intended_use, not_intended_for,
labels_used_for_training, limitations. For
"user_model", also includes n_features, n_train,
n_positives, cv_auc_mean, cv_auc_sd, top_pos,
top_neg, seed, alpha, lambda_min.
score_anchor_similarity(),
fit_user_evidence_model().
model_card("anchor_similarity") if (requireNamespace("glmnet", quietly = TRUE)) { feats <- make_evidence_features(scale = "z", drop_na_rows = TRUE) y <- as.integer(feats$gene_symbol %in% c("LGALS3BP", "TIMP1", "LRG1")) fit <- fit_user_evidence_model(feats, y) model_card(source = "user_model", model = fit) }model_card("anchor_similarity") if (requireNamespace("glmnet", quietly = TRUE)) { feats <- make_evidence_features(scale = "z", drop_na_rows = TRUE) y <- as.integer(feats$gene_symbol %in% c("LGALS3BP", "TIMP1", "LRG1")) fit <- fit_user_evidence_model(feats, y) model_card(source = "user_model", model = fit) }
One row per public dataset that contributed to the v0.99.x
pdactrace reference atlas, covering bulk RNA-seq, tissue
proteomics, single-cell RNA, serum proteomics, pancreatitis
context, and validation cohorts. Backs the list_data_sources()
helper and is the source-of-truth for the manuscript's
data-availability section.
pdactrace_data_sourcespdactrace_data_sources
data.table with one row per accession and columns
accession, layer, source_type, used_for, citation,
url. Generated by data-raw/build_data_sources.R.
Literature and database anchors used only for enrichment evaluation of the frozen pdactrace audit ranking. These anchors are not used to fit or tune the audit score.
pdactrace_external_anchorspdactrace_external_anchors
A data.frame with provenance columns:
HGNC gene symbol.
Short source description.
Primary study, database, review, or related source.
T1 validated, T2 literature/database, or exploratory.
Serum, plasma, tissue, cyst fluid, or mixed context.
Whether the source supports early-detection use.
Direct, indirect, or excluded mapping status.
Primary-enrichment inclusion flag.
Secondary-enrichment inclusion flag.
PMID or URL provenance.
Curation note.
Bundled per-gene tissue-protein stage coefficients and 12-template
best-match labels, used by plot_template_atlas() and
plot_gene_template() for the protein layer (the main
pdactrace_reference only carries categorical prot_pattern /
prot_tier, not the per-stage betas needed for trajectory
visualisation). Generated by data-raw/build_protein_betas.R
from phase34_protein_pooled_12template.csv in the companion
manuscript-monorepo.
pdactrace_protein_betaspdactrace_protein_betas
data.table, 5,917 rows x 8 cols, keyed on gene_symbol:
gene_symbol character HGNC symbol
prot_beta_N numeric, always 0 (Normal is the reference)
prot_beta_E numeric, log2 fold change vs Normal at Early
prot_beta_M numeric, ditto at Mid
prot_beta_L numeric, ditto at Late
prot_pattern_12 character, full 12-template best-match
(Early × 4 + Mid × 4 + Late × 2 + Monotonic × 2 +
"Unclassified" for non-significant rows)
prot_pattern_rho numeric, Pearson rho with the matched
template
prot_lrt_padj numeric, BH-adjusted F-test p-value
Convenience wrapper used in vignettes; logs filename + size.
pdactrace_save(p, dir, name, w, h)pdactrace_save(p, dir, name, w, h)
p |
A ggplot object. |
dir |
Output directory. |
name |
File stem (no extension). |
w, h
|
Width/height in inches. |
Invisibly returns the saved file path.
library(ggplot2) p <- ggplot(mtcars, aes(wt, mpg)) + geom_point() tmp <- tempdir() fp <- pdactrace_save(p, tmp, "demo", w = 3, h = 2.5) file.exists(fp) unlink(fp)library(ggplot2) p <- ggplot(mtcars, aes(wt, mpg)) + geom_point() tmp <- tempdir() fp <- pdactrace_save(p, tmp, "demo", w = 3, h = 2.5) file.exists(fp) unlink(fp)
Named character vectors for ggplot2 scale_*_manual().
pdactrace_pal_class - Class A / B / Other
pdactrace_pal_group - HC / Pancreatitis / PDAC
pdactrace_pal_dir - UP / DOWN / NS
pdactrace_pal_pattern - Early × 4 pattern colors (atlas-surfaced subset of the v0.4.0 12-template catalog)
pdactrace_pal_class pdactrace_pal_group pdactrace_pal_dir pdactrace_pal_patternpdactrace_pal_class pdactrace_pal_group pdactrace_pal_dir pdactrace_pal_pattern
An object of class character of length 4.
An object of class character of length 4.
An object of class character of length 3.
An object of class character of length 4.
pdactrace_pal_class pdactrace_pal_patternpdactrace_pal_class pdactrace_pal_pattern
Bundles the publication-grade ggplot2 theme used across the BiB
manuscript figures. Source-of-truth: BiB_framework/scripts/bib_ncs_theme.R.
NCS_W_SINGLE NCS_W_15COL NCS_W_DOUBLE NCS_W_TRIPLE pdactrace_panel_theme() pdactrace_axes_theme()NCS_W_SINGLE NCS_W_15COL NCS_W_DOUBLE NCS_W_TRIPLE pdactrace_panel_theme() pdactrace_axes_theme()
An object of class numeric of length 1.
An object of class numeric of length 1.
An object of class numeric of length 1.
An object of class numeric of length 1.
Two flavors:
pdactrace_panel_theme() - theme_void base, for schematics
pdactrace_axes_theme() - theme_minimal base, for plots with axes
Width constants (NCS spec, inches):
NCS_W_SINGLE = 3.46 (88 mm, single column)
NCS_W_15COL = 4.72 (120 mm, 1.5-column)
NCS_W_DOUBLE = 7.08 (180 mm, double column)
NCS_W_TRIPLE = 10.50 (full-width composite)
library(ggplot2) p <- ggplot(mtcars, aes(wt, mpg)) + geom_point() + pdactrace_axes_theme() identical(NCS_W_DOUBLE, 7.08)library(ggplot2) p <- ggplot(mtcars, aes(wt, mpg)) + geom_point() + pdactrace_axes_theme() identical(NCS_W_DOUBLE, 7.08)
Scatter plot of atlas-surfaced Early × 4 genes (12-template classifier surface) with measurable tissue + serum evidence. X-axis: tissue protein effect (max |beta| across stages, signed by direction). Y-axis: serum log2FC PDAC vs HC. Color: translation_class (A / B / C / unclassified). Selected genes (default LTBP1, SERPINA1, CDH13, SPARC) get text labels.
plot_candidate_landscape( highlight = c("LTBP1", "SERPINA1", "CDH13", "SPARC"), min_serum_n = 1L )plot_candidate_landscape( highlight = c("LTBP1", "SERPINA1", "CDH13", "SPARC"), min_serum_n = 1L )
highlight |
Character vector of gene symbols to label prominently. |
min_serum_n |
Integer. Drop genes detected in fewer cohorts. |
A ggplot2 object.
plot_candidate_landscape() plot_candidate_landscape(highlight = c("LTBP1", "SERPINA1", "CDH13", "SPARC"))plot_candidate_landscape() plot_candidate_landscape(highlight = c("LTBP1", "SERPINA1", "CDH13", "SPARC"))
Replaces the v0.1.0 plot_gene_evidence() top-3 cell-type panel
with the full 11-celltype distribution from the scRNA atlas.
Useful when the dominant cell type is borderline or when the user
wants to see the long tail (e.g., mast cells, plasma cells).
plot_celltype_full( gene_symbol, highlight = c("myCAF", "iCAF", "Acinar", "Ductal") )plot_celltype_full( gene_symbol, highlight = c("myCAF", "iCAF", "Acinar", "Ductal") )
gene_symbol |
HGNC symbol. |
highlight |
Optional character vector of cell types to draw
in red (default |
A ggplot2 object.
plot_celltype_full("LTBP1")plot_celltype_full("LTBP1")
For each of the 7 phase60 filter steps, shows pass/fail status as
a horizontal bar and annotates each row with the underlying metric
(e.g., pool padj = 0.32) so the user can see why a step failed.
plot_filter_diagnostics(gene_symbol)plot_filter_diagnostics(gene_symbol)
gene_symbol |
HGNC symbol. |
Distinct from plot_filter_trace() which compares multiple genes
across PASS/FAIL only. plot_filter_diagnostics() focuses on a
single gene with full numeric audit.
A ggplot2 object.
plot_filter_diagnostics("LTBP1")plot_filter_diagnostics("LTBP1")
For each gene, draws the 7-step phase60 filter trail (filled = pass, open = fail, grey = not evaluated) with two extra layers that the original filter-trace view lacked:
plot_filter_trace(gene, show_routes = TRUE, show_serum = TRUE)plot_filter_trace(gene, show_routes = TRUE, show_serum = TRUE)
gene |
Character vector of HGNC symbols. |
show_routes |
Logical. If |
show_serum |
Logical. If |
A serum direction strip above the filter grid showing
the per-gene serum log2FC vs healthy control and vs
pancreatitis (the values that actually drive the
direction-match filter step), coloured by translation
class (Class A blue / Class B red / Class C grey / NA
light-grey).
A per-gene title prefix naming the translation class so the reader can read the trail in context.
Multi-gene calls show one row per gene, ordered by phase60
pass count descending; this lets you compare phase60_final
exemplars (e.g. SERPINA1) against phase77 Class B exemplars
(e.g. LTBP1, CDH13, SPARC) at a glance.
A ggplot2 object (or patchwork composite if
show_routes = TRUE or show_serum = TRUE).
plot_filter_trace(c("SERPINA1", "LTBP1", "SPARC", "CDH13")) plot_filter_trace("LTBP1", show_routes = FALSE)plot_filter_trace(c("SERPINA1", "LTBP1", "SPARC", "CDH13")) plot_filter_trace("LTBP1", show_routes = FALSE)
Builds a publication-ready composite (patchwork) showing:
4-point trajectory (RNA + Protein overlay)
Cell origin distribution bar
Serum log2FC (PDAC, Pancreatitis vs HC)
Provenance + summary footer
plot_gene_evidence( gene_symbol, layers = c("trajectory", "cell_origin", "serum", "summary") )plot_gene_evidence( gene_symbol, layers = c("trajectory", "cell_origin", "serum", "summary") )
gene_symbol |
HGNC standard symbol. |
layers |
Subset of panels to draw. Default all four
( |
Width/height: NCS spec single column (NCS_W_SINGLE = 3.46 in) by ~3 in.
A patchwork object. Returns NULL invisibly with message
if gene is not in atlas.
p <- plot_gene_evidence("LTBP1") print(p)p <- plot_gene_evidence("LTBP1") print(p)
Draws a compact 6-axis hexagonal radar chart summarising the
pdactrace audit-feature components for one or more genes. Inspired
by the multi-polygon radar style used in graph-of-graphs analyses
(e.g., GATE; Liu and Cheng 2025), but reuses the
six interpretable feature axes from extract_graph_features()
rather than learned graph embeddings.
plot_gene_hexagon( gene_symbol, comparison = NULL, show_score = TRUE, palette = NULL )plot_gene_hexagon( gene_symbol, comparison = NULL, show_score = TRUE, palette = NULL )
gene_symbol |
Character vector of one or more HGNC gene symbols. Multiple genes are overlaid as separate polygons. |
comparison |
Optional. Either |
show_score |
Logical. If |
palette |
Optional named character vector of polygon colors keyed by gene symbol. Defaults to the pdactrace audit-class palette where possible, otherwise to a Set1-style palette. |
The six axes (clockwise from the top vertex) are:
Multi-layer — score_layer (fraction of RNA/Protein/scRNA/Serum
layers with a measurable signal).
Direction — score_direction (cross-cohort + cross-layer
direction concordance).
Stage-onset — score_early (Pearson rho against the four
Early templates, weighted by LRT significance).
Serum bridge — score_serum (serum detected + signal
peptide + tissue-to-serum direction concordance).
Leakage safety — leakage_mult (1 if clean, 0.5 if plasma
high-abundance, 0 if housekeeping).
Cohort consistency — het_mult (1 if I² < 70, 0.7 if 70-90,
0.3 if >= 90).
Each axis is plotted on a fixed 0–1 scale; concentric hexagons mark the 0.25 / 0.50 / 0.75 / 1.00 contours.
A ggplot2 object (NCS-grade compact, cairo-pdf safe).
plot_gene_hexagon("LTBP1") plot_gene_hexagon(c("LGALS3BP", "LTBP1")) plot_gene_hexagon("LTBP1", comparison = "high_confidence_mean")plot_gene_hexagon("LTBP1") plot_gene_hexagon(c("LGALS3BP", "LTBP1")) plot_gene_hexagon("LTBP1", comparison = "high_confidence_mean")
For one gene/protein, draws the trajectory-template panel that
the gene was matched to (12-template Pearson-rho argmax) with the
gene's own z-scored Normal/Early/Mid/Late trajectory overlaid as
a highlight line. Companion to the atlas-wide
plot_template_atlas(): that one walks all 12 templates without
a gene; this one zeroes in on a single gene's matched panel.
plot_gene_template( gene_symbol, layer = c("rna", "protein"), highlight_color = "#C62828", output_file = NULL, width = 1.55, height = 1.4, reference = NULL )plot_gene_template( gene_symbol, layer = c("rna", "protein"), highlight_color = "#C62828", output_file = NULL, width = 1.55, height = 1.4, reference = NULL )
gene_symbol |
HGNC gene symbol (length-1 character). |
layer |
Either |
highlight_color |
Colour of the gene-highlight line. Default
|
output_file |
Optional output PDF path. If |
width, height
|
PDF size in inches when |
reference |
Optional override of the bundled
|
The matched template is recovered via the same Pearson-rho argmax
across the 12 bundled templates that backs classify_trajectory()
and score_trajectory(). The matched rho is annotated as a small
caption.
Either a ggplot object (when output_file is NULL) or
the absolute path of the written PDF (invisibly).
p <- plot_gene_template("LGALS3BP", "rna") class(p) p$labels$titlep <- plot_gene_template("LGALS3BP", "rna") class(p) p$labels$title
Visualises the per-cohort log2FoldChange estimates with 95%
confidence intervals, plus the random-effects meta-summary diamond
for each of three contrasts: Mid_vs_Early, Late_vs_Early,
Normal_vs_Early. Heterogeneity (I2) is annotated.
plot_meta_forest( gene_symbol, contrast = c("Mid_vs_Early", "Late_vs_Early", "Normal_vs_Early"), per_cohort_path = NULL )plot_meta_forest( gene_symbol, contrast = c("Mid_vs_Early", "Late_vs_Early", "Normal_vs_Early"), per_cohort_path = NULL )
gene_symbol |
HGNC standard symbol. |
contrast |
Character, one of |
per_cohort_path |
Optional path to the per-cohort betas CSV
(long-format with |
Reveals cohort divergence that the headline pattern label can hide. E.g., for LTBP1 the forest plot shows TCGA mostly null, CPTAC clearly elevated, and the meta-summary diamond crossing zero.
A ggplot2 object.
plot_meta_forest("LTBP1") plot_meta_forest("SERPINA1", contrast = "Normal_vs_Early")plot_meta_forest("LTBP1") plot_meta_forest("SERPINA1", contrast = "Normal_vs_Early")
Builds a multi-row heatmap (genes x evidence columns) showing key RNA / protein / serum / class / route evidence side-by-side. Useful for paper Figure 7 (Class A vs Class B comparison).
plot_panel_heatmap(genes, layers = c("rna", "protein", "serum", "class"))plot_panel_heatmap(genes, layers = c("rna", "protein", "serum", "class"))
genes |
Character vector of HGNC symbols. |
layers |
Character vector of evidence groups to include.
Default: |
A ggplot2 object.
plot_panel_heatmap(c("LTBP1", "SERPINA1", "CDH13", "SPARC", "CP", "FGB"))plot_panel_heatmap(c("LTBP1", "SERPINA1", "CDH13", "SPARC", "CP", "FGB"))
For each of the 4 RNA cohorts (TCGA, CPTAC, GSE224564, GSE79668), shows the gene's trend direction (Increasing / Decreasing / Non-monotonic) and whether the trend is monotonic. Headline annotation displays Stouffer aggregate p-value and cohort agreement %.
plot_per_cohort(gene_symbol)plot_per_cohort(gene_symbol)
gene_symbol |
HGNC symbol. |
This plot reveals cohort divergence that the headline pattern label may hide.
A ggplot2 object.
plot_per_cohort("LTBP1") # reveals TCGAup but CPTACdown divergenceplot_per_cohort("LTBP1") # reveals TCGAup but CPTACdown divergence
Bar plot of per-gene serum log2FC against healthy control (HC)
and against pancreatitis (Pan), faceted by contrast and
coloured by translation class (Class A / B / C). These two
values together drive the direction-match step of the phase60
tissue-to-serum filter audit; the panel is the visual analog of
the serum_log2fc_PDAC_vs_HC and serum_log2fc_Pan_vs_HC
columns from pdactrace_reference, with the categorical
translation_class mapped to the bar fill.
plot_serum_direction(gene)plot_serum_direction(gene)
gene |
Character vector of HGNC gene symbols. |
Used as a standalone diagnostic and as one of the six
viz_gene() panels.
A ggplot2 object, or NULL invisibly if none of the
requested genes are in the bundled atlas.
plot_filter_trace() which embeds the same panel
above its filter grid by default; viz_gene() for the
6-panel composite.
plot_serum_direction("LTBP1") plot_serum_direction(c("SERPINA1", "LTBP1", "LGALS3BP"))plot_serum_direction("LTBP1") plot_serum_direction(c("SERPINA1", "LTBP1", "LGALS3BP"))
For RNA, draws log2FC +/- 1.96 x lfcSE per stage with significance asterisks at per-stage Wald padj < 0.05. For tissue protein, draws log2FC point estimates per stage; the bundled per-stage SE is unavailable so no CI is drawn (the overall F-test padj is reported in the subtitle instead).
plot_stage_effect(gene_symbol, layer = c("rna", "protein"))plot_stage_effect(gene_symbol, layer = c("rna", "protein"))
gene_symbol |
HGNC symbol. |
layer |
One of |
A ggplot2 object.
plot_stage_effect("LTBP1") plot_stage_effect("LTBP1", layer = "protein")plot_stage_effect("LTBP1") plot_stage_effect("LTBP1", layer = "protein")
Renders one panel per trajectory template in the bundled
12-template catalogue. Each panel shows the cohort of
genes / proteins whose z-scored Normal / Early / Mid / Late
trajectory matches that template best (Pearson rho argmax across
the 12 templates; deterministic given the bundled atlas), as thin
translucent lines plus a mean line and a +/-1 SD ribbon. Reproduces
the figures in
analysis/manuscript/PDAC_졸업v1/fig2/individual/fig2C_RNA_*.pdf
inside the package and extends them to the four templates that
did not exist in the v0.3.0 era (Late_Burst_Up, Late_Loss_Down,
Monotonic_Up, Monotonic_Down).
plot_template_atlas( layer = c("rna", "protein"), templates = NULL, output_dir = NULL, filename_pattern = "template_{layer}_{template}.pdf", width = 1.55, height = 1.4, reference = NULL )plot_template_atlas( layer = c("rna", "protein"), templates = NULL, output_dir = NULL, filename_pattern = "template_{layer}_{template}.pdf", width = 1.55, height = 1.4, reference = NULL )
layer |
Either |
templates |
Optional character vector of template names to
restrict the output to. Default |
output_dir |
Optional directory. If non-NULL, one cairo PDF
per template is written via |
filename_pattern |
File-name template containing
|
width, height
|
Output PDF size in inches. Defaults match the
compact |
reference |
Optional override of the bundled
|
Cohort assignment is recomputed inside the package via the same
z-scored Pearson-rho argmax that backs classify_trajectory() and
score_trajectory(); the bundled atlas's rna_pattern column
surfaces only the four Early templates, so the eight non-Early
panels rely on this argmax recovery rather than on a directly
bundled label.
Edge case: very small cohorts degrade gracefully — singletons drop the ribbon, cohorts of 2-4 drop the ribbon but keep individual lines, cohorts of >=5 show the full thin-lines + mean + ribbon.
A named list of ggplot objects, one per template, in
c(early_pattern_names(), mid_pattern_names_excluded(), "Late_Burst_Up", "Late_Loss_Down", "Monotonic_Up", "Monotonic_Down") order. When output_dir is non-NULL, the
list also carries the file paths in attr(out, "files").
panels <- plot_template_atlas("rna", templates = "Early_Burst_Up") length(panels) names(panels)panels <- plot_template_atlas("rna", templates = "Early_Burst_Up") length(panels) names(panels)
pdactrace_user_model
Predict from a pdactrace_user_model
predict_user_evidence_model(model, new_features, s = "lambda.min")predict_user_evidence_model(model, new_features, s = "lambda.min")
model |
A |
new_features |
|
s |
|
A data.table with gene_symbol and predicted_prob
(P(label=1) under the fitted model). Rows with any NA
feature are returned with predicted_prob = NA.
if (requireNamespace("glmnet", quietly = TRUE)) { set.seed(1) feats <- data.frame(gene_symbol = paste0("G", seq_len(30)), x1 = rnorm(30), x2 = rnorm(30)) y <- rep(c(0L, 1L), each = 15) fit <- fit_user_evidence_model(feats, y, nfolds = 3L) head(predict_user_evidence_model(fit, feats)) } feats <- make_evidence_features(scale = "z", drop_na_rows = TRUE) y <- as.integer(feats$gene_symbol %in% c("LGALS3BP", "TIMP1", "LRG1")) fit <- fit_user_evidence_model(feats, y) head(predict_user_evidence_model(fit, feats))if (requireNamespace("glmnet", quietly = TRUE)) { set.seed(1) feats <- data.frame(gene_symbol = paste0("G", seq_len(30)), x1 = rnorm(30), x2 = rnorm(30)) y <- rep(c(0L, 1L), each = 15) fit <- fit_user_evidence_model(feats, y, nfolds = 3L) head(predict_user_evidence_model(fit, feats)) } feats <- make_evidence_features(scale = "z", drop_na_rows = TRUE) y <- as.integer(feats$gene_symbol %in% c("LGALS3BP", "TIMP1", "LRG1")) fit <- fit_user_evidence_model(feats, y) head(predict_user_evidence_model(fit, feats))
One-call wrapper that takes a user RNA-seq cohort (and optionally a tissue-protein cohort) and walks it end-to-end through the four v0.99 framework steps: stage-aware DE fit, 12-template trajectory matching, evidence-table assembly, and frozen audit scoring. Returns a structured list with each intermediate object plus the final audit table, so the user can inspect at any step.
project_user_cohort( rna, coldata = NULL, stage_col, cohort_col = NULL, protein = NULL, protein_assay_name = "intensity", signal_peptide = NULL, sig_only = FALSE )project_user_cohort( rna, coldata = NULL, stage_col, cohort_col = NULL, protein = NULL, protein_assay_name = "intensity", signal_peptide = NULL, sig_only = FALSE )
rna |
Either an integer count matrix / data.frame (genes by
samples) or a |
coldata |
Optional |
stage_col |
Name of the column in |
cohort_col |
Optional name of the cohort column. Default
|
protein |
Optional second |
protein_assay_name |
Assay slot to use when |
signal_peptide |
Optional character vector of gene symbols
carrying a signal peptide; passed straight to
|
sig_only |
Passed to |
This is a convenience around the chain
fit_stage_de() -> classify_trajectory() ->
assemble_user_evidence() -> compute_audit_score().
Calling those four explicitly continues to work; this wrapper
reduces a typical user-cohort workflow to a single line and
provides a consistent return shape for reporting and review.
Bioconductor-native input is supported via the same S4 method
dispatch as fit_stage_de(): the rna argument can be either a
count matrix / data.frame plus coldata, or a
SummarizedExperiment whose assay() is the count matrix and
whose colData() carries the stage / cohort columns.
A list of class pdactrace_user_projection with
elements:
rna_fit – output of fit_stage_de().
rna_pattern – output of classify_trajectory().
prot_fit – output of fit_stage_de_protein() (or NULL).
prot_pattern– output of classify_protein_trajectory()
(or NULL).
evidence – output of assemble_user_evidence().
audit – output of compute_audit_score(evidence = ...).
summary – one-row data.table with input shape +
audit-class counts.
data(toy_counts) data(toy_coldata) if (requireNamespace("DESeq2", quietly = TRUE)) { res <- project_user_cohort( rna = toy_counts, coldata = toy_coldata, stage_col = "stage", cohort_col = "cohort") res$summary } if (requireNamespace("DESeq2", quietly = TRUE)) { res <- project_user_cohort( rna = toy_counts, coldata = toy_coldata, stage_col = "stage", cohort_col = "cohort", protein = toy_protein) res$summary head(res$audit[order(-audit_score)]) }data(toy_counts) data(toy_coldata) if (requireNamespace("DESeq2", quietly = TRUE)) { res <- project_user_cohort( rna = toy_counts, coldata = toy_coldata, stage_col = "stage", cohort_col = "cohort") res$summary } if (requireNamespace("DESeq2", quietly = TRUE)) { res <- project_user_cohort( rna = toy_counts, coldata = toy_coldata, stage_col = "stage", cohort_col = "cohort", protein = toy_protein) res$summary head(res$audit[order(-audit_score)]) }
The serum side of the framework only requires binary group
contrasts – PDAC vs healthy control (HC) and optionally
Pancreatitis vs HC – not stage-aware data. This makes user
projection asymmetric to the tissue side: where
project_user_cohort() needs Normal / Early / Mid / Late stage
labels for its 12-template trajectory matching, this helper
accepts the kind of serum DIA dataset most public PDAC serum
studies actually publish (PDAC + HC +/- pancreatitis, no clinical
stage labels needed).
project_user_serum_cohort( intensity, coldata, group_col = "group", pdac_label = "PDAC", hc_label = "HC", pan_label = NULL, test = c("limma_eBayes", "wilcox", "t_test"), padj_cutoff = 0.05, link_to_atlas = TRUE, reference = NULL )project_user_serum_cohort( intensity, coldata, group_col = "group", pdac_label = "PDAC", hc_label = "HC", pan_label = NULL, test = c("limma_eBayes", "wilcox", "t_test"), padj_cutoff = 0.05, link_to_atlas = TRUE, reference = NULL )
intensity |
Log2 protein abundance matrix (genes x samples). |
coldata |
|
group_col |
Name of the column in |
pdac_label |
Group label for PDAC samples. Default |
hc_label |
Group label for healthy-control samples.
Default |
pan_label |
Group label for pancreatitis samples (optional).
Default |
test |
One of |
padj_cutoff |
Significance threshold for |
link_to_atlas |
Logical. If |
reference |
Optional |
A data.table with one row per gene in intensity and
columns:
gene_symbol
serum_log2fc_PDAC_vs_HC, serum_padj_PDAC_vs_HC
serum_log2fc_Pan_vs_HC, serum_padj_Pan_vs_HC
(NA if pan_label = NULL)
translation_class ("A" / "B" / "C" / NA)
serum_detected (logical)
Suitable for direct use as assemble_user_evidence( serum_summary = ...).
Splits samples into PDAC / HC / (optional) Pancreatitis
groups by coldata[[group_col]].
Computes serum_log2fc_PDAC_vs_HC = mean(PDAC) - mean(HC)
and (if pan_label is set)
serum_log2fc_Pan_vs_HC = mean(Pan) - mean(HC) per gene.
Runs a per-gene two-group test (default limma_eBayes;
fallback to wilcox or t_test) to attach BH-adjusted
p-values for each contrast.
Optionally joins the bundled
pdactrace_reference's rna_pattern direction to derive a
per-gene translation_class (A / B / C):
Class A – tissue and serum agree on direction ('same dir.', concordant translation).
Class B – tissue and serum oppose ('opposite', inverse translation; the rare, pancreatitis-discriminating case).
Class C – decoupled (tissue direction unclear, or serum log2FC very small).
Set link_to_atlas = FALSE to skip the atlas join and emit
translation_class = NA (deferring class assignment to
downstream code).
Output is shaped to plug straight into
assemble_user_evidence() via the serum_summary argument.
intensityA numeric matrix or data.frame of
log2 protein abundance, with genes (HGNC symbols) in
rows and samples in columns. Pre-log2 transformation
is required; raw MS intensities will produce nonsensical
log2FC values.
coldataA data.frame with at least one column
(group_col) carrying group labels matching pdac_label,
hc_label, and (optionally) pan_label. nrow(coldata)
must equal ncol(intensity). Sample order must match
column order of intensity.
Minimum 3 samples per group is recommended (limma and
wilcox need at least that for a stable variance estimate /
rank distribution). Fewer samples emit a warning.
project_user_cohort() for the tissue side
(stage-aware), assemble_user_evidence() for combining
tissue + serum into the audit-rule input,
plot_serum_direction() for visualisation.
set.seed(1) intensity <- matrix(rnorm(20 * 12, mean = 5), nrow = 20, dimnames = list(paste0("G", seq_len(20)), paste0("S", seq_len(12)))) coldata <- data.frame(group = rep(c("PDAC", "HC"), each = 6)) serum <- project_user_serum_cohort( intensity, coldata, test = "t_test", link_to_atlas = FALSE) head(serum) # Synthetic example: 50 genes x 24 samples (8 PDAC, 8 HC, # 8 Pancreatitis) with PDAC-up + Pan-flat signal. set.seed(1) g <- 50; n <- 24 intensity <- matrix(rnorm(g * n, mean = 5), nrow = g, ncol = n, dimnames = list(paste0("GENE", seq_len(g)), paste0("S", seq_len(n)))) intensity[1:10, 1:8] <- intensity[1:10, 1:8] + 2 # PDAC-up coldata <- data.frame( sample = colnames(intensity), group = rep(c("PDAC", "HC", "Pancreatitis"), each = 8)) serum_summary <- project_user_serum_cohort( intensity, coldata, group_col = "group", pdac_label = "PDAC", hc_label = "HC", pan_label = "Pancreatitis") head(serum_summary) # Feed into the downstream evidence assembler: ev <- assemble_user_evidence(serum_summary = serum_summary)set.seed(1) intensity <- matrix(rnorm(20 * 12, mean = 5), nrow = 20, dimnames = list(paste0("G", seq_len(20)), paste0("S", seq_len(12)))) coldata <- data.frame(group = rep(c("PDAC", "HC"), each = 6)) serum <- project_user_serum_cohort( intensity, coldata, test = "t_test", link_to_atlas = FALSE) head(serum) # Synthetic example: 50 genes x 24 samples (8 PDAC, 8 HC, # 8 Pancreatitis) with PDAC-up + Pan-flat signal. set.seed(1) g <- 50; n <- 24 intensity <- matrix(rnorm(g * n, mean = 5), nrow = g, ncol = n, dimnames = list(paste0("GENE", seq_len(g)), paste0("S", seq_len(n)))) intensity[1:10, 1:8] <- intensity[1:10, 1:8] + 2 # PDAC-up coldata <- data.frame( sample = colnames(intensity), group = rep(c("PDAC", "HC", "Pancreatitis"), each = 8)) serum_summary <- project_user_serum_cohort( intensity, coldata, group_col = "group", pdac_label = "PDAC", hc_label = "HC", pan_label = "Pancreatitis") head(serum_summary) # Feed into the downstream evidence assembler: ev <- assemble_user_evidence(serum_summary = serum_summary)
By default this returns the stored Monte Carlo uncertainty summary from
the atlas. If n_mc is supplied, the uncertainty is recomputed over the
full atlas using the frozen scoring rule and perturbing evidence values
only.
propagate_uncertainty(gene_symbol, n_mc = NULL, seed = 42, evidence = NULL)propagate_uncertainty(gene_symbol, n_mc = NULL, seed = 42, evidence = NULL)
gene_symbol |
Character vector of HGNC gene symbols. |
n_mc |
Optional integer number of Monte Carlo iterations. |
seed |
Random seed used when |
evidence |
Optional user-supplied evidence table (see
|
A data.table with score CI, rank CI, uncertainty width, and class.
propagate_uncertainty(c("LTBP1", "THBS2", "GAPDH"))propagate_uncertainty(c("LTBP1", "THBS2", "GAPDH"))
Returns a layered list with all evidence available for gene_symbol
across the requested layers. If the gene is not in the LRT-significant
atlas universe, returns NULL with an informative message.
query_gene( gene_symbol, layers = c("rna", "protein", "scrna", "serum", "clinical", "filter_status", "annotation") )query_gene( gene_symbol, layers = c("rna", "protein", "scrna", "serum", "clinical", "filter_status", "annotation") )
gene_symbol |
HGNC standard symbol (case-sensitive). |
layers |
Character vector subset of
|
Named list with one slot per requested layer plus $summary
(1-line text) and $provenance (comma-separated source phase
scripts). Returns NULL invisibly if gene_symbol is not in the
atlas.
q <- query_gene("LTBP1") q$rna$pattern # "Early_Burst_Up" q$serum$translation_class # "B"q <- query_gene("LTBP1") q$rna$pattern # "Early_Burst_Up" q$serum$translation_class # "B"
Returns a named list of data.tables exposing the hidden per-stage,
per-cohort, per-celltype, per-filter-step, and per-serum-cohort detail
that query_gene() summarizes only at the headline level.
query_gene_detailed(gene_symbol)query_gene_detailed(gene_symbol)
gene_symbol |
HGNC standard symbol (case-sensitive). |
Use this for reviewer-grade audit (e.g., "is the LTBP1 upregulation consistent across all 4 RNA cohorts?") or for downstream computation.
Named list with 5 slots (each a data.table) plus
$summary (1-line text) and $provenance. Returns NULL
invisibly with a message if gene_symbol is not in the atlas.
per_stage - 4 rows (Normal, Early, Mid, Late) with
log2FC, lfcSE, ci_lo, ci_hi, lrt_padj, wald_padj,
significant. lrt_padj is the omnibus DESeq2 LRT padj
(identical across stages by construction); wald_padj is the
per-contrast Wald padj from a nbinomWaldTest() refit of the
same model (v0.4.0). The significant column uses Wald padj.
per_cohort - 4 rows (TCGA, CPTAC, GSE224564, GSE79668) with
trend (-1/0/+1), monotonic (lgl), plus Stouffer summary as
table attribute.
per_celltype - 11 rows with mean_expression, pct_of_total,
ranked descending.
filter_diag - 7 rows (phase60 steps) with pass (lgl),
underlying_metric, cutoff, note.
serum_per_cohort - 3 rows (PDAC, Pancreatitis, HC) with
mean, n_unknown (cohort sample n not always available),
plus PDAC-vs-Pan t-test p-value as attribute.
d <- query_gene_detailed("LTBP1") d$per_stage # log2FC + 95% CI per stage d$per_cohort # cohort x trend x monotonic d$filter_diag # 7-step audit with underlying numbersd <- query_gene_detailed("LTBP1") d$per_stage # log2FC + 95% CI per stage d$per_cohort # cohort x trend x monotonic d$filter_diag # 7-step audit with underlying numbers
Convenience join of query_gene() outputs across multiple genes.
query_panel( genes, joined = TRUE, layers = c("rna", "protein", "scrna", "serum", "clinical", "filter_status", "annotation") )query_panel( genes, joined = TRUE, layers = c("rna", "protein", "scrna", "serum", "clinical", "filter_status", "annotation") )
genes |
Character vector of HGNC symbols. |
joined |
Logical. If |
layers |
Character vector subset of available layers (passed
through to |
data.table (wide or long).
query_panel(c("LTBP1", "SERPINA1", "CDH13"))query_panel(c("LTBP1", "SERPINA1", "CDH13"))
Renders a self-contained HTML report summarising the bundled
atlas's evidence for a single gene OR for a multi-gene panel. The
single-gene layout (length-1 input) carries the audit class + score,
the audit-component table, the six-axis evidence radar, the
cohort-adjusted stage trajectory, the per-cohort breakdown, and the
tissue-to-serum filter trace. The panel layout (length >= 2)
starts with a side-by-side comparison table from
compare_candidates() (audit class, RNA pattern, translation
class, cell origin, serum detectability, redundancy hint) and
follows with one condensed section per gene: explain_score()
rationale plus the evidence radar.
report_gene( gene_symbol, output_file = NULL, output_dir = tempdir(), quiet = TRUE )report_gene( gene_symbol, output_file = NULL, output_dir = tempdir(), quiet = TRUE )
gene_symbol |
HGNC gene symbol — character vector of length 1 or more. Length 1 produces the single-gene template; length 2+ produces the panel template. |
output_file |
Optional output filename (without directory).
Defaults to |
output_dir |
Output directory. Defaults to |
quiet |
Logical. If |
The render is deterministic given (gene_symbol, atlas) because the audit rule is frozen.
Invisibly returns the absolute path to the rendered HTML file.
args(report_gene) if (requireNamespace("rmarkdown", quietly = TRUE) && requireNamespace("knitr", quietly = TRUE)) { # Single-gene report: fp1 <- report_gene("LTBP1", output_dir = tempdir()) # Panel report (3 genes): fp2 <- report_gene(c("LGALS3BP", "LTBP1", "GAPDH"), output_dir = tempdir()) file.exists(c(fp1, fp2)) }args(report_gene) if (requireNamespace("rmarkdown", quietly = TRUE) && requireNamespace("knitr", quietly = TRUE)) { # Single-gene report: fp1 <- report_gene("LTBP1", output_dir = tempdir()) # Panel report (3 genes): fp2 <- report_gene(c("LGALS3BP", "LTBP1", "GAPDH"), output_dir = tempdir()) file.exists(c(fp1, fp2)) }
Samples weight vectors over the three audit axes and reports how often each gene remains inside top-N sets. This is a sensitivity analysis, not a new trained model.
run_weight_robustness( atlas = NULL, genes = NULL, n_draws = 1000L, top_n = c(50L, 100L, 500L), weight_floor = 0.05, seed = 20260527L )run_weight_robustness( atlas = NULL, genes = NULL, n_draws = 1000L, top_n = c(50L, 100L, 500L), weight_floor = 0.05, seed = 20260527L )
atlas |
Optional atlas-like data table. |
genes |
Optional genes to return after atlas-wide ranking. |
n_draws |
Number of sampled weight vectors. |
top_n |
Integer vector of top-N cutoffs. |
weight_floor |
Minimum weight assigned to each axis. The residual mass is sampled uniformly on the simplex. |
seed |
Random seed. |
A data.table with rank intervals and top-N stability columns.
run_weight_robustness(genes = "LGALS3BP", n_draws = 10) run_weight_robustness(genes = c("LGALS3BP", "LTBP1"), n_draws = 50)run_weight_robustness(genes = "LGALS3BP", n_draws = 10) run_weight_robustness(genes = c("LGALS3BP", "LTBP1"), n_draws = 50)
Average precision
sb_average_precision(truth, score)sb_average_precision(truth, score)
truth |
Logical or binary vector. |
score |
Numeric score; larger values predict positives. |
A single numeric value in [0, 1], or NA_real_ when no
positive remains after dropping missing and non-finite entries. Tied
scores are collapsed into one threshold.
sb_average_precision(c(TRUE, FALSE, TRUE, FALSE), c(4, 3, 2, 1))sb_average_precision(c(TRUE, FALSE, TRUE, FALSE), c(4, 3, 2, 1))
Binary area under the ROC curve
sb_binary_auc(truth, score)sb_binary_auc(truth, score)
truth |
Logical or binary vector. |
score |
Numeric score; larger values predict positives. |
A single numeric value in [0, 1], or NA_real_ when either
class is absent after dropping missing and non-finite entries.
sb_binary_auc(c(TRUE, TRUE, FALSE, FALSE), c(4, 3, 2, 1))sb_binary_auc(c(TRUE, TRUE, FALSE, FALSE), c(4, 3, 2, 1))
sb_one_shot()
These are the thresholds as first frozen in
prospective/locks/PXD055218_crc_v1/DECISION_RULE.json, which lives in
the archived cross-cancer working tree rather than in this package (see
audit/PROVENANCE.md). They are reused unchanged as the PDAC default so
that the numbers are traceable to a rule that predates any PDAC outcome
label, and tests/testthat/test-sb-one-shot.R keeps a golden-equivalence
test against that original audit. Supply your own rule to
sb_one_shot() for a new lock.
sb_default_one_shot_rule()sb_default_one_shot_rule()
Named list of the frozen coverage, endpoint and resampling
thresholds consumed by sb_one_shot().
str(sb_default_one_shot_rule())str(sb_default_one_shot_rule())
Leave-one-cohort-out rank stability
sb_loco_stability(effects, detection = NULL, source_score = NULL, top_k = 50L)sb_loco_stability(effects, detection = NULL, source_score = NULL, top_k = 50L)
effects |
StageBridge effect table. |
detection |
Optional detection table. |
source_score |
Optional source score. |
top_k |
Top-ranked set used for selection frequency. |
Stability summary by feature.
sim <- sb_simulate(n_features = 40L, seed = 1L) head(sb_loco_stability(sim$effects, sim$detection, top_k = 10L), 3)sim <- sb_simulate(n_features = 40L, seed = 1L) head(sb_loco_stability(sim$effects, sim$detection, top_k = 10L), 3)
Score candidates with StageBridge and benchmark comparators
sb_method_scores(effects, detection = NULL, source_score = NULL)sb_method_scores(effects, detection = NULL, source_score = NULL)
effects |
Stage-resolved effect table. |
detection |
Optional blood detection table. |
source_score |
Optional source score used by StageBridge only. |
Wide feature-by-method score table.
sim <- sb_simulate(n_features = 20L, seed = 1L) head(sb_method_scores(sim$effects, sim$detection), 3)sim <- sb_simulate(n_features = 20L, seed = 1L) head(sb_method_scores(sim$effects, sim$detection), 3)
Fits the dense multiblock PLS-DA model implemented by mixOmics and combines block-specific loading magnitudes into a shared-feature priority score. This comparator requires the same observations, in the same order, in every block; it is therefore not applicable to unpaired cohort-level effect tables.
sb_multiblock_plsda_scores(blocks, outcome, ncomp = 2L, design = 0.1)sb_multiblock_plsda_scores(blocks, outcome, ncomp = 2L, design = 0.1)
blocks |
Named list of sample-by-feature numeric matrices. |
outcome |
Factor or vector of class labels, one per sample. |
ncomp |
Number of latent components. |
design |
Off-diagonal connection strength between omics blocks. |
A feature-by-score data frame. The fitted model is attached as the
model attribute.
if (requireNamespace("mixOmics", quietly = TRUE)) { outcome <- factor(rep(c("Normal", "Tumor"), each = 12)) dn <- list(paste0("S", seq_len(24)), paste0("F", seq_len(8))) rna <- matrix(withr::with_seed(7, stats::rnorm(24 * 8)), 24, dimnames = dn) protein <- rna + withr::with_seed(8, stats::rnorm(24 * 8, sd = 0.5)) head(sb_multiblock_plsda_scores(list(RNA = rna, Protein = protein), outcome), 3) }if (requireNamespace("mixOmics", quietly = TRUE)) { outcome <- factor(rep(c("Normal", "Tumor"), each = 12)) dn <- list(paste0("S", seq_len(24)), paste0("F", seq_len(8))) rna <- matrix(withr::with_seed(7, stats::rnorm(24 * 8)), 24, dimnames = dn) protein <- rna + withr::with_seed(8, stats::rnorm(24 * 8, sd = 0.5)) head(sb_multiblock_plsda_scores(list(RNA = rna, Protein = protein), outcome), 3) }
A detection in a shallow cohort contributes more information than the same detection in a cohort where nearly every candidate is observed.
sb_observability(detection)sb_observability(detection)
detection |
Data frame with feature, cohort, and detected columns. |
Data frame with one observability score per feature.
sim <- sb_simulate(n_features = 20L, seed = 1L) head(sb_observability(sim$detection), 3)sim <- sb_simulate(n_features = 20L, seed = 1L) head(sb_observability(sim$detection), 3)
Applies the frozen gate stack (ontology/group-count, broad coverage, top-10 and
top-20 panel coverage, complete panel) and, only if every gate passes, the locked
statistical endpoint (rank-weighted panel AUROC with a permutation test and a
feature-replication count). Returns a terminal decision whose status is exactly
one of PASS, FAIL or INCONCLUSIVE. INCONCLUSIVE ("the test never ran")
is returned whenever a gate halts execution and is operationally distinct from a
biological FAIL (the endpoint ran and did not meet the criteria).
sb_one_shot( abundance, frozen, panel, groups, expected_counts, rule = sb_default_one_shot_rule() )sb_one_shot( abundance, frozen, panel, groups, expected_counts, rule = sb_default_one_shot_rule() )
abundance |
Long data frame: |
frozen |
Broad frozen score table with |
panel |
Ordered top-k panel with |
groups |
List with |
expected_counts |
Named integer vector of expected samples per group. |
rule |
Named list of frozen thresholds (see |
A terminal decision list with status, gates, statistical_runner_entered
and, when the runner ran, the endpoint statistics.
frozen <- data.frame( feature = sprintf("G%03d", 1:320), frozen_direction = rep(c(1L, -1L), length.out = 320L) ) panel <- data.frame( feature = frozen$feature[1:20], frozen_direction = frozen$frozen_direction[1:20], rank_weight = 1 / log2(2:21) ) samples <- c(sprintf("CP_%02d", 1:20), sprintf("CN_%02d", 1:20), sprintf("HC_%02d", 1:20)) abundance <- expand.grid( gene = frozen$feature[1:50], sample = samples, KEEP.OUT.ATTRS = FALSE, stringsAsFactors = FALSE ) abundance$group <- sub("_.*$", "", abundance$sample) abundance$log2_abundance <- withr::with_seed( 1, stats::rnorm(nrow(abundance), 8, 1) ) # Only 50 of the 320 frozen candidates are quantifiable, so the frozen # coverage gate halts before the endpoint runs: a terminal INCONCLUSIVE, # which is operationally distinct from a biological FAIL. decision <- sb_one_shot( abundance, frozen, panel, groups = list(case = "CP", primary_reference = "CN", secondary_reference = "HC"), expected_counts = c(CP = 20L, CN = 20L, HC = 20L) ) decision$status decision$failed_gatesfrozen <- data.frame( feature = sprintf("G%03d", 1:320), frozen_direction = rep(c(1L, -1L), length.out = 320L) ) panel <- data.frame( feature = frozen$feature[1:20], frozen_direction = frozen$frozen_direction[1:20], rank_weight = 1 / log2(2:21) ) samples <- c(sprintf("CP_%02d", 1:20), sprintf("CN_%02d", 1:20), sprintf("HC_%02d", 1:20)) abundance <- expand.grid( gene = frozen$feature[1:50], sample = samples, KEEP.OUT.ATTRS = FALSE, stringsAsFactors = FALSE ) abundance$group <- sub("_.*$", "", abundance$sample) abundance$log2_abundance <- withr::with_seed( 1, stats::rnorm(nrow(abundance), 8, 1) ) # Only 50 of the 320 frozen candidates are quantifiable, so the frozen # coverage gate halts before the endpoint runs: a terminal INCONCLUSIVE, # which is operationally distinct from a biological FAIL. decision <- sb_one_shot( abundance, frozen, panel, groups = list(case = "CP", primary_reference = "CN", secondary_reference = "HC"), expected_counts = c(CP = 20L, CN = 20L, HC = 20L) ) decision$status decision$failed_gates
Assign exact non-dominated Pareto fronts
sb_pareto_fronts(components)sb_pareto_fronts(components)
components |
Numeric matrix; larger values are preferred. |
Integer front labels, where 1 is non-dominated.
sb_pareto_fronts(cbind(a = c(1, 0.5, 0.2), b = c(0.2, 0.6, 0.1)))sb_pareto_fronts(cbind(a = c(1, 0.5, 0.2), b = c(0.2, 0.6, 0.1)))
Simulate a multi-cohort, multi-omic biomarker benchmark
sb_simulate( n_features = 1200L, positive_fraction = 0.06, scenario = c("translation", "generic_signal", "heterogeneity", "dropout", "neutral_observability", "mixed_relation", "partial_destination", "anti_observability"), seed = 1L )sb_simulate( n_features = 1200L, positive_fraction = 0.06, scenario = c("translation", "generic_signal", "heterogeneity", "dropout", "neutral_observability", "mixed_relation", "partial_destination", "anti_observability"), seed = 1L )
n_features |
Number of simulated features. |
positive_fraction |
Fraction of true translatable markers. |
scenario |
One of generic_signal, translation, heterogeneity, dropout, neutral_observability, mixed_relation, partial_destination, or anti_observability. Translation scenarios include coherent tissue-only and inflammation-associated blood decoys; the final three deliberately violate a default StageBridge assumption. |
seed |
Random seed. |
List with effects, detection, and feature-level truth.
sim <- sb_simulate(n_features = 40L, seed = 1L) vapply(sim, nrow, integer(1))sim <- sb_simulate(n_features = 40L, seed = 1L) vapply(sim, nrow, integer(1))
Recall among the top-ranked candidates
sb_topk_recall(truth, score, k = 50L)sb_topk_recall(truth, score, k = 50L)
truth |
Logical or binary vector. |
score |
Numeric score. |
k |
Number of top candidates. |
A single numeric value in [0, 1] giving the fraction of
positives recovered in the top k scores, or NA_real_ when no
positive remains after dropping missing and non-finite entries.
sb_topk_recall(c(TRUE, TRUE, FALSE, FALSE), c(4, 3, 2, 1), k = 2)sb_topk_recall(c(TRUE, TRUE, FALSE, FALSE), c(4, 3, 2, 1), k = 2)
Validate a StageBridge effect table
sb_validate_effects(effects)sb_validate_effects(effects)
effects |
Data frame with one row per feature, cohort, modality, and contrast. |
A normalized data frame with numeric estimates and standard errors.
sim <- sb_simulate(n_features = 20L, seed = 1L) str(sb_validate_effects(sim$effects))sim <- sb_simulate(n_features = 20L, seed = 1L) str(sb_validate_effects(sim$effects))
Returns the canonical column list with type and T2.5/T3 status.
Used by data-raw/build_reference.R to allocate columns and by
tests/testthat/test-schema.R to verify completeness.
schema_spec(include_derived = FALSE)schema_spec(include_derived = FALSE)
include_derived |
Logical. If TRUE, also include derived algorithm-output columns that can be attached by data-raw scripts but are not part of the bundled reference atlas by default. |
data.table with columns: name, type, layer, t25_status.
head(schema_spec())head(schema_spec())
Computes how close each gene's evidence-feature vector is to the centroid of a curated positive-anchor reference set (cosine or inverse-Euclidean similarity in the z-scored feature space). This is the descriptive layer that gives a continuous, ML-flavoured prioritisation signal without training a supervised classifier – the bundled anchor labels are used only to define the centroid, never as training labels for a shipped predictor.
score_anchor_similarity( genes = NULL, anchors = NULL, method = c("cosine", "euclidean"), tier = c("primary", "secondary", "all"), reference = NULL )score_anchor_similarity( genes = NULL, anchors = NULL, method = c("cosine", "euclidean"), tier = c("primary", "secondary", "all"), reference = NULL )
genes |
Optional character vector of gene symbols. |
anchors |
Optional |
method |
One of |
tier |
Anchor tier filter: |
reference |
Optional |
This complements evaluate_anchor_enrichment()
(post-hoc top-N hypergeometric evaluation) and the deterministic
audit_score. The three are independent: audit_score ranks
by frozen rule, anchor_similarity ranks by feature-space
proximity to known biomarkers, and evaluate_anchor_enrichment()
is the evaluation harness that consumes either ranking via its
score_col argument.
A data.table with one row per requested gene and
columns gene_symbol, anchor_similarity, anchor_n
(number of anchor rows the centroid was built from), and
anchor_tier. Rows are sorted by anchor_similarity
descending with NA last.
Build the per-gene feature matrix via
make_evidence_features() with scale = "z" (mean 0, sd 1
per feature over complete cases).
Resolve the anchor set via the same internal helper
evaluate_anchor_enrichment() uses, filtered by tier.
Anchor centroid c_k = mean over selected anchors of feature_k (NAs skipped per feature).
For each atlas gene g, compute sim(g) = <z_g, c> / (||z_g|| * ||c||) (cosine, default) or
sim(g) = 1 / (1 + sqrt(sum_k (z_g_k - c_k)^2)) (Euclidean).
Genes with too few non-NA features (< 3) get
anchor_similarity = NA.
make_evidence_features(),
evaluate_anchor_enrichment(), model_card().
sim <- score_anchor_similarity(tier = "primary") head(sim, 10)sim <- score_anchor_similarity(tier = "primary") head(sim, 10)
Returns full rho vector (12 values) per gene. Useful for inspecting how clearly a gene maps to a single pattern vs ambiguous/borderline, and for diagnosing whether a non-Early best-match excluded the gene from the Early × 4 atlas surface.
score_trajectory(pat, gene)score_trajectory(pat, gene)
pat |
A |
gene |
Character vector. One or more gene symbols. |
data.table with gene_symbol and 12 rho columns
(one per template): rho_Early_Burst_Up, rho_Early_Loss_Down,
rho_Early_Peak, rho_Early_Trough, rho_Mid_Plateau_Up,
rho_Mid_Plateau_Down, rho_Mid_Peak, rho_Mid_Trough,
rho_Late_Burst_Up, rho_Late_Loss_Down, rho_Monotonic_Up,
rho_Monotonic_Down.
fit <- data.table::data.table( gene_symbol = "G1", beta_N = 0, beta_E = 2, beta_M = 0.5, beta_L = 0, lrt_padj = 0.01, lrt_significant = TRUE) pat <- classify_trajectory(fit, sig_only = FALSE) score_trajectory(pat, "G1")fit <- data.table::data.table( gene_symbol = "G1", beta_N = 0, beta_E = 2, beta_M = 0.5, beta_L = 0, lrt_padj = 0.01, lrt_significant = TRUE) pat <- classify_trajectory(fit, sig_only = FALSE) score_trajectory(pat, "G1")
Rank stage-resolved multi-omic biomarker candidates
stagebridge( effects, detection = NULL, source_score = NULL, target_modality = NULL, target_relation = c("concordant", "inverse", "agnostic", "exclude"), weights = c(target = 0.55, anchor = 0.1, evidence = 0.05, replication = 0.08, concordance = 0.07, observability = 0.05, coverage = 0.05, source = 0.05), compute_pareto = TRUE )stagebridge( effects, detection = NULL, source_score = NULL, target_modality = NULL, target_relation = c("concordant", "inverse", "agnostic", "exclude"), weights = c(target = 0.55, anchor = 0.1, evidence = 0.05, replication = 0.08, concordance = 0.07, observability = 0.05, coverage = 0.05, source = 0.05), compute_pareto = TRUE )
effects |
Stage-resolved effect table accepted by |
detection |
Optional blood detection table accepted by |
source_score |
Optional named numeric vector or data frame with feature and source_score. |
target_modality |
Optional destination modality. If omitted, plasma, serum, or blood is detected automatically. |
target_relation |
Predeclared relationship between tissue and destination effects: concordant, inverse, agnostic, or exclude. |
weights |
Named component weights. |
compute_pareto |
Whether to calculate exact non-dominated fronts. |
Ranked data frame and auditable component scores. pareto_tier is
populated only when compute_pareto = TRUE; score_percentile_tier is an
explicitly separate score-only top-5%/top-20% tier.
sim <- sb_simulate(n_features = 40L, seed = 1L) ranked <- stagebridge(sim$effects, detection = sim$detection) head(ranked[, c("feature", "stagebridge_score", "pareto_front")], 3)sim <- sb_simulate(n_features = 40L, seed = 1L) ranked <- stagebridge(sim$effects, detection = sim$detection) head(ranked[, c("feature", "stagebridge_score", "pareto_front")], 3)
Returns a multi-line, glue-formatted text summary of all evidence
available for gene_symbol in the pdactrace reference atlas.
summarize_gene_evidence(gene_symbol, detail = FALSE)summarize_gene_evidence(gene_symbol, detail = FALSE)
gene_symbol |
HGNC standard symbol. |
detail |
Logical. If |
A character scalar (single string with \\n separators).
Returns NULL invisibly with a message if gene is not in atlas.
cat(summarize_gene_evidence("LTBP1"))cat(summarize_gene_evidence("LTBP1"))
Summarize the tissue-to-blood translation gap
summarize_translation_gap(atlas = NULL, tau_tissue = 0.5, tau_serum = 0.1)summarize_translation_gap(atlas = NULL, tau_tissue = 0.5, tau_serum = 0.1)
atlas |
Optional atlas-like data table. Defaults to the bundled
|
tau_tissue |
Minimum absolute tissue effect used by
|
tau_serum |
Minimum absolute serum log2 fold-change used by
|
A data.table with claim-tier counts and percentages.
summarize_translation_gap()summarize_translation_gap()
Sample-level metadata that pairs with toy_counts and
toy_protein. 24 samples balanced across the four canonical stages
and two synthetic cohorts.
toy_coldatatoy_coldata
data.frame with 24 rows and 3 columns:
sample (character): S01..S24.
stage (character): "Normal", "Early", "Mid", "Late",
6 samples per stage.
cohort (character): "CohortA", "CohortB",
12 samples per cohort.
Tiny synthetic RNA-seq count matrix bundled so the user-cohort
workflow (fit_stage_de -> classify_trajectory ->
assemble_user_evidence -> compute_audit_score) can be exercised
end-to-end inside examples and the user-cohort vignette without an
external download. The first 10 rows (TGENE01-TGENE10) carry an
injected Early_Burst_Up signal (count lift of ~60-90 reads from
Stage I onward); the remaining 40 rows are negative-binomial noise.
Generated by data-raw/build_toy_data.R with set.seed(2026).
toy_countstoy_counts
Integer matrix, 50 genes x 24 samples. Row names
TGENE01..TGENE50; column names S01..S24 matching
toy_coldata$sample.
data("toy_counts", package = "pdactrace") data("toy_coldata", package = "pdactrace") if (requireNamespace("DESeq2", quietly = TRUE)) { fit <- fit_stage_de(toy_counts, stage = toy_coldata$stage, cohort = toy_coldata$cohort) head(fit) }data("toy_counts", package = "pdactrace") data("toy_coldata", package = "pdactrace") if (requireNamespace("DESeq2", quietly = TRUE)) { fit <- fit_stage_de(toy_counts, stage = toy_coldata$stage, cohort = toy_coldata$cohort) head(fit) }
Tiny synthetic protein intensity matrix paired with toy_counts /
toy_coldata. The first 8 rows (TPROT01-TPROT08) carry an
injected Early_Burst_Up shape (log2 lift of ~0.6-1.0 from
Stage I); the remaining 42 rows are Gaussian noise around 12.
Generated by data-raw/build_toy_data.R with set.seed(2026).
toy_proteintoy_protein
Numeric matrix (log2 intensity), 50 proteins x 24 samples.
Row names TPROT01..TPROT50; column names S01..S24.
Returns the gene's pass/fail status for each step of pdactrace's two parallel narrowing funnels:
trace_filters(gene)trace_filters(gene)
gene |
Character vector of HGNC symbols. |
phase60 7-step pipeline - strict cumulative funnel
(signal peptide -> serum measurable -> pool significance -> vs
pancreatitis -> HC-in-middle -> direction match -> final).
phase77 strict candidate set - independent narrow funnel
producing the 22 strict tissue+serum convergent candidates
that anchor manual Class B curation.
Most genes (including LTBP1) pass one of the two funnels but not both - this is the audit-trail message of pdactrace.
A data.table with one row per requested gene and one
column per filter step (logical). Includes n_phase60_pass
(0-7) and class_route summary column.
trace_filters("LTBP1") trace_filters(c("LTBP1", "SPARC", "CDH13", "SERPINA1"))trace_filters("LTBP1") trace_filters(c("LTBP1", "SPARC", "CDH13", "SERPINA1"))
Returns a 2x3 patchwork composite that puts one panel per
evidence layer plus the final audit-axis radar for a gene on
a single page (v0.99.8 expansion from the previous 4-panel
layout). The figure shows the entire prioritisation flow on one
page: four input layers (RNA, tissue protein, scRNA cell
origin, serum direction), the 7-step tissue-to-serum filter
trail that gates them, and the 6-axis hexagon that compresses
all of the above into the final audit-score components.
viz_gene( gene_symbol, title = NULL, ncol = 3L, layout = c("split", "compact"), output_dir = NULL, width = 6, height = 4.5 )viz_gene( gene_symbol, title = NULL, ncol = 3L, layout = c("split", "compact"), output_dir = NULL, width = 6, height = 4.5 )
gene_symbol |
HGNC gene symbol (length-1 character). |
title |
Optional title override. |
ncol |
Layout: |
layout |
One of |
output_dir |
Optional directory path. Only used when
|
width, height
|
Per-panel width and height in inches when
|
Top-left – bulk RNA-seq: per-stage log2FC forest (mean +/- 95% CI vs Normal).
Top-middle – tissue proteomics: per-stage protein log2FC trajectory (point estimates; per-stage SE not available from the bundled limma F-test fit).
Top-right – scRNA cell origin: 11-celltype expression distribution with the dominant lineage highlighted.
Bottom-left – serum direction: per-gene PDAC vs HC and Pancreatitis vs HC log2FC, coloured by translation class (Class A blue, Class B red, Class C grey).
Bottom-middle – 7-step filter trace: the phase60 tissue-to-serum audit trail with per-gene pass-count badge.
Bottom-right – 6-axis audit hexagon: the final
score's six component axes (multi-layer, direction,
stage-onset, serum bridge, leakage safety, cohort
consistency), the same axes explain_score() decomposes.
A title strip across the top names the gene, its matched
template, audit class, and translation class. This single
figure is the visual analog of summarize_gene_evidence() +
explain_score() combined and is the recommended first
call for a gene a clinician or biologist hands you – one
plot, the whole evidence-to-score chain, no per-axis function
names required.
Internally composes plot_stage_effect() (RNA + protein),
plot_celltype_full(), plot_serum_direction(),
plot_filter_trace(), and plot_gene_hexagon() via
patchwork::wrap_plots(). Every sub-panel remains available
standalone; the previous RNA per-cohort sign-vote view is at
plot_per_cohort().
A patchwork object printable to any active graphics
device or saveable via ggsave() / pdactrace_save().
summarize_gene_evidence() for the text counterpart;
report_gene() for an HTML report (requires pandoc).
viz_gene("LGALS3BP") # Alternative layouts (skipped in R CMD check examples for time; # all run normally in interactive use). viz_gene("LTBP1", ncol = 2) # 3x2 grid viz_gene("LTBP1", ncol = 1) # vertical strip # Split mode: get each panel as its own full-size figure panels <- viz_gene("LTBP1", layout = "split") panels$rna # bulk RNA per-stage forest panels$protein # tissue protein per-stage trajectory panels$cell # scRNA cell-of-origin distribution panels$serum # serum direction strip panels$filter # 7-step filter trail panels$hexagon # 6-axis audit hexagon # Or write each panel to a separate PDF in one call: viz_gene("LTBP1", layout = "split", output_dir = tempdir())viz_gene("LGALS3BP") # Alternative layouts (skipped in R CMD check examples for time; # all run normally in interactive use). viz_gene("LTBP1", ncol = 2) # 3x2 grid viz_gene("LTBP1", ncol = 1) # vertical strip # Split mode: get each panel as its own full-size figure panels <- viz_gene("LTBP1", layout = "split") panels$rna # bulk RNA per-stage forest panels$protein # tissue protein per-stage trajectory panels$cell # scRNA cell-of-origin distribution panels$serum # serum direction strip panels$filter # 7-step filter trail panels$hexagon # 6-axis audit hexagon # Or write each panel to a separate PDF in one call: viz_gene("LTBP1", layout = "split", output_dir = tempdir())