Skip to content

Commit e385304

Browse files
committed
Wire Sequence View residue click to filter the Tag Table
Clicking a covered amino acid in the Sequence View now filters the Tag Table to the tags covering that residue, matching the legacy cross-link. - _build_sequence_frame emits a sequence_offset column so the SequenceView can report protein-absolute residue positions even when the displayed sequence is sliced to the proteoform substring (offset is 0 / unchanged for the bundled example proteoforms). - SequenceView interactivity gains {selectedAApos: "residue_position"} (keeps the peak_id mapping); the Tag Table gains range_filters={selectedAApos: ("StartPos", "EndPos")} alongside the existing proteoform filter, so it shows tags with StartPos <= pos <= EndPos.
1 parent 85d20d4 commit e385304

1 file changed

Lines changed: 32 additions & 1 deletion

File tree

content/FLASHTnT/FLASHTnTViewerOI.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@
7474
TAG_KEY = "tagData"
7575
TAG_MASSES_KEY = "tagMasses"
7676
MASS_KEY = "massIndex"
77+
# Residue -> Tag-Table cross-link (legacy `selectionStore.selectedAApos`).
78+
# Clicking a covered residue in the SequenceView sets this to the residue's
79+
# PROTEIN-ABSOLUTE 0-based position; the Tag Table range-filters its rows to tags
80+
# whose [StartPos, EndPos] span contains that position (StartPos <= pos <= EndPos),
81+
# clearing on re-click (toggle). The SequenceView publishes protein-absolute
82+
# coordinates via the per-proteoform `sequence_offset` carried in the sequence
83+
# frame, so this matches StartPos/EndPos for ALL proteoforms (not just the
84+
# bundled full-protein example).
85+
AA_KEY = "selectedAApos"
7786

7887

7988
def _component_cache_dir(file_manager, experiment_id: str) -> str:
@@ -223,6 +232,11 @@ def _build_tag_table(file_manager, experiment_id: str, cache_dir: str):
223232
cache_id=f"tag_table_{experiment_id}",
224233
data=tag_lf,
225234
filters={PROTEIN_KEY: "proteoform_index"},
235+
# Residue -> Tag-Table cross-link (legacy StartPos<=selectedAApos<=EndPos):
236+
# when a covered residue is clicked in the SequenceView, AA_KEY holds its
237+
# protein-absolute position and the tags are narrowed to those whose span
238+
# contains it; cleared (no-op) when no residue is selected.
239+
range_filters={AA_KEY: ("StartPos", "EndPos")},
226240
interactivity={TAG_KEY: "TagIndex"},
227241
index_field="TagIndex",
228242
column_definitions=_TAG_COLUMN_DEFINITIONS,
@@ -357,6 +371,7 @@ def _build_sequence_frame(
357371
coverages: List[list] = []
358372
max_coverages: List[float] = []
359373
fixed_mods: List[list] = []
374+
sequence_offsets: List[int] = []
360375
for entry in rows:
361376
pid = entry.get("proteoform_index")
362377
if pid is None:
@@ -370,15 +385,26 @@ def _build_sequence_frame(
370385
# negative/absent bound means render the full protein.
371386
if start is None or end is None or start < 0 or end < 0:
372387
sub_seq, sub_cov = full, cov
388+
offset = 0
373389
else:
374390
sub_seq, sub_cov = full[start:end + 1], cov[start:end + 1]
391+
offset = int(start)
392+
# Coordinate decision (a): the displayed sequence is the proteoform
393+
# substring starting at protein position `start`, so grid index i maps to
394+
# protein-absolute position `start + i`. We carry `offset` (clamped to >= 0,
395+
# mirroring the legacy AminoAcidCell.start getter) so the residue-click
396+
# cross-link emits protein-absolute positions matching tag StartPos/EndPos.
397+
# For the bundled example (start=0, end=-2 => full protein) offset is 0, so
398+
# the emitted position equals the grid index exactly as before — the example
399+
# render and coordinates are unchanged.
375400
proteoform_indices.append(int(pid))
376401
sequences.append("".join(str(a) for a in sub_seq))
377402
coverages.append([float(c) for c in sub_cov])
378403
mc = entry.get("maxCoverage")
379404
max_coverages.append(float(mc) if mc is not None else 0.0)
380405
fm = entry.get("fixed_modifications") or []
381406
fixed_mods.append([str(m) for m in fm])
407+
sequence_offsets.append(max(offset, 0))
382408

383409
if not proteoform_indices:
384410
return None
@@ -390,6 +416,7 @@ def _build_sequence_frame(
390416
"coverage": coverages,
391417
"maxCoverage": max_coverages,
392418
"fixed_modifications": fixed_mods,
419+
"sequence_offset": sequence_offsets,
393420
})
394421
return out.lazy()
395422

@@ -424,7 +451,11 @@ def _build_sequence_view(file_manager, experiment_id: str, cache_dir: str):
424451
sequence_data=seq_frame,
425452
peaks_data=peaks,
426453
filters={PROTEIN_KEY: "proteoform_index"},
427-
interactivity={MASS_KEY: "peak_id"},
454+
# Two click sources: a fragment-table row click sets MASS_KEY to the
455+
# matched peak's peak_id (combined-spectrum cross-link), and a SequenceView
456+
# RESIDUE click sets AA_KEY to the clicked residue's protein-absolute
457+
# position via the "residue_position" sentinel (Tag-Table range filter).
458+
interactivity={MASS_KEY: "peak_id", AA_KEY: "residue_position"},
428459
deconvolved=True,
429460
compute_fixed_mods=True,
430461
settings=settings,

0 commit comments

Comments
 (0)