34
34
logger = law .logger .get_logger (__name__ )
35
35
36
36
37
- def reverse_inf_proc (proc ):
38
- """
39
- Helper function that reverses the transformations done by inf_proc.
40
- """
41
- if proc .startswith ("ggHH_" ):
42
- # Adjust pattern to split the last part into two groups
43
- pattern = r"ggHH_kl_([mp\d]+)_kt_([mp\d]+)_([a-zA-Z\d]{3})([a-zA-Z\d]+)"
44
- replacement = r"hh_ggf_\3_\4_kl\1_kt\2"
45
- return re .sub (pattern , replacement , proc )
46
- elif proc .startswith ("qqHH_" ):
47
- # Adjust pattern to split the last part into two groups
48
- pattern = r"qqHH_CV_([mp\d]+)_C2V_([mp\d]+)_kl_([mp\d]+)_([a-zA-Z\d]{3})([a-zA-Z\d]+)"
49
- replacement = r"hh_vbf_\4_\5_kv\1_k2v\2_kl\3"
50
- return re .sub (pattern , replacement , proc )
51
- elif proc == "qqH" :
52
- pattern = r"qqH"
53
- replacement = r"h_vbf"
54
- return re .sub (pattern , replacement , proc )
55
- elif proc == "ggH" :
56
- pattern = r"ggH"
57
- replacement = r"h_ggf"
58
- return re .sub (pattern , replacement , proc )
59
- elif proc == "ggZH" :
60
- pattern = r"ggZH"
61
- replacement = r"zh_gg"
62
- return re .sub (pattern , replacement , proc )
63
- elif "H" in proc :
64
- proc = proc .lower ()
65
- return proc
66
- else :
67
- # If the string doesn't match the patterns, return it unchanged
68
- return proc
37
+ # def reverse_inf_proc(proc):
38
+ # """
39
+ # Helper function that reverses the transformations done by inf_proc.
40
+ # """
41
+ # if proc.startswith("ggHH_"):
42
+ # # Adjust pattern to split the last part into two groups
43
+ # pattern = r"ggHH_kl_([mp\d]+)_kt_([mp\d]+)_([a-zA-Z\d]{3})([a-zA-Z\d]+)"
44
+ # replacement = r"hh_ggf_\3_\4_kl\1_kt\2"
45
+ # return re.sub(pattern, replacement, proc)
46
+ # elif proc.startswith("qqHH_"):
47
+ # # Adjust pattern to split the last part into two groups
48
+ # pattern = r"qqHH_CV_([mp\d]+)_C2V_([mp\d]+)_kl_([mp\d]+)_([a-zA-Z\d]{3})([a-zA-Z\d]+)"
49
+ # replacement = r"hh_vbf_\4_\5_kv\1_k2v\2_kl\3"
50
+ # return re.sub(pattern, replacement, proc)
51
+ # elif proc == "qqH":
52
+ # pattern = r"qqH"
53
+ # replacement = r"h_vbf"
54
+ # return re.sub(pattern, replacement, proc)
55
+ # elif proc == "ggH":
56
+ # pattern = r"ggH"
57
+ # replacement = r"h_ggf"
58
+ # return re.sub(pattern, replacement, proc)
59
+ # elif proc == "ggZH":
60
+ # pattern = r"ggZH"
61
+ # replacement = r"zh_gg"
62
+ # return re.sub(pattern, replacement, proc)
63
+ # elif "H" in proc:
64
+ # proc = proc.lower()
65
+ # return proc
66
+ # else:
67
+ # # If the string doesn't match the patterns, return it unchanged
68
+ # return proc
69
69
70
70
71
71
def load_hists_uproot (fit_diagnostics_path , fit_type ):
@@ -152,9 +152,8 @@ def get_hists_from_multidimfit(tfile):
152
152
apply_process_settings ,
153
153
)
154
154
155
-
156
155
def plot_postfit_shapes (
157
- hists : OrderedDict [od .Process , hist .Hist ],
156
+ h : OrderedDict , # [od.Process, hist.Hist],
158
157
config_inst : od .Config ,
159
158
category_inst : od .Category ,
160
159
variable_insts : list [od .Variable ],
@@ -168,7 +167,7 @@ def plot_postfit_shapes(
168
167
** kwargs ,
169
168
) -> tuple (plt .Figure , tuple (plt .Axes )):
170
169
variable_inst = law .util .make_tuple (variable_insts )[0 ]
171
- hists = apply_process_settings (hists , process_settings )
170
+ hists = apply_process_settings (h . copy () , process_settings )
172
171
plot_config = prepare_plot_config (
173
172
hists ,
174
173
shape_norm = shape_norm ,
@@ -232,11 +231,20 @@ class PlotPostfitShapes(
232
231
description = "Whether to do prefit or postfit plots; defaults to False" ,
233
232
)
234
233
234
+ @property
235
+ def fit_type (self ) -> str :
236
+ if self .prefit :
237
+ fit_type = "prefit"
238
+ else :
239
+ fit_type = "postfit"
240
+ self ._fit_type = fit_type
241
+ return self ._fit_type
242
+
235
243
def requires (self ):
236
244
return {}
237
245
238
246
def output (self ):
239
- return {"plots" : self .target ("plots " , dir = True )}
247
+ return {"plots" : self .target (f"plots_ { self . fit_type } " , dir = True )}
240
248
241
249
@view_output_plots
242
250
def run (self ):
@@ -246,21 +254,18 @@ def run(self):
246
254
)
247
255
248
256
outp = self .output ()
249
- if self .prefit :
250
- fit_type = "prefit"
251
- else :
252
- fit_type = "postfit"
253
257
254
- all_hists = load_hists_uproot (self .fit_diagnostics_file , fit_type )
258
+ all_hists = load_hists_uproot (self .fit_diagnostics_file , self . fit_type )
255
259
process_insts = list (map (self .config_inst .get_process , self .processes ))
256
260
257
261
for channel , h_in in all_hists .items ():
258
262
has_category = self .inference_model_inst .has_category (channel )
259
263
if not has_category :
260
264
logger .warning (f"Category { channel } is not part of the inference model { self .inference_model } " )
261
265
262
- hists = defaultdict (OrderedDict )
266
+ hist_map = defaultdict (list )
263
267
268
+ # First map process inst for plotting to processes of root shapes
264
269
for proc_key in list (h_in .keys ()):
265
270
proc_inst = None
266
271
# try getting the config process via InferenceModel
@@ -272,23 +277,32 @@ def run(self):
272
277
# try getting proc inst directly via config
273
278
proc_inst = self .config_inst .get_process (proc_key , default = None )
274
279
275
- # replace string keys with process instances
280
+ # replace string keys with process instances
281
+ # map HHinference processes to plotting proc_inst
276
282
if proc_inst :
277
283
plot_proc = [
278
284
proc for proc in process_insts if proc .has_process (proc_inst ) or proc .name == proc_inst .name
279
285
]
280
286
if len (plot_proc ) != 1 :
281
287
if len (plot_proc ) > 1 :
282
- raise Exception (f"{ proc_key } was assigned to more then one porcess insts ({ plot_proc } ) " )
288
+ logger . warning (f"{ proc_key } was assigned to more then one process insts ({ plot_proc } ) " )
283
289
else :
284
290
logger .warning (f"{ proc_key } in root file, but won't be plotted." )
285
- continue
291
+ continue
286
292
287
- if plot_proc [0 ] not in hists :
288
- hists [plot_proc [0 ]] = {}
289
- hists [plot_proc [0 ]] = h_in [proc_key ]
293
+ if plot_proc [0 ] not in hist_map :
294
+ hist_map [plot_proc [0 ]] = [proc_key ]
290
295
else :
291
- hists [plot_proc [0 ]] = hists [plot_proc [0 ]] + h_in [proc_key ]
296
+ hist_map [plot_proc [0 ]].append (proc_key )
297
+
298
+ # Plot Pre/Postfit plot for each channel
299
+ for channel , h_in in all_hists .items ():
300
+ hists = defaultdict (OrderedDict )
301
+ for proc in hist_map :
302
+ plot_proc = proc .copy ()
303
+ hists [plot_proc ] = h_in [hist_map [proc ][0 ]]
304
+ for p in hist_map [proc ][1 :]:
305
+ hists [plot_proc ] += h_in [p ]
292
306
293
307
if has_category :
294
308
inference_category = self .inference_model_inst .get_category (channel )
@@ -299,14 +313,18 @@ def run(self):
299
313
config_category = od .Category (channel , id = 1 )
300
314
variable_inst = od .Variable ("dummy" )
301
315
316
+ # take copy of proc_inst so labeling, sclaing etc is not modified on proc inst directly
317
+
318
+ # __import__("IPYthon").embed()
319
+ h = hists .copy ()
302
320
# call the plot function
303
321
fig , _ = self .call_plot_func (
304
322
self .plot_function ,
305
- hists = hists ,
323
+ h = h ,
306
324
config_inst = self .config_inst ,
307
325
category_inst = config_category ,
308
326
variable_insts = variable_inst ,
309
327
** self .get_plot_parameters (),
310
328
)
311
329
312
- outp ["plots" ].child (f"{ channel } _{ fit_type } .pdf" , type = "f" ).dump (fig , formatter = "mpl" )
330
+ outp ["plots" ].child (f"{ channel } _{ self . fit_type } .pdf" , type = "f" ).dump (fig , formatter = "mpl" )
0 commit comments