ATLAS Offline Software
roofit/ROOTUtils.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
2 
3 # $Id: ROOTUtils.py 759047 2016-07-01 00:45:13Z beringer $
4 """
5 Miscellaneous utilities for PyROOT.
6 """
7 __author__ = 'Juerg Beringer'
8 __version__ = '$Id: ROOTUtils.py 759047 2016-07-01 00:45:13Z beringer $'
9 
10 
11 import ROOT
12 from array import array
13 
14 
15 protectedObjectList = []
16 
17 def protect(obj):
18  """Utility function to prevent ROOT objects from being garbage-collected,
19  (thus disappearing from plots) when they go out of scope."""
20  protectedObjectList.append(obj)
21  return obj
22 
23 
24 # Define a set of useful canvas sizes for different purposes
25 myCanvasSizes = { 'default': (700, 500),
26  'default2d': (545, 500),
27  'slide1': (900,560),
28  'slide2': (450,560),
29  'slide2text': (400,500),
30  'fig1': (700, 500),
31  'fig2': (1400, 500),
32  'page': (750,1000),
33  'landscape': (1600,1000),
34  'wide': (1000,500),
35  'extrawide': (1500,500),
36  'square': (700,700)
37  }
38 
39 
40 class MyCanvas(ROOT.TCanvas):
41  """Class MyCanvas is a ROOT TCanvas that allows choosing one of
42  several typically used canvas sizes. It can automatically save
43  the canvas in different formats upon destruction provided the
44  user makes sure that all histograms still exist."""
45 
46  # Class defaults
47  saveAsList = [ '.gif' ]
48  autoSaveOnExit = False
49  autoName = '%s.autosave%s'
50 
51  def __init__(self,name='MyCanvas', size='default', xdivs=1, ydivs=1, saveAsList=None, autoSaveOnExit=None):
52  super(MyCanvas,self).__init__(name,name,myCanvasSizes[size][0],myCanvasSizes[size][1])
53  self.name = name
54  if saveAsList!=None:
55  self.saveAsList = saveAsList
56  else:
57  self.saveAsList = MyCanvas.saveAsList
58  if autoSaveOnExit!=None:
59  self.autoSaveOnExit = autoSaveOnExit
60  else:
61  self.autoSaveOnExit = MyCanvas.autoSaveOnExit
62  self.autoName = MyCanvas.autoName
63  self.Divide(xdivs,ydivs)
64 
65  def __del__(self):
66  if self.autoSaveOnExit:
67  self.save()
68 
69  def save(self):
70  for o in self.saveAsList:
71  if o[0]=='.':
72  self.SaveAs(self.autoName % (self.name,o))
73  else:
74  self.SaveAs(o)
75 
76 
78  """PlotLibrary is a base class that can be used to manage a set of
79  plots. Each individual plot should be created as a method of a
80  derived class. Other methods of the derived class that do not
81  generate plots should either have names starting with
82  underscore, or should be declared when calling __init__ of the
83  base class."""
84 
85  def __init__(self, name = 'MyPlots', otherMethods=[]):
86  """Constructor. otherMethods specifies a list of methods of the derived
87  class that are not creating plots and should not be called by plot()."""
88  self.name = name
89  self.otherMethods = []
90  self.otherMethods.extend(otherMethods)
91  self.rootObjects = []
92 
93  # Variables used by genPlot
94  self.whatList = []
95  self.singleCanvasSize = 'default'
96  self.allCanvasSize = 'page'
97  self.allCanvasDivs = (3,4)
98  self.saveAsList = []
99  self.gPadSaveAsList = []
100 
101  def protect(self,obj):
102  """Protect ROOT object from garbage collection."""
103  self.rootObjects.append(obj)
104  return obj
105 
106  def plot(self, plotName='',*args):
107  """Make one or all (if plotName=='') plots."""
108  if plotName:
109  self.__class__.__dict__[plotName](self,*args)
110  else:
111  for i in self.__class__.__dict__:
112  if i[0]=='_': continue # skip private methods
113  if i in self.otherMethods: continue
114  self.__class__.__dict__[i](self,*args)
115 
116  def genPlot(self,what='ALL',code='plot',labels=[],*args):
117  """Make plots using a general code. genPlot makes either a single plot defined
118  by argument what, or all plots (if what=''). The plots made in the latter
119  case are specified by whatList. A canvas that is subdivided if necessary
120  is created before the plotting code is called."""
121  if what=='' or what.upper()=='ALL':
122  c = self.protect( MyCanvas('%s-%s-%s' % (self.name,what,code),
123  self.allCanvasSize,self.allCanvasDivs[0],self.allCanvasDivs[1]) )
124  iCanvas = 0
125  for w in self.whatList:
126  iCanvas += 1
127  c.cd(iCanvas)
128  try:
129  self.__class__.__dict__[code](self,w,*args)
130  except:
131  self.__class__.__bases__[0].__dict__[code](self,w,*args)
132  ROOT.gPad.Update()
133  # For some strange reason, this works only for .eps, but not e.g. for gif files...???
134  for o in self.gPadSaveAsList:
135  if o[0]=='.':
136  ROOT.gPad.SaveAs('%s-%s-%s%s' % (self.name,code,w,o))
137  else:
138  ROOT.gPad.SaveAs(o)
139 
140  # If we want to put some labels on an empty pad, add them now.
141  if labels!=[] and self.allCanvasDivs[0]*self.allCanvasDivs[1] > len(self.whatList):
142  iCanvas+=1
143  c.cd(iCanvas)
144  xtext=0.0
145  ytext=0.8
146  for label in labels:
147  drawText(xtext,ytext,0.06,label)
148  ytext=ytext-0.1
149  elif labels!=[]:
150  print "ERROR: can't add labels unless we have an empty pad to use. Ignoring labels."
151 
152  for o in self.saveAsList:
153  if o[0]=='.':
154  c.SaveAs('%s-%s-%s%s' % (self.name,code,what,o))
155  else:
156  c.SaveAs(o)
157 
158  else:
159  c = self.protect( MyCanvas(what,self.singleCanvasSize) )
160  try:
161  self.__class__.__dict__[code](self,what,*args)
162  except:
163  self.__class__.__bases__[0].__dict__[code](self,what,*args)
164  ROOT.gPad.Update()
165  for o in self.saveAsList:
166  if o[0]=='.':
167  c.SaveAs('%s-%s-%s%s' % (self.name,code,what,o))
168  else:
169  c.SaveAs(o)
170 
172  """StyleFactory is a helper class for assigning marker styles, line styles,
173  and colors in ROOT plots."""
174 
175  markerSequence = [ 8, 21, 22, 23, 29, 4, 25, 26, 27, 28, 30, 2, 3, 6]
176  lineSequence = [ 1, 2, 3, 4]
177  colorSequence = [ 1, 2, 4, 6, 8]
178 
179  def __init__(self,incMarker=True,incLine=True,incColor=True):
180  self.idMarker = -1
181  self.idLine = -1
182  self.idColor = -1
183  self.incMarker = 1 if incMarker else 0
184  self.incLine = 1 if incLine else 0
185  self.incColor = 1 if incColor else 0
186 
187  def nextStyle(self):
188  """Get next style cycling through markers, lines and colors as specified by
189  the flags in the constructor. Returns a triplet of (marker,line,color) styles."""
190  self.idMarker += self.incMarker
191  self.idLine += self.incLine
192  self.idColor += self.incColor
193  return (StyleFactory.markerSequence[self.idMarker % len(StyleFactory.markerSequence)],
194  StyleFactory.lineSequence[self.idLine % len(StyleFactory.lineSequence)],
195  StyleFactory.colorSequence[self.idColor % len(StyleFactory.colorSequence)])
196 
197  def nextMarkerStyle(self):
198  """Get next marker style."""
199  self.idMarker +=1
200  return StyleFactory.markerSequence[self.idMarker % len(StyleFactory.markerSequence)]
201 
202  def nextLineStyle(self):
203  """Get next line style."""
204  self.idLine +=1
205  return StyleFactory.lineSequence[self.idLine % len(StyleFactory.lineSequence)]
206 
207  def nextColorStyle(self):
208  """Get next color."""
209  self.idColor +=1
210  return StyleFactory.colorSequence[self.idColor % len(StyleFactory.colorSequence)]
211 
212 
213 def drawAxisFrame(xmin,xmax,ymin,ymax,title='',xTitleOffset=None,yTitleOffset=None,doPlot=True,protectFrame=True):
214  frame = ROOT.TH2F('axisFrame',title,100,xmin,xmax,100,ymin,ymax)
215  frame.SetStats(False)
216  if xTitleOffset!=None:
217  frame.GetXaxis().SetTitleOffset(xTitleOffset)
218  if yTitleOffset!=None:
219  frame.GetYaxis().SetTitleOffset(yTitleOffset)
220  if doPlot:
221  frame.Draw()
222  if protectFrame:
223  protect(frame)
224  return frame
225 
226 
227 def drawHorizontalBand(xmin,xmax,y,ywidth,color=33,protectBand=True,centralLine=False):
228  """Draw a horizontal band of width +-ywidth. Nice colors are 19 and 33."""
229  b = ROOT.TH1F('band','band',1,xmin,xmax)
230  b.SetBinContent(1,y)
231  b.SetBinError(1,ywidth)
232  b.SetFillColor(color)
233  b.SetMarkerColor(color)
234  b.SetMarkerSize(0.01)
235  b.Draw('SAMEe2')
236  if centralLine:
237  b.Draw('SAMEL')
238  if protectBand:
239  protect(b)
240  return b
241 
242 
243 def drawText(x=0.74,y=0.87,dy=0.06,text='',font=62,color=1,align=11,linesep=';'):
244  """Draw a variable number of lines of text."""
245  t = ROOT.TLatex()
246  t.SetNDC()
247  t.SetTextFont(font)
248  t.SetTextColor(color)
249  t.SetTextAlign(align)
250  t.SetTextSize(dy/1.2)
251  for line in text.split(linesep):
252  t.DrawLatex(x,y,line)
253  y = y-dy
254  # Seems TLatex text doesn't need to be protected - why not?
255  return t
256 
257 
258 #def drawLegend(x=0.18,y=0.9,s=0.07,legendList=[],fillColor=0,lineColor=0):
259 def drawLegend(x1,y1,x2,y2,legendList=[],fillColor=0,lineColor=0,textSize=None,protectLegend=True):
260  """Draw a legend with one or more entries. legendList is a list of lists,
261  where each inner list defines the object, text and option of a legend entry.
262  NOTE: Must store returned TLegend, otherwise legend will disappear!"""
263  nlines = len(legendList)
264  if not nlines:
265  print "ERROR: drawLegend called w/o any legend entries"
266  #maxchar = 0
267  #for e in legendList:
268  # maxchar = max(len(e[1]),maxchar)
269  #l = ROOT.TLegend(x,y-nlines*s,x+(2+maxchar)*s/3.7,y)
270  l = ROOT.TLegend(x1,y1,x2,y2)
271  l.SetFillColor(fillColor)
272  l.SetLineColor(lineColor)
273  l.SetShadowColor(lineColor)
274  if textSize:
275  l.SetTextSize(textSize)
276  for e in legendList:
277  l.AddEntry(e[0],e[1],e[2])
278  l.Draw()
279  if protectLegend:
280  protect(l)
281  return l
282 
283 
284 def moveStats(h,dx,dy,xw=0,yw=0,label=''):
285  if not h:
286  return
287  ROOT.gPad.Update()
288  st = h.GetListOfFunctions().FindObject('stats')
289  if not st:
290  print 'ERROR: No stats found - cannot move it'
291  return
292  st.SetTextColor(h.GetLineColor())
293  st.SetX1NDC(st.GetX1NDC()+dx)
294  st.SetY1NDC(st.GetY1NDC()+dy)
295  st.SetX2NDC(st.GetX2NDC()+xw if xw!=0 else st.GetX2NDC()+dx)
296  st.SetY2NDC(st.GetY2NDC()+yw if yw!=0 else st.GetY2NDC()+dy)
297  if not label:
298  h.SetName(label)
299  ROOT.gPad.Modified()
300  ROOT.gPad.Update
301 
302 
303 def atlasLabel(x,y,isPreliminary=False,color=1,offset=0.115,isForApproval=False,energy=8,customstring="",size=0.05):
304  if x==None or y==None:
305  print "Must set (x,y) position using --atlasx and --atlasy to add labels. No ATLAS labels created."
306  return
307  offset = offset/0.05*size
308  l = ROOT.TLatex()
309  l.SetNDC()
310  l.SetTextFont(72)
311  l.SetTextSize(size)
312  l.SetTextColor(color)
313  l.DrawLatex(x,y,"ATLAS")
314 
315  p = ROOT.TLatex()
316  p.SetNDC()
317  p.SetTextFont(42)
318  p.SetTextSize(size)
319  p.SetTextColor(color)
320 
321  if customstring != "":
322  p.DrawLatex(x+offset,y,customstring)
323  else:
324  if (isPreliminary):
325  p.DrawLatex(x+offset,y,"Preliminary")
326  if (isForApproval):
327  #p.DrawLatex(x+offset,y,"Internal for approval")
328  p.DrawLatex(x+offset,y,"Internal")
329 
330  if energy:
331  if float(energy)<15:
332  p.DrawLatex(x, y-(0.07/0.05*size), "#sqrt{s} = %s TeV" % energy)
333  else:
334  p.DrawLatex(x, y-(0.07/0.05*size), "#sqrt{s} = %s GeV" % energy)
335 
336 
337 
338 def atlasStyle(protectStyle=True):
339  s = ROOT.TStyle('ATLAS','ATLAS Style V2.02')
340 
341  # use plain black on white colors
342  icol=0 # WHITE
343  s.SetFrameBorderMode(icol);
344  s.SetFrameFillColor(icol);
345  s.SetCanvasBorderMode(icol);
346  s.SetCanvasColor(icol);
347  s.SetPadBorderMode(icol);
348  s.SetPadColor(icol);
349  s.SetStatColor(icol);
350  #s.SetFillColor(icol); # don't use: white fill color floa *all* objects
351 
352  # set the paper & margin sizes
353  s.SetPaperSize(20,26);
354  s.SetPadTopMargin(0.05);
355  s.SetPadRightMargin(0.05);
356  s.SetPadBottomMargin(0.16);
357  s.SetPadLeftMargin(0.16);
358 
359  # set title offsets (for axis label)
360  s.SetTitleXOffset(1.4)
361  s.SetTitleYOffset(1.4)
362 
363  # use large fonts
364  #Int_t font=72; # Helvetica italics
365  font = 42 # Helvetica
366  tsize = 0.05
367  s.SetTextFont(font);
368 
369  s.SetTextSize(tsize);
370  s.SetLabelFont(font,"x");
371  s.SetTitleFont(font,"x");
372  s.SetLabelFont(font,"y");
373  s.SetTitleFont(font,"y");
374  s.SetLabelFont(font,"z");
375  s.SetTitleFont(font,"z");
376 
377  s.SetLabelSize(tsize,"x");
378  s.SetTitleSize(tsize,"x");
379  s.SetLabelSize(tsize,"y");
380  s.SetTitleSize(tsize,"y");
381  s.SetLabelSize(tsize,"z");
382  s.SetTitleSize(tsize,"z");
383 
384  # use bold lines and markers
385  s.SetMarkerStyle(20);
386  s.SetMarkerSize(1.2);
387  s.SetHistLineWidth(2);
388  s.SetLineStyleString(2,"[12 12]"); # postscript dashes
389 
390  # get rid of X error bars and y error bar caps
391  #s.SetErrorX(0.001);
392 
393  # get rid of error bar caps
394  s.SetEndErrorSize(0.);
395 
396  # do not display any of the standard histogram decorations
397  s.SetOptTitle(0);
398  #s.SetOptStat(1111);
399  s.SetOptStat(0);
400  #s.SetOptFit(1111);
401  s.SetOptFit(0);
402 
403  # put tick marks on top and RHS of plots
404  s.SetPadTickX(1);
405  s.SetPadTickY(1);
406 
407  if protectStyle:
408  protect(s)
409 
410  return s
411 
412 
413 def setStyle(style = None):
414  if not style:
415  style = atlasStyle()
416  print '\nApplying style %s (%s) ...\n' % (style.GetName(),style.GetTitle())
417  ROOT.gROOT.SetStyle(style.GetName())
418  ROOT.gROOT.ForceStyle()
ROOTUtils.drawText
def drawText(x=0.74, y=0.87, dy=0.06, text='', font=62, color=1, align=11, linesep=';')
Definition: roofit/ROOTUtils.py:243
ROOTUtils.StyleFactory.nextStyle
def nextStyle(self)
Definition: roofit/ROOTUtils.py:187
ROOTUtils.moveStats
def moveStats(h, dx, dy, xw=0, yw=0, label='')
Definition: roofit/ROOTUtils.py:284
ROOTUtils.StyleFactory.nextColorStyle
def nextColorStyle(self)
Definition: roofit/ROOTUtils.py:207
ROOTUtils.drawAxisFrame
def drawAxisFrame(xmin, xmax, ymin, ymax, title='', xTitleOffset=None, yTitleOffset=None, doPlot=True, protectFrame=True)
Definition: roofit/ROOTUtils.py:213
ROOTUtils.PlotLibrary.genPlot
def genPlot(self, what='ALL', code='plot', labels=[], *args)
Definition: roofit/ROOTUtils.py:116
ROOTUtils.MyCanvas
Definition: roofit/ROOTUtils.py:40
ROOTUtils.setStyle
def setStyle(style=None)
Definition: roofit/ROOTUtils.py:413
ROOTUtils.PlotLibrary.gPadSaveAsList
gPadSaveAsList
Definition: roofit/ROOTUtils.py:99
ROOTUtils.MyCanvas.autoSaveOnExit
bool autoSaveOnExit
Definition: roofit/ROOTUtils.py:48
ROOTUtils.PlotLibrary.allCanvasDivs
allCanvasDivs
Definition: roofit/ROOTUtils.py:97
ROOTUtils.protect
def protect(obj)
Definition: roofit/ROOTUtils.py:17
ROOTUtils.PlotLibrary.whatList
whatList
Definition: roofit/ROOTUtils.py:94
ROOTUtils.MyCanvas.autoName
string autoName
Definition: roofit/ROOTUtils.py:49
ROOTUtils.StyleFactory.nextLineStyle
def nextLineStyle(self)
Definition: roofit/ROOTUtils.py:202
ROOTUtils.PlotLibrary.saveAsList
saveAsList
Definition: roofit/ROOTUtils.py:98
ROOTUtils.StyleFactory.incMarker
incMarker
Definition: roofit/ROOTUtils.py:183
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
ROOTUtils.PlotLibrary.name
name
Definition: roofit/ROOTUtils.py:88
ROOTUtils.atlasLabel
def atlasLabel(x, y, isPreliminary=False, color=1, offset=0.115, isForApproval=False, energy=8, customstring="", size=0.05)
Definition: roofit/ROOTUtils.py:303
ROOTUtils.PlotLibrary.protect
def protect(self, obj)
Definition: roofit/ROOTUtils.py:101
ROOTUtils.MyCanvas.save
def save(self)
Definition: roofit/ROOTUtils.py:69
ROOTUtils.MyCanvas.__del__
def __del__(self)
Definition: roofit/ROOTUtils.py:65
ROOTUtils.PlotLibrary.otherMethods
otherMethods
Definition: roofit/ROOTUtils.py:89
ROOTUtils.StyleFactory.__init__
def __init__(self, incMarker=True, incLine=True, incColor=True)
Definition: roofit/ROOTUtils.py:179
ROOTUtils.PlotLibrary.singleCanvasSize
singleCanvasSize
Definition: roofit/ROOTUtils.py:95
ROOTUtils.drawHorizontalBand
def drawHorizontalBand(xmin, xmax, y, ywidth, color=33, protectBand=True, centralLine=False)
Definition: roofit/ROOTUtils.py:227
ROOTUtils.MyCanvas.saveAsList
list saveAsList
Definition: roofit/ROOTUtils.py:47
ROOTUtils.StyleFactory.incColor
incColor
Definition: roofit/ROOTUtils.py:185
ROOTUtils.MyCanvas.name
name
Definition: roofit/ROOTUtils.py:53
ROOTUtils.PlotLibrary.rootObjects
rootObjects
Definition: roofit/ROOTUtils.py:91
ROOTUtils.StyleFactory.idColor
idColor
Definition: roofit/ROOTUtils.py:182
ROOTUtils.PlotLibrary.__init__
def __init__(self, name='MyPlots', otherMethods=[])
Definition: roofit/ROOTUtils.py:85
ROOTUtils.StyleFactory.nextMarkerStyle
def nextMarkerStyle(self)
Definition: roofit/ROOTUtils.py:197
ROOTUtils.PlotLibrary
Definition: roofit/ROOTUtils.py:77
ROOTUtils.StyleFactory.incLine
incLine
Definition: roofit/ROOTUtils.py:184
ROOTUtils.atlasStyle
def atlasStyle(protectStyle=True)
Definition: roofit/ROOTUtils.py:338
ActsTrk::detail::MakeDerivedVariant::extend
constexpr std::variant< Args..., T > extend(const std::variant< Args... > &, const T &)
Definition: MakeDerivedVariant.h:17
ROOTUtils.PlotLibrary.plot
def plot(self, plotName='', *args)
Definition: roofit/ROOTUtils.py:106
ROOTUtils.PlotLibrary.allCanvasSize
allCanvasSize
Definition: roofit/ROOTUtils.py:96
ROOTUtils.StyleFactory.idMarker
idMarker
Definition: roofit/ROOTUtils.py:180
ROOTUtils.MyCanvas.__init__
def __init__(self, name='MyCanvas', size='default', xdivs=1, ydivs=1, saveAsList=None, autoSaveOnExit=None)
Definition: roofit/ROOTUtils.py:51
ROOTUtils.StyleFactory.idLine
idLine
Definition: roofit/ROOTUtils.py:181
ROOTUtils.drawLegend
def drawLegend(x1, y1, x2, y2, legendList=[], fillColor=0, lineColor=0, textSize=None, protectLegend=True)
Definition: roofit/ROOTUtils.py:259
readCCLHist.float
float
Definition: readCCLHist.py:83
ROOTUtils.StyleFactory
Definition: roofit/ROOTUtils.py:171