7474TAG_KEY = "tagData"
7575TAG_MASSES_KEY = "tagMasses"
7676MASS_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
7988def _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