2626 from qtpy .QtWidgets import QWidget
2727
2828
29+ def alpha_label (index : int ) -> str :
30+ """Return an alphabetic label for a 0-based index.
31+
32+ Mapping: ``0 → "a"``, ``1 → "b"``, ..., ``25 → "z"``, ``26 → "aa"``, ...
33+
34+ Used to label axis-marker cursors (X_MARKERS / Y_MARKERS) and the
35+ corresponding rows in the merged result label, so they can be matched
36+ to the dashed cursors drawn on the plot.
37+ """
38+ if index < 0 :
39+ return ""
40+ label = ""
41+ n = index
42+ while True :
43+ label = chr (ord ("a" ) + (n % 26 )) + label
44+ n = n // 26 - 1
45+ if n < 0 :
46+ break
47+ return label
48+
49+
2950@dataclasses .dataclass
3051class ResultData :
3152 """Result data associated to a shapetype"""
@@ -355,6 +376,32 @@ def resultadapter_to_html(
355376 # Remove roi_index column for display calculations
356377 display_df = df .drop (columns = ["roi_index" ]) if "roi_index" in df .columns else df
357378
379+ # If this is a marker result (XY/X/Y_MARKERS) and the user opted in,
380+ # prepend a "marker label" column so each row in the displayed table
381+ # can be matched with the cross / dashed cursor drawn on the plot
382+ # (XY markers use numeric labels ``#1, #2, ...``; axis markers use
383+ # alphabetic labels ``a, b, c, ...``). Forces the fast HTML path
384+ # below to honor the injected column (the standard ``adapter.to_html``
385+ # path does not see DataFrame mutations made here).
386+ marker_labels_injected = False
387+ result = adapter .result
388+ if ( # pylint: disable=too-many-boolean-expressions
389+ Conf .view .show_marker_labels_in_table .get (True )
390+ and hasattr (result , "is_xy_markers" )
391+ and (
392+ result .is_xy_markers ()
393+ or result .is_x_markers ()
394+ or (hasattr (result , "is_y_markers" ) and result .is_y_markers ())
395+ )
396+ ):
397+ if result .is_xy_markers ():
398+ marker_col = [f"#{ i + 1 } " for i in range (len (display_df ))]
399+ else :
400+ marker_col = [alpha_label (i ) for i in range (len (display_df ))]
401+ display_df = display_df .copy ()
402+ display_df .insert (0 , _ ("Marker" ), marker_col )
403+ marker_labels_injected = True
404+
358405 # For merged labels, limit display columns for readability
359406 max_display_cols = Conf .view .max_cols_in_label .get (20 )
360407 num_cols = len (display_df .columns )
@@ -369,7 +416,7 @@ def resultadapter_to_html(
369416 num_cells = num_rows * num_cols
370417
371418 # Check if truncation is needed BEFORE calling to_html()
372- if num_cells > max_cells or cols_truncated :
419+ if num_cells > max_cells or cols_truncated or marker_labels_injected :
373420 # Calculate how many rows we can display given max_cells
374421 max_rows = max (1 , max_cells // num_cols ) if num_cols > 0 else num_rows
375422
@@ -379,6 +426,10 @@ def resultadapter_to_html(
379426 # Generate HTML directly from truncated DataFrame for performance
380427 # This is MUCH faster than calling adapter.to_html() on full data
381428 html_kwargs = {"border" : 0 }
429+ if marker_labels_injected :
430+ # Hide pandas' numeric index since the injected "Marker"
431+ # column already provides per-row identification.
432+ html_kwargs ["index" ] = False
382433 html_kwargs .update (kwargs )
383434
384435 # Format numeric columns efficiently
0 commit comments