Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
4c56f80
Add exact residue numbering, pLDDT colours and comparison lookup helpers
CedricHermansBIT Sep 29, 2026
e6bda44
Redesign Compare workspace and add indexed, confidence-labelled seque…
CedricHermansBIT Sep 29, 2026
667cc38
Add visible residue numbers, per-residue pLDDT scores and per-chain j…
CedricHermansBIT Sep 29, 2026
95d12d9
Wire aligned-pair selection across table, plot, sequence and model-aw…
CedricHermansBIT Sep 29, 2026
36a38c8
Link NGL superposition clicks, paired highlights and selection-aware …
CedricHermansBIT Sep 29, 2026
bd3cbbb
Show the current sequence position and expose its pLDDT for quick nav…
CedricHermansBIT Sep 29, 2026
cb8a6e7
Make comparison scatter points select paired residues and mark both a…
CedricHermansBIT Sep 29, 2026
97c0e6f
Add direct position jump and selected-residue status to the sequence …
CedricHermansBIT Sep 29, 2026
6cf0334
Lay out paired plot/3D comparison and legible numbered pLDDT sequence…
CedricHermansBIT Sep 29, 2026
0736269
Use NGL stage vector for framing and preserve selected highlights on …
CedricHermansBIT Sep 29, 2026
f95b7bc
Test exact numbered navigation, confidence tiers and aligned-pair lookup
CedricHermansBIT Sep 29, 2026
42cb143
Correct paired alignment index for insertion fixture
CedricHermansBIT Sep 29, 2026
b24ea63
Test paired NGL click mapping, selection highlights and chain-aware v…
CedricHermansBIT Sep 29, 2026
6f92b94
Run linked NGL comparison tests and JavaScript syntax check on Linux …
CedricHermansBIT Sep 29, 2026
e99df28
Exercise numbered sequence jump and aligned 2D/3D comparison in real …
CedricHermansBIT Sep 29, 2026
b140972
Verify exact pLDDT values and confidence strips in live sequence navi…
CedricHermansBIT Sep 29, 2026
8771465
Document linked comparison, permanent residue indices and independent…
CedricHermansBIT Sep 29, 2026
2fe4596
Use Puppeteer multi-element query when checking permanent residue labels
CedricHermansBIT Sep 29, 2026
00f51af
Fix Puppeteer selector to evaluate all visible numbering markers
CedricHermansBIT Sep 29, 2026
97258d3
Avoid redundant NGL highlight rebuilds and camera resets after render…
CedricHermansBIT Sep 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/scientific-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ jobs:
- name: Test browser message handler and source selection
run: |
node --check shinyRam/www/custom.js
node --check shinyRam/www/compare.js
node --check shinyRam/www/prediction.js
node tests/compare-ui.test.cjs
node --check shinyRam/www/density.js
node --check shinyRam/www/plotly-loader.js
node tests/plotly-loader.test.cjs
Expand Down
37 changes: 32 additions & 5 deletions docs/inspection-user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,19 @@ and missing-angle positions. Expand the navigator to reveal independently
scrollable, one-letter residue strips for all selected chains. Clicking a
letter updates the same inspector, Ramachandran point and NGL focus.

The map always retains full biological sequence positions, even when
amino-acid or pre-proline filters hide most plotted points. Residues excluded
by those filters appear dimmed and cannot be selected until the filters are
relaxed; the sequence itself is never shortened into an artificial fragment.
The map always retains true **PDB residue numbers**, even when amino-acid
or pre-proline filters hide most plotted points. The expanded strip labels
every tenth PDB position (plus its first and last residue) and shows the
currently selected number next to the chain heading. Use **Go to residue**
beside any chain, or press Enter in its number field, to find positions
directly, such as residue 104. A hidden residue is still located, with a
message explaining that its selection is blocked by current plot filters.

For predicted models, each residue button also shows its numerical
**pLDDT** below the amino-acid letter. A separate coloured underline and
legend distinguish high, confident, low and very low pLDDT from the
Ramachandran classification fill. Positions with unavailable confidence
show a dash, never an invented zero.

## The residue table

Expand Down Expand Up @@ -55,7 +64,24 @@ If atom records are inconsistent or the parser cannot extract complete multi-mod

The optional **Compare** tab accepts a second PDB accession or PDB/mmCIF file. Choose one chain from each structure. Residues are paired by a bounded global amino-acid sequence alignment, **not by residue number**. The difference in each angle wraps correctly across ±180°. Gaps remain visible and do not receive invented dihedrals; classification differences are reported only for available classifications.

The paired Ramachandran plot displays the two structures in contrasting colours. Export the aligned table as CSV. The optional 3D viewer superposes the selected chains for qualitative inspection. A large-chain comparison can exceed the alignment size limit; select shorter chains instead.
The paired Ramachandran plot and the **3D superposition are side by side**
on wide screens. The 3D viewer initially fits both selected chains rather
than the complete uploaded structures, even if hidden chains are very large.
Selecting a plotted point or aligned table row highlights both corresponding
residues in the superposition and focuses the camera on their local
positions. Clicking a residue in either 3D structure finds its aligned
partner. If one structure contains an insertion/deletion at the selected
position, only the available residue is highlighted and the missing
partner is shown as an alignment gap.

Use **Find aligned pair** to jump by the true residue number in either
selected chain (for example 104), then inspect the primary/comparison
amino acids, φ/ψ angles and wrapped Δφ/Δψ directly below the views.
**Fit both chains** resets the camera without clearing the current
selection. The shared primary-structure inspector and sequence navigator
follow the selected primary residue when it is visible under current plot
filters. Export the aligned table as CSV for reproducibility. A large-chain
comparison can exceed the alignment size limit; select shorter chains instead.

Identical Ramachandran coordinates do not imply identical Cartesian structure, and an angular difference alone is not evidence of a clinically meaningful change. Distinct models from the same structure are related observations, not independent experiments.

Expand All @@ -71,6 +97,7 @@ Record the software version, reference dataset, background, classification mode,
- `Rscript tests/reports.R`: export real vector SVG, PNG and self-contained HTML.
- `Rscript tests/model-integration.R`: an actual multi-model 1D3Z NMR PDB.
- `node tests/ui.test.cjs`: JS message-handler and residue-selection contracts.
- `node tests/compare-ui.test.cjs`: aligned 3D selection, chain-aware framing, invisible viewers and fit-both reset.
- `node tests/ui-browser.cjs`: live Shiny browser workflow, plot-to-NGL/table/sequence selection, default palette, responsive sizing and pairwise self-comparison.

Scientific tests run on Ubuntu and Windows; full-browser checks run on Ubuntu. For changes that affect validation criteria or reference grids, the scientific regression tests must remain unchanged or include explicitly reviewed new reference fixtures.
40 changes: 40 additions & 0 deletions shinyRam/R/inspection.R
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,46 @@ ram_sequence_status <- function(region) {
out
}

# Confidence is an independent per-residue signal: never use its colours to
# replace the Ramachandran classification background.
ram_plddt_color <- function(score) {
vapply(as.numeric(score), function(value) {
if (!is.finite(value)) "#cbd7db" else if (value < 50) "#d75e56"
else if (value < 70) "#d6ac52" else if (value < 90) "#7bbcb1"
else "#126e74"
}, character(1))
}

# Permanent position labels mark every tenth *PDB residue number*, not every
# tenth item in the sequence. Keep insertion codes on labelled residues.
ram_sequence_position_labels <- function(resi, insertion_code = rep("", length(resi))) {
stopifnot(length(resi) == length(insertion_code))
if (!length(resi)) return(character())
index <- seq_along(resi)
label <- index == 1L | index == length(resi) |
(!is.na(resi) & resi %% 10L == 0L)
out <- rep("", length(resi))
out[label] <- paste0(resi[label], ifelse(is.na(insertion_code[label]), "",
insertion_code[label]))
out
}

# Map an NGL/sequence residue to its pair using chain, PDB numbering and
# insertion code. The displayed amino-acid order may contain alignment gaps.
ram_comparison_find <- function(data, side, chain, resi, insertion_code = "") {
stopifnot(side %in% c("a", "b"))
if (!nrow(data) || length(chain) != 1L || length(resi) != 1L ||
length(insertion_code) != 1L || is.na(chain) || is.na(resi) ||
is.na(insertion_code)) return(NA_integer_)
number <- suppressWarnings(as.integer(resi))
if (is.na(number)) return(NA_integer_)
ix <- which(!is.na(data[[paste0("residue_", side)]]) &
data[[paste0("chain_", side)]] == as.character(chain) &
data[[paste0("residue_", side)]] == number &
data[[paste0("insertion_", side)]] == as.character(insertion_code))
if (!length(ix)) NA_integer_ else as.integer(ix[[1L]])
}

# Small overview strips represent *positions*, not aggregate percentages.
# For long chains each strip cell represents a consecutive residue bin.
# A bin takes the highest-priority review state so isolated outliers remain
Expand Down
Loading
Loading