@@ -42,6 +42,7 @@ def __init__(self, project_lib: ProjectLib, parent=None):
4242 self ._sld_x_reversed = False
4343 self ._scale_shown = False
4444 self ._bkg_shown = False
45+ self ._residual_range_cache = None
4546 self ._chartRefs = {
4647 'QtCharts' : {
4748 'samplePage' : {
@@ -65,6 +66,7 @@ def reset_data(self):
6566 self ._sample_data = {}
6667 self ._model_data = {}
6768 self ._sld_data = {}
69+ self ._residual_range_cache = None
6870 console .debug (IO .formatMsg ('sub' , 'Sample and SLD data cleared' ))
6971
7072 def _apply_rq4 (self , x , y ):
@@ -454,13 +456,22 @@ def experimentMinY(self):
454456 return np .log10 (valid_y .min ())
455457
456458 # Residual ranges
459+ def _invalidate_residual_range_cache (self ):
460+ """Clear the cached residual range so it is recomputed on next access."""
461+ self ._residual_range_cache = None
462+
457463 def _get_residual_range (self ) -> tuple :
458464 """Return (min_x, max_x, min_y, max_y) for the residual chart.
459465
460466 X range matches the filtered analysis domain. Y range is computed
461467 from residual values across all currently selected experiments, with
462468 a 10 % margin. Safe fallback values are returned when data is empty.
469+
470+ The result is cached until invalidated by ``_invalidate_residual_range_cache``.
463471 """
472+ if self ._residual_range_cache is not None :
473+ return self ._residual_range_cache
474+
464475 min_x , max_x = float ('inf' ), float ('-inf' )
465476 min_y , max_y = float ('inf' ), float ('-inf' )
466477
@@ -496,10 +507,13 @@ def _get_residual_range(self) -> tuple:
496507 console .debug (f'Error computing residual range: { e } ' )
497508
498509 if min_x == float ('inf' ):
499- return (0.0 , 1.0 , - 1.0 , 1.0 )
510+ result = (0.0 , 1.0 , - 1.0 , 1.0 )
511+ else :
512+ y_margin = max (abs (min_y ), abs (max_y )) * 0.10 or 0.1
513+ result = (min_x , max_x , min_y - y_margin , max_y + y_margin )
500514
501- y_margin = max ( abs ( min_y ), abs ( max_y )) * 0.10 or 0.1
502- return ( min_x , max_x , min_y - y_margin , max_y + y_margin )
515+ self . _residual_range_cache = result
516+ return result
503517
504518 @Property (float , notify = sampleChartRangesChanged )
505519 def residualMinX (self ) -> float :
@@ -674,7 +688,7 @@ def _get_aligned_analysis_values(self, experiment_index: int) -> list:
674688 calc_idx = 0
675689 for point in exp_data .data_points ():
676690 q = point [0 ]
677- if self ._project_lib .q_min < q < self ._project_lib .q_max :
691+ if self ._project_lib .q_min <= q <= self ._project_lib .q_max :
678692 r_meas = point [1 ]
679693 calc_y_val = calc_y [calc_idx ] if calc_idx < len (calc_y ) else r_meas
680694 sigma_linear = float (np .sqrt (max (point [2 ], 0.0 )))
@@ -747,6 +761,7 @@ def refreshExperimentPage(self):
747761
748762 def refreshAnalysisPage (self ):
749763 self ._model_data = {}
764+ self ._invalidate_residual_range_cache ()
750765 self .drawCalculatedAndMeasuredOnAnalysisChart ()
751766 # Notify the residual chart to re-poll data and ranges
752767 self .sampleChartRangesChanged .emit ()
0 commit comments