CMS 3D CMS Logo

tree2hists.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 """
3 Create ROOT Histograms from one or more ROOT TTrees or TNtuples.
4 
5 Options are specified in the given configuration file.
6 """
7 
8 # Create configuration file:
9 # tree2hists.py
10 # Edit, then run with config file:
11 # tree2hists.py config.py
12 
13 __license__ = '''\
14 Copyright (c) 2010 Michael Anderson <mbanderson@wisc.edu>
15 
16 Permission is hereby granted, free of charge, to any person obtaining a copy
17 of this software and associated documentation files (the "Software"), to deal
18 in the Software without restriction, including without limitation the rights
19 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20 copies of the Software, and to permit persons to whom the Software is
21 furnished to do so, subject to the following conditions:
22 
23 The above copyright notice and this permission notice shall be included in
24 all copies or substantial portions of the Software.
25 
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32 THE SOFTWARE.
33 '''
34 
35 ######## Import python libraries #############################################
36 
37 import sys # For exiting program
38 if '-h' in sys.argv or '--help' in sys.argv:
39  print '''\
40 Create ROOT Histograms from one or more ROOT TTrees or TNtuples.
41 
42 Run by specifying configuration file:
43  tree2hists config.py
44 
45 Create default config file by running with no arguments:
46  tree2hists'''
47  sys.exit(0)
48 try:
49  from ROOT import TFile, TTree, TH1F, TH2F, TH3F, gROOT
50 except Exception as e:
51  print e
52  print ("Use a python that has PyROOT installed.")
53  sys.exit(0)
54 from copy import deepcopy # For copying histograms
55 from math import pi # For use in histogram bounds
56 from array import array # For making Float_t array ROOT wants (for hists)
57 from datetime import datetime # For output filename
58 from os import path # For finding file
59 
60 ######## Define classes and generators #######################################
61 
62 class RootTree:
63  """Wrapper for TTrees and TNtuples, allowing association with
64  a scale and cuts."""
65  def __init__(self, treeName, fileName, scale=1.0, cuts=""):
66  self.fileName = fileName
67  self.treeName = treeName
68  self.scale = scale
69  self.cuts = cuts
70  self.tfile = TFile()
71  self.ttree = TTree()
72 
73 class Plot:
74  """Wrapper for TH1 objects, associating TTree variables with a histogram"""
75  def __init__(self, treeVariable, histogram, cuts="", storeErrors=True):
76  self.treeVariable = treeVariable
77  self.histogram = histogram
78  self.name = histogram.GetName()
79  self.cuts = cuts
80  if storeErrors: self.histogram.Sumw2()
81 
82 def join_cuts(*list_of_cuts):
83  """Joins list of cuts (strings) into something ROOT can handle.
84  Example: given ('1<2','','5>4') returns '1<2&&5>4'"""
85  list_of_nonempty_cuts = []
86  for cut in list_of_cuts:
87  if cut:
88  list_of_nonempty_cuts.append(cut)
89  return '&&'.join(list_of_nonempty_cuts)
90 
91 def duration_to_string(start, end):
92  timeTaken = end - start
93  hours, remainder = divmod(timeTaken.seconds, 3600)
94  minutes, seconds = divmod(remainder, 60)
95  if hours>0:
96  return "%i hours, %i minutes" % (hours, minutes)
97  elif minutes>0:
98  return "%i minutes" % minutes
99  return "%i seconds" % seconds
100 
102  """Writes configuration file for tree2hists"""
103  defaultConfig = '''# Configuration file for tree2hists
104 # Created %s.
105 try:
106  ## the normal way to import from rootplot
107  from rootplot.tree2hists import RootTree, Plot
108 except ImportError:
109  ## special import for CMSSW installations of rootplot
110  from PhysicsTools.PythonAnalysis.rootplot.tree2hists import RootTree, Plot
111 from array import array # to allow making Float_t arrays for ROOT hists
112 from math import pi
113 from ROOT import TH1F, TH2F # import other kinds of hists as neeeded
114 
115 list_of_files = [RootTree("Treename", fileName="photons.root", scale=1.0, cuts=""),
116  RootTree("Treename", fileName="photons2.root", scale=1.0, cuts="")]
117 
118 output_filename = "Hists_photons.root"
119 
120 cut_for_all_files = "(!TTBit[36] && !TTBit[37] && !TTBit[38] && !TTBit[39] && !vtxIsFake && vtxNdof>4 && abs(vtxZ)<=15)"
121 
122 # All plots are made for each "cut set".
123 # A "cut set" is 3 things: folder name to store hists in, string to add to hist titles, and cuts for these hists.
124 # Let cut_sets = [] to make all plots.
125 cut_sets = [
126  ("barrel15to20", "(|#eta|<1.45, 15<E_{T}<20)", "et>15&&et<20&&abs(eta)<1.45"),
127  ("barrel20to30", "(|#eta|<1.45, 20<E_{T}<30)", "et>20&&et<30&&abs(eta)<1.45"),
128  ("endcap15to20", "(1.7<|#eta|<2.5, 15<E_{T}<20)", "et>15&&et<20&&abs(eta)>1.7&&abs(eta)<2.5"),
129  ("endcap20to30", "(1.7<|#eta|<2.5, 20<E_{T}<30)", "et>20&&et<30&&abs(eta)>1.7&&abs(eta)<2.5")
130  ]
131 
132 # Define histograms to plot
133 bins_et = array("f", [15.0, 20.0, 30.0, 50.0, 80.0, 120.0]) # example custom bins
134 list_of_plots = [
135  Plot("et" , TH1F("pho_et" , "Lead #gamma: E_{T};E_{T} (GeV);entries/bin", 25, 0.0, 100.0)),
136  Plot("eta" , TH1F("pho_eta" , "Lead #gamma: #eta;#eta;entries/bin" , 25, -3.0, 3.0)),
137  Plot("et" , TH1F("pho_et_binned" , "Lead #gamma: E_{T};E_{T} (GeV);entries/bin", len(bins_et)-1, bins_et)),
138  Plot("sigmaIetaIeta", TH1F("pho_sigmaIEtaIEta", "Lead #gamma: #sigma_{i#etai#eta};#sigma_{i#etai#eta};entries/bin",20, 0, 0.06)),
139  Plot("metEt/et" , TH1F("metEt_over_phoEt" , "MET / E_{T}(#gamma);MET/E_{T}(sc);entries/bin" , 20, 0.0, 3.0)),
140  Plot("phi:eta" , TH2F("phoPhi_vs_phoEta" , "Lead #gamma: #phi vs #eta;#eta;#phi" , 50, -2.5, 2.5, 18, -pi, pi))
141  ]
142 ''' % datetime.now().strftime("%b %d, %Y")
143  f = open('t2h_config.py', 'w')
144  f.write(defaultConfig)
145  f.close()
146  print "Created default configuration file: t2h_config.py"
147  print "Edit it, then run by typing:"
148  print " tree2hists t2h_config.py"
149 ##############################################################################
150 
151 def make_all_hists_all_files(list_of_RootTrees, list_of_Plots, cut_for_all_files, list_of_cutSets):
152  '''Open root files one at a time, make plots, then close them.'''
153  list_of_plots_to_write = []
154 
155  # Create plots for each set of cuts
156  for set_of_cuts in list_of_cutSets:
157  histname_fix, title_fix, current_cut_set = set_of_cuts
158  for plot in list_of_Plots:
159  new_plot = deepcopy(plot)
160  new_title = ' '.join((plot.histogram.GetTitle(), title_fix))
161  new_plot.histogram.SetTitle(new_title)
162  list_of_plots_to_write.append((new_plot, set_of_cuts))
163 
164  for j, rootTree in enumerate(list_of_RootTrees):
165  rootTree.tfile = TFile(rootTree.fileName, "read") # Open TFile
166  if rootTree.tfile.IsZombie():
167  print "Error opening %s, exiting..." % rootTree.fileName
168  sys.exit(0)
169  try: # Try to get TTree from file.
170  rootTree.tfile.GetObject(rootTree.treeName, rootTree.ttree)
171  except:
172  print "Error: %s not found in %s, exiting..." % (rootTree.treeName,
173  rootTree.fileName)
174  sys.exit(1)
175 
176  print "\n%s: Opened %s %i MB" % (datetime.now().strftime("%I:%M%p"),
177  rootTree.fileName,
178  path.getsize(rootTree.fileName)/1048576)
179  print " %s has %i entries, will plot with scale=%.2e, cuts='%s'" % (rootTree.treeName,
180  rootTree.ttree.GetEntries(),
181  rootTree.scale,
182  rootTree.cuts)
183 
184  # Loop over plots
185  print " # entries var >> histogram"
186  for i, (plot, set_of_cuts) in enumerate(list_of_plots_to_write):
187  histname_fix, title_fix, current_cut_set = set_of_cuts
188  tmp_hist = plot.histogram.Clone("temp") # Create temp hist
189  all_cuts = join_cuts(cut_for_all_files, rootTree.cuts,
190  current_cut_set, plot.cuts) # Set cuts
191  rootTree.ttree.Draw( "%s >> temp" % plot.treeVariable, all_cuts,
192  "goff") # Draw with graphics off
193  tmp_hist.Scale(rootTree.scale) # Scale temp
194  entries_before = plot.histogram.GetEntries()
195  plot.histogram.Add(tmp_hist) # Add temp hist to total
196  entries_after = plot.histogram.GetEntries()
197  print " %3i %7i %20s >> %s/%s" % (i, entries_after-entries_before,
198  plot.treeVariable, histname_fix,
199  plot.histogram.GetName()),
200  if plot.cuts:
201  print "\textra cuts: %s" % plot.cuts, # plot-specific cuts
202  print
203 
204  rootTree.tfile.Close() # Close TFile
205  print "%s: Closed %s" % (datetime.now().strftime("%I:%M%p"),
206  rootTree.fileName)
207  return list_of_plots_to_write
208 
209 
210 ######## Define the main program #############################################
211 def tree2hists_main(config_file):
212  try:
213  # Import only certain variables
214  sys.path.insert(0, '')
215  _temp = __import__(config_file, globals(), locals(),
216  ['list_of_files','output_filename',
217  'cut_for_all_files','cut_sets','list_of_plots'], -1)
218  list_of_files = _temp.list_of_files
219  output_filename = _temp.output_filename
220  cut_for_all_files = _temp.cut_for_all_files
221  cut_sets = _temp.cut_sets
222  list_of_plots = _temp.list_of_plots
223  for rootTree in list_of_files:
224  if not path.isfile(rootTree.fileName):
225  print "Error:\n %s\nnot found for input." % rootTree.fileName
226  sys.exit(1)
227  hist_names = [plot.name for plot in list_of_plots]
228  if len(hist_names)>len(set(hist_names)):
229  print hist_names
230  print "Error: Each plot needs a unique name, exiting..."
231  sys.exit(1)
232  if path.isfile(output_filename):
233  print "Warning: %s exists" % output_filename
234  except Exception as e:
235  print e
236  print "Error with %s" % config_file
237  sys.exit(1)
238 
239  if path.isfile('rootlogon.C'):
240  print "Loading rootlogon.C"
241  gROOT.Macro('rootlogon.C') # Load functions from rootlogon script
242 
243  if cut_sets:
244  print "\n%i defined cut sets:" % len(cut_sets)
245  for cut in cut_sets:
246  name, title_fix, current_cut_set = cut
247  print " %s\t: '%s'" % (name, current_cut_set)
248  cut_names = [name for name,num,cut in cut_sets]
249  if len(cut_names)>len(set(cut_names)):
250  print "Error: Each cut set needs a unique name, exiting..."
251  sys.exit(1)
252  else:
253  cut_sets = [("","","")] # Make all plots, no extra cuts
254 
255  print "\nCuts to apply to all files:\n\t'%s'" % cut_for_all_files
256 
257  start_time = datetime.now()
258  list_of_plots_to_write = make_all_hists_all_files(list_of_files,
259  list_of_plots,
260  cut_for_all_files,
261  cut_sets)
262  end_time = datetime.now()
263  print "Done drawing all plots after %s." % duration_to_string(start_time, end_time)
264 
265  # Store and save/close files
266  outputFile = TFile(output_filename, "recreate")
267  if outputFile.IsZombie():
268  print "Error opening %s for output exiting..." % output_filename
269  sys.exit(1)
270  print "\nOpened output file. Saving histograms..."
271  outputFile.cd()
272  for set_of_cuts in cut_sets:
273  outputFile.mkdir(set_of_cuts[0])
274  print " # entries histogram"
275  for i, (plot, cutset) in enumerate(list_of_plots_to_write):
276  outputFile.cd(cutset[0])
277  print " %3i %7i %s/%s" % (i, plot.histogram.GetEntries(),
278  cutset[0],
279  plot.histogram.GetName())
280  plot.histogram.Write()
281  outputFile.Close()
282  print "Done saving."
283  print "\nScaled & added histograms from %i TTrees saved in\n %s" % (len(list_of_files), output_filename)
284 ##############################################################################
285 
286 def main():
287  if len(sys.argv) > 1:
288  if path.isfile(sys.argv[1]):
289  config_file = sys.argv[1].split('.')[0]
290  tree2hists_main(config_file)
291  else:
292  print "%s not found." % sys.argv[1]
293  print("Create default config file by running tree2hists "
294  "with no argument.")
295  sys.exit(1)
296  else:
297  if path.exists('t2h_config.py'):
298  print "Run with specific config file, like:"
299  print " tree2hists t2h_config.py"
300  sys.exit(1)
302  sys.exit(0)
303 
304 if __name__ == "__main__":
305  main()
std::string print(const Track &, edm::Verbosity=edm::Concise)
Track print utility.
Definition: print.cc:10
def join_cuts(list_of_cuts)
Definition: tree2hists.py:82
def make_all_hists_all_files(list_of_RootTrees, list_of_Plots, cut_for_all_files, list_of_cutSets)
Definition: tree2hists.py:151
def __init__(self, treeVariable, histogram, cuts="", storeErrors=True)
Definition: tree2hists.py:75
def __init__(self, treeName, fileName, scale=1.0, cuts="")
Definition: tree2hists.py:65
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
Definition: main.py:1
def duration_to_string(start, end)
Definition: tree2hists.py:91
Define classes and generators #######################################.
Definition: tree2hists.py:62
double split
Definition: MVATrainer.cc:139
def tree2hists_main(config_file)
Define the main program #############################################.
Definition: tree2hists.py:211