1010import json
1111import math
1212import os
13+ from array import array
1314
1415from ROOT import ( # pylint: disable=import-error,no-name-in-module
1516 TCanvas ,
1617 TFile ,
1718 TGraphErrors ,
19+ TH1F ,
1820 TLegend ,
1921 TPaveText ,
2022 TLine ,
23+ TPad ,
2124 gROOT ,
2225 gStyle ,
2326 kAzure ,
@@ -66,14 +69,40 @@ def get_legend(x_1, y_1, x_2, y_2, num_hists):
6669 leg .SetFillStyle (0 )
6770 return leg
6871
69- def prepare_canvas (cname ):
70- canv = TCanvas (cname , "" )
71- canv .SetCanvasSize (900 , 600 )
72- canv .SetTickx ()
73- canv .SetTicky ()
74- canv .SetLeftMargin (0.15 )
75- canv .SetBottomMargin (0.15 )
76- return canv
72+ def prepare_canvas (cname , logy ):
73+ canv = TCanvas (cname , "" , 443 , 100 , 700 , 700 )
74+ canv .Range (0 , 0 , 1 , 1 )
75+ #canv.SetTickx()
76+ #canv.SetTicky()
77+ #canv.SetLeftMargin(0.15)
78+ #canv.SetBottomMargin(0.15)
79+
80+ canv_top = TPad (f"{ cname } _top" , "" , 0.01 , 0.3 , 0.99 , 0.99 )
81+ if logy :
82+ canv_top .SetLogy ()
83+ canv_top .SetLeftMargin (0.13 )
84+ canv_top .SetRightMargin (0.05 )
85+ canv_top .SetBottomMargin (0.1 )
86+ canv_top .SetTopMargin (0.05 )
87+
88+ canv .Modified ()
89+ canv .cd ()
90+ canvr = TPad (f"{ cname } _ratio" , "" , 0.01 , 0.01 , 0.99 , 0.365 )
91+ canvr .SetBottomMargin (0.25 )
92+ canvr .SetLeftMargin (0.13 )
93+ canvr .SetRightMargin (0.05 )
94+
95+ for canvas in (canv , canv_top , canvr ):
96+ canvas .SetFillColor (0 )
97+ canvas .SetBorderMode (0 )
98+ canvas .SetBorderSize (2 )
99+ canvas .SetFrameBorderMode (0 )
100+ canvas .SetGridy ()
101+ canvr .Draw ()
102+ canv_top .cd ()
103+ canv_top .Draw ()
104+
105+ return canv , canv_top , canvr
77106
78107
79108def save_canvas (canv , cfg , filename ):
@@ -158,14 +187,14 @@ def get_graph_systematics(hist, label, color, cfg):
158187 graph_syst = fin .Get (cfg ["hists" ][label ]["systematics" ][1 ])
159188 else :
160189 graph_syst = TGraphErrors ()
190+ graph_syst .SetName (f"graph_{ label } _syst" )
161191 for binn in range (hist .GetNbinsX ()):
162192 syst_err = combine_syst_errors (cfg ["hists" ][label ]["systematics" ][binn ],
163193 hist .GetBinContent (binn + 1 ))
164194 print (f"Syst error { label } bin { binn + 1 } { syst_err } " )
165195 x_point = hist .GetBinCenter (binn + 1 )
166196 y_point = hist .GetBinContent (binn + 1 )
167- x_width = hist .GetBinWidth (binn + 1 ) / 2.0
168- x_width /= 2.0 # We want syst boxes to be of half-bin width
197+ x_width = hist .GetBinWidth (binn + 1 ) / 4.0
169198 if y_point != 0 :
170199 graph_syst .SetPoint (binn , x_point , y_point )
171200 graph_syst .SetPointError (binn , x_width , syst_err )
@@ -187,11 +216,7 @@ def get_hist_model(label, color, style, cfg):
187216 return hist
188217
189218
190- def plot_compare (cfg ):
191- canv = prepare_canvas (f'c_{ cfg ["histoname" ]} ' )
192- if cfg .get ("log_scale" , False ):
193- canv .SetLogy ()
194-
219+ def plot_compare (cfg , canv_main , canv ):
195220 maxy = 0.
196221 miny = 1000000.
197222
@@ -217,13 +242,20 @@ def plot_compare(cfg):
217242
218243 hists = {}
219244 graphs_syst = []
245+ central_graph = None
220246 for ind , (label , color ) in enumerate (zip (cfg ["hists" ], COLORS )):
221247 hist = get_hist_for_label (label , color , cfg )
222248 print (label )
223249 miny , maxy = get_hist_limits (hist , None , miny , maxy )
224250
225251 canv .cd ()
226252 draw_opt = "same" if ind != 0 or len (hists_models ) > 0 else ""
253+ for axis in (hist .GetXaxis (), hist .GetYaxis ()):
254+ axis .SetLabelFont (42 )
255+ axis .SetLabelSize (0.05 )
256+ axis .SetTitleSize (0.058 )
257+ axis .SetTitleOffset (1.05 )
258+ axis .SetTitleFont (42 )
227259 hist .Draw (draw_opt )
228260 leg .AddEntry (hist , label , "p" )
229261
@@ -235,8 +267,10 @@ def plot_compare(cfg):
235267 miny , maxy = get_hist_limits (hist , graph_syst , miny , maxy )
236268 graph_syst .Draw ("sameE2" )
237269 graphs_syst .append (graph_syst )
270+ if label == cfg ["default" ]:
271+ central_graph = graph_syst
238272
239- margin = 0.1
273+ margin = 1.0
240274 #k = 1.0 - 2 * margin
241275 #rangey = maxy - miny
242276 #miny = miny - margin / k * rangey
@@ -245,7 +279,8 @@ def plot_compare(cfg):
245279 #miny = min(miny - margin * miny, 0)
246280 miny = miny - margin * miny
247281 if miny <= 0 :
248- miny = 0.1
282+ miny = 0.006
283+ maxy = 4000
249284 print (f"Recalculated hist maxy: { maxy + margin * maxy } miny: { miny } " )
250285 for hist_models in hists_models :
251286 hist_models .GetYaxis ().SetRangeUser (miny , maxy + margin * maxy )
@@ -263,48 +298,124 @@ def plot_compare(cfg):
263298 alice_text = get_alice_text (cfg ["alice_text" ])
264299 alice_text .Draw ("same" )
265300
266- return canv , hists , graphs_syst , hists_models , leg , leg_models , alice_text
267-
268-
269- def plot_ratio (cfg , hists ):
270- canvr = prepare_canvas (f'c_ratio_{ cfg ["histoname" ]} ' )
271- #legr = get_legend(0.32, 0.15, 0.82, 0.31, len(cfg["hists"]))
301+ canv_main .cd ()
302+ canv .Draw ()
303+ canv_main .Draw ()
304+
305+ return canv_main , canv , hists , graphs_syst , hists_models , leg , leg_models , alice_text , central_graph
306+
307+
308+ def get_average (hist , graph_syst ):
309+ width_combined = hist .GetBinWidth (hist .GetNbinsX () - 1 ) + hist .GetBinWidth (hist .GetNbinsX ())
310+ val = ((hist .GetBinContent (hist .GetNbinsX () - 1 ) * hist .GetBinWidth (hist .GetNbinsX () - 1 ) + \
311+ hist .GetBinContent (hist .GetNbinsX ()) * hist .GetBinWidth (hist .GetNbinsX ())) / \
312+ width_combined )
313+ err = math .sqrt ((hist .GetBinError (hist .GetNbinsX () - 1 ) * \
314+ hist .GetBinWidth (hist .GetNbinsX () - 1 ) / \
315+ width_combined ) ** 2 + \
316+ (hist .GetBinError (hist .GetNbinsX ()) * \
317+ hist .GetBinWidth (hist .GetNbinsX ()) / \
318+ width_combined ) ** 2 )
319+ syst_err = math .sqrt ((graph_syst .GetErrorYlow (hist .GetNbinsX () - 2 ) * \
320+ hist .GetBinWidth (hist .GetNbinsX () - 1 ) / \
321+ width_combined ) ** 2 + \
322+ (graph_syst .GetErrorYlow (hist .GetNbinsX () - 1 ) * \
323+ hist .GetBinWidth (hist .GetNbinsX ()) / \
324+ width_combined ) ** 2 )
325+ return val , err , syst_err
326+
327+
328+ def hist_for_ratio (hist , graph , central_hist ):
329+ hist2 = TH1F (hist .GetName (), "" , central_hist .GetNbinsX (),
330+ array ('d' , central_hist .GetXaxis ().GetXbins ()))
331+ graph2 = TGraphErrors ()
332+ for binn in range (central_hist .GetNbinsX () - 1 ):
333+ hist2 .SetBinContent (binn + 1 , hist .GetBinContent (binn + 1 ))
334+ hist2 .SetBinError (binn + 1 , hist .GetBinError (binn + 1 ))
335+ graph2 .SetPoint (binn , graph .GetPointX (binn ), graph .GetPointY (binn ))
336+ graph2 .SetPointError (binn , graph .GetErrorX (binn ), graph .GetErrorY (binn ))
337+ val , err , syst_err = get_average (hist , graph )
338+ hist2 .SetBinContent (hist2 .GetNbinsX (), val )
339+ hist2 .SetBinError (hist2 .GetNbinsX (), err )
340+ graph2 .SetPoint (hist2 .GetNbinsX () - 1 , hist2 .GetBinCenter (hist2 .GetNbinsX ()), val )
341+ graph2 .SetPointError (hist2 .GetNbinsX () - 1 , hist2 .GetBinWidth (hist2 .GetNbinsX ()) / 4.0 , syst_err )
342+ return hist2 , graph2
343+
344+
345+ def divide_syst_error (val , val1 , val2 , err1 , err2 , hist , binn ):
346+ return val * math .sqrt ((err1 / val1 ) ** 2 + (err2 / val2 ) ** 2 )
347+
348+
349+ def plot_ratio (cfg , hists , graphs_syst , central_graph , canv , canvr ):
272350 legr = get_legend (* cfg ["legend_ratio" ], len (cfg ["hists" ]))
273351
274352 histsr = []
275- miny = 0.85
276- maxy = 1.15
353+ graphsr = []
354+ miny = 0.45
355+ maxy = 1.55
277356 maxx = 0.0
278357 central_hist = hists [cfg ["default" ]]
279- for ind , (label , color ) in enumerate (zip (hists , COLORS )):
280- print (f"central hist bins: { central_hist .GetNbinsX ()} { label } bins: { hists [label ].GetNbinsX ()} " )
281- if label != cfg ["default" ] and hists [label ].GetNbinsX () == central_hist .GetNbinsX ():
282- #histr = hists[label].Clone()
358+ for ind , (label , graph , color ) in enumerate (zip (hists , graphs_syst , COLORS )):
359+ print (f"central hist bins: { central_hist .GetNbinsX ()} " \
360+ f"{ label } bins: { hists [label ].GetNbinsX ()} " )
361+ if label != cfg ["default" ]: #and hists[label].GetNbinsX() == central_hist.GetNbinsX():
362+ print ("Doing ratio" )
363+ hist_ratio , graph_ratio = hist_for_ratio (hists [label ], graph , central_hist )
283364 histr = central_hist .Clone ()
365+ graphr = central_graph .Clone ()
284366 for binn in range (1 , central_hist .GetNbinsX () + 1 ):
285- histr .SetBinContent (binn , hists [label ].GetBinContent (binn ))
286- histr .SetBinError (binn , hists [label ].GetBinError (binn ))
287- print (f"Central hist bin { binn } { central_hist .GetBinContent (binn )} { label } hist bin: { hists [label ].GetBinContent (binn )} " )
288- histr .SetName (f"h_ratio_{ label } " )
289- histr .SetMarkerColor (color )
290- histr .SetLineColor (color )
291-
367+ histr .SetBinContent (binn , hist_ratio .GetBinContent (binn ))
368+ histr .SetBinError (binn , hist_ratio .GetBinError (binn ))
369+ print (f"Central hist bin { binn } [{ central_hist .GetXaxis ().GetBinLowEdge (binn )} , " \
370+ f"{ central_hist .GetXaxis ().GetBinLowEdge (binn + 1 )} ): { central_hist .GetBinContent (binn )} " \
371+ f"{ label } hist bin [{ hist_ratio .GetXaxis ().GetBinLowEdge (binn )} , " \
372+ f"{ hist_ratio .GetXaxis ().GetBinLowEdge (binn + 1 )} ): { hist_ratio .GetBinContent (binn )} " )
292373 histr .Divide (central_hist )
293- #histr.SetBinContent(histr.GetNbinsX(), 0.0)
294- #histr.SetBinError(histr.GetNbinsX(), 0.0)
295- #histr.SetBinContent(1, 0.0)
296- #histr.SetBinError(1, 0.0)
297- #miny, maxy = get_hist_limits(histr, None, miny, maxy)
298- #for binn in range(histr.GetNbinsX()):
299- # print(f"ratio bin {binn + 1}: {histr.GetBinContent(binn + 1)}")
374+ for binn in range (2 , central_hist .GetNbinsX () + 1 ):
375+ x_err = histr .GetBinWidth (binn ) / 4.0
376+ y_low = divide_syst_error (histr .GetBinContent (binn ),
377+ hist_ratio .GetBinContent (binn ),
378+ central_hist .GetBinContent (binn ),
379+ central_graph .GetErrorYlow (binn - 1 ),
380+ graph_ratio .GetErrorYlow (binn - 1 ), histr , binn )
381+ y_high = divide_syst_error (histr .GetBinContent (binn ),
382+ hist_ratio .GetBinContent (binn ),
383+ central_hist .GetBinContent (binn ),
384+ central_graph .GetErrorYhigh (binn - 1 ),
385+ graph_ratio .GetErrorYhigh (binn - 1 ), histr , binn )
386+ graphr .SetPoint (binn - 1 , histr .GetBinCenter (binn ), histr .GetBinContent (binn ))
387+ graphr .SetPointError (binn - 1 , x_err , x_err , y_low , y_high )
388+ print (f"Central graph bin { binn - 1 } low { central_graph .GetErrorYlow (binn - 1 )} " \
389+ f"{ label } low: { graph_ratio .GetErrorYlow (binn - 1 )} " \
390+ f"up { central_graph .GetErrorYhigh (binn - 1 )} { label } up: { graph_ratio .GetErrorYhigh (binn - 1 )} " )
391+ histr .SetName (f"h_ratio_{ label } " )
392+ graphr .SetName (f"g_ratio_{ label } " )
393+ for fig in (histr , graphr ):
394+ fig .SetMarkerColor (color )
395+ fig .SetLineColor (color )
396+ fig .SetLineWidth (2 )
397+ fig .SetMarkerStyle (1 )
398+ fig .SetMarkerSize (1 )
399+ for binn in range (histr .GetNbinsX ()):
400+ print (f"ratio bin { binn + 1 } : { histr .GetBinContent (binn + 1 )} " )
300401 print (f"maxy { maxy } miny { miny } " )
301- draw_opt = "same" if ind != 0 else ""
302- histr . GetYaxis (). SetTitle ( "Ratio" )
402+ canvr . cd ()
403+ draw_opt = "samePE1" if ind != 0 else "PE1"
303404 histr .SetMaximum (maxy )
304405 histr .SetMinimum (miny )
406+ for axis in (histr .GetXaxis (), histr .GetYaxis ()):
407+ axis .SetLabelFont (42 )
408+ axis .SetLabelSize (0.1 )
409+ axis .SetTitleSize (0.12 )
410+ axis .SetTitleOffset (0.95 )
411+ axis .SetTitleFont (42 )
412+ histr .GetYaxis ().SetTitleOffset (0.5 )
413+ histr .GetYaxis ().SetTitle ("Ratio" )
305414 histr .Draw (draw_opt )
415+ graphr .Draw ("sameE2" )
306416 legr .AddEntry (histr , label , "p" )
307417 histsr .append (histr )
418+ graphsr .append (graphr )
308419 maxx = max (maxx , histr .GetBinLowEdge (histr .GetNbinsX () + 1 ))
309420
310421 line = TLine (0.0 , 1.0 , maxx , 1.0 )
@@ -313,9 +424,12 @@ def plot_ratio(cfg, hists):
313424 line .SetLineStyle (kDashed )
314425 line .Draw ()
315426
316- legr .Draw ()
427+ #legr.Draw()
428+ canv .cd ()
429+ canvr .Draw ()
430+ canv .Draw ()
317431
318- return canvr , histsr , legr , line
432+ return canv , canvr , histsr , graphsr , legr , line
319433
320434
321435def calc_systematics (cfg , hists ):
@@ -351,6 +465,7 @@ def main():
351465 gROOT .SetBatch (True )
352466
353467 gStyle .SetOptStat (0 )
468+ gStyle .SetOptTitle (0 )
354469 gStyle .SetFrameLineWidth (2 )
355470
356471 parser = argparse .ArgumentParser (description = "Arguments to pass" )
@@ -363,26 +478,34 @@ def main():
363478 with TFile (os .path .join (cfg ["output" ]["outdir" ],
364479 f'{ cfg ["output" ]["file" ]} .root' ), "recreate" ) as output :
365480
366- canv , hists , graphs_syst , hists_models , leg , leg_models , alice_text = plot_compare (cfg ) # pylint: disable=unused-variable
481+ canv , canv_top , canvr = prepare_canvas (f'c_{ cfg ["histoname" ]} ' , cfg .get ("log_scale" , False ))
482+ canv , canv_top , hists , graphs_syst , hists_models , leg , leg_models , alice_text , central_graph = plot_compare (cfg , canv , canv_top ) # pylint: disable=unused-variable
367483 output .cd ()
368- canv .Write ()
369- save_canvas (canv , cfg , cfg ["output" ]["file" ])
484+ canv_top .Write ()
485+ save_canvas (canv_top , cfg , f' { cfg ["output" ]["file" ]} _top' )
370486 for _ , hist in hists .items ():
371487 hist .Write ()
372488 for graph in graphs_syst :
373489 graph .Write ()
374490 for hist in hists_models :
375491 hist .Write ()
376492
377- canvr , histr , legr , line = plot_ratio (cfg , hists )
493+ canv , canvr , histr , graphr , legr , line = plot_ratio (cfg , hists , graphs_syst , central_graph , canv , canvr )
378494 output .cd ()
495+ canv .Write ()
496+ save_canvas (canv , cfg , f'{ cfg ["output" ]["file" ]} ' )
379497 canvr .Write ()
380498 save_canvas (canvr , cfg , f'{ cfg ["output" ]["file" ]} _ratio' )
381499 for hist in histr :
382500 hist .Write ()
501+ for graph in graphr :
502+ graph .Write ()
383503
384504 calc_systematics (cfg , hists )
385505
506+ canv_top .Delete ()
507+ canvr .Delete ()
508+
386509
387510if __name__ == "__main__" :
388511 main ()
0 commit comments