CombineHarvester
plotting.py
Go to the documentation of this file.
1 from __future__ import absolute_import
2 from __future__ import print_function
3 import ROOT as R
4 import math
5 from array import array
6 import re
7 import json
8 import types
9 import six
10 import ctypes
11 from six.moves import range
12 
13 COL_STORE = []
14 
15 
20 
21 
22 def SetTDRStyle():
23  """Sets the PubComm recommended style
24 
25  Just a copy of <http://ghm.web.cern.ch/ghm/plots/MacroExample/tdrstyle.C>
26  @sa ModTDRStyle() to use this style with some additional customisation.
27  """
28  # For the canvas:
29  R.gStyle.SetCanvasBorderMode(0)
30  R.gStyle.SetCanvasColor(R.kWhite)
31  R.gStyle.SetCanvasDefH(600) # Height of canvas
32  R.gStyle.SetCanvasDefW(600) # Width of canvas
33  R.gStyle.SetCanvasDefX(0) # POsition on screen
34  R.gStyle.SetCanvasDefY(0)
35 
36  # For the Pad:
37  R.gStyle.SetPadBorderMode(0)
38  # R.gStyle.SetPadBorderSize(Width_t size = 1)
39  R.gStyle.SetPadColor(R.kWhite)
40  R.gStyle.SetPadGridX(False)
41  R.gStyle.SetPadGridY(False)
42  R.gStyle.SetGridColor(0)
43  R.gStyle.SetGridStyle(3)
44  R.gStyle.SetGridWidth(1)
45 
46  # For the frame:
47  R.gStyle.SetFrameBorderMode(0)
48  R.gStyle.SetFrameBorderSize(1)
49  R.gStyle.SetFrameFillColor(0)
50  R.gStyle.SetFrameFillStyle(0)
51  R.gStyle.SetFrameLineColor(1)
52  R.gStyle.SetFrameLineStyle(1)
53  R.gStyle.SetFrameLineWidth(1)
54 
55  # For the histo:
56  # R.gStyle.SetHistFillColor(1)
57  # R.gStyle.SetHistFillStyle(0)
58  R.gStyle.SetHistLineColor(1)
59  R.gStyle.SetHistLineStyle(0)
60  R.gStyle.SetHistLineWidth(1)
61  # R.gStyle.SetLegoInnerR(Float_t rad = 0.5)
62  # R.gStyle.SetNumberContours(Int_t number = 20)
63 
64  R.gStyle.SetEndErrorSize(2)
65  # R.gStyle.SetErrorMarker(20)
66  # R.gStyle.SetErrorX(0.)
67 
68  R.gStyle.SetMarkerStyle(20)
69 
70  # For the fit/function:
71  R.gStyle.SetOptFit(1)
72  R.gStyle.SetFitFormat('5.4g')
73  R.gStyle.SetFuncColor(2)
74  R.gStyle.SetFuncStyle(1)
75  R.gStyle.SetFuncWidth(1)
76 
77  # For the date:
78  R.gStyle.SetOptDate(0)
79  # R.gStyle.SetDateX(Float_t x = 0.01)
80  # R.gStyle.SetDateY(Float_t y = 0.01)
81 
82  # For the statistics box:
83  R.gStyle.SetOptFile(0)
84  R.gStyle.SetOptStat(0)
85  # To display the mean and RMS: SetOptStat('mr')
86  R.gStyle.SetStatColor(R.kWhite)
87  R.gStyle.SetStatFont(42)
88  R.gStyle.SetStatFontSize(0.025)
89  R.gStyle.SetStatTextColor(1)
90  R.gStyle.SetStatFormat('6.4g')
91  R.gStyle.SetStatBorderSize(1)
92  R.gStyle.SetStatH(0.1)
93  R.gStyle.SetStatW(0.15)
94  # R.gStyle.SetStatStyle(Style_t style = 1001)
95  # R.gStyle.SetStatX(Float_t x = 0)
96  # R.gStyle.SetStatY(Float_t y = 0)
97 
98  # Margins:
99  R.gStyle.SetPadTopMargin(0.05)
100  R.gStyle.SetPadBottomMargin(0.13)
101  R.gStyle.SetPadLeftMargin(0.16)
102  R.gStyle.SetPadRightMargin(0.02)
103 
104  # For the Global title:
105  R.gStyle.SetOptTitle(0)
106  R.gStyle.SetTitleFont(42)
107  R.gStyle.SetTitleColor(1)
108  R.gStyle.SetTitleTextColor(1)
109  R.gStyle.SetTitleFillColor(10)
110  R.gStyle.SetTitleFontSize(0.05)
111  # R.gStyle.SetTitleH(0); # Set the height of the title box
112  # R.gStyle.SetTitleW(0); # Set the width of the title box
113  # R.gStyle.SetTitleX(0); # Set the position of the title box
114  # R.gStyle.SetTitleY(0.985); # Set the position of the title box
115  # R.gStyle.SetTitleStyle(Style_t style = 1001)
116  # R.gStyle.SetTitleBorderSize(2)
117 
118  # For the axis titles:
119  R.gStyle.SetTitleColor(1, 'XYZ')
120  R.gStyle.SetTitleFont(42, 'XYZ')
121  R.gStyle.SetTitleSize(0.06, 'XYZ')
122  # Another way to set the size?
123  # R.gStyle.SetTitleXSize(Float_t size = 0.02)
124  # R.gStyle.SetTitleYSize(Float_t size = 0.02)
125  R.gStyle.SetTitleXOffset(0.9)
126  R.gStyle.SetTitleYOffset(1.25)
127  # R.gStyle.SetTitleOffset(1.1, 'Y'); # Another way to set the Offset
128 
129  # For the axis labels:
130 
131  R.gStyle.SetLabelColor(1, 'XYZ')
132  R.gStyle.SetLabelFont(42, 'XYZ')
133  R.gStyle.SetLabelOffset(0.007, 'XYZ')
134  R.gStyle.SetLabelSize(0.05, 'XYZ')
135 
136  # For the axis:
137 
138  R.gStyle.SetAxisColor(1, 'XYZ')
139  R.gStyle.SetStripDecimals(True)
140  R.gStyle.SetTickLength(0.03, 'XYZ')
141  R.gStyle.SetNdivisions(510, 'XYZ')
142  R.gStyle.SetPadTickX(1)
143  R.gStyle.SetPadTickY(1)
144 
145  # Change for log plots:
146  R.gStyle.SetOptLogx(0)
147  R.gStyle.SetOptLogy(0)
148  R.gStyle.SetOptLogz(0)
149 
150  # Postscript options:
151  R.gStyle.SetPaperSize(20., 20.)
152  # R.gStyle.SetLineScalePS(Float_t scale = 3)
153  # R.gStyle.SetLineStyleString(Int_t i, const char* text)
154  # R.gStyle.SetHeaderPS(const char* header)
155  # R.gStyle.SetTitlePS(const char* pstitle)
156 
157  # R.gStyle.SetBarOffset(Float_t baroff = 0.5)
158  # R.gStyle.SetBarWidth(Float_t barwidth = 0.5)
159  # R.gStyle.SetPaintTextFormat(const char* format = 'g')
160  # R.gStyle.SetPalette(Int_t ncolors = 0, Int_t* colors = 0)
161  # R.gStyle.SetTimeOffset(Double_t toffset)
162  # R.gStyle.SetHistMinimumZero(kTRUE)
163 
164  R.gStyle.SetHatchesLineWidth(5)
165  R.gStyle.SetHatchesSpacing(0.05)
166 
167 
168 def ModTDRStyle(width=600, height=600, t=0.06, b=0.12, l=0.16, r=0.04):
169  """Modified version of the tdrStyle
170 
171  Args:
172  width (int): Canvas width in pixels
173  height (int): Canvas height in pixels
174  t (float): Pad top margin [0-1]
175  b (float): Pad bottom margin [0-1]
176  l (float): Pad left margin [0-1]
177  r (float): Pad right margin [0-1]
178  """
179  SetTDRStyle()
180 
181  # Set the default canvas width and height in pixels
182  R.gStyle.SetCanvasDefW(width)
183  R.gStyle.SetCanvasDefH(height)
184 
185  # Set the default margins. These are given as fractions of the pad height
186  # for `Top` and `Bottom` and the pad width for `Left` and `Right`. But we
187  # want to specify all of these as fractions of the shortest length.
188  def_w = float(R.gStyle.GetCanvasDefW())
189  def_h = float(R.gStyle.GetCanvasDefH())
190 
191  scale_h = (def_w / def_h) if (def_h > def_w) else 1.
192  scale_w = (def_h / def_w) if (def_w > def_h) else 1.
193 
194  def_min = def_h if (def_h < def_w) else def_w
195 
196  R.gStyle.SetPadTopMargin(t * scale_h)
197  # default 0.05
198  R.gStyle.SetPadBottomMargin(b * scale_h)
199  # default 0.13
200  R.gStyle.SetPadLeftMargin(l * scale_w)
201  # default 0.16
202  R.gStyle.SetPadRightMargin(r * scale_w)
203  # default 0.02
204  # But note the new CMS style sets these:
205  # 0.08, 0.12, 0.12, 0.04
206 
207  # Set number of axis tick divisions
208  R.gStyle.SetNdivisions(506, 'XYZ') # default 510
209 
210  # Some marker properties not set in the default tdr style
211  R.gStyle.SetMarkerColor(R.kBlack)
212  R.gStyle.SetMarkerSize(1.0)
213 
214  R.gStyle.SetLabelOffset(0.007, 'YZ')
215  # This is an adhoc adjustment to scale the x-axis label
216  # offset when we stretch plot vertically
217  # Will also need to increase if first x-axis label has more than one digit
218  R.gStyle.SetLabelOffset(0.005 * (3. - 2. / scale_h), 'X')
219 
220  # In this next part we do a slightly involved calculation to set the axis
221  # title offsets, depending on the values of the TPad dimensions and
222  # margins. This is to try and ensure that regardless of how these pad
223  # values are set, the axis titles will be located towards the edges of the
224  # canvas and not get pushed off the edge - which can often happen if a
225  # fixed value is used.
226  title_size = 0.05
227  title_px = title_size * def_min
228  label_size = 0.04
229  R.gStyle.SetTitleSize(title_size, 'XYZ')
230  R.gStyle.SetLabelSize(label_size, 'XYZ')
231 
232  R.gStyle.SetTitleXOffset(0.5 * scale_h *
233  (1.2 * (def_h * b * scale_h - 0.6 * title_px)) /
234  title_px)
235  R.gStyle.SetTitleYOffset(0.5 * scale_w *
236  (1.2 * (def_w * l * scale_w - 0.6 * title_px)) /
237  title_px)
238 
239  # Only draw ticks where we have an axis
240  R.gStyle.SetPadTickX(0)
241  R.gStyle.SetPadTickY(0)
242  R.gStyle.SetTickLength(0.02, 'XYZ')
243 
244  R.gStyle.SetLegendBorderSize(0)
245  R.gStyle.SetLegendFont(42)
246  R.gStyle.SetLegendFillColor(0)
247  R.gStyle.SetFillColor(0)
248 
249  R.gROOT.ForceStyle()
250 
251 
252 def SetBirdPalette():
253  nRGBs = 9
254  stops = array(
255  'd', [0.0000, 0.1250, 0.2500, 0.3750, 0.5000, 0.6250, 0.7500, 0.8750, 1.0000])
256  red = array(
257  'd', [0.2082, 0.0592, 0.0780, 0.0232, 0.1802, 0.5301, 0.8186, 0.9956, 0.9764])
258  green = array(
259  'd', [0.1664, 0.3599, 0.5041, 0.6419, 0.7178, 0.7492, 0.7328, 0.7862, 0.9832])
260  blue = array(
261  'd', [0.5293, 0.8684, 0.8385, 0.7914, 0.6425, 0.4662, 0.3499, 0.1968, 0.0539])
262  R.TColor.CreateGradientColorTable(nRGBs, stops, red, green, blue, 255, 1)
263 
264 
265 def SetDeepSeaPalette():
266  nRGBs = 9
267  stops = array(
268  'd', [0.0000, 0.1250, 0.2500, 0.3750, 0.5000, 0.6250, 0.7500, 0.8750, 1.0000])
269  red = array(
270  'd', reversed([0./255., 9./255., 13./255., 17./255., 24./255., 32./255., 27./255., 25./255., 29./255.]))
271  green = array(
272  'd', reversed([0./255., 0./255., 0./255., 2./255., 37./255., 74./255., 113./255., 160./255., 221./255.]))
273  blue = array(
274  'd', reversed([28./255., 42./255., 59./255., 78./255., 98./255., 129./255., 154./255., 184./255., 221./255.]))
275  R.TColor.CreateGradientColorTable(nRGBs, stops, red, green, blue, 255, 1)
276 
277 
278 def SetCorrMatrixPalette():
279  R.TColor.CreateGradientColorTable(3,
280  array ("d", [0.00, 0.50, 1.00]),
281  array ("d", [1.00, 1.00, 0.00]),
282  array ("d", [0.70, 1.00, 0.34]),
283  array ("d", [0.00, 1.00, 0.82]),
284  255, 1.0)
285 
286 
287 def CreateTransparentColor(color, alpha):
288  adapt = R.gROOT.GetColor(color)
289  new_idx = R.gROOT.GetListOfColors().GetLast() + 1
290  trans = R.TColor(
291  new_idx, adapt.GetRed(), adapt.GetGreen(), adapt.GetBlue(), '', alpha)
292  COL_STORE.append(trans)
293  trans.SetName('userColor%i' % new_idx)
294  return new_idx
295 
296 
297 def Set(obj, **kwargs):
298  for key, value in six.iteritems(kwargs):
299  if value is None:
300  getattr(obj, 'Set' + key)()
301  elif isinstance(value, (list, tuple)):
302  getattr(obj, 'Set' + key)(*value)
303  else:
304  getattr(obj, 'Set' + key)(value)
305 
306 
307 
308 
309 
314 
315 def OnePad():
316  pad = R.TPad('pad', 'pad', 0., 0., 1., 1.)
317  pad.Draw()
318  pad.cd()
319  result = [pad]
320  return result
321 
322 
323 def TwoPadSplit(split_point, gap_low, gap_high):
324  upper = R.TPad('upper', 'upper', 0., 0., 1., 1.)
325  upper.SetBottomMargin(split_point + gap_high)
326  upper.SetFillStyle(4000)
327  upper.Draw()
328  lower = R.TPad('lower', 'lower', 0., 0., 1., 1.)
329  lower.SetTopMargin(1 - split_point + gap_low)
330  lower.SetFillStyle(4000)
331  lower.Draw()
332  upper.cd()
333  result = [upper, lower]
334  return result
335 
336 def ThreePadSplit(upper_split_point, split_point, gap_low, gap_high):
337  upper2 = R.TPad('upper2', 'upper2', 0., 0., 1., 1.)
338  upper2.SetTopMargin(1 - upper_split_point)
339  upper2.SetBottomMargin(split_point + gap_high)
340  upper2.SetFillStyle(4000)
341  upper2.Draw()
342  upper1 = R.TPad('upper1', 'upper1', 0., 0., 1., 1.)
343  upper1.SetBottomMargin(upper_split_point)
344  upper1.SetFillStyle(4000)
345  upper1.Draw()
346  lower = R.TPad('lower', 'lower', 0., 0., 1., 1.)
347  lower.SetTopMargin(1 - split_point + gap_low)
348  lower.SetFillStyle(4000)
349  lower.Draw()
350  upper1.cd()
351  result = [upper1, lower, upper2]
352  return result
353 
354 def MultiRatioSplit(split_points, gaps_low, gaps_high):
355  """Create a set of TPads split vertically on the TCanvas
356 
357  This is a generalisation of the two pad main/ratio split but for the case
358  of multiple ratio pads.
359 
360  Args:
361 
362  split_points (list[float]): Height of each ratio pad as a fraction of the
363  canvas height. Pads will be created from the bottom of the frame
364  upwards. The final, main pad will occupy however much space remains,
365  therefore the size of this list should be [number of pads] - 1.
366  gaps_low (list[float]): Gaps between ratio pad frames created on the
367  lower pad side at each boundary. Give a list of zeroes for no gap
368  between pad frames. Should be the same length as `split_points`.1
369  gaps_high (list[float]): Gaps between ratio pad frames created on the
370  upper pad side at each boundary. Give a list of zeroes for no gap
371  between pad frames.
372 
373  Returns:
374  list[TPad]: List of TPads, indexed from top to bottom on the canvas.
375  """
376  pads = []
377  for i in range(len(split_points)+1):
378  pad = R.TPad('pad%i'%i, '', 0., 0., 1., 1.)
379  if i > 0:
380  pad.SetBottomMargin(sum(split_points[0:i])+gaps_high[i-1])
381  if i < len(split_points):
382  pad.SetTopMargin(1.-sum(split_points[0:i+1])+gaps_low[i])
383  pad.SetFillStyle(4000)
384  pad.Draw()
385  pads.append(pad)
386  pads.reverse()
387  return pads
388 
389 
390 def TwoPadSplitColumns(split_point, gap_left, gap_right):
391  left = R.TPad('left', 'left', 0., 0., 1., 1.)
392  left.SetRightMargin(1 - split_point + gap_right)
393  left.SetFillStyle(4000)
394  left.Draw()
395  right = R.TPad('right', 'right', 0., 0., 1., 1.)
396  right.SetLeftMargin(split_point + gap_left)
397  right.SetFillStyle(4000)
398  right.Draw()
399  left.cd()
400  result = [left, right]
401  return result
402 
403 
404 def MultiRatioSplitColumns(split_points, gaps_left, gaps_right):
405  pads = []
406  for i in range(len(split_points)+1):
407  pad = R.TPad('pad%i'%i, '', 0., 0., 1., 1.)
408  if i > 0:
409  pad.SetLeftMargin(sum(split_points[0:i])+gaps_left[i-1])
410  if i < len(split_points):
411  pad.SetRightMargin(1.-sum(split_points[0:i+1])+gaps_right[i])
412  pad.SetFillStyle(4000)
413  pad.Draw()
414  pads.append(pad)
415  pads[0].cd()
416  # pads.reverse()
417  return pads
418 
419 
420 def SetupTwoPadSplitAsRatio(pads, upper, lower, y_title, y_centered,
421  y_min, y_max):
422  if lower.GetXaxis().GetTitle() == '':
423  lower.GetXaxis().SetTitle(upper.GetXaxis().GetTitle())
424  upper.GetXaxis().SetTitle("")
425  upper.GetXaxis().SetLabelSize(0)
426  upper_h = 1. - pads[0].GetTopMargin() - pads[0].GetBottomMargin()
427  lower_h = 1. - pads[1].GetTopMargin() - pads[1].GetBottomMargin()
428  lower.GetYaxis().SetTickLength(R.gStyle.GetTickLength() * upper_h / lower_h)
429  pads[1].SetTickx(1)
430  pads[1].SetTicky(1)
431  lower.GetYaxis().SetTitle(y_title)
432  lower.GetYaxis().CenterTitle(y_centered)
433  if y_max > y_min:
434  lower.SetMinimum(y_min)
435  lower.SetMaximum(y_max)
436 
437 
438 def StandardAxes(xaxis, yaxis, var, units, fmt='.1f'):
439  width = xaxis.GetBinWidth(1)
440  w_label = ("%"+fmt) % width
441  if units == "":
442  xaxis.SetTitle(var)
443  yaxis.SetTitle("Events / " + w_label)
444  else:
445  xaxis.SetTitle(var + " (" + units + ")")
446  yaxis.SetTitle("Events / " + w_label + " " + units)
447 
448 
449 
450 
451 
452 
453 
460 
461 def CreateAxisHist(src, at_limits=True):
462  backup = R.gPad
463  tmp = R.TCanvas()
464  tmp.cd()
465  src.Draw('AP')
466  result = src.GetHistogram().Clone('tmp')
467  if (at_limits):
468  min = 0.
469  max = 0.
470  x = ctypes.c_double(0.)
471  y = ctypes.c_double(0.)
472  src.GetPoint(0, x, y)
473  min = float(x.value)
474  max = float(x.value)
475  for i in range(1, src.GetN()):
476  src.GetPoint(i, x, y)
477  if x < min:
478  min = float(x.value)
479  if x > max:
480  max = float(x.value)
481  result.GetXaxis().SetLimits(min, max)
482  R.gPad = backup
483  return result
484 
485 
486 def CreateAxisHists(n, src, at_limits):
487  res = []
488  h = CreateAxisHist(src, at_limits)
489  for i in range(n):
490  res.append(h.Clone('tmp%i'%i))
491  return res
492 
493 
494 def GetAxisHist(pad):
495  pad_obs = pad.GetListOfPrimitives()
496  if pad_obs is None:
497  return None
498  obj = None
499  for obj in pad_obs:
500  if obj.InheritsFrom(R.TH1.Class()):
501  return obj
502  if obj.InheritsFrom(R.TMultiGraph.Class()):
503  return obj.GetHistogram()
504  if obj.InheritsFrom(R.TGraph.Class()):
505  return obj.GetHistogram()
506  if obj.InheritsFrom(R.THStack.Class()):
507  return obj.GetHistogram()
508  return None
509 
510 
511 
512 
513 
517 
518 def TFileIsGood(filename):
519  """Performs a series of tests on a TFile to ensure that it can be opened
520  without errors
521 
522  Args:
523  filename: `str` The name of the TFile to check
524 
525  Returns:
526  `bool` True if the file can opened, is not a zombie, and if ROOT did
527  not need to try and recover the contents
528  """
529  fin = R.TFile(filename)
530  if not fin:
531  return False
532  if fin and not fin.IsOpen():
533  return False
534  elif fin and fin.IsOpen() and fin.IsZombie():
535  fin.Close()
536  return False
537  elif fin and fin.IsOpen() and fin.TestBit(R.TFile.kRecovered):
538  fin.Close()
539  # don't consider a recovered file to be OK
540  return False
541  else:
542  fin.Close()
543  return True
544 
545 
546 def MakeTChain(files, tree):
547  chain = R.TChain(tree)
548  for f in files:
549  chain.Add(f)
550  return chain
551 
552 
553 def Get(file, obj):
554  R.TH1.AddDirectory(False)
555  f_in = R.TFile(file)
556  res = R.gDirectory.Get(obj)
557  f_in.Close()
558  return res
559 
560 
561 def ParamFromFilename(filename, param):
562  if len(re.findall(param + '\.\d+\.\d+', filename)):
563  num1 = re.findall(
564  param + '\.\d+\.\d+', filename)[0].replace(param + '.', '')
565  return float(num1)
566  elif len(re.findall(param + '\.\d+', filename)):
567  num1 = re.findall(param + '\.\d+', filename)[0].replace(param + '.', '')
568  return int(num1)
569  else:
570  print("Error: parameter " + param + " not found in filename")
571 
572 
573 
574 
575 
576 
581 
582 def TGraphFromTree(tree, xvar, yvar, selection):
583  tree.Draw(xvar + ':' + yvar, selection, 'goff')
584  gr = R.TGraph(tree.GetSelectedRows(), tree.GetV1(), tree.GetV2())
585  return gr
586 
587 
588 def TGraph2DFromTree(tree, xvar, yvar, zvar, selection):
589  tree.Draw(xvar + ':' + yvar + ':' + zvar, selection, 'goff')
590  gr = R.TGraph2D(
591  tree.GetSelectedRows(), tree.GetV1(), tree.GetV2(), tree.GetV3())
592  return gr
593 
594 
595 def RocCurveFrom1DHists(h_x, h_y, cut_is_greater_than):
596  backup = R.TH1.AddDirectoryStatus()
597  R.TH1.AddDirectory(False)
598  x_den = h_x.Clone()
599  x_num = h_x.Clone()
600  x_err = ctypes.c_double(0.)
601  x_int = h_x.IntegralAndError(0, h_x.GetNbinsX() + 1, x_err)
602  for i in range(1, h_x.GetNbinsX() + 1):
603  x_part_err = ctypes.c_double(0.)
604  x_part_int = h_x.IntegralAndError(i, h_x.GetNbinsX(
605  ) + 1, x_part_err) if cut_is_greater_than else h_x.IntegralAndError(0, i, x_part_err)
606  x_den.SetBinContent(i, x_int)
607  x_den.SetBinError(i, x_err)
608  x_num.SetBinContent(i, x_part_int)
609  x_num.SetBinError(i, x_part_err)
610  y_den = h_y.Clone()
611  y_num = h_y.Clone()
612  y_err = ctypes.c_double(0.)
613  y_int = h_y.IntegralAndError(0, h_y.GetNbinsX() + 1, y_err)
614  for i in range(1, h_y.GetNbinsX() + 1):
615  y_part_err = ctypes.c_double(0.)
616  y_part_int = h_y.IntegralAndError(i, h_y.GetNbinsX(
617  ) + 1, y_part_err) if cut_is_greater_than else h_y.IntegralAndError(0, i, y_part_err)
618  y_den.SetBinContent(i, y_int)
619  y_den.SetBinError(i, y_err)
620  y_num.SetBinContent(i, y_part_int)
621  y_num.SetBinError(i, y_part_err)
622  # x_den.Print('all')
623  # x_num.Print('all')
624  # y_den.Print('all')
625  # y_num.Print('all')
626  x_gr = R.TGraphAsymmErrors(x_num, x_den)
627  y_gr = R.TGraphAsymmErrors(y_num, y_den)
628 
629  res = y_gr.Clone()
630  for i in range(0, res.GetN()):
631  res.GetX()[i] = x_gr.GetY()[i]
632  res.GetEXlow()[i] = x_gr.GetEYlow()[i]
633  res.GetEXhigh()[i] = x_gr.GetEYhigh()[i]
634  res.Sort()
635  R.TH1.AddDirectory(backup)
636  return res
637 
638 
639 def TH2FromTGraph2D(graph, method='BinEdgeAligned',
640  force_x_width=None,
641  force_y_width=None):
642  """Build an empty TH2 from the set of points in a TGraph2D
643 
644  There is no unique way to define a TH2 binning given an arbitrary
645  TGraph2D, therefore this function supports multiple named methods:
646 
647  - `BinEdgeAligned` simply takes the sets of x- and y- values in the
648  TGraph2D and uses these as the bin edge arrays in the TH2. The
649  implication of this is that when filling the bin contents interpolation
650  will be required when evaluating the TGraph2D at the bin centres.
651  - `BinCenterAligned` will try to have the TGraph2D points at the bin
652  centers, but this will only work completely correctly when the input
653  point spacing is regular. The algorithm first identifies the bin width
654  as the smallest interval between points on each axis. The start
655  position of the TH2 axis is then defined as the lowest value in the
656  TGraph2D minus half this width, and the axis continues with regular
657  bins until the graph maximum is passed.
658 
659  Args:
660  graph (TGraph2D): Should have at least two unique x and y values,
661  otherwise we can't define any bins
662  method (str): The binning algorithm to use
663  force_x_width (bool): Override the derived x-axis bin width in the
664  CenterAligned method
665  force_y_width (bool): Override the derived y-axis bin width in the
666  CenterAligned method
667 
668  Raises:
669  RuntimeError: If the method name is not recognised
670 
671  Returns:
672  TH2F: The exact binning of the TH2F depends on the chosen method
673  """
674  x_vals = set()
675  y_vals = set()
676 
677  for i in range(graph.GetN()):
678  x_vals.add(graph.GetX()[i])
679  y_vals.add(graph.GetY()[i])
680 
681  x_vals = sorted(x_vals)
682  y_vals = sorted(y_vals)
683  if method == 'BinEdgeAligned':
684  h_proto = R.TH2F('prototype', '',
685  len(x_vals) - 1, array('d', x_vals),
686  len(y_vals) - 1, array('d', y_vals))
687  elif method == 'BinCenterAligned':
688  x_widths = []
689  y_widths = []
690  for i in range(1, len(x_vals)):
691  x_widths.append(x_vals[i] - x_vals[i - 1])
692  for i in range(1, len(y_vals)):
693  y_widths.append(y_vals[i] - y_vals[i - 1])
694  x_min = min(x_widths) if force_x_width is None else force_x_width
695  y_min = min(y_widths) if force_y_width is None else force_y_width
696  x_bins = int(((x_vals[-1] - (x_vals[0] - 0.5 * x_min)) / x_min) + 0.5)
697  y_bins = int(((y_vals[-1] - (y_vals[0] - 0.5 * y_min)) / y_min) + 0.5)
698  print('[TH2FromTGraph2D] x-axis binning: (%i, %g, %g)' % (x_bins, x_vals[0] - 0.5 * x_min, x_vals[0] - 0.5 * x_min + x_bins * x_min))
699  print('[TH2FromTGraph2D] y-axis binning: (%i, %g, %g)' % (y_bins, y_vals[0] - 0.5 * y_min, y_vals[0] - 0.5 * y_min + y_bins * y_min))
700  # Use a number slightly smaller than 0.49999 because the TGraph2D interpolation
701  # is fussy about evaluating on the boundary
702  h_proto = R.TH2F('prototype', '',
703  x_bins, x_vals[
704  0] - 0.49999 * x_min, x_vals[0] - 0.50001 * x_min + x_bins * x_min,
705  y_bins, y_vals[0] - 0.49999 * y_min, y_vals[0] - 0.50001 * y_min + y_bins * y_min)
706  else:
707  raise RuntimeError(
708  '[TH2FromTGraph2D] Method %s not supported' % method)
709  h_proto.SetDirectory(0)
710  return h_proto
711 
712 
713 def MakeErrorBand(LowerGraph, UpperGraph):
714  errorBand = R.TGraphAsymmErrors()
715  lower_list = []
716  upper_list = []
717  for i in range(LowerGraph.GetN()):
718  lower_list.append(
719  (float(LowerGraph.GetX()[i]), float(LowerGraph.GetY()[i])))
720  upper_list.append(
721  (float(UpperGraph.GetX()[i]), float(UpperGraph.GetY()[i])))
722  lower_list = sorted(set(lower_list))
723  upper_list = sorted(set(upper_list))
724  for i in range(LowerGraph.GetN()):
725  errorBand.SetPoint(i, lower_list[i][0], lower_list[i][1])
726  errorBand.SetPointEYlow(i, lower_list[i][1] - lower_list[i][1])
727  errorBand.SetPointEYhigh(i, upper_list[i][1] - lower_list[i][1])
728  return errorBand
729 
730 
731 def LimitTGraphFromJSON(js, label):
732  xvals = []
733  yvals = []
734  for key in js:
735  xvals.append(float(key))
736  yvals.append(js[key][label])
737  graph = R.TGraph(len(xvals), array('d', xvals), array('d', yvals))
738  graph.Sort()
739  return graph
740 
741 
742 def LimitTGraphFromJSONFile(jsfile, label):
743  with open(jsfile) as jsonfile:
744  js = json.load(jsonfile)
745  return LimitTGraphFromJSON(js, label)
746 
747 def ToyTGraphFromJSON(js, label):
748  xvals = []
749  yvals = []
750  if isinstance(label,(str,)):
751  for entry in js[label]:
752  xvals.append(float(entry))
753  yvals.append(1.0)
754  else:
755  if len(label) == 1:
756  return ToyTGraphFromJSON(js,label[0])
757  else:
758  return ToyTGraphFromJSON(js[label[0]],label[1:])
759  graph = R.TGraph(len(xvals), array('d', xvals), array('d', yvals))
760  graph.Sort()
761  return graph
762  # hist = R.TH1F("toy", "toy", 100, min(xvals), max(xvals))
763  # for xval in xvals:
764  # hist.AddBinContent(hist.GetXaxis().FindBin(xval))
765  # return hist
766 
767 
768 
769 def ToyTGraphFromJSONFile(jsfile, label):
770  with open(jsfile) as jsonfile:
771  js = json.load(jsonfile)
772  return ToyTGraphFromJSON(js, label)
773 
774 def LimitBandTGraphFromJSON(js, central, lo, hi):
775  xvals = []
776  yvals = []
777  yvals_lo = []
778  yvals_hi = []
779  for key in js:
780  xvals.append(float(key))
781  yvals.append(js[key][central])
782  yvals_lo.append(js[key][central] - js[key][lo])
783  yvals_hi.append(js[key][hi] - js[key][central])
784  graph = R.TGraphAsymmErrors(len(xvals), array('d', xvals), array('d', yvals), array(
785  'd', [0]), array('d', [0]), array('d', yvals_lo), array('d', yvals_hi))
786  graph.Sort()
787  return graph
788 
789 
790 def StandardLimitsFromJSONFile(json_file, draw=['obs', 'exp0', 'exp1', 'exp2']):
791  graphs = {}
792  data = {}
793  with open(json_file) as jsonfile:
794  data = json.load(jsonfile)
795  if 'obs' in draw:
796  graphs['obs'] = LimitTGraphFromJSON(data, 'obs')
797  if 'exp0' in draw or 'exp' in draw:
798  graphs['exp0'] = LimitTGraphFromJSON(data, 'exp0')
799  if 'exp1' in draw or 'exp' in draw:
800  graphs['exp1'] = LimitBandTGraphFromJSON(data, 'exp0', 'exp-1', 'exp+1')
801  if 'exp2' in draw or 'exp' in draw:
802  graphs['exp2'] = LimitBandTGraphFromJSON(data, 'exp0', 'exp-2', 'exp+2')
803  return graphs
804 
805 
806 def bestFit(tree, x, y, cut):
807  nfind = tree.Draw(y + ":" + x, cut + "deltaNLL == 0")
808  gr0 = R.TGraph(1)
809  if (nfind == 0):
810  gr0.SetPoint(0, -999, -999)
811  else:
812  grc = R.gROOT.FindObject("Graph").Clone()
813  if (grc.GetN() > 1):
814  grc.Set(1)
815  gr0.SetPoint(0, grc.GetXmax(), grc.GetYmax())
816  gr0.SetMarkerStyle(34)
817  gr0.SetMarkerSize(2.0)
818  return gr0
819 
820 
821 def treeToHist2D(t, x, y, name, cut, xmin, xmax, ymin, ymax, xbins, ybins):
822  t.Draw("2*deltaNLL:%s:%s>>%s_prof(%d,%10g,%10g,%d,%10g,%10g)" %
823  (y, x, name, xbins, xmin, xmax, ybins, ymin, ymax), cut + "deltaNLL != 0", "PROF")
824  prof = R.gROOT.FindObject(name + "_prof")
825  h2d = R.TH2D(name, name, xbins, xmin, xmax, ybins, ymin, ymax)
826  for ix in range(1, xbins + 1):
827  for iy in range(1, ybins + 1):
828  z = prof.GetBinContent(ix, iy)
829  if (z != z) or (z > 4294967295): # protect against NANs
830  z = 0
831  h2d.SetBinContent(ix, iy, z)
832  h2d.GetXaxis().SetTitle(x)
833  h2d.GetYaxis().SetTitle(y)
834  h2d.SetDirectory(0)
835  h2d = NewInterpolate(h2d)
836  return h2d
837 
838 
839 def makeHist1D(name, xbins, graph, scaleXrange=1.0, absoluteXrange=None):
840  len_x = graph.GetX()[graph.GetN() - 1] - graph.GetX()[0]
841  binw_x = (len_x * 0.5 / (float(xbins) - 1.)) - 1E-5
842  if absoluteXrange:
843  hist = R.TH1F(name, '', xbins, absoluteXrange[0], absoluteXrange[1])
844  else:
845  hist = R.TH1F(
846  name, '', xbins, graph.GetX()[0], scaleXrange * (graph.GetX()[graph.GetN() - 1] + binw_x))
847  return hist
848 
849 
850 def makeHist2D(name, xbins, ybins, graph2d):
851  len_x = graph2d.GetXmax() - graph2d.GetXmin()
852  binw_x = (len_x * 0.5 / (float(xbins) - 1.)) - 1E-5
853  len_y = graph2d.GetYmax() - graph2d.GetYmin()
854  binw_y = (len_y * 0.5 / (float(ybins) - 1.)) - 1E-5
855  hist = R.TH2F(name, '', xbins, graph2d.GetXmin() - binw_x, graph2d.GetXmax() +
856  binw_x, ybins, graph2d.GetYmin() - binw_y, graph2d.GetYmax() + binw_y)
857  return hist
858 
859 
860 def makeVarBinHist2D(name, xbins, ybins):
861  # create new arrays in which bin low edge is adjusted to make measured
862  # points at the bin centres
863  xbins_new = [None] * (len(xbins) + 1)
864  for i in range(len(xbins) - 1):
865  if i == 0 or i == 1:
866  xbins_new[i] = xbins[i] - ((xbins[i + 1] - xbins[i]) / 2) + 1E-5
867  else:
868  xbins_new[i] = xbins[i] - ((xbins[i + 1] - xbins[i]) / 2)
869  xbins_new[len(xbins) - 1] = xbins[len(xbins) - 2] + \
870  ((xbins[len(xbins) - 2] - xbins[len(xbins) - 3]) / 2)
871  xbins_new[len(xbins)] = xbins[len(xbins) - 1] + \
872  ((xbins[len(xbins) - 1] - xbins[len(xbins) - 2]) / 2) - 1E-5
873 
874  ybins_new = [None] * (len(ybins) + 1)
875  for i in range(len(ybins) - 1):
876  if i == 0 or i == 1:
877  ybins_new[i] = ybins[i] - ((ybins[i + 1] - ybins[i]) / 2) + 1E-5
878  else:
879  ybins_new[i] = ybins[i] - ((ybins[i + 1] - ybins[i]) / 2)
880  ybins_new[len(ybins) - 1] = ybins[len(ybins) - 2] + \
881  ((ybins[len(ybins) - 2] - ybins[len(ybins) - 3]) / 2)
882  ybins_new[len(ybins)] = ybins[len(ybins) - 1] + \
883  ((ybins[len(ybins) - 1] - ybins[len(ybins) - 2]) / 2) - 1E-5
884  hist = R.TH2F(name, '', len(
885  xbins_new) - 1, array('d', xbins_new), len(ybins_new) - 1, array('d', ybins_new))
886  return hist
887 
888 
889 def GraphDifference(graph1,graph2,relative):
890  xvals =[]
891  yvals =[]
892  if graph1.GetN() != graph2.GetN():
893  return graph1
894  for i in range(graph1.GetN()):
895  xvals.append(graph1.GetX()[i])
896  if relative :
897  yvals.append(2*abs(graph1.GetY()[i]-graph2.GetY()[i])/(graph1.GetY()[i]+graph2.GetY()[i]))
898  else:
899  yvals.append(2*(graph1.GetY()[i]-graph2.GetY()[i])/(graph1.GetY()[i]+graph2.GetY()[i]))
900  diff_graph = R.TGraph(len(xvals),array('d',xvals),array('d',yvals))
901  diff_graph.Sort()
902  return diff_graph
903 
904 
905 def GraphDivide(num, den):
906  res = num.Clone()
907  for i in range(num.GetN()):
908  res.GetY()[i] = res.GetY()[i]/den.Eval(res.GetX()[i])
909  if type(res) is R.TGraphAsymmErrors:
910  for i in range(num.GetN()):
911  res.GetEYhigh()[i] = res.GetEYhigh()[i]/den.Eval(res.GetX()[i])
912  res.GetEYlow()[i] = res.GetEYlow()[i]/den.Eval(res.GetX()[i])
913 
914  return res
915 
916 
917 def MakeRatioHist(num, den, num_err, den_err):
918  """Make a new ratio TH1 from numerator and denominator TH1s with optional
919  error propagation
920 
921  Args:
922  num (TH1): Numerator histogram
923  den (TH1): Denominator histogram
924  num_err (bool): Propagate the error in the numerator TH1
925  den_err (bool): Propagate the error in the denominator TH1
926 
927  Returns:
928  TH1: A new TH1 containing the ratio
929  """
930  result = num.Clone()
931  if not num_err:
932  for i in range(1, result.GetNbinsX()+1):
933  result.SetBinError(i, 0.)
934  den_fix = den.Clone()
935  if not den_err:
936  for i in range(1, den_fix.GetNbinsX()+1):
937  den_fix.SetBinError(i, 0.)
938  result.Divide(den_fix)
939  return result
940 
941 
942 
943 
948 def RemoveGraphXDuplicates(graph):
949  i = 0
950  while i < graph.GetN() - 1:
951  if graph.GetX()[i + 1] == graph.GetX()[i]:
952  # print 'Removing duplicate point (%f, %f)' % (graph.GetX()[i+1], graph.GetY()[i+1])
953  graph.RemovePoint(i + 1)
954  else:
955  i += 1
956 
957 
958 def ApplyGraphYOffset(graph, y_off):
959  for i in range(graph.GetN() - 1):
960  graph.GetY()[i] = graph.GetY()[i] + y_off
961 
962 
963 def RemoveGraphYAll(graph, val):
964  for i in range(graph.GetN()):
965  if graph.GetY()[i] == val:
966  print('[RemoveGraphYAll] Removing point (%f, %f)' % (graph.GetX()[i], graph.GetY()[i]))
967  graph.RemovePoint(i)
968  RemoveGraphYAll(graph, val)
969  break
970 
971 
972 def RemoveSmallDelta(graph, val):
973  for i in range(graph.GetN()):
974  diff = abs(graph.GetY()[i])
975  if diff < val:
976  print('[RemoveSmallDelta] Removing point (%f, %f)' % (graph.GetX()[i], graph.GetY()[i]))
977  graph.RemovePoint(i)
978  RemoveSmallDelta(graph, val)
979  break
980 
981 
982 def RemoveGraphYAbove(graph, val):
983  for i in range(graph.GetN()):
984  if graph.GetY()[i] > val:
985  # print 'Removing point (%f, %f)' % (graph.GetX()[i],
986  # graph.GetY()[i])
987  graph.RemovePoint(i)
988  RemoveGraphYAbove(graph, val)
989  break
990 
991 
992 def SetMinToZero(graph):
993  min = 999.
994  minNum = -1
995  for i in range(graph.GetN()):
996  if graph.GetY()[i] < min :
997  min = graph.GetY()[i]
998  minNum = i
999  for i in range(graph.GetN()):
1000  graph.SetPoint(i, graph.GetX()[i], graph.GetY()[i]-min)
1001 
1002 
1003 
1004 def ImproveMinimum(graph, func, doIt=False):
1005  fit_x = 0.
1006  fit_y = 999.
1007  fit_i = 0
1008  for i in range(graph.GetN()):
1009  if graph.GetY()[i] < fit_y:
1010  fit_i = i
1011  fit_x = graph.GetX()[i]
1012  fit_y = graph.GetY()[i]
1013  if fit_i == 0 or fit_i == (graph.GetN() - 1):
1014  if doIt:
1015  min_x = graph.GetX()[fit_i]
1016  min_y = graph.GetY()[fit_i]
1017  for i in range(graph.GetN()):
1018  before = graph.GetY()[i]
1019  graph.GetY()[i] -= min_y
1020  after = graph.GetY()[i]
1021  print('Point %i, before=%f, after=%f' % (i, before, after))
1022  return (fit_x, fit_y)
1023  search_min = fit_i - 2 if fit_i >= 2 else fit_i - 1
1024  search_max = fit_i + 2 if fit_i + 2 < graph.GetN() else fit_i + 1
1025  min_x = func.GetMinimumX(graph.GetX()[search_min], graph.GetX()[search_max])
1026  min_y = func.Eval(min_x)
1027  print('[ImproveMinimum] Fit minimum was (%f, %f)' % (fit_x, fit_y))
1028  print('[ImproveMinimum] Better minimum was (%f, %f)' % (min_x, min_y))
1029  if doIt:
1030  for i in range(graph.GetN()):
1031  before = graph.GetY()[i]
1032  graph.GetY()[i] -= min_y
1033  after = graph.GetY()[i]
1034  print('Point %i, before=%f, after=%f' % (i, before, after))
1035  graph.Set(graph.GetN() + 1)
1036  graph.SetPoint(graph.GetN() - 1, min_x, 0)
1037  graph.Sort()
1038  return (min_x, min_y)
1039 
1040 
1041 def FindCrossingsWithSpline(graph, func, yval):
1042  crossings = []
1043  intervals = []
1044  current = None
1045  for i in range(graph.GetN() - 1):
1046  if (graph.GetY()[i] - yval) * (graph.GetY()[i + 1] - yval) < 0.:
1047  cross = func.GetX(yval, graph.GetX()[i], graph.GetX()[i + 1])
1048  if (graph.GetY()[i] - yval) > 0. and current is None:
1049  current = {
1050  'lo': cross,
1051  'hi': graph.GetX()[graph.GetN() - 1],
1052  'valid_lo': True,
1053  'valid_hi': False
1054  }
1055  if (graph.GetY()[i] - yval) < 0. and current is None:
1056  current = {
1057  'lo': graph.GetX()[0],
1058  'hi': cross,
1059  'valid_lo': False,
1060  'valid_hi': True
1061  }
1062  intervals.append(current)
1063  current = None
1064  if (graph.GetY()[i] - yval) < 0. and current is not None:
1065  current['hi'] = cross
1066  current['valid_hi'] = True
1067  intervals.append(current)
1068  current = None
1069  # print 'Crossing between: (%f, %f) -> (%f, %f) at %f' %
1070  # (graph.GetX()[i], graph.GetY()[i], graph.GetX()[i+1],
1071  # graph.GetY()[i+1], cross)
1072  crossings.append(cross)
1073  if current is not None:
1074  intervals.append(current)
1075  if len(intervals) == 0:
1076  current = {
1077  'lo': graph.GetX()[0],
1078  'hi': graph.GetX()[graph.GetN() - 1],
1079  'valid_lo': False,
1080  'valid_hi': False
1081  }
1082  intervals.append(current)
1083  print(intervals)
1084  return intervals
1085  # return crossings
1086 
1087 
1088 def ReZeroTGraph(gr, doIt=False):
1089  fit_x = 0.
1090  fit_y = 0.
1091  for i in range(gr.GetN()):
1092  if gr.GetY()[i] == 0.:
1093  fit_x = gr.GetX()[i]
1094  fit_y = gr.GetY()[i]
1095  break
1096  min_x = 0.
1097  min_y = 0.
1098  for i in range(gr.GetN()):
1099  if gr.GetY()[i] < min_y:
1100  min_y = gr.GetY()[i]
1101  min_x = gr.GetX()[i]
1102  if min_y < fit_y:
1103  print('[ReZeroTGraph] Fit minimum was (%f, %f)' % (fit_x, fit_y))
1104  print('[ReZeroTGraph] Better minimum was (%f, %f)' % (min_x, min_y))
1105  if doIt:
1106  for i in range(gr.GetN()):
1107  before = gr.GetY()[i]
1108  gr.GetY()[i] -= min_y
1109  after = gr.GetY()[i]
1110  # print 'Point %i, before=%f, after=%f' % (i, before, after)
1111  return min_y
1112 
1113 def FilterGraph(gr, n=3):
1114  counter = 0
1115  remove_list = []
1116  for i in range(gr.GetN()):
1117  if gr.GetY()[i] == 0.:
1118  continue
1119  if counter % n < (n - 1):
1120  remove_list.append(i)
1121  counter += 1
1122 
1123  for i in reversed(remove_list):
1124  gr.RemovePoint(i)
1125 
1126 
1127 def RemoveInXRange(gr, xmin=0, xmax=1):
1128  remove_list = []
1129  for i in range(gr.GetN()):
1130  if gr.GetY()[i] == 0.:
1131  continue
1132  if gr.GetX()[i] > xmin and gr.GetX()[i] < xmax:
1133  remove_list.append(i)
1134 
1135  for i in reversed(remove_list):
1136  gr.RemovePoint(i)
1137 
1138 
1139 def RemoveNearMin(graph, val, spacing=None):
1140  # assume graph is sorted:
1141  n = graph.GetN()
1142  if n < 5:
1143  return
1144  if spacing is None:
1145  spacing = (graph.GetX()[n - 1] - graph.GetX()[0]) / float(n - 2)
1146  # print '[RemoveNearMin] Graph has spacing of %.3f' % spacing
1147  bf_i = None
1148  for i in range(graph.GetN()):
1149  if graph.GetY()[i] == 0.:
1150  bf = graph.GetX()[i]
1151  bf_i = i
1152  # print '[RemoveNearMin] Found best-fit at %.3f' % bf
1153  break
1154  if bf_i is None:
1155  print('[RemoveNearMin] No minimum found!')
1156  return
1157  for i in range(graph.GetN()):
1158  if i == bf_i:
1159  continue
1160  if abs(graph.GetX()[i] - bf) < (val * spacing):
1161  print('[RemoveNearMin] Removing point (%f, %f) close to minimum at %f' % (graph.GetX()[i], graph.GetY()[i], bf))
1162  graph.RemovePoint(i)
1163  RemoveNearMin(graph, val, spacing)
1164  break
1165 
1166 
1167 def SortGraph(Graph):
1168  sortedGraph = R.TGraph()
1169  graph_list = []
1170  for i in range(Graph.GetN()):
1171  graph_list.append((float(Graph.GetX()[i]), float(Graph.GetY()[i])))
1172  graph_list = sorted(set(graph_list))
1173  for i in range(Graph.GetN()):
1174  sortedGraph.SetPoint(i, graph_list[i][0], graph_list[i][1])
1175  return sortedGraph
1176 
1177 
1178 
1179 
1180 
1181 
1187 def FixTopRange(pad, fix_y, fraction):
1188  hobj = GetAxisHist(pad)
1189  ymin = hobj.GetMinimum()
1190  hobj.SetMaximum((fix_y - fraction * ymin) / (1. - fraction))
1191  if R.gPad.GetLogy():
1192  if ymin == 0.:
1193  print('Cannot adjust log-scale y-axis range if the minimum is zero!')
1194  return
1195  maxval = (math.log10(fix_y) - fraction * math.log10(ymin)) / \
1196  (1 - fraction)
1197  maxval = math.pow(10, maxval)
1198  hobj.SetMaximum(maxval)
1199 
1200 
1201 def FixBothRanges(pad, fix_y_lo, frac_lo, fix_y_hi, frac_hi):
1202  """Adjusts y-axis range such that a lower and a higher value are located a
1203  fixed fraction of the frame height away from a new minimum and maximum
1204  respectively.
1205 
1206  This function is useful in conjunction with GetPadYMax which returns the
1207  maximum or minimum y value of all histograms and graphs drawn on the pad.
1208 
1209  In the example below, the minimum and maximum values found via this function
1210  are used as the `fix_y_lo` and `fix_y_hi` arguments, and the spacing fractions
1211  as 0.15 and 0.30 respectively.
1212 
1213  @code
1214  FixBothRanges(pad, GetPadYMin(pad), 0.15, GetPadYMax(pad), 0.30)
1215  @endcode
1216 
1217  ![](figures/FixBothRanges.png)
1218 
1219  Args:
1220  pad (TPad): A TPad on which histograms and graphs have already been drawn
1221  fix_y_lo (float): The y value which will end up a fraction `frac_lo` above
1222  the new axis minimum.
1223  frac_lo (float): A fraction of the y-axis height
1224  fix_y_hi (float): The y value which will end up a fraction `frac_hi` below
1225  from the new axis maximum.
1226  frac_hi (float): A fraction of the y-axis height
1227  """
1228  hobj = GetAxisHist(pad)
1229  ymin = fix_y_lo
1230  ymax = fix_y_hi
1231  if R.gPad.GetLogy():
1232  if ymin == 0.:
1233  print('Cannot adjust log-scale y-axis range if the minimum is zero!')
1234  return
1235  ymin = math.log10(ymin)
1236  ymax = math.log10(ymax)
1237  fl = frac_lo
1238  fh = frac_hi
1239 
1240  ymaxn = (
1241  (1. / (1. - (fh*fl/((1.-fl)*(1.-fh))))) *
1242  (1. / (1. - fh)) *
1243  (ymax - fh*ymin)
1244  )
1245  yminn = (ymin - fl*ymaxn) / (1. - fl)
1246  if R.gPad.GetLogy():
1247  yminn = math.pow(10, yminn)
1248  ymaxn = math.pow(10, ymaxn)
1249  hobj.SetMinimum(yminn)
1250  hobj.SetMaximum(ymaxn)
1251 
1252 
1253 def GetPadYMaxInRange(pad, x_min, x_max, do_min=False):
1254  pad_obs = pad.GetListOfPrimitives()
1255  if pad_obs is None:
1256  return 0.
1257  h_max = -99999.
1258  h_min = +99999.
1259  for obj in pad_obs:
1260  if obj.InheritsFrom(R.TH1.Class()):
1261  hobj = obj
1262  for j in range(1, hobj.GetNbinsX()+1):
1263  if (hobj.GetBinLowEdge(j) + hobj.GetBinWidth(j) < x_min or
1264  hobj.GetBinLowEdge(j) > x_max):
1265  continue
1266  if (hobj.GetBinContent(j) + hobj.GetBinError(j) > h_max):
1267  h_max = hobj.GetBinContent(j) + hobj.GetBinError(j)
1268  if (hobj.GetBinContent(j) - hobj.GetBinError(j) < h_min) and not do_min:
1269  # If we're looking for the minimum don't count TH1s
1270  # because we probably only care about graphs
1271  h_min = hobj.GetBinContent(j) - hobj.GetBinError(j)
1272  elif obj.InheritsFrom(R.TGraphAsymmErrors.Class()):
1273  gobj = obj
1274  n = gobj.GetN()
1275  for k in range(0, n):
1276  x = gobj.GetX()[k]
1277  y = gobj.GetY()[k]
1278  if x < x_min or x > x_max:
1279  continue
1280  if (y + gobj.GetEYhigh()[k]) > h_max:
1281  h_max = y + gobj.GetEYhigh()[k]
1282  if (y - gobj.GetEYlow()[k]) < h_min:
1283  h_min = y - gobj.GetEYlow()[k]
1284  elif obj.InheritsFrom(R.TGraphErrors.Class()):
1285  gobj = obj
1286  n = gobj.GetN()
1287  for k in range(0, n):
1288  x = gobj.GetX()[k]
1289  y = gobj.GetY()[k]
1290  if x < x_min or x > x_max:
1291  continue
1292  if (y + gobj.GetEY()[k]) > h_max:
1293  h_max = y + gobj.GetEY()[k]
1294  if (y - gobj.GetEY()[k]) < h_min:
1295  h_min = y - gobj.GetEY()[k]
1296  elif obj.InheritsFrom(R.TGraph.Class()):
1297  gobj = obj
1298  n = gobj.GetN()
1299  for k in range(0, n):
1300  x = gobj.GetX()[k]
1301  y = gobj.GetY()[k]
1302  if x < x_min or x > x_max:
1303  continue
1304  if y > h_max:
1305  h_max = y
1306  if y < h_min:
1307  h_min = y
1308  return h_max if do_min is False else h_min
1309 
1310 
1311 def GetPadYMax(pad, do_min=False):
1312  pad_obs = pad.GetListOfPrimitives()
1313  if pad_obs is None:
1314  return 0.
1315  xmin = GetAxisHist(pad).GetXaxis().GetXmin()
1316  xmax = GetAxisHist(pad).GetXaxis().GetXmax()
1317  return GetPadYMaxInRange(pad, xmin, xmax, do_min)
1318 
1319 
1320 def GetPadYMin(pad):
1321  return GetPadYMax(pad, True)
1322 
1323 
1324 def FixOverlay():
1325  R.gPad.GetFrame().Draw()
1326  R.gPad.RedrawAxis()
1327 
1328 
1329 def FixBoxPadding(pad, box, frac):
1330  # Get the bounds of the box - these are in the normalised
1331  # Pad co-ordinates.
1332  p_x1 = box.GetX1()
1333  p_x2 = box.GetX2()
1334  p_y1 = box.GetY1()
1335 
1336  #Convert to normalised co-ordinates in the frame
1337  f_x1 = (p_x1 - pad.GetLeftMargin()) / (1. - pad.GetLeftMargin() - pad.GetRightMargin())
1338  f_x2 = (p_x2 - pad.GetLeftMargin()) / (1. - pad.GetLeftMargin() - pad.GetRightMargin())
1339  f_y1 = (p_y1 - pad.GetBottomMargin()) / (1. - pad.GetTopMargin() - pad.GetBottomMargin())
1340 
1341  # Extract histogram providing the frame and axes
1342  hobj = GetAxisHist(pad)
1343 
1344  xmin = hobj.GetBinLowEdge(hobj.GetXaxis().GetFirst())
1345  xmax = hobj.GetBinLowEdge(hobj.GetXaxis().GetLast()+1)
1346  ymin = hobj.GetMinimum()
1347  ymax = hobj.GetMaximum()
1348 
1349  # Convert box bounds to x-axis values
1350  a_x1 = xmin + (xmax - xmin) * f_x1
1351  a_x2 = xmin + (xmax - xmin) * f_x2
1352 
1353  # Get the histogram maximum in this range, given as y-axis value
1354  a_max_h = GetPadYMaxInRange(pad, a_x1, a_x2)
1355 
1356  # Convert this to a normalised frame value
1357  f_max_h = (a_max_h - ymin) / (ymax - ymin);
1358  if R.gPad.GetLogy() and f_max_h > 0.:
1359  f_max_h = (math.log10(a_max_h) - math.log10(ymin)) / (math.log10(ymax) - math.log10(ymin))
1360 
1361  if f_y1 - f_max_h < frac:
1362  f_target = 1. - (f_y1 - frac)
1363  FixTopRange(pad, a_max_h, f_target)
1364 
1365 
1366 
1367 
1371 
1372 
1373 def StandardAxes(xaxis, yaxis, var, units):
1374  width = xaxis.GetBinWidth(1)
1375  w_label = "%.1f" % width
1376  if units == "":
1377  xaxis.SetTitle(var)
1378  yaxis.SetTitle("Events / " + w_label)
1379  else:
1380  xaxis.SetTitle(var + " (" + units + ")")
1381  yaxis.SetTitle("Events / " + w_label + " " + units)
1382 
1383 
1384 def DrawCMSLogo(pad, cmsText, extraText, iPosX, relPosX, relPosY, relExtraDY, extraText2='', cmsTextSize=0.8):
1385  """Blah
1386 
1387  Args:
1388  pad (TYPE): Description
1389  cmsText (TYPE): Description
1390  extraText (TYPE): Description
1391  iPosX (TYPE): Description
1392  relPosX (TYPE): Description
1393  relPosY (TYPE): Description
1394  relExtraDY (TYPE): Description
1395  extraText2 (str): Description
1396  cmsTextSize (float): Description
1397 
1398  Returns:
1399  TYPE: Description
1400  """
1401  pad.cd()
1402  cmsTextFont = 62 # default is helvetic-bold
1403 
1404  writeExtraText = len(extraText) > 0
1405  writeExtraText2 = len(extraText2) > 0
1406  extraTextFont = 52
1407 
1408  # text sizes and text offsets with respect to the top frame
1409  # in unit of the top margin size
1410  lumiTextOffset = 0.2
1411  # cmsTextSize = 0.8
1412  # float cmsTextOffset = 0.1; // only used in outOfFrame version
1413 
1414  # ratio of 'CMS' and extra text size
1415  extraOverCmsTextSize = 0.76
1416 
1417  outOfFrame = False
1418  if iPosX / 10 == 0:
1419  outOfFrame = True
1420 
1421  alignY_ = 3
1422  alignX_ = 2
1423  if (iPosX / 10 == 0):
1424  alignX_ = 1
1425  if (iPosX == 0):
1426  alignX_ = 1
1427  if (iPosX == 0):
1428  alignY_ = 1
1429  if (iPosX / 10 == 1):
1430  alignX_ = 1
1431  if (iPosX / 10 == 2):
1432  alignX_ = 2
1433  if (iPosX / 10 == 3):
1434  alignX_ = 3
1435  # if (iPosX == 0): relPosX = 0.14
1436  align_ = 10 * alignX_ + alignY_
1437 
1438  l = pad.GetLeftMargin()
1439  t = pad.GetTopMargin()
1440  r = pad.GetRightMargin()
1441  b = pad.GetBottomMargin()
1442 
1443  latex = R.TLatex()
1444  latex.SetNDC()
1445  latex.SetTextAngle(0)
1446  latex.SetTextColor(R.kBlack)
1447 
1448  extraTextSize = extraOverCmsTextSize * cmsTextSize
1449  pad_ratio = (float(pad.GetWh()) * pad.GetAbsHNDC()) / \
1450  (float(pad.GetWw()) * pad.GetAbsWNDC())
1451  if (pad_ratio < 1.):
1452  pad_ratio = 1.
1453 
1454  if outOfFrame:
1455  latex.SetTextFont(cmsTextFont)
1456  latex.SetTextAlign(11)
1457  latex.SetTextSize(cmsTextSize * t * (1./pad_ratio))
1458  latex.DrawLatex(l, 1 - t + lumiTextOffset * t, cmsText)
1459 
1460  posX_ = 0
1461  if iPosX % 10 <= 1:
1462  posX_ = l + relPosX * (1 - l - r)
1463  elif (iPosX % 10 == 2):
1464  posX_ = l + 0.5 * (1 - l - r)
1465  elif (iPosX % 10 == 3):
1466  posX_ = 1 - r - relPosX * (1 - l - r)
1467 
1468  posY_ = 1 - t - relPosY * (1 - t - b)
1469  if not outOfFrame:
1470  latex.SetTextFont(cmsTextFont)
1471  latex.SetTextSize(cmsTextSize * t * pad_ratio)
1472  latex.SetTextAlign(align_)
1473  latex.DrawLatex(posX_, posY_, cmsText)
1474  if writeExtraText:
1475  latex.SetTextFont(extraTextFont)
1476  latex.SetTextAlign(align_)
1477  latex.SetTextSize(extraTextSize * t * pad_ratio)
1478  latex.DrawLatex(
1479  posX_, posY_ - relExtraDY * cmsTextSize * t, extraText)
1480  if writeExtraText2:
1481  latex.DrawLatex(
1482  posX_, posY_ - 1.8 * relExtraDY * cmsTextSize * t, extraText2)
1483  elif writeExtraText:
1484  if iPosX == 0:
1485  posX_ = l + relPosX * (1 - l - r)
1486  posY_ = 1 - t + lumiTextOffset * t
1487  latex.SetTextFont(extraTextFont)
1488  latex.SetTextSize(extraTextSize * t * (1./pad_ratio))
1489  latex.SetTextAlign(align_)
1490  latex.DrawLatex(posX_, posY_, extraText)
1491 
1492 
1493 def PositionedLegend(width, height, pos, offset, horizontaloffset=None):
1494  o = offset
1495  ho = horizontaloffset
1496  if not ho:
1497  ho = o
1498  w = width
1499  h = height
1500  l = R.gPad.GetLeftMargin()
1501  t = R.gPad.GetTopMargin()
1502  b = R.gPad.GetBottomMargin()
1503  r = R.gPad.GetRightMargin()
1504  if pos == 1:
1505  return R.TLegend(l + ho, 1 - t - o - h, l + ho + w, 1 - t - o, '', 'NBNDC')
1506  if pos == 2:
1507  c = l + 0.5 * (1 - l - r)
1508  return R.TLegend(c - 0.5 * w, 1 - t - o - h, c + 0.5 * w, 1 - t - o, '', 'NBNDC')
1509  if pos == 3:
1510  return R.TLegend(1 - r - ho - w, 1 - t - o - h, 1 - r - ho, 1 - t - o, '', 'NBNDC')
1511  if pos == 4:
1512  return R.TLegend(l + ho, b + o, l + ho + w, b + o + h, '', 'NBNDC')
1513  if pos == 5:
1514  c = l + 0.5 * (1 - l - r)
1515  return R.TLegend(c - 0.5 * w, b + o, c + 0.5 * w, b + o + h, '', 'NBNDC')
1516  if pos == 6:
1517  return R.TLegend(1 - r - ho - w, b + o, 1 - r - ho, b + o + h, '', 'NBNDC')
1518 
1519 
1520 def DrawHorizontalLine(pad, line, yval):
1521  axis = GetAxisHist(pad)
1522  xmin = axis.GetXaxis().GetXmin()
1523  xmax = axis.GetXaxis().GetXmax()
1524  line.DrawLine(xmin, yval, xmax, yval)
1525 
1526 
1527 def DrawVerticalLine(pad, line, xval):
1528  axis = GetAxisHist(pad)
1529  ymin = axis.GetYaxis().GetXmin()
1530  ymax = axis.GetYaxis().GetXmax()
1531  line.DrawLine(xval, ymin, xval, ymax)
1532 
1533 def DrawVerticalBand(pad, box, x1, x2):
1534  axis = GetAxisHist(pad)
1535  ymin = axis.GetYaxis().GetXmin()
1536  ymax = axis.GetYaxis().GetXmax()
1537  box.DrawBox(x1, ymin, x2, ymax)
1538 
1539 
1540 def DrawTitle(pad, text, align, textOffset=0.2,textSize=0.6):
1541  pad_backup = R.gPad
1542  pad.cd()
1543  t = pad.GetTopMargin()
1544  l = pad.GetLeftMargin()
1545  r = pad.GetRightMargin()
1546 
1547  pad_ratio = (float(pad.GetWh()) * pad.GetAbsHNDC()) / \
1548  (float(pad.GetWw()) * pad.GetAbsWNDC())
1549  if pad_ratio < 1.:
1550  pad_ratio = 1.
1551 
1552  latex = R.TLatex()
1553  latex.SetNDC()
1554  latex.SetTextAngle(0)
1555  latex.SetTextColor(R.kBlack)
1556  latex.SetTextFont(42)
1557  latex.SetTextSize(textSize * t * pad_ratio)
1558 
1559  y_off = 1 - t + textOffset * t
1560  if align == 1:
1561  latex.SetTextAlign(11)
1562  if align == 1:
1563  latex.DrawLatex(l, y_off, text)
1564  if align == 2:
1565  latex.SetTextAlign(21)
1566  if align == 2:
1567  latex.DrawLatex(l + (1 - l - r) * 0.5, y_off, text)
1568  if align == 3:
1569  latex.SetTextAlign(31)
1570  if align == 3:
1571  latex.DrawLatex(1 - r, y_off, text)
1572  pad_backup.cd()
1573 
1574 
1575 
1576 
1577 
1583 
1584 def isclose(a, b, rel_tol=1e-9, abs_tol=0.0):
1585  return abs(a-b) <= max(abs_tol, rel_tol * max(abs(a),abs(b)))
1586 
1587 def StyleLimitBand(graph_dict, overwrite_style_dict=None):
1588  style_dict = {
1589  'obs' : { 'LineWidth' : 2},
1590  'exp0' : { 'LineWidth' : 2, 'LineColor' : R.kRed},
1591  'exp1' : { 'FillColor' : R.kGreen},
1592  'exp2' : { 'FillColor' : R.kYellow}
1593  }
1594  if overwrite_style_dict is not None:
1595  for key in overwrite_style_dict:
1596  if key in style_dict:
1597  style_dict[key].update(overwrite_style_dict[key])
1598  else:
1599  style_dict[key] = overwrite_style_dict[key]
1600  for key in graph_dict:
1601  Set(graph_dict[key],**style_dict[key])
1602 
1603 def DrawLimitBand(pad, graph_dict, draw=['exp2', 'exp1', 'exp0', 'obs'], draw_legend=None,
1604  legend=None, legend_overwrite=None):
1605  legend_dict = {
1606  'obs' : { 'Label' : 'Observed', 'LegendStyle' : 'LP', 'DrawStyle' : 'PLSAME'},
1607  'exp0' : { 'Label' : 'Expected', 'LegendStyle' : 'L', 'DrawStyle' : 'LSAME'},
1608  'exp1' : { 'Label' : '#pm1#sigma Expected', 'LegendStyle' : 'F', 'DrawStyle' : '3SAME'},
1609  'exp2' : { 'Label' : '#pm2#sigma Expected', 'LegendStyle' : 'F', 'DrawStyle' : '3SAME'}
1610  }
1611  if legend_overwrite is not None:
1612  for key in legend_overwrite:
1613  if key in legend_dict:
1614  legend_dict[key].update(legend_overwrite[key])
1615  else:
1616  legend_dict[key] = legend_overwrite[key]
1617  pad.cd()
1618  for key in draw:
1619  if key in graph_dict:
1620  graph_dict[key].Draw(legend_dict[key]['DrawStyle'])
1621  if legend is not None:
1622  if draw_legend is None:
1623  draw_legend = reversed(draw)
1624  for key in draw_legend:
1625  if key in graph_dict:
1626  legend.AddEntry(graph_dict[key],legend_dict[key]['Label'],legend_dict[key]['LegendStyle'])
1627 
1628 
1629 
1630 
1631 
1632 
1633 
1637 def contourFromTH2(h2in, threshold, minPoints=10, frameValue=1000.):
1638  # // http://root.cern.ch/root/html/tutorials/hist/ContourList.C.html
1639  contoursList = [threshold]
1640  contours = array('d', contoursList)
1641  # if (h2in.GetNbinsX() * h2in.GetNbinsY()) > 10000: minPoints = 50
1642  # if (h2in.GetNbinsX() * h2in.GetNbinsY()) <= 100: minPoints = 10
1643 
1644  h2 = frameTH2D(h2in, threshold, frameValue)
1645 
1646  h2.SetContour(1, contours)
1647 
1648  # Draw contours as filled regions, and Save points
1649  # backup = R.gPad # doesn't work in pyroot, backup behaves like a ref to gPad
1650  canv = R.TCanvas('tmp', 'tmp')
1651  canv.cd()
1652  h2.Draw('CONT Z LIST')
1653  R.gPad.Update() # Needed to force the plotting and retrieve the contours in
1654 
1655  conts = R.gROOT.GetListOfSpecials().FindObject('contours')
1656  contLevel = None
1657 
1658  if conts is None or conts.GetSize() == 0:
1659  print('*** No Contours Were Extracted!')
1660  return None
1661  ret = R.TList()
1662  for i in range(conts.GetSize()):
1663  contLevel = conts.At(i)
1664  print('>> Contour %d has %d Graphs' % (i, contLevel.GetSize()))
1665  for j in range(contLevel.GetSize()):
1666  gr1 = contLevel.At(j)
1667  print('\t Graph %d has %d points' % (j, gr1.GetN()))
1668  if gr1.GetN() > minPoints:
1669  ret.Add(gr1.Clone())
1670  # // break;
1671  # backup.cd()
1672  canv.Close()
1673  return ret
1674 
1675 
1676 def frameTH2D(hist, threshold, frameValue=1000):
1677  # Now supports variable-binned histograms First adds a narrow frame (1% of
1678  # of bin widths) around the outside with same values as the real edge. Then
1679  # adds another frame another frame around this one filled with some chosen
1680  # value that will make the contours close
1681 
1682  # Get lists of the bin edges
1683  x_bins = [hist.GetXaxis().GetBinLowEdge(x)
1684  for x in range(1, hist.GetNbinsX() + 2)]
1685  y_bins = [hist.GetYaxis().GetBinLowEdge(y)
1686  for y in range(1, hist.GetNbinsY() + 2)]
1687 
1688  # New bin edge arrays will need an extra four values
1689  x_new = [0.] * (len(x_bins) + 4)
1690  y_new = [0.] * (len(y_bins) + 4)
1691 
1692  # Calculate bin widths at the edges
1693  xw1 = x_bins[1] - x_bins[0]
1694  xw2 = x_bins[-1] - x_bins[-2]
1695  yw1 = y_bins[1] - y_bins[0]
1696  yw2 = y_bins[-1] - y_bins[-2]
1697 
1698  # Set the edges of the outer framing bins and the adjusted
1699  # edge of the real edge bins
1700  x_new[0] = x_bins[0] - 2 * xw1 * 0.02
1701  x_new[1] = x_bins[0] - 1 * xw1 * 0.02
1702  x_new[-1] = x_bins[-1] + 2 * xw2 * 0.02
1703  x_new[-2] = x_bins[-1] + 1 * xw2 * 0.02
1704  y_new[0] = y_bins[0] - 2 * yw1 * 0.02
1705  y_new[1] = y_bins[0] - 1 * yw1 * 0.02
1706  y_new[-1] = y_bins[-1] + 2 * yw2 * 0.02
1707  y_new[-2] = y_bins[-1] + 1 * yw2 * 0.02
1708 
1709  # Copy the remaining bin edges from the hist
1710  for i in range(0, len(x_bins)):
1711  x_new[i + 2] = x_bins[i]
1712  for i in range(0, len(y_bins)):
1713  y_new[i + 2] = y_bins[i]
1714 
1715  # print x_new
1716  # print y_new
1717 
1718  framed = R.TH2D('%s framed' % hist.GetName(), '%s framed' % hist.GetTitle(), len(
1719  x_new) - 1, array('d', x_new), len(y_new) - 1, array('d', y_new))
1720  framed.SetDirectory(0)
1721 
1722  for x in range(1, framed.GetNbinsX() + 1):
1723  for y in range(1, framed.GetNbinsY() + 1):
1724  if x == 1 or x == framed.GetNbinsX() or y == 1 or y == framed.GetNbinsY():
1725  # This is a a frame bin
1726  framed.SetBinContent(x, y, frameValue)
1727  else:
1728  # adjust x and y if we're in the first frame so as to copy the output
1729  # values from the real TH2
1730  ux = x
1731  uy = y
1732  if x == 2:
1733  ux += 1
1734  elif x == (len(x_new) - 2):
1735  ux -= 1
1736  if y == 2:
1737  uy += 1
1738  elif y == (len(y_new) - 2):
1739  uy -= 1
1740  framed.SetBinContent(x, y, hist.GetBinContent(ux - 2, uy - 2))
1741  return framed
1742 
1743 def fastFillTH2(hist2d, graph, initalValue=99999, interpolateMissing=False):
1744  for x in range(1,hist2d.GetNbinsX()+1):
1745  for y in range(1,hist2d.GetNbinsY()+1):
1746  hist2d.SetBinContent(x,y,initalValue)
1747  # for i in xrange(graph.GetN()):
1748  # hist2d.Fill(graph.GetX()[i],graph.GetY()[i],graph.GetZ()[i])
1749  for i in range(graph.GetN()):
1750  xbin = hist2d.GetXaxis().FindBin(graph.GetX()[i])
1751  ybin = hist2d.GetYaxis().FindBin(graph.GetY()[i])
1752  if isclose(hist2d.GetXaxis().GetBinCenter(xbin), graph.GetX()[i], rel_tol=1e-2) and isclose(hist2d.GetYaxis().GetBinCenter(ybin), graph.GetY()[i], rel_tol=1e-2):
1753  hist2d.SetBinContent(xbin, ybin, graph.GetZ()[i])
1754  interpolated = 0
1755  if interpolateMissing:
1756  for x in range(1,hist2d.GetNbinsX()+1):
1757  for y in range(1,hist2d.GetNbinsY()+1):
1758  if hist2d.GetBinContent(x,y) == initalValue:
1759  interpolated += 1
1760  hist2d.SetBinContent(x, y, graph.Interpolate(hist2d.GetXaxis().GetBinCenter(x),hist2d.GetYaxis().GetBinCenter(y)))
1761 
1762 def fillTH2(hist2d, graph):
1763  for x in range(1, hist2d.GetNbinsX() + 1):
1764  for y in range(1, hist2d.GetNbinsY() + 1):
1765  xc = hist2d.GetXaxis().GetBinCenter(x)
1766  yc = hist2d.GetYaxis().GetBinCenter(y)
1767  val = graph.Interpolate(xc, yc)
1768  hist2d.SetBinContent(x, y, val)
1769 
1770 def fillInvertedTH2(hist2d, graph):
1771  for x in range(1, hist2d.GetNbinsX() + 1):
1772  for y in range(1, hist2d.GetNbinsY() + 1):
1773  xc = hist2d.GetXaxis().GetBinCenter(x)
1774  yc = hist2d.GetYaxis().GetBinCenter(y)
1775  val = graph.Interpolate(xc, yc)
1776  hist2d.SetBinContent(x, y, 1-val)
1777 
1778 
1779 
1780 # Functions 'NewInterpolate' and 'rebin' are taken, translated and modified into python from:
1781 # https://indico.cern.ch/event/256523/contribution/2/attachments/450198/624259/07JUN2013_cawest.pdf
1782 # http://hep.ucsb.edu/people/cawest/interpolation/interpolate.h
1783 def NewInterpolate(hist):
1784  histCopy = hist.Clone()
1785 
1786  # make temporary histograms to store the results of both steps
1787  hist_step1 = histCopy.Clone()
1788  hist_step1.Reset()
1789  hist_step2 = histCopy.Clone()
1790  hist_step2.Reset()
1791 
1792  nBinsX = histCopy.GetNbinsX()
1793  nBinsY = histCopy.GetNbinsY()
1794 
1795  xMin = 1
1796  yMin = 1
1797  xMax = histCopy.GetNbinsX() + 1
1798  yMax = histCopy.GetNbinsY() + 1
1799 
1800  for i in range(1, nBinsX + 1):
1801  for j in range(1, nBinsY + 1):
1802  # do not extrapolate outside the scan
1803  if (i < xMin) or (i > xMax) or (j < yMin) or (j > yMax):
1804  continue
1805  binContent = histCopy.GetBinContent(i, j)
1806  binContentNW = histCopy.GetBinContent(i + 1, j + 1)
1807  binContentSE = histCopy.GetBinContent(i - 1, j - 1)
1808  binContentNE = histCopy.GetBinContent(i + 1, j - 1)
1809  binContentSW = histCopy.GetBinContent(i - 1, j + 1)
1810  binContentUp = histCopy.GetBinContent(i, j + 1)
1811  binContentDown = histCopy.GetBinContent(i, j - 1)
1812  binContentLeft = histCopy.GetBinContent(i - 1, j)
1813  binContentRight = histCopy.GetBinContent(i + 1, j)
1814  nFilled = 0
1815  if(binContentNW > 0):
1816  nFilled += 1
1817  if(binContentSE > 0):
1818  nFilled += 1
1819  if(binContentNE > 0):
1820  nFilled += 1
1821  if(binContentSW > 0):
1822  nFilled += 1
1823  if(binContentUp > 0):
1824  nFilled += 1
1825  if(binContentDown > 0):
1826  nFilled += 1
1827  if(binContentRight > 0):
1828  nFilled += 1
1829  if(binContentLeft > 0):
1830  nFilled += 1
1831  # if we are at an empty bin and there are neighbors
1832  # in specified direction with non-zero entries
1833  if(binContent == 0) and (nFilled > 1):
1834  # average over non-zero entries
1835  binContent = (binContentNW + binContentSE + binContentNE + binContentSW +
1836  binContentUp + binContentDown + binContentRight + binContentLeft) / nFilled
1837  hist_step1.SetBinContent(i, j, binContent)
1838 
1839  # add result of interpolation
1840  histCopy.Add(hist_step1)
1841 
1842  for i in range(1, nBinsX):
1843  for j in range(1, nBinsY):
1844  if(i < xMin) or (i > xMax) or (j < yMin) or (j > yMax):
1845  continue
1846  binContent = histCopy.GetBinContent(i, j)
1847  # get entries for "Swiss Cross" average
1848  binContentUp = histCopy.GetBinContent(i, j + 1)
1849  binContentDown = histCopy.GetBinContent(i, j - 1)
1850  binContentLeft = histCopy.GetBinContent(i - 1, j)
1851  binContentRight = histCopy.GetBinContent(i + 1, j)
1852  nFilled = 0
1853  if(binContentUp > 0):
1854  nFilled += 1
1855  if(binContentDown > 0):
1856  nFilled += 1
1857  if(binContentRight > 0):
1858  nFilled += 1
1859  if(binContentLeft > 0):
1860  nFilled += 1
1861  if(binContent == 0) and (nFilled > 0):
1862  # only average over non-zero entries
1863  binContent = (
1864  binContentUp + binContentDown + binContentRight + binContentLeft) / nFilled
1865  hist_step2.SetBinContent(i, j, binContent)
1866  # add "Swiss Cross" average
1867  histCopy.Add(hist_step2)
1868 
1869  return histCopy
1870 
1871 
1872 def rebin(hist):
1873  histName = hist.GetName()
1874  histName += "_rebin"
1875 
1876  # bin widths are needed so as to not shift histogram by half a bin with each rebinning
1877  # assume constant binning
1878  # binWidthX = hist.GetXaxis().GetBinWidth(1)
1879  # binWidthY = hist.GetYaxis().GetBinWidth(1)
1880 
1881  # histRebinned = R.TH2F(histName, histName, 2*hist.GetNbinsX(), hist.GetXaxis().GetXmin()+binWidthX/4, hist.GetXaxis().GetXmax()+binWidthX/4, 2*hist.GetNbinsY(), hist.GetYaxis().GetXmin()+binWidthY/4, hist.GetYaxis().GetXmax()+binWidthY/4)
1882  histRebinned = R.TH2F(histName, histName, 2 * hist.GetNbinsX() - 1, hist.GetXaxis().GetXmin(),
1883  hist.GetXaxis().GetXmax(), 2 * hist.GetNbinsY() - 1, hist.GetYaxis().GetXmin(), hist.GetYaxis().GetXmax())
1884 
1885  # copy results from previous histogram
1886  for iX in range(1, hist.GetNbinsX() + 1):
1887  for iY in range(1, hist.GetNbinsY() + 1):
1888  binContent = hist.GetBinContent(iX, iY)
1889  histRebinned.SetBinContent(2 * iX - 1, 2 * iY - 1, binContent)
1890  histRebinned.SetMaximum(hist.GetMaximum())
1891  histRebinned.SetMinimum(hist.GetMinimum())
1892 
1893  # use interpolation to re-fill histogram
1894  histRebinnedInterpolated = NewInterpolate(histRebinned)
1895 
1896  return histRebinnedInterpolated
1897 
1898 
1899 def higgsConstraint(model, higgstype):
1900  higgsBand = R.TGraph2D()
1901  masslow = 150
1902  masshigh = 500
1903  massstep = 10
1904  n = 0
1905  for mass in range(masslow, masshigh, massstep):
1906  myfile = open("../../HiggsAnalysis/HiggsToTauTau/data/Higgs125/" +
1907  model + "/higgs_" + str(mass) + ".dat", 'r')
1908  for line in myfile:
1909  tanb = (line.split())[0]
1910  mh = float((line.split())[1])
1911  mH = float((line.split())[3])
1912  if higgstype == "h":
1913  higgsBand.SetPoint(n, mass, float(tanb), mh)
1914  elif higgstype == "H":
1915  higgsBand.SetPoint(n, mass, float(tanb), mH)
1916  n = n + 1
1917  myfile.close()
1918  return higgsBand
1919 
1920 
1921 def getOverlayMarkerAndLegend(legend, entries, options, borderSize=2.0/3, markerStyle="P"):
1922  borderLegend = legend.Clone()
1923  borderLegend.Clear()
1924  graphs = []
1925  for i in range(legend.GetNRows()):
1926  if i in entries:
1927  graph = entries[i].Clone()
1928  options[i]["MarkerSize"] = graph.GetMarkerSize()*borderSize
1929  Set(graph,**options[i])
1930  borderLegend.AddEntry(graph, " ", markerStyle)
1931  graphs.append(graph)
1932  else:
1933  borderLegend.AddEntry("", " ", "")
1934  borderLegend.SetFillStyle(0)
1935  borderLegend.SetFillColor(0)
1936  return (borderLegend,graphs)
void FixBoxPadding(TPad *pad, TBox *box, double frac)
Modify the pad y-axis range to ensure there is at least a given gap between a particular TBox and the...
Definition: Plotting.h:902
void DrawTitle(TPad *pad, TString text, int align)
Draw text in the top-margin region of a TPad.
Definition: Plotting.h:713
void FixOverlay()
Just re-draws the axes on the current TPad.
Definition: Plotting.h:945
TH1 * MakeRatioHist(TH1 *num, TH1 *den, bool num_err, bool den_err)
Create a new histogram by dividing one by the other.
Definition: Plotting.h:567
void FixTopRange(TPad *pad, double fix_y, double fraction)
Adjusts the y-axis maximum on the pad such that the specified y-value is positioned a fixed fraction ...
Definition: Plotting.h:885
TLegend * PositionedLegend(double width, double height, int pos, double offset)
Create a legend with fixed height, width and positioning.
Definition: Plotting.h:669
TGraph TGraphFromTree(TTree *tree, TString const &xvar, TString const &yvar, TString const &selection="")
Create a TGraph from entries in a TTree.
Definition: Plotting.h:581
double GetPadYMax(TPad *pad, double x_min, double x_max)
Find the maximum value of all drawn objects in a given x-axis range.
Definition: Plotting.h:844
void StandardAxes(TAxis *xaxis, TAxis *yaxis, TString var, TString units)
Sets standard x- and y-axis titles with given units.
Definition: Plotting.h:651
std::vector< TPad * > OnePad()
Just creates a single pad filling the entire canvas.
Definition: Plotting.h:459
TLine * DrawHorizontalLine(TPad *pad, TLine *line, double yval)
Use an existing TLine to draw a new horizontal line across the current frame.
Definition: Plotting.h:705
std::vector< TH1 * > CreateAxisHists(unsigned n, TH1 *src, double xmin=0, double xmax=-1)
Create multiple axis TH1s from another TH1.
Definition: Plotting.h:494
TH1 * GetAxisHist(TPad *pad)
Finds the TH1 used to draw the axes on a given TPad.
Definition: Plotting.h:536
void SetupTwoPadSplitAsRatio(std::vector< TPad * > const &pads, TH1 *upper, TH1 *lower, TString y_title, bool y_centered, float y_min, float y_max)
Set a few style options for a two-pad setup used to show a data-MC comparison and ratio plot.
Definition: Plotting.h:632
void DrawCMSLogo(TPad *pad, TString cmsText, TString extraText, int iPosX, float relPosX, float relPosY, float relExtraDY)
Draw the CMS logo and subtitle in the new style.
Definition: Plotting.h:744
TH1 * CreateAxisHist(TH1 *src, double xmin=0, double xmax=-1)
Create an empty TH1 from another TH1 for drawing the axes.
Definition: Plotting.h:485
int CreateTransparentColor(int color, float alpha)
Create a transparent version of a colour.
Definition: Plotting.h:614
std::vector< TPad * > TwoPadSplit(double split_point, double gap_low, double gap_high)
Create two pads, split horizontally, on the current canvas split.
Definition: Plotting.h:468
void ReZeroTGraph(TGraph *gr)
Shift all the graph y-values upwards such that there are no negative values and the minimum point is ...
Definition: Plotting.h:595
TGraph2D TGraph2DFromTree(TTree *tree, TString const &xvar, TString const &yvar, TString const &zvar, TString const &selection="")
Create a TGraph2D from entries in a TTree.
Definition: Plotting.h:588
TH2D * frameTH2D(TH2D *in, double threshold)
TGraph * bestFit(TTree *t, TString x, TString y, TCut cut)
TList * contourFromTH2(TH2 *h2in, double threshold, int minPoints=20)
TH2 * treeToHist2D(TTree *t, TString x, TString y, TString name, TCut cut, double xmin, double xmax, double ymin, double ymax, int xbins, int ybins)
void SetTDRStyle()
Sets the semi-official CMS plotting global style.
void ModTDRStyle(int width, int height, double t, double b, double l, double r)
Sets an improved plotting style, using the CMS default as a base.