@@ -1142,7 +1142,6 @@ def _draw_stacked_panel(
11421142 h_mc_sumw2 ,
11431143 mc_scaled ,
11441144 mc_norm_factor ,
1145- bins ,
11461145 * ,
11471146 log_scale = False ,
11481147 style = None ,
@@ -1211,7 +1210,8 @@ def _get_grouped_vals(hist_obj, grouping_map):
12111210
12121211 mc_sumw2_vals [proc_name ] = grouped_vals + fallback_vals
12131212
1214- bins = np .array (bins , dtype = float , copy = True )
1213+ bins = h_data [{"process" : sum }].as_hist ({}).axes [var ].edges
1214+ bins = np .append (bins , [bins [- 1 ] + (bins [- 1 ] - bins [- 2 ]) * 0.3 ])
12151215
12161216 log_scale_requested = bool (log_scale )
12171217 log_y_baseline = None
@@ -3308,206 +3308,6 @@ def make_region_stacked_ratio_fig(
33083308 if getattr (h_data , "empty" , False ) and h_data .empty ():
33093309 return None
33103310
3311- def _clone_histogram (obj ):
3312- if obj is None :
3313- return None
3314- if hasattr (obj , "copy" ):
3315- return obj .copy ()
3316- return copy .deepcopy (obj )
3317-
3318- def _extract_nominal_histogram_edges (histogram , axis_name ):
3319- try :
3320- hist_view = histogram [{"process" : sum }].as_hist ({})
3321- edges = np .array (hist_view .axes [axis_name ].edges , dtype = float , copy = True )
3322- values = np .asarray (hist_view .values (flow = True ), dtype = float )
3323- if values .size >= 2 :
3324- values = values [1 :- 1 ]
3325- else :
3326- values = np .asarray (hist_view .values (), dtype = float )
3327- return edges , values
3328- except Exception :
3329- return None , None
3330-
3331- def _locate_edge_index (edges , value ):
3332- matches = np .nonzero (np .isclose (edges , value , rtol = 0 , atol = 1e-9 ))[0 ]
3333- if matches .size :
3334- return int (matches [0 ])
3335- raise ValueError
3336-
3337- def _rebin_syst_arrays (
3338- err_up ,
3339- err_down ,
3340- ratio_up ,
3341- ratio_down ,
3342- nominal_values ,
3343- old_edges ,
3344- new_edges ,
3345- ):
3346- if (
3347- nominal_values is None
3348- or old_edges is None
3349- or new_edges is None
3350- or nominal_values .size != max (len (old_edges ) - 1 , 0 )
3351- ):
3352- return err_up , err_down , ratio_up , ratio_down
3353-
3354- old_edge_count = len (old_edges )
3355- new_edge_count = len (new_edges )
3356- if old_edge_count < 2 or new_edge_count < 2 :
3357- return err_up , err_down , ratio_up , ratio_down
3358-
3359- try :
3360- start_indices = [
3361- _locate_edge_index (old_edges , new_edges [idx ])
3362- for idx in range (new_edge_count - 1 )
3363- ]
3364- end_indices = [
3365- _locate_edge_index (old_edges , new_edges [idx + 1 ])
3366- for idx in range (new_edge_count - 1 )
3367- ]
3368- except ValueError :
3369- logger .warning (
3370- "Unable to rebin systematic arrays: custom bin edges do not align with the original histogram binning."
3371- )
3372- return err_up , err_down , ratio_up , ratio_down
3373-
3374- nominal_values = np .asarray (nominal_values , dtype = float )
3375- rebinned_nominal = np .zeros (new_edge_count - 1 , dtype = float )
3376-
3377- if err_up is not None :
3378- err_up = np .asarray (err_up , dtype = float )
3379- syst_up_deltas = np .clip (err_up - nominal_values , a_min = 0 , a_max = None )
3380- rebinned_err_up = np .zeros_like (rebinned_nominal )
3381- else :
3382- syst_up_deltas = None
3383- rebinned_err_up = None
3384-
3385- if err_down is not None :
3386- err_down = np .asarray (err_down , dtype = float )
3387- syst_down_deltas = np .clip (nominal_values - err_down , a_min = 0 , a_max = None )
3388- rebinned_err_down = np .zeros_like (rebinned_nominal )
3389- else :
3390- syst_down_deltas = None
3391- rebinned_err_down = None
3392-
3393- for idx , (start , end ) in enumerate (zip (start_indices , end_indices )):
3394- if end < start :
3395- start , end = end , start
3396- rebinned_nominal [idx ] = nominal_values [start :end ].sum ()
3397- if rebinned_err_up is not None :
3398- delta = syst_up_deltas [start :end ]
3399- rebinned_err_up [idx ] = np .clip (
3400- rebinned_nominal [idx ] + np .sqrt (np .sum (delta ** 2 )),
3401- a_min = 0 ,
3402- a_max = None ,
3403- )
3404- if rebinned_err_down is not None :
3405- delta = syst_down_deltas [start :end ]
3406- rebinned_err_down [idx ] = np .clip (
3407- rebinned_nominal [idx ] - np .sqrt (np .sum (delta ** 2 )),
3408- a_min = 0 ,
3409- a_max = None ,
3410- )
3411-
3412- if rebinned_err_up is not None :
3413- rebinned_ratio_up = _safe_divide (
3414- rebinned_err_up ,
3415- rebinned_nominal ,
3416- default = 1.0 ,
3417- zero_over_zero = 1.0 ,
3418- )
3419- else :
3420- rebinned_ratio_up = ratio_up
3421-
3422- if rebinned_err_down is not None :
3423- rebinned_ratio_down = _safe_divide (
3424- rebinned_err_down ,
3425- rebinned_nominal ,
3426- default = 1.0 ,
3427- zero_over_zero = 1.0 ,
3428- )
3429- else :
3430- rebinned_ratio_down = ratio_down
3431-
3432- return (
3433- rebinned_err_up if rebinned_err_up is not None else err_up ,
3434- rebinned_err_down if rebinned_err_down is not None else err_down ,
3435- rebinned_ratio_up ,
3436- rebinned_ratio_down ,
3437- )
3438-
3439- orig_edges , orig_nominal_vals = _extract_nominal_histogram_edges (h_mc , var )
3440- bins_array = None
3441- if bins :
3442- rebin_edges = np .array (bins , dtype = float , copy = True )
3443- axis_name = var
3444- try :
3445- axis_name = getattr (h_mc .axes [var ], "name" , var )
3446- except Exception :
3447- axis_name = var
3448-
3449- new_axis = hist .axis .Variable (rebin_edges , name = axis_name )
3450-
3451- h_mc = _clone_histogram (h_mc )
3452- h_data = _clone_histogram (h_data )
3453- h_mc = h_mc .rebin (axis_name , new_axis )
3454- h_data = h_data .rebin (axis_name , new_axis )
3455-
3456- if h_mc_sumw2 is not None :
3457- h_mc_sumw2 = _clone_histogram (h_mc_sumw2 )
3458- try :
3459- h_mc_sumw2 = h_mc_sumw2 .rebin (axis_name , new_axis )
3460- except Exception :
3461- logger .warning (
3462- (
3463- "Failed to rebin MC sumw2 histogram for variable '%s'; "
3464- "disabling MC statistical uncertainty for rebinned plots."
3465- ),
3466- var ,
3467- )
3468- h_mc_sumw2 = None
3469-
3470- if any (
3471- arr is not None
3472- for arr in (err_p_syst , err_m_syst , err_ratio_p_syst , err_ratio_m_syst )
3473- ):
3474- (
3475- err_p_syst ,
3476- err_m_syst ,
3477- err_ratio_p_syst ,
3478- err_ratio_m_syst ,
3479- ) = _rebin_syst_arrays (
3480- err_p_syst ,
3481- err_m_syst ,
3482- err_ratio_p_syst ,
3483- err_ratio_m_syst ,
3484- orig_nominal_vals ,
3485- orig_edges ,
3486- rebin_edges ,
3487- )
3488-
3489- if rebin_edges .size :
3490- if rebin_edges .size >= 2 :
3491- last_width = rebin_edges [- 1 ] - rebin_edges [- 2 ]
3492- else :
3493- last_width = rebin_edges [- 1 ]
3494- bins_array = np .append (rebin_edges , [rebin_edges [- 1 ] + last_width * 0.3 ])
3495- else :
3496- bins_array = rebin_edges
3497- else :
3498- default_edges = h_data [{"process" : sum }].as_hist ({}).axes [var ].edges
3499- default_edges = np .array (default_edges , dtype = float , copy = True )
3500- if default_edges .size :
3501- if default_edges .size >= 2 :
3502- last_width = default_edges [- 1 ] - default_edges [- 2 ]
3503- else :
3504- last_width = default_edges [- 1 ]
3505- bins_array = np .append (
3506- default_edges , [default_edges [- 1 ] + last_width * 0.3 ]
3507- )
3508- else :
3509- bins_array = default_edges
3510-
35113311 default_colors = [
35123312 "tab:blue" ,
35133313 "darkgreen" ,
@@ -3601,7 +3401,6 @@ def _rebin_syst_arrays(
36013401 h_mc_sumw2 ,
36023402 mc_scaled ,
36033403 mc_norm_factor ,
3604- bins_array ,
36053404 log_scale = log_scale ,
36063405 style = style ,
36073406 )
0 commit comments