CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
plotting.py
Go to the documentation of this file.
1 import sys
2 import math
3 
4 import ROOT
5 ROOT.gROOT.SetBatch(True)
6 ROOT.PyConfig.IgnoreCommandLineOptions = True
7 
8 # Flag to indicate if it is ok to have missing files or histograms
9 # Set to true e.g. if there is no reference histograms
10 missingOk = False
11 
12 class AlgoOpt:
13  """Class to allow algorithm-specific values for e.g. plot bound values"""
14  def __init__(self, default, **kwargs):
15  """Constructor.
16 
17  Arguments:
18  default -- default value
19 
20  Keyword arguments are treated as a dictionary where the key is a name of an algorithm, and the value is a value for that algorithm
21  """
22  self._default = default
23  self._values = {}
24  self._values.update(kwargs)
25 
26  def value(self, algo):
27  """Get a value for an algorithm."""
28  if algo in self._values:
29  return self._values[algo]
30  return self._default
31 
32 def _getObject(tdirectory, name):
33  obj = tdirectory.Get(name)
34  if not obj:
35  print "Did not find {obj} from {dir}".format(obj=name, dir=tdirectory.GetPath())
36  if missingOk:
37  return None
38  else:
39  sys.exit(1)
40  return obj
41 
42 
44  return max([th1.GetBinContent(i)+th1.GetBinError(i) for i in xrange(1, th1.GetNbinsX()+1)])
45 
46 def _findBounds(th1s, xmin=None, xmax=None, ymin=None, ymax=None):
47  """Find x-y axis boundaries encompassing a list of TH1s if the bounds are not given in arguments.
48 
49  Arguments:
50  th1s -- List of TH1s
51 
52  Keyword arguments:
53  xmin -- Minimum x value; if None, take the minimum of TH1s
54  xmax -- Maximum x value; if None, take the maximum of TH1s
55  xmin -- Minimum y value; if None, take the minimum of TH1s
56  xmax -- Maximum y value; if None, take the maximum of TH1s
57  """
58  if xmin is None or xmax is None or ymin is None or ymax is None or isinstance(ymax, list):
59  xmins = []
60  xmaxs = []
61  ymins = []
62  ymaxs = []
63  for th1 in th1s:
64  xaxis = th1.GetXaxis()
65  xmins.append(xaxis.GetBinLowEdge(xaxis.GetFirst()))
66  xmaxs.append(xaxis.GetBinUpEdge(xaxis.GetLast()))
67  ymins.append(th1.GetMinimum())
68  ymaxs.append(th1.GetMaximum())
69 # ymaxs.append(_getYmaxWithError(th1))
70 
71  if xmin is None:
72  xmin = min(xmins)
73  if xmax is None:
74  xmax = max(xmaxs)
75  if ymin is None:
76  ymin = min(ymins)
77  if ymax is None:
78  ymax = 1.05*max(ymaxs)
79  elif isinstance(ymax, list):
80  ym = max(ymaxs)
81  ymaxs_above = filter(lambda y: y>ym, ymax)
82  if len(ymaxs_above) == 0:
83  raise Exception("Histogram maximum y %f is above all given ymax values %s" % (ym, str(ymax)))
84  ymax = min(ymaxs_above)
85 
86  for th1 in th1s:
87  th1.GetXaxis().SetRangeUser(xmin, xmax)
88  th1.GetYaxis().SetRangeUser(ymin, ymax)
89 
90  return (xmin, ymin, xmax, ymax)
91 
92 
94  """Class to calculate the fake+duplicate rate"""
95  def __init__(self, name, assoc, dup, reco, title=""):
96  """Constructor.
97 
98  Arguments:
99  name -- String for the name of the resulting efficiency histogram
100  assoc -- String for the name of the "associated" histogram
101  dup -- String for the name of the "duplicates" histogram
102  reco -- String for the name of the "reco" (denominator) histogram
103 
104  Keyword arguments:
105  title -- String for a title of the resulting histogram (default "")
106 
107  The result is calculated as 1 - (assoc - dup) / reco
108  """
109  self._name = name
110  self._assoc = assoc
111  self._dup = dup
112  self._reco = reco
113  self._title = title
114 
115  def __str__(self):
116  """String representation, returns the name"""
117  return self._name
118 
119  def create(self, tdirectory):
120  """Create and return the efficiency histogram from a TDirectory"""
121  # Get the numerator/denominator histograms
122  hassoc = _getObject(tdirectory, self._assoc)
123  hdup = _getObject(tdirectory, self._dup)
124  hreco = _getObject(tdirectory, self._reco)
125 
126  # Skip if any of them does not exist
127  if not hassoc or not hdup or not hreco:
128  return None
129 
130  hfakedup = hreco.Clone(self._name)
131  hfakedup.SetTitle(self._title)
132 
133  for i in xrange(1, hassoc.GetNbinsX()+1):
134  numerVal = hassoc.GetBinContent(i) - hdup.GetBinContent(i)
135  denomVal = hreco.GetBinContent(i)
136 
137  fakedupVal = (1 - numerVal / denomVal) if denomVal != 0.0 else 0.0
138  errVal = math.sqrt(fakedupVal*(1-fakedupVal)/denomVal) if (denomVal != 0.0 and fakedupVal <= 1) else 0.0
139 
140  hfakedup.SetBinContent(i, fakedupVal)
141  hfakedup.SetBinError(i, errVal)
142 
143  return hfakedup
144 
146  def __init__(self, name, histoName, mapping, normalizeTo=None, scale=None):
147  self._name = name
148  self._histoName = histoName
149  self._mapping = mapping
150  self._normalizeTo = normalizeTo
151  self._scale = scale
152 
153  def __str__(self):
154  return self._name
155 
156  def create(self, tdirectory):
157  th1 = _getObject(tdirectory, self._histoName)
158  if th1 is None:
159  return None
160 
161  result = ROOT.TH1F(self._name, self._name, len(self._mapping), 0, len(self._mapping))
162 
163  if isinstance(self._mapping, list):
164  for i, label in enumerate(self._mapping):
165  bin = th1.GetXaxis().FindBin(label)
166  if bin > 0:
167  result.SetBinContent(i+1, th1.GetBinContent(bin))
168  result.GetXaxis().SetBinLabel(i+1, label)
169  else:
170  for i, (key, labels) in enumerate(self._mapping.iteritems()):
171  sumTime = 0
172  for l in labels:
173  bin = th1.GetXaxis().FindBin(l)
174  if bin > 0:
175  sumTime += th1.GetBinContent(bin)
176  result.SetBinContent(i+1, sumTime)
177  result.GetXaxis().SetBinLabel(i+1, key)
178 
179  if self._normalizeTo is not None:
180  bin = th1.GetXaxis().FindBin(self._normalizeTo)
181  if bin <= 0:
182  print "Trying to normalize {name} to {binlabel}, which does not exist".format(name=self._name, binlabel=self._normalizeTo)
183  sys.exit(1)
184  value = th1.GetBinContent(bin)
185  if value != 0:
186  result.Scale(1/value)
187 
188  if self._scale is not None:
189  result.Scale(self._scale)
190 
191  return result
192 
194  def __init__(self, name, mapping, normalizeTo=None):
195  self._name = name
196  self._mapping = mapping
197  self._normalizeTo = normalizeTo
198 
199  def __str__(self):
200  return self._name
201 
202  def create(self, tdirectory):
203  result = []
204  for key, histoName in self._mapping.iteritems():
205  th1 = _getObject(tdirectory, histoName)
206  if th1 is None:
207  continue
208  result.append( (key, th1.Integral(0, th1.GetNbinsX()+1)) ) # include under- and overflow bins
209  if len(result) == 0:
210  return None
211 
212  res = ROOT.TH1F(self._name, self._name, len(result), 0, len(result))
213 
214  for i, (name, count) in enumerate(result):
215  res.SetBinContent(i+1, count)
216  res.GetXaxis().SetBinLabel(i+1, name)
217 
218  if self._normalizeTo is not None:
219  th1 = _getObject(tdirectory, self._normalizeTo)
220  if th1 is None:
221  return None
222  scale = th1.Integral(0, th1.GetNbinsX()+1)
223  res.Scale(1/scale)
224 
225  return res
226 
227 # Plot styles
228 _plotStylesColor = [4, 2, ROOT.kBlack, ROOT.kOrange+7, ROOT.kMagenta-3]
229 _plotStylesMarker = [21, 20, 22, 34, 33]
230 
231 class Plot:
232  """Represents one plot, comparing one or more histograms."""
233  def __init__(self, name, **kwargs):
234  """ Constructor.
235 
236  Arguments:
237  name -- String for name of the plot, or Efficiency object
238 
239  Keyword arguments:
240  title -- String for a title of the plot (default None)
241  xtitle -- String for x axis title (default None)
242  ytitle -- String for y axis title (default None)
243  ytitlesize -- Float for y axis title size (default None)
244  ytitleoffset -- Float for y axis title offset (default None)
245  xmin -- Float for x axis minimum (default None, i.e. automatic)
246  xmax -- Float for x axis maximum (default None, i.e. automatic)
247  ymin -- Float for y axis minimum (default 0)
248  ymax -- Float for y axis maximum (default None, i.e. automatic)
249  xlog -- Bool for x axis log status (default False)
250  ylog -- Bool for y axis log status (default False)
251  xgrid -- Bool for x axis grid status (default True)
252  ygrid -- Bool for y axis grid status (default True)
253  stat -- Draw stat box? (default False)
254  fit -- Do gaussian fit? (default False)
255  statx -- Stat box x coordinate (default 0.65)
256  staty -- Stat box y coordinate (default 0.8)
257  statyadjust -- List of floats for stat box y coordinate adjustments (default None)
258  normalizeToUnitArea -- Normalize histograms to unit area? (default False)
259  profileX -- Take histograms via ProfileX()? (default False)
260  fitSlicesY -- Take histograms via FitSlicesY() (default False)
261  scale -- Scale histograms by a number (default None)
262  xbinlabels -- List of x axis bin labels (if given, default None)
263  xbinlabelsize -- Size of x axis bin labels (default None)
264  xbinlabeloption -- Option string for x axis bin labels (default None)
265  drawStyle -- If "hist", draw as line instead of points (default None)
266  drawCommand -- Deliver this to Draw() (default: None for same as drawStyle)
267  lineWidth -- If drawStyle=="hist", the width of line (default 2)
268  legendDx -- Float for moving TLegend in x direction for separate=True (default None)
269  legendDy -- Float for moving TLegend in y direction for separate=True (default None)
270  legendDw -- Float for changing TLegend width for separate=True (default None)
271  legendDh -- Float for changing TLegend height for separate=True (default None)
272  histogramModifier -- Function to be called in create() to modify the histograms (default None)
273  """
274  self._name = name
275 
276  def _set(attr, default):
277  setattr(self, "_"+attr, kwargs.get(attr, default))
278 
279  _set("title", None)
280  _set("xtitle", None)
281  _set("ytitle", None)
282  _set("ytitlesize", None)
283  _set("ytitleoffset", None)
284 
285  _set("xmin", None)
286  _set("xmax", None)
287  _set("ymin", 0.)
288  _set("ymax", None)
289 
290  _set("xlog", False)
291  _set("ylog", False)
292  _set("xgrid", True)
293  _set("ygrid", True)
294 
295  _set("stat", False)
296  _set("fit", False)
297 
298  _set("statx", 0.65)
299  _set("staty", 0.8)
300  _set("statyadjust", None)
301 
302  _set("normalizeToUnitArea", False)
303  _set("profileX", False)
304  _set("fitSlicesY", False)
305  _set("scale", None)
306  _set("xbinlabels", None)
307  _set("xbinlabelsize", None)
308  _set("xbinlabeloption", None)
309 
310  _set("drawStyle", None)
311  _set("drawCommand", None)
312  _set("lineWidth", 2)
313 
314  _set("legendDx", None)
315  _set("legendDy", None)
316  _set("legendDw", None)
317  _set("legendDh", None)
318 
319  _set("histogramModifier", None)
320 
321  self._histograms = []
322 
324  """Return number of existing histograms."""
325  return len(self._histograms)
326 
327  def getName(self):
328  return str(self._name)
329 
330  def _createOne(self, tdir):
331  """Create one histogram from a TDirectory."""
332  if tdir == None:
333  return None
334 
335  # If name is Efficiency instead of string, call its create()
336  if hasattr(self._name, "create"):
337  th1 = self._name.create(tdir)
338  else:
339  th1 = tdir.Get(self._name)
340 
341  # Check the histogram exists
342  if th1 == None:
343  print "Did not find {histo} from {dir}".format(histo=self._name, dir=tdir.GetPath())
344  if missingOk:
345  return None
346  else:
347  sys.exit(1)
348 
349  return th1
350 
351  def create(self, tdirs):
352  """Create histograms from list of TDirectories"""
353  self._histograms = [self._createOne(tdir) for tdir in tdirs]
354 
355  if self._histogramModifier is not None:
356  self._histograms = self._histogramModifier(self._histograms)
357 
358  if len(self._histograms) > len(_plotStylesColor):
359  raise Exception("More histograms (%d) than there are plot styles (%d) defined. Please define more plot styles in this file" % (len(self._histograms), len(_plotStylesColor)))
360 
361  # Modify histograms here in case self._name returns numbers
362  # and self._histogramModifier creates the histograms from
363  # these numbers
364  def _modifyHisto(th1):
365  if th1 is None:
366  return None
367 
368  if self._profileX:
369  th1 = th1.ProfileX()
370 
371  if self._fitSlicesY:
372  ROOT.TH1.AddDirectory(True)
373  th1.FitSlicesY()
374  th1 = ROOT.gDirectory.Get(th1.GetName()+"_2")
375  th1.SetDirectory(None)
376  #th1.SetName(th1.GetName()+"_ref")
377  ROOT.TH1.AddDirectory(False)
378 
379  if self._title is not None:
380  th1.SetTitle(self._title)
381 
382  if self._scale is not None:
383  th1.Scale(self._scale)
384 
385  return th1
386 
387  self._histograms = map(_modifyHisto, self._histograms)
388 
389 
390  def _setStats(self, startingX, startingY):
391  """Set stats box."""
392  if not self._stat:
393  for h in self._histograms:
394  if h is not None and hasattr(h, "SetStats"):
395  h.SetStats(0)
396  return
397 
398  def _doStats(h, col, dy):
399  if h is None:
400  return
401  h.SetStats(1)
402 
403  if self._fit:
404  h.Fit("gaus", "Q")
405  f = h.GetListOfFunctions().FindObject("gaus")
406  if f == None:
407  h.SetStats(0)
408  return
409  f.SetLineColor(col)
410  f.SetLineWidth(1)
411  h.Draw()
412  ROOT.gPad.Update()
413  st = h.GetListOfFunctions().FindObject("stats")
414  if self._fit:
415  st.SetOptFit(0010)
416  st.SetOptStat(1001)
417  st.SetX1NDC(startingX)
418  st.SetX2NDC(startingX+0.3)
419  st.SetY1NDC(startingY+dy)
420  st.SetY2NDC(startingY+dy+0.15)
421  st.SetTextColor(col)
422 
423  dy = 0.0
424  for i, h in enumerate(self._histograms):
425  if self._statyadjust is not None and i < len(self._statyadjust):
426  dy += self._statyadjust[i]
427 
428  _doStats(h, _plotStylesColor[i], dy)
429  dy -= 0.19
430 
431  def _normalize(self):
432  """Normalise histograms to unit area"""
433 
434  for h in self._histograms:
435  if h is None:
436  continue
437  i = h.Integral()
438  if i == 0:
439  continue
440  h.Scale(1.0/i)
441 
442  def draw(self, algo):
443  """Draw the histograms using values for a given algorithm."""
444  if self._normalizeToUnitArea:
445  self._normalize()
446 
447  def _styleMarker(h, msty, col):
448  h.SetMarkerStyle(msty)
449  h.SetMarkerColor(col)
450  h.SetMarkerSize(0.7)
451  h.SetLineColor(1)
452  h.SetLineWidth(1)
453 
454  def _styleHist(h, msty, col):
455  _styleMarker(h, msty, col)
456  h.SetLineColor(col)
457  h.SetLineWidth(self._lineWidth)
458 
459  # Use marker or hist style
460  style = _styleMarker
461  if self._drawStyle is not None:
462  if "hist" in self._drawStyle.lower():
463  style = _styleHist
464  if isinstance(self._histograms[0], ROOT.TGraph):
465  if "l" in self._drawStyle.lower():
466  style = _styleHist
467 
468  # Apply style to histograms, filter out Nones
469  histos = []
470  for i, h in enumerate(self._histograms):
471  if h is None:
472  continue
473  style(h, _plotStylesMarker[i], _plotStylesColor[i])
474  histos.append(h)
475  if len(histos) == 0:
476  print "No histograms for plot {name}".format(name=self._name)
477  return
478 
479  # Set log and grid
480  ROOT.gPad.SetLogx(self._xlog)
481  ROOT.gPad.SetLogy(self._ylog)
482  ROOT.gPad.SetGridx(self._xgrid)
483  ROOT.gPad.SetGridy(self._ygrid)
484 
485  # Return value if number, or algo-specific value if AlgoOpt
486  def _getVal(val):
487  if hasattr(val, "value"):
488  return val.value(algo)
489  return val
490 
491  bounds = _findBounds(histos,
492  xmin=_getVal(self._xmin), xmax=_getVal(self._xmax),
493  ymin=_getVal(self._ymin), ymax=_getVal(self._ymax))
494 
495  # Create bounds before stats in order to have the
496  # SetRangeUser() calls made before the fit
497  self._setStats(self._statx, self._staty)
498 
499  xbinlabels = self._xbinlabels
500  if xbinlabels is None:
501  if len(histos[0].GetXaxis().GetBinLabel(1)) > 0:
502  xbinlabels = []
503  for i in xrange(1, histos[0].GetNbinsX()+1):
504  xbinlabels.append(histos[0].GetXaxis().GetBinLabel(i))
505 
506  # Create frame
507  if xbinlabels is None:
508  frame = ROOT.gPad.DrawFrame(*bounds)
509  else:
510  # Special form needed if want to set x axis bin labels
511  nbins = len(xbinlabels)
512  frame = ROOT.TH1F("hframe", "hframe", nbins, bounds[0], bounds[2])
513  frame.SetBit(ROOT.TH1.kNoStats)
514  frame.SetBit(ROOT.kCanDelete)
515  frame.SetMinimum(bounds[1])
516  frame.SetMaximum(bounds[3])
517  frame.GetYaxis().SetLimits(bounds[1], bounds[3])
518  frame.Draw("")
519 
520  xaxis = frame.GetXaxis()
521  for i in xrange(nbins):
522  xaxis.SetBinLabel(i+1, xbinlabels[i])
523  if self._xbinlabelsize is not None:
524  xaxis.SetLabelSize(self._xbinlabelsize)
525  if self._xbinlabeloption is not None:
526  frame.LabelsOption(self._xbinlabeloption)
527 
528  # Set properties of frame
529  frame.SetTitle(histos[0].GetTitle())
530  if self._xtitle is not None:
531  frame.GetXaxis().SetTitle(self._xtitle)
532  if self._ytitle is not None:
533  frame.GetYaxis().SetTitle(self._ytitle)
534  if self._ytitlesize is not None:
535  frame.GetYaxis().SetTitleSize(self._ytitlesize)
536  if self._ytitleoffset is not None:
537  frame.GetYaxis().SetTitleOffset(self._ytitleoffset)
538 
539  # Draw histograms
540  opt = "sames" # s for statbox or something?
541  ds = ""
542  if self._drawStyle is not None:
543  ds = self._drawStyle
544  if self._drawCommand is not None:
545  ds = self._drawCommand
546  if len(ds) > 0:
547  opt += " "+ds
548  for h in histos:
549  h.Draw(opt)
550 
551  ROOT.gPad.RedrawAxis()
552  self._frame = frame # keep the frame in memory for sure
553 
554  def addToLegend(self, legend, legendLabels):
555  """Add histograms to a legend.
556 
557  Arguments:
558  legend -- TLegend
559  legendLabels -- List of strings for the legend labels
560  """
561  for h, label in zip(self._histograms, legendLabels):
562  if h is None:
563  continue
564  legend.AddEntry(h, label, "LP")
565 
566 class PlotGroup:
567  """Group of plots, results a TCanvas"""
568  def __init__(self, name, plots, **kwargs):
569  """Constructor.
570 
571  Arguments:
572  name -- String for name of the TCanvas, used also as the basename of the picture files
573  plots -- List of Plot objects
574 
575  Keyword arguments:
576  legendDx -- Float for moving TLegend in x direction (default None)
577  legendDy -- Float for moving TLegend in y direction (default None)
578  legendDw -- Float for changing TLegend width (default None)
579  legendDh -- Float for changing TLegend height (default None)
580  overrideLegendLabels -- List of strings for legend labels, if given, these are used instead of the ones coming from Plotter (default None)
581  """
582  self._name = name
583  self._plots = plots
584 
585  if len(self._plots) <= 2:
586  self._canvas = ROOT.TCanvas(self._name, self._name, 1000, 500)
587  elif len(self._plots) <= 4:
588  self._canvas = ROOT.TCanvas(self._name, self._name, 1000, 1050)
589  elif len(self._plots) <= 6:
590  self._canvas = ROOT.TCanvas(self._name, self._name, 1000, 1400)
591  elif len(self._plots) <= 8:
592  self._canvas = ROOT.TCanvas(self._name, self._name, 1000, 1750)
593  elif len(self._plots) <= 10:
594  self._canvas = ROOT.TCanvas(self._name, self._name, 1000, 2100)
595  else:
596  self._canvas = ROOT.TCanvas(self._name, self._name, 1000, 2450)
597 
598  self._canvasSingle = ROOT.TCanvas(self._name+"Single", self._name, 500, 500)
599  # from TDRStyle
600  self._canvasSingle.SetTopMargin(0.05)
601  self._canvasSingle.SetBottomMargin(0.13)
602  self._canvasSingle.SetLeftMargin(0.16)
603  self._canvasSingle.SetRightMargin(0.05)
604 
605 
606  def _set(attr, default):
607  setattr(self, "_"+attr, kwargs.get(attr, default))
608 
609  _set("legendDx", None)
610  _set("legendDy", None)
611  _set("legendDw", None)
612  _set("legendDh", None)
613 
614  _set("overrideLegendLabels", None)
615 
616  def create(self, tdirectories):
617  """Create histograms from a list of TDirectories."""
618  for plot in self._plots:
619  plot.create(tdirectories)
620 
621  def draw(self, algo, legendLabels, prefix=None, separate=False, saveFormat=".pdf"):
622  """Draw the histograms using values for a given algorithm.
623 
624  Arguments:
625  algo -- string for algorithm
626  legendLabels -- List of strings for legend labels (corresponding to the tdirectories in create())
627  prefix -- Optional string for file name prefix (default None)
628  separate -- Save the plots of a group to separate files instead of a file per group (default False)
629  saveFormat -- String specifying the plot format (default '.pdf')
630  """
631 
632  if self._overrideLegendLabels is not None:
633  legendLabels = self._overrideLegendLabels
634 
635  if separate:
636  return self._drawSeparate(algo, legendLabels, prefix, saveFormat)
637 
638  self._canvas.Divide(2, int((len(self._plots)+1)/2)) # this should work also for odd n
639 
640  # Draw plots to canvas
641  for i, plot in enumerate(self._plots):
642  self._canvas.cd(i+1)
643  plot.draw(algo)
644 
645  # Setup legend
646  self._canvas.cd()
647  if len(self._plots) <= 4:
648  lx1 = 0.2
649  lx2 = 0.9
650  ly1 = 0.48
651  ly2 = 0.53
652  else:
653  lx1 = 0.1
654  lx2 = 0.9
655  ly1 = 0.64
656  ly2 = 0.69
657  if self._legendDx is not None:
658  lx1 += self._legendDx
659  lx2 += self._legendDx
660  if self._legendDy is not None:
661  ly1 += self._legendDy
662  ly2 += self._legendDy
663  if self._legendDw is not None:
664  lx2 += self._legendDw
665  if self._legendDh is not None:
666  ly1 -= self._legendDh
667  plot = max(self._plots, key=lambda p: p.getNumberOfHistograms())
668  legend = self._createLegend(plot, legendLabels, lx1, ly1, lx2, ly2)
669 
670  return self._save(self._canvas, saveFormat, prefix=prefix)
671 
672  def _drawSeparate(self, algo, legendLabels, prefix, saveFormat):
673  lx1def = 0.6
674  lx2def = 0.95
675  ly1def = 0.85
676  ly2def = 0.95
677 
678  ret = []
679 
680  for plot in self._plots:
681  # Draw plot to canvas
682  self._canvasSingle.cd()
683  plot.draw(algo)
684 
685  # Setup legend
686  lx1 = lx1def
687  lx2 = lx2def
688  ly1 = ly1def
689  ly2 = ly2def
690 
691  if plot._legendDx is not None:
692  lx1 += plot._legendDx
693  lx2 += plot._legendDx
694  if plot._legendDy is not None:
695  ly1 += plot._legendDy
696  ly2 += plot._legendDy
697  if plot._legendDw is not None:
698  lx2 += plot._legendDw
699  if plot._legendDh is not None:
700  ly1 -= plot._legendDh
701 
702  legend = self._createLegend(plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.03)
703 
704  ret.extend(self._save(self._canvasSingle, saveFormat, prefix=prefix, postfix="_"+plot.getName()))
705  return ret
706 
707  def _createLegend(self, plot, legendLabels, lx1, ly1, lx2, ly2, textSize=0.016):
708  l = ROOT.TLegend(lx1, ly1, lx2, ly2)
709  l.SetTextSize(textSize)
710  l.SetLineColor(1)
711  l.SetLineWidth(1)
712  l.SetLineStyle(1)
713  l.SetFillColor(0)
714  l.SetMargin(0.07)
715 
716  plot.addToLegend(l, legendLabels)
717  l.Draw()
718  return l
719 
720  def _save(self, canvas, saveFormat, prefix=None, postfix=None):
721  # Save the canvas to file and clear
722  name = self._name
723  if prefix is not None:
724  name = prefix+name
725  if postfix is not None:
726  name = name+postfix
727  canvas.SaveAs(name+saveFormat)
728  canvas.Clear()
729 
730  return [name+saveFormat]
731 
732 
733 class Plotter:
734  """Represent a collection of PlotGroups."""
735  def __init__(self, possibleDirs, plotGroups, saveFormat=".pdf"):
736  """Constructor.
737 
738  Arguments:
739  possibleDirs -- List of strings for possible directories of histograms in TFiles
740  plotGroups -- List of PlotGroup objects
741  saveFormat -- String specifying the plot format (default '.pdf')
742  """
743  self._possibleDirs = possibleDirs
744  self._plotGroups = plotGroups
745  self._saveFormat = saveFormat
746 
747  ROOT.gROOT.SetStyle("Plain")
748  ROOT.gStyle.SetPadRightMargin(0.07)
749  ROOT.gStyle.SetPadLeftMargin(0.13)
750  ROOT.gStyle.SetTitleFont(42, "XYZ")
751  ROOT.gStyle.SetTitleSize(0.05, "XYZ")
752  ROOT.gStyle.SetTitleOffset(1.2, "Y")
753  #ROOT.gStyle.SetTitleFontSize(0.05)
754  ROOT.gStyle.SetLabelFont(42, "XYZ")
755  ROOT.gStyle.SetLabelSize(0.05, "XYZ")
756  ROOT.gStyle.SetTextSize(0.05)
757 
758  ROOT.TH1.AddDirectory(False)
759 
760  def setPossibleDirectoryNames(self, possibleDirs):
761  self._possibleDirs = possibleDirs
762 
764  """Return the list of possible directory names."""
765  return self._possibleDirs
766 
767  def append(self, plotGroup):
768  self._plotGroups.append(plotGroup)
769 
770  def set(self, plotGroups):
771  self._plotGroups = plotGroups
772 
773  def _getDir(self, tfile, subdir):
774  """Get TDirectory from TFile."""
775  if tfile is None:
776  return None
777  for pd in self._possibleDirs:
778  d = tfile.Get(pd)
779  if d:
780  if subdir is not None:
781  # Pick associator if given
782  d = d.Get(subdir)
783  if d:
784  return d
785  else:
786  msg = "Did not find subdirectory '%s' from directory '%s' in file %s" % (subdir, pd, tfile.GetName())
787  if missingOk:
788  print msg
789  return None
790  else:
791  raise Exception(msg)
792  else:
793  return d
794  msg = "Did not find any of directories '%s' from file %s" % (",".join(self._possibleDirs), tfile.GetName())
795  if missingOk:
796  print msg
797  return None
798  else:
799  raise Exception(msg)
800 
801  def create(self, files, labels, subdir=None):
802  """Create histograms from a list of TFiles.
803 
804  Arguments:
805  files -- List of TFiles
806  labels -- List of strings for legend labels corresponding the files
807  subdir -- Optional string for subdirectory inside the possibleDirs; if list of strings, then each corresponds to a TFile
808  """
809  dirs = []
810  self._labels = []
811  if isinstance(subdir, list):
812  for f, l, s in zip(files, labels, subdir):
813  d = self._getDir(f, s)
814  dirs.append(d)
815  self._labels.append(l)
816  else:
817  for f, l in zip(files, labels):
818  d = self._getDir(f, subdir)
819  dirs.append(d)
820  self._labels.append(l)
821 
822  for pg in self._plotGroups:
823  pg.create(dirs)
824 
825  def draw(self, algo, prefix=None, separate=False, saveFormat=None):
826  """Draw and save all plots using settings of a given algorithm.
827 
828  Arguments:
829  algo -- String for the algorithm
830  prefix -- Optional string for file name prefix (default None)
831  separate -- Save the plots of a group to separate files instead of a file per group (default False)
832  saveFormat -- If given, overrides the saveFormat
833  """
834  ret = []
835 
836  sf = self._saveFormat
837  if saveFormat is not None:
838  sf = saveFormat
839 
840  for pg in self._plotGroups:
841  ret.extend(pg.draw(algo, self._labels, prefix=prefix, separate=separate, saveFormat=sf))
842  return ret
843 
def _normalize
Definition: plotting.py:431
def _createOne
Definition: plotting.py:330
def _getYmaxWithError
Definition: plotting.py:43
def _findBounds
Definition: plotting.py:46
def getPossibleDirectoryNames
Definition: plotting.py:763
def setPossibleDirectoryNames
Definition: plotting.py:760
T min(T a, T b)
Definition: MathUtil.h:58
def _getObject
Definition: plotting.py:32
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
def getNumberOfHistograms
Definition: plotting.py:323
def addToLegend
Definition: plotting.py:554