ATLAS Offline Software
pydraw.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 #
4 # File: pydraw.py
5 # Created: sss, a while ago. Added to ATLAS repository, Dec 2008
6 # Purpose: Interactive python commands for plotting from a tuple-like object.
7 #
8 
9 from __future__ import print_function
10 
11 """Interactive python commands for plotting from a tuple-like object.
12 This module provides in python functionality similar to TTree::Draw
13 and TTree::Scan. The major conceptual differences are:
14 
15  - All expressions are written in python (and not the specialized
16  TTree::Draw language).
17  - This can be applied to any type of object providing a simple loop
18  interface (explained below), not just to TTree's. (A TTree will work;
19  there is also a wrapper for the Athena event loop.)
20 
21 In addition, this style of query may be somewhat
22 easier to type interactively.
23 
24 
25 Quick start
26 ===========
27 
28 Here are some examples of plotting commands to give you the flavor:
29 
30  d tt.metx
31  d tt.ele_pt$i; 50 0 100*gev
32  d tt.metx:mety
33  d tt[100:1000].muo$i.pt() if abs(muo.eta)<2
34  d tt.(ele$i+ele$j).m() if $i<$j; same
35  scan tt.metx:mety
36 
37 To use these commands, you can pass them as strings to pydraw.cmd:
38 
39  from pydraw import cmd
40  cmd('d tt.metx')
41 
42 Alternatively, if you execute the cmdhook function, you can type them
43 directly:
44 
45  from pydraw import cmdhook
46  cmdhook()
47  d tt.metx
48 
49 (Note that this second form doesn't work in general for code that's read
50 from a file.)
51 
52 
53 Draw syntax
54 ===========
55 
56 The general syntax for drawing a histogram looks like this:
57 
58  d TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR] [; HISTSPEC]
59 
60 These pieces are explained in more detail below.
61 
62 
63 Tuple specifications
64 --------------------
65 
66 The object on which the draw operation is to be performed is given
67 by TUPLESPEC. This should be the name of some object in the python
68 global dictionary. Note that if the expression for the tuple
69 itself contains a period or brackets, you'll need to enclose it in parentheses:
70 
71  d (trees.tt[1])[:100].ele_pt$i
72 
73 Optionally, this can include a slice-like notation
74 to restrict the rows to which the draw applies:
75 
76  tuple[i:j] --- process rows i <= n < j
77  tuple[:j] --- process rows n < j
78  tuple[i:] --- process rows n >= i
79  tuple[i] --- process row i
80 
81 i and j can be expressions as well.
82 
83 The tuple object should contain a method like this:
84 
85  def loop (self, func, looplo, loophi)
86 
87 This function should loop over rows [looplo, loophi) and
88 call func on each. func will take two arguments, the first
89 being the row number and the second being the event object
90 (which may just be the tuple itself).
91 
92 If a method named loop is not available, but GetEntry and GetEntries
93 methods are available, then those will be used instead.
94 Similarly, if size and seekEvent are available, a wrapper
95 appropriate for the Athena event loop will be used.
96 
97 Thus, you can make plots from within Athena like this:
98 
99  d theApp.ElectronAODCollection$i.eta()
100 
101 
102 Expressions
103 -----------
104 
105 Once a tuple is specified, one then needs to specify what to plot.
106 This is done with an arbitrary python expression, with some extensions.
107 
108 To plot a simple numeric variable from the tuple, just give its name.
109 For example:
110 
111  d tt.foo
112 
113 will plot the variable `foo' from each row of the tuple. You can of course
114 also use more complicated expressions:
115 
116  d tt.r*cos(phi)
117 
118 In the common case, though, the members of the tuple will be vectors
119 of numbers of objects over which you want to iterate. You can iterate
120 plotting over such a vector by specifying a dummy index. This is an
121 identifier starting with a dollar sign:
122 
123  d tt.pt_e$i
124 
125 (Making the dummy indices explicit was a deliberate change from the
126 implicit iteration of root/paw. Such implicit iteration sometimes
127 caused confusion about just what was being iterated over, and also
128 when people needed to distinguish between accessing attributes
129 of a container and attributes of the contained objects.)
130 
131 This will automatically step $i over the contents of the vector pt_e,
132 plotting each one. The vector being iterated over may contain objects
133 as well as numbers:
134 
135  d tt.ele$i.pt()
136 
137 Note that the limits of the iteration are handled automatically.
138 The index $i can also be used in contexts other than that of an index.
139 For example, to limit the iteration in the above example to the first
140 four items, one can use:
141 
142  d tt.ele$i.pt() if $i<4
143 
144 (This uses a selection clause. This is to be described later, but the meaning
145 should be obvious.)
146 
147 If a dummy index is used for more than one vector, the iteration limit
148 will be taken from whichever vector is smaller. For example:
149 
150  d tt.ele$i+muo$i
151 
152 will iterate min(len(ele),len(muo)) times.
153 
154 Multiple dummy indices may be used. In that case, all possible index
155 combinations are used (a simple nested loop). If there is a symmetry
156 involved, a selection clause may be used to eliminate duplicates.
157 For example (given an appropriate ele definition), this will plot the
158 invariant masses of all electron pairs:
159 
160  d tt.(ele$i+ele$j).m() if $i>$j
161 
162 One can also reference individual elements of a vector using the
163 notation $N. Here, the indexing is 1-based (so $1 is the first element).
164 Example: to plot the pt of the leading electron
165 
166  d tt.ele$1.pt()
167 
168 Note that one can do something similar just using standard python
169 indexing directly:
170 
171  d tt.ele[0].pt()
172 
173 This, however, will crash if ele is empty; if the $N form is used,
174 an implicit selection is added to ensure that the index is in range.
175 Thus, the proper equivalent of the $N-form example is:
176 
177  d tt.ele[0].pt() if len(ele)>0
178 
179 You can also use $nCONT as an abbreviation for len(CONT):
180 
181  d tt.ele[0].pt() if $nele>0
182 
183 Names used in expressions will be looked up first in the tuple object,
184 then in the global dictionary. Note that the lookup in the tuple happens
185 before looping starts, so all needed variables must already be present
186 in the tuple. If you want to refer to the tuple object itself,
187 you can use the special variable `_ev'. (This can be changed by assigning
188 a string to pydraw._evtvar.)
189 
190 Multiple expressions may be given, separated by `:'. For drawing histograms,
191 you can give two expressions, for the x and y axis expressions. For scanning
192 tuples (see below), you give the list of expressions to be scanned.
193 
194 
195 Selections
196 ----------
197 
198 You can select items to be filled using a boolean expression, set off
199 with an `if' keyword:
200 
201  d tt.ele$i.pt() if abs(ele$i.eta())<2
202 
203 All dummy variables are common between the variable expressions
204 and the selection.
205 
206 
207 Statements
208 ----------
209 
210 You can specify arbitrary Python expressions to be executed before looping
211 starts. These come before the variables expressions, and are delimited
212 with `@'. This is useful mostly for defining short aliases for tuple
213 variables. For example:
214 
215  d tt.ele=ElectronAODCollection@ele$i.eta() if ele$i.pt()>100*gev
216 
217 
218 Histogram specifications
219 ------------------------
220 
221 Histogram specifications follow a semicolon. They can have the forms:
222 
223  ! OPTIONS...
224  >>NAME OPTIONS...
225  NX XLO XHI OPTIONS...
226  NX XLO XHI NY YLO YHI OPTIONS...
227  OPTIONS...
228 
229 For the first form, specifying ! reuses the same histogram that was used
230 for the last plot.
231 
232 For the second form, specifying >>NAME looks in the global dictionary
233 for a histogram NAME and uses that.
234 
235 Otherwise, a new histogram is created. The binning for this histogram
236 may be specified by NX XLO XHI and NY YLO YHI.
237 
238 Plotting options may also be given. The special option `prof' means
239 to create a profile histogram. Otherwise, root drawing options may
240 be used. This package uses PyAnalysisUtils.draw_obj to draw the
241 histograms, so the extra options supported by that function may
242 also be used. See draw_obj.py for details.
243 
244 The last histogram to have been drawn is available is pydraw.last_hist.
245 
246 
247 Scan syntax
248 ===========
249 
250 The scan command is very similar to draw:
251 
252  scan TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR]
253 
254 Instead of drawing a histogram, scan prints out a table of the expression
255 values.
256 
257 The formatting of the data printed by scan is currently pretty rudimentary.
258 This should probably be improved.
259 
260 
261 Loop syntax
262 ===========
263 
264 There is also a loop command:
265 
266  loop TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR]
267 
268 Loop will evaluate the given expressions in the same manner as draw and scan,
269 but the results of this are ignored. So it only makes sense to use loop
270 to evaluate expressions for their side effects. This can be used,
271 for example, to call a function that fills some large set of histograms.
272 
273 
274 Running commands
275 ================
276 
277 The general interface to execute one of these commands is the `cmd' function,
278 which takes the command as a string:
279 
280  from pydraw import cmd
281  cmd ('d tt.foo')
282 
283 Each command is also implemented by a single function, which may be called
284 directly. The command name should not be included in this case:
285 
286  from pydraw import draw
287  draw ('tt.foo')
288 
289 Finally, if you call the function cmdhook(), then you can give the commands
290 directly on the python command line:
291 
292  from pydraw import cmdhook
293  cmdhook()
294  d tt.foo
295 
296 
297 Bugs/stuff missing
298 ==================
299  - No way to specify an event weight when filling a histogram using
300  the draw command.
301 
302  - Hoist selection code out of the dummy index loops, when they don't
303  depend on the index? For example,
304 
305  d tt.foo$i if ht>100
306 
307  gets implemented like:
308 
309  for _it_foo in foo:
310  if _ev.ht>100:
311  Fill(_it_foo)
312 
313  but it would be more efficient to pull the selection out of the loop.
314 
315  - In an expr like d em.foo$i if em.bar$i>1
316  then foo always gets evaluated even if the condition is false.
317 
318  - Scan formatting.
319 
320 
321 """
322 
323 
324 import sys
325 import string
326 import tokenize
327 import token
328 import copy
329 import ROOT
330 import cppyy # noqa: F401
331 import six
332 if six.PY2:
333  from StringIO import StringIO #pragma: NO COVER
334 else:
335  from io import StringIO #pragma: NO COVER
336 from PyAnalysisUtils.draw_obj import draw_obj, get_canvas
337 
338 
339 try:
340  ScatterH2 = ROOT.RootUtils.ScatterH2
341 except AttributeError: #pragma: NO COVER
342  ScatterH2 = ROOT.TH2F #pragma: NO COVER
343  print ("WARNING: RootUtils::ScatterH2 not available; using TH2F instead") #pragma: NO COVER
344 
345 
346 try:
347  ROOT.TH1.kCanRebin
348  def _setCanRebin (h): #pragma: NO COVER
349  h.SetBit (ROOT.TH1.kCanRebin) #pragma: NO COVER
350  def _hasCanRebin (h): #pragma: NO COVER
351  return h.TestBit (ROOT.TH1.kCanRebin) #pragma: NO COVER
352 except AttributeError: #pragma: NO COVER
353  def _setCanRebin (h): #pragma: NO COVER
354  h.GetXaxis().SetCanExtend(True) #pragma: NO COVER
355  def _hasCanRebin (h): #pragma: NO COVER
356  return h.GetXaxis().CanExtend() #pragma: NO COVER
357 
358 
359 # The last histogram we made.
360 last_hist = None
361 
362 
363 # Dictionary in which to find global names.
364 _globals = sys.modules['__main__'].__dict__
365 
366 
367 # Characters that are legal in identifiers.
368 _idchars = string.ascii_letters + string.digits + '_'
369 
370 # This is what's used as the event formal argument in the generated functions.
371 _evtvar = '_ev'
372 
373 # Set this to true to dump out the generated function bodies.
374 _debug = False
375 
377  """Name a string safe to use as a histogram name.
378 
379  Root does bad things if you put / in a histogram name, so we remove them.
380  Examples:
381  >>> print (_sanitize_hname('foo'))
382  foo
383  >>> print (_sanitize_hname('foo/bar'))
384  foo DIV bar
385  """
386  return s.replace ('/', ' DIV ')
387 
388 
389 def _untokenize (tokens):
390  """Transform tokens back into Python source code.
391 
392  Each element returned by the iterable must be a token sequence
393  with at least two elements, a token number and token value.
394 
395  Unlike tokenize.untokenize(), this does not handle multiple lines.
396  It also tries not to add unneeded spaces.
397 
398  Examples:
399  >>> from tokenize import generate_tokens, untokenize
400  >>> import six
401  >>> if six.PY2:
402  ... from StringIO import StringIO
403  ... else:
404  ... from io import StringIO
405  >>> def untokenize1(tt):
406  ... tt=list(tt)
407  ... if tt[-1][0]==0: tt=tt[:-1]
408  ... return untokenize(tt)
409  >>> untokenize1(generate_tokens(StringIO('1+1').readline))
410  '1+1'
411  >>> _untokenize(generate_tokens(StringIO('1+1').readline))
412  '1+1'
413  >>> untokenize1(generate_tokens(StringIO('foo$i>2*h').readline))
414  'foo$i>2*h'
415  >>> _untokenize(generate_tokens(StringIO('foo$i>2*h').readline))
416  'foo$i>2*h'
417  """
418  lastname = False
419  toks = []
420  toks_append = toks.append
421  for tok in tokens:
422  toknum, tokval = tok[:2]
423  tokval = tokval.strip()
424  if toknum in (token.NAME, token.NUMBER):
425  if lastname:
426  tokval = ' ' + tokval
427  lastname = True
428  else:
429  lastname = False
430  toks_append (tokval)
431  return ''.join(toks)
432 
433 
434 def _find_outer (haystack, needle, ignore_delim = False):
435  """Look for NEEDLE in HAYSTACK (token-based. Return pair (HEAD, TAIL).
436 
437  HAYSTACK and NEEDLE are both strings. Look for a token in HAYSTACK with
438  a value matching NEEDLE that is outside of any paired delimiters.
439  Also ignores things in strings.
440  If IGNORE_DELIM is True, then we do find things inside delimiters
441  (strings are still ignored).
442 
443  Returns a pair (HEAD, TAIL) of the pieces of the string before and
444  after NEEDLE. If there is no match, returns (HAYSTACK, None).
445  Note that whitespace and formatting in HEAD and TAIL may differ
446  from the original string.
447 
448  Examples:
449  >>> _find_outer ("head.tail1.tail2", ".")
450  ('head', 'tail1.tail2')
451  >>> _find_outer ("(head.tail1).tail2", ".")
452  ('(head.tail1)', 'tail2')
453  >>> _find_outer ("[a for a in foo if good(a)] if bar", "if")
454  ('[a for a in foo if good(a)]', 'bar')
455  >>> _find_outer ("(a [b {c . d } ] ) . e", ".")
456  ('(a [b {c . d } ] )', 'e')
457  >>> _find_outer ("a.b", ";")
458  ('a.b', None)
459  >>> _find_outer ("a '$' b", '$')
460  ("a '$' b", None)
461  >>> _find_outer ("a $ b", '$')
462  ('a', 'b')
463  >>> _find_outer ("(head.tail1).tail2", ".", True)
464  ('(head', 'tail1).tail2')
465  >>> _find_outer ('a; 1 -1 1', ';')
466  ('a', '1 -1 1')
467 """
468  tlist = tokenize.generate_tokens (StringIO(haystack).readline)
469  pend = []
470  head = []
471  for (i, (tnum, val, a, b, c)) in enumerate (tlist):
472  if tnum != token.STRING and not pend and val == needle:
473  col1 = a[1]
474  col2 = b[1]
475  return (haystack[:col1].strip(),
476  haystack[col2:].strip())
477  if not ignore_delim:
478  if val == '(':
479  pend.append (')')
480  elif val == '[':
481  pend.append (']')
482  elif val == '{':
483  pend.append ('}')
484  elif pend and val == pend[-1]:
485  pend.pop()
486  head.append ((tnum, val))
487  return (haystack, None)
488 
489 
490 def _split_outer (haystack, needle):
491  """Split HAYSTACK at the delimiters NEEDLE, as in _find_outer.
492 
493  Examples:
494  >>> _split_outer ("a,(b,c),d", ",")
495  ['a', '(b,c)', 'd']
496  >>> _split_outer ("a,,b", ",")
497  ['a', '', 'b']
498  >>> _split_outer ("a", ",")
499  ['a']
500  >>> #_split_outer ("", ",")
501  []
502 """
503  out = []
504  while True:
505  (head, tail) = _find_outer (haystack, needle)
506  head = head.strip()
507  out.append (head)
508  if tail is None:
509  break
510  else:
511  haystack = tail
512  return out
513 
514 
516  """Wrapper for TTree, supplying a loop method.
517 
518  This class wraps a TTree class and provides a loop method
519  that will work with pydraw.
520 """
521 
522  def __init__ (self, tree):
523  """Make a wrapper for a tree."""
524  self._tree = tree
525  return
526 
527  def loop (self, f, looplo=0, loophi=sys.maxsize):
528  """Call f(i,tree) on rows [looplo, loophi)"""
529  tree = self._tree
530  loophi = min (loophi, tree.GetEntries())
531  getentry = tree.GetEntry
532  for i in range(looplo, loophi):
533  getentry(i)
534  f(i, tree)
535  return
536 
537 
539  """Wrapper for the Athena event loop, supplying a loop method.
540 
541  This class wraps an application manager object and provides a loop method
542  that will work with pydraw.
543 """
544  def __init__ (self, app=None):
545  from AthenaPython import PyAthena #pragma: NO COVER
546  if app is None: #pragma: NO COVER
547  from AthenaCommon.AppMgr import theApp #pragma: NO COVER
548  app = theApp #pragma: NO COVER
549  self._app = app #pragma: NO COVER
550  self._sg = PyAthena.py_svc('StoreGateSvc') #pragma: NO COVER
551  return #pragma: NO COVER
552 
553 
554  def loop (self, f, looplo=0, loophi=sys.maxsize):
555  """Call f(i,tree) on rows [looplo, loophi)"""
556  loophi = min (loophi, self._app.size()) #pragma: NO COVER
557  getentry = self._app.seekEvent #pragma: NO COVER
558  for i in range(looplo, loophi): #pragma: NO COVER
559  getentry(i) #pragma: NO COVER
560  f(i, self) #pragma: NO COVER
561  return #pragma: NO COVER
562 
563 
564  def __getattr__ (self, v):
565  if not v.startswith('_'): #pragma: NO COVER
566  return self._sg[v] #pragma: NO COVER
567  raise AttributeError() #pragma: NO COVER
568 
569 
571  """Holds information about a dummy loop variable.
572 
573  Attributes:
574  name - The name of the dummy variable.
575  ids - Set of loop identifiers (`foo' in `foo$i') with which
576  this dummy has been used.
577  explicit - Set to true if this variable is ever used on its own
578  (just $i)
579  """
580 
581  def __init__ (self, name):
582  """Initialize given the name."""
583  self.name = name
584  self.ids = set()
585  self.explicit = 0
586  return
587 
588  def itname (self, id):
589  """Return the iterator variable for this dummy and loop identifier ID.
590  """
591  return "_it_%s_%s" % (self.name, id)
592 
593  def dumname (self):
594  """Return the dummy variable name for this dummy."""
595  return "_dum_" + self.name
596 
597  def add_id (self, id):
598  """Notice this this dummy is used with loop identifier ID.
599 
600  Return the iterator variable.
601  """
602  self.ids.add (id)
603  return self.itname (id)
604 
605  def get_ids (self):
606  """Return the list of loop identifiers with which we've been used."""
607  return list (self.ids)
608 
609 
611  """Holds information used to implement a draw/scan/loop command.
612 
613  Pass the draw string to the constructor. See the file-level comments
614  for details on the syntax of this. This will define the
615  following attributes:
616 
617  errstr - If set to a string, there was an error.
618  Should be None if everything's ok.
619  tuple - The name of the tuple object.
620  tuple_o - Tuple object.
621  lo - The lower bound for row iteration.
622  hi - The upper bound for row iteration.
623  stmts - List of additional statements.
624  exprs - List of draw expressions.
625  sel - Selection expression or None.
626  sel_orig - Untransformed selection expression or None.
627  expr_orig- Untransformed plotting expression.
628  histspec - The text following `;', split into space-separated words.
629 
630  Other attributes:
631  _iddict - Map from loop identifiers (`foo' in `foo$i')
632  to temp variables used to reference
633  them in the loop function.
634  _limdict - Map from loop identifiers (`foo' in `foo$2')
635  to the largest explicit index seen.
636  _loopdict - Map of loop dummy variable names to _Loopvar instances.
637 """
638 
639  def __init__ (self, s):
640  """Initialize from a draw string. See above for more details."""
641 
642  # Assume no error.
643  self.errstr = None
644 
645  self._iddict = {}
646  self._limdict = {}
647  self._loopdict = {}
648 
649  try:
650  self._tupleparse (s)
651  except Exception as e:
652  import traceback
653  self.errstr = str(e)
654  self.excstr = traceback.format_exc()
655  return
656 
657 
658 
659  def _tupleparse (self, s):
660  """Parse a draw string. See above for more details."""
661 
662  # Split off the histspec.
663  (s, self.histspec) = _find_outer (s, ';')
664 
665  # ??? Don't split at spaces in delimiters.
666  # _find_outer doesn't really work for this since it operates
667  # on the tokenized string, in which whitespace doesn't appear.
668  if self.histspec is None:
669  self.histspec = []
670  else:
671  self.histspec = self.histspec.split ()
672 
673  # Gotta have something.
674  s = s.strip()
675  if not s:
676  self.errstr = "Empty draw string."
677  return
678 
679  # Split off the tuple part --- before the first period.
680  (tuple, s) = _find_outer (s, '.')
681  if not s:
682  self.errstr = "Missing period in tuple specification."
683  return
684 
685  # Handle a range specification on the sample.
686  self._parserange (tuple)
687 
688  # Try to find the sample.
689  try:
690  self.tuple_o = eval (self.tuple, _globals)
691  except NameError:
692  self.tuple_o = None
693  if not self.tuple_o:
694  self.errstr = "Can't find sample " + self.tuple
695  return
696 
697  # Look for additional statements.
698  self.stmts = _split_outer (s, '@')
699  s = self.stmts[-1]
700  del self.stmts[-1]
701  self.stmts = [self._mung_expr(x) for x in self.stmts]
702 
703  # Split off the selection.
704  (self.expr_orig, self.sel_orig) = _find_outer (s, "if")
705  self.sel = self._mung_expr (self.sel_orig)
706 
707  self.exprs = [self._mung_expr(x) for x in
708  _split_outer (self.expr_orig, ':')]
709 
710  # Check the interface of the sample. If it doesn't have
711  # the loop interface but has the root tree interface,
712  # use a wrapper.
713  if hasattr (self.tuple_o, 'loop'):
714  # Ok --- has the loop interface.
715  pass
716  elif (hasattr (self.tuple_o, 'GetEntry') and
717  hasattr (self.tuple_o, 'GetEntries')):
718  # Has the TTree interface. Use a wrapper.
719  self.tuple_o = TreeLoopWrapper (self.tuple_o)
720  elif (hasattr (self.tuple_o, 'size') and
721  hasattr (self.tuple_o, 'seekEvent')): #pragma: NO COVER
722  # Has the appmgr interface. Use a wrapper.
723  self.tuple_o = AthenaLoopWrapper (self.tuple_o) #pragma: NO COVER
724  else:
725  # An error --- complain.
726  self.errstr = ("Sample " + self.tuple +
727  " doesn't have a correct interface.")
728  return
729 
730  return
731 
732 
733 
734  def _parserange (self, tuple):
735  """Parse the range part of a draw string.
736 
737  See above for more details.
738  Fills self.tuple, self.lo, self.hi.
739  """
740  lo = 0
741  hi = sys.maxsize
742  (tuple, tail) = _find_outer (tuple, '[')
743  if tail:
744  g = copy.copy (_globals)
745 
746  pos = tail.find (':')
747  pos2 = tail.find (']')
748  if pos2 < 0:
749  pos2 = len (tail) #pragma: NO COVER
750  if pos < 0:
751  slo = tail[:pos2].strip()
752  if len (slo) > 0:
753  lo = int (eval (slo, g))
754  hi = lo + 1
755  else:
756  slo = tail[:pos].strip()
757  if len (slo) > 0:
758  lo = int (eval (slo, g))
759  shi = tail[pos+1:pos2].strip()
760  if len (shi) > 0:
761  hi = int (eval (shi, g))
762 
763  if tuple[0] == '(' and tuple[-1] == ')':
764  tuple = tuple[1:-1].strip()
765  self.tuple = tuple
766  self.lo = lo
767  self.hi = hi
768  return
769 
770 
771  def _mung_id (self, id):
772  """Given a loop identifier (`foo' in `foo$i'), return the identifier
773  used to reference it in loop functions.
774  """
775  out = self._iddict.get (id)
776  if not out:
777  out = '_e_' + id
778  self._iddict[id] = out
779  return out
780 
781 
782  def _mung_index (self, s1, s2):
783  """Handle an explicit index reference; i.e., `foo$2'.
784 
785  S1 and S2 are pieces of the string before and after the `$'.
786  Returns the modified string.
787  """
788  pos2 = 0
789  while pos2 < len(s2) and s2[pos2] in string.digits:
790  pos2 += 1
791  if pos2 == 0:
792  self.errstr = "Bad index"
793  return ''
794  i = int (s2[:pos2])
795  if i < 1:
796  self.errstr = "Bad index"
797  return ''
798  s = ("[%d]" % (i-1)) + s2[pos2:]
799  pos2 = len(s1)-1
800  while pos2 >= 0 and s1[pos2] in _idchars:
801  pos2 -= 1
802  pos2 += 1
803  if pos2 == len(s1):
804  self.errstr = "Bad index"
805  return ''
806  id = s1[pos2:]
807  s = s1[:pos2] + self._mung_id (id) + s
808  self._limdict[id] = max (i, self._limdict.get(id, 0))
809  return s
810 
811 
812  def _mung_n (self, s1, s2):
813  """Handle a length reference; i.e., `$nfoo'.
814 
815  S1 and S2 are pieces of the string before and after the `$'.
816  Returns the modified string.
817  """
818  pos2 = 1
819  while pos2 < len(s2) and s2[pos2] in _idchars:
820  pos2 += 1
821  id = s2[1:pos2]
822  s = s1 + (" len(%s)" % self._mung_id(id)) + s2[pos2:]
823  return s
824 
825 
826  def _mung_loop (self, s1, s2):
827  """Handle use of a dummy loop variable, such as foo$i.
828 
829  S1 and S2 are pieces of the string before and after the `$'.
830  Returns the modified string.
831  """
832 
833  # Scan after the $ to find the dummy variable.
834  pos2 = 0
835  while pos2 < len(s2) and s2[pos2] in _idchars:
836  pos2 += 1
837  if pos2 == 0:
838  self.errstr = "Bad loop var"
839  return ''
840  loopvar = s2[:pos2]
841 
842  # Look it up. Make a new _Loopvar object if it's not in the map.
843  ll = self._loopdict.get (loopvar)
844  if not ll:
845  ll = _Loopvar(loopvar)
846  self._loopdict[loopvar] = ll
847 
848  # Is the $ after an identifier?
849  if len(s1) > 0 and s1[-1] in _idchars:
850  # Yes --- find the identifier.
851  pos3 = len(s1)-1
852  while pos3 >= 0 and s1[pos3] in _idchars:
853  pos3 -= 1
854  pos3 += 1
855  assert (len(s1) - pos3 >= 1)
856  id = s1[pos3:]
857 
858  # Replace with the iterator.
859  s = s1[:pos3] + ll.add_id(id) + s2[pos2:]
860  self._mung_id (id)
861  else:
862  # Explicit use of the dummy.
863  # Replace with the dummy name and note that it was used explicitly.
864  s = s1 + ("%s" % ll.dumname()) + s2[pos2:]
865  ll.explicit = 1
866  return s
867 
868 
869  def _mung_expr_dollar (self, s):
870  """Process $ constructions in string S.
871 
872  Returns the modified string.
873  """
874  if not s:
875  return s
876  pos = 0
877  while 1:
878  (s1, s2) = _find_outer (s[pos:], '$', True)
879  if s2 is None:
880  break
881  snew = None
882  if len(s2) > 0:
883  if s2[0] in string.digits:
884  snew = self._mung_index (s1, s2)
885  elif (s2[0] == 'n' and
886  (not (len(s1) > 0 and s1[-1] in _idchars) or
887  s1.endswith (' and') or
888  s1.endswith (' or') or
889  s1.endswith ('not'))):
890  snew = self._mung_n (s1, s2)
891  elif s2[0] in string.ascii_letters:
892  snew = self._mung_loop (s1, s2)
893  s = s[:pos]
894  if snew is None:
895  snew = s1 + '$' + s2
896  pos = pos + len(s1)+1
897  s = s + snew
898  return s
899 
900 
901  def _mung_expr_ids (self, s):
902  """Perform id substitution in S.
903 
904  For identifiers in S that are attributes of our tuple,
905  replace them with references to the tuple attribute
906  (using _mung_id).
907 
908  Returns the modified string.
909  """
910  if not s:
911  return s
912 
913  tlist = tokenize.generate_tokens (StringIO(s).readline)
914  out = []
915  afterDot = False
916  for tnum, val, a, b, c in tlist:
917  if tnum == token.NAME and not afterDot:
918  if hasattr (self.tuple_o, val):
919  val = self._mung_id (val)
920  #val = _evtvar + '.' + val
921  out.append ((tnum, val))
922  # Don't mung names after a period. We may have attributes
923  # with the same names as variables in the tuple.
924  if tnum == token.OP and val == '.':
925  afterDot = True
926  else:
927  afterDot = False
928  return _untokenize (out)
929 
930 
931  def _mung_expr (self, s):
932  """Process $ constructions and id substitution in string S.
933 
934  Returns the modified string.
935  """
936  s = self._mung_expr_dollar (s)
937  return self._mung_expr_ids (s)
938 
939 
940  def _make_func (self, payload, extargs = ''):
941  """Create the text for the function to process this query.
942 
943  PAYLOAD is the payload expression to plug in.
944  EXTARGS is an additional string to add to the end of the
945  function's argument list (to set default values, for example).
946  Returns the function definition as a string.
947  """
948 
949  sel = self.sel
950  if self._limdict:
951  limsel = ' and '.join (["len(%s)>=%d" % (self._iddict[p[0]], p[1])
952  for p in self._limdict.items()])
953  if not sel:
954  sel = limsel
955  else:
956  sel = limsel + " and (" + sel + ")"
957 
958  ftext = "def _loopfunc(_i, %s%s):\n" % (_evtvar, extargs)
959  for (id1, id2) in sorted(self._iddict.items()):
960  ftext += " %s = %s.%s\n" % (id2, _evtvar, id1)
961  indent = 2
962 
963  for (i,l) in sorted(self._loopdict.items()):
964  ids = sorted(l.get_ids())
965  assert (not not ids)
966  if len(ids) == 1:
967  vars = l.itname (ids[0])
968  lists = self._iddict[ids[0]]
969  else:
970  vars = "(" + ','.join([l.itname (id) for id in ids]) + ")"
971  lists = ("zip(" + ','.join([self._iddict[id] for id in ids])
972  + ")")
973  if l.explicit:
974  vars = "(%s,%s)" % (l.dumname(), vars)
975  lists = "enumerate(%s)" % lists
976  ftext += ' '*indent + "for %s in %s:\n" % (vars, lists)
977  indent += 2
978 
979  for s in self.stmts:
980  ftext += ' '*indent + s + '\n'
981 
982  if sel and sel != '1':
983  ftext += ' '*indent + "if (%s):\n" % sel
984  indent += 2
985 
986  ftext += ' '*indent + "%s\n" % payload
987 
988  if _debug:
989  print (ftext)
990 
991  return ftext
992 
993 
994 class _Bins(object):
995  """Holds the results of _get_bins. Defined attributes:
996 
997  nbins
998  lo
999  hi
1000  rebin
1001  """
1002 
1003 
1004 def _get_bins (args, ndim, axis):
1005  """Parse bin specifications from split list of arguments ARGS.
1006  NDIM is 1 or 2, and AXIS is 0 or 1, for the x or y axis.
1007 
1008  Examples:
1009  >>> from PyAnalysisUtils import pydraw
1010  >>> pydraw._globals = globals()
1011  >>> import ROOT
1012  >>> ROOT.gPad.Range(0, 1,2,3)
1013  >>> b = _get_bins (["50", "10", "100"], 1, 0)
1014  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1015  50 10.0 100.0 0
1016  >>> b = _get_bins ([], 1, 0)
1017  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1018  50 0 1 1
1019  >>> b = _get_bins (["!", "10"], 1, 0)
1020  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1021  50 10.0 11.0 1
1022  >>> b = _get_bins (["!", "!", "10"], 1, 0)
1023  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1024  50 0 10.0 0
1025  >>> scale = 10
1026  >>> b = _get_bins (["50", "0", "2*scale"], 1, 0)
1027  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1028  50 0.0 20.0 0
1029  >>> b = _get_bins ([], 2, 0)
1030  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1031  50 0.0 2.0 1
1032  >>> b = _get_bins ([], 2, 1)
1033  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1034  50 1.0 3.0 1
1035  >>> b = _get_bins ([], 2, 2)
1036  Traceback (most recent call last):
1037  ...
1038  AssertionError
1039  """
1040 
1041  g = copy.copy (_globals)
1042 
1043  bins = _Bins()
1044 
1045  bins.nbins = 0
1046  if len(args) >= 1 and args[0] != '!' and len(args[0]) > 0:
1047  bins.nbins = int (eval (args[0], g))
1048  if bins.nbins <= 0:
1049  bins.nbins = 50
1050 
1051  bins.lo = 0
1052  if len(args) >= 2 and args[1] != '!' and len(args[1]) > 0:
1053  bins.lo = float (eval (args[1], g))
1054 
1055  bins.hi = 0
1056  if len(args) >= 3 and args[2] != '!' and len(args[2]) > 0:
1057  bins.hi = float (eval (args[2], g))
1058 
1059  bins.rebin = 0
1060  if bins.hi <= bins.lo:
1061  bins.rebin = 1
1062  if ndim == 1:
1063  bins.hi = bins.lo + 1
1064  elif axis == 0:
1065  bins.lo = ROOT.gPad.GetUxmin()
1066  bins.hi = ROOT.gPad.GetUxmax()
1067  elif axis == 1:
1068  bins.lo = ROOT.gPad.GetUymin()
1069  bins.hi = ROOT.gPad.GetUymax()
1070  else:
1071  assert 0
1072 
1073  return bins
1074 
1075 
1076 def _get_hist (ndim, args, hname, htitle):
1077  """Create a new histogram from options.
1078 
1079  NDIM is the dimensionality of the histogram (1 or 2).
1080  ARGS is a list of the arguments given to specify the histogram.
1081  HNAME and HTITLE are the histogram name and title, respectively.
1082  """
1083  get_canvas()
1084 
1085  # Get the x-axis bin specifications.
1086  xbins = _get_bins (args, ndim, 0)
1087  rebin = xbins.rebin
1088 
1089  # Get the y-axis bin specifications.
1090  if ndim >= 2:
1091  ybins = _get_bins (args[3:], ndim, 1)
1092  rebin = rebin or ybins.rebin
1093 
1094  profile = 0
1095  # Look for drawing options.
1096  options = ''
1097  for i in range (0, len(args)):
1098  if args[i][0] in string.ascii_letters:
1099  for j in range (i, len(args)):
1100  if ndim == 2 and args[j].lower() == "prof":
1101  profile = 1
1102  args[j] = ''
1103  options = ' '.join (args[i:])
1104  break
1105 
1106  # Delete any old object of the same name.
1107  hold = ROOT.gROOT.FindObject (hname)
1108  if hold:
1109  ROOT.gROOT.Remove (hold)
1110 
1111  # Create the histogram.
1112  if profile:
1113  hist = ROOT.TProfile (hname, htitle, xbins.nbins, xbins.lo, xbins.hi)
1114  if not ybins.rebin:
1115  hist.SetMinimum (ybins.lo)
1116  hist.SetMaximum (ybins.hi)
1117  elif ndim == 1:
1118  hist = ROOT.TH1F (hname, htitle, xbins.nbins, xbins.lo, xbins.hi)
1119  elif ndim == 2:
1120  hist = ScatterH2 (hname, htitle,
1121  xbins.nbins, xbins.lo, xbins.hi,
1122  ybins.nbins, ybins.lo, ybins.hi)
1123  if hasattr (hist, 'scatter'):
1124  hist.scatter (1)
1125 
1126  # Automatic rebinning?
1127  if rebin:
1128  _setCanRebin (hist)
1129 
1130  return (hist, options)
1131 
1132 
1133 def draw (arg):
1134  """Process a draw command.
1135 
1136  ARG is the command arguments (without the command word itself).
1137  See the header comments for the command syntax.
1138  """
1139 
1140  global last_hist
1141 
1142  # Initial parsing of the arguments.
1143  c = Draw_Cmd (arg)
1144  if c.errstr:
1145  print (c.errstr)
1146  return False
1147 
1148  # Construct the expression to use to fill the histogram.
1149  if len (c.exprs) == 1:
1150  ndim = 1
1151  payload = "_hfill (%s)" % c.exprs[0]
1152  else:
1153  ndim = 2
1154  payload = "_hfill ((%s),(%s))" % (c.exprs[0], c.exprs[1])
1155 
1156  # Construct the histogram title.
1157  htitle = "%s.%s" % (c.tuple, c.expr_orig)
1158  if c.sel_orig:
1159  htitle = htitle + '{%s}' % c.sel_orig
1160 
1161  # Make the histogram.
1162  # If it's `!', then we just use the last one.
1163  if len(c.histspec) >= 1 and c.histspec[0] == "!" and last_hist is not None:
1164  hist = last_hist
1165  options = ' '.join (c.histspec[1:])
1166  elif len(c.histspec) >= 1 and c.histspec[0][:2] == '>>':
1167  hname = c.histspec[0][2:]
1168  hist = _globals.get (hname)
1169  options = ' '.join (c.histspec[1:])
1170  else:
1171  (hist, options) = _get_hist (ndim, c.histspec,
1172  _sanitize_hname(c.tuple+'.'+c.expr_orig), htitle)
1173 
1174  # Remember it.
1175  last_hist = hist
1176 
1177  # Generate the function.
1178  # It will be defined as _loopfunc in g.
1179  g = copy.copy (_globals)
1180  g['_hfill'] = hist.Fill
1181  ftext = c._make_func (payload, ', _hfill = _hfill')
1182  exec (ftext, g)
1183 
1184  # Execute the loop over the data.
1185  c.tuple_o.loop (g['_loopfunc'], c.lo, c.hi)
1186 
1187  # Adjust binning, if requested.
1188  if _hasCanRebin (hist):
1189  hist.LabelsDeflate ("X")
1190  if ndim > 1:
1191  hist.LabelsDeflate ("Y")
1192 
1193  # Draw the histogram.
1194  draw_obj (hist, options)
1195  return True
1196 
1197 
1198 def _scan_print (i, *args):
1199  """Helper to print out one row of a scan.
1200 
1201  I is the row number and ARGS is a tuple of the column values."""
1202 
1203  s = '%6d' % i
1204  for a in args:
1205  if isinstance(a, six.integer_types):
1206  s += ' %8d' % a
1207  else:
1208  s += ' %8g' % a
1209  print (s)
1210  return
1211 
1212 
1213 def scan (arg):
1214  """Process a scan command.
1215 
1216  ARG is the command arguments (without the command word itself).
1217  See the header comments for the command syntax.
1218  """
1219 
1220  # Initial parsing of the arguments.
1221  c = Draw_Cmd (arg)
1222  if c.errstr:
1223  print (c.errstr)
1224  return False
1225 
1226  payload = "_print (_i, %s)" % \
1227  ','.join (['(%s)'%e for e in c.exprs])
1228 
1229  # Generate the function.
1230  # It will be defined as _loopfunc in g.
1231  g = copy.copy (_globals)
1232  g['_print'] = _scan_print
1233  ftext = c._make_func (payload, ', _print = _print')
1234  exec (ftext, g)
1235 
1236  # Execute the loop over the data.
1237  c.tuple_o.loop (g['_loopfunc'], c.lo, c.hi)
1238 
1239  return True
1240 
1241 
1242 def loop (arg):
1243  """Process a loop command.
1244 
1245  ARG is the command arguments (without the command word itself).
1246  See the header comments for the command syntax.
1247  """
1248 
1249  # Initial parsing of the arguments.
1250  c = Draw_Cmd (arg)
1251  if c.errstr:
1252  print (c.errstr)
1253  return False
1254 
1255  payload = "(%s,)" % ','.join (c.exprs)
1256 
1257  # Generate the function.
1258  # It will be defined as _loopfunc in g.
1259  g = copy.copy (_globals)
1260  ftext = c._make_func (payload)
1261  exec (ftext, g)
1262 
1263  # Execute the loop over the data.
1264  c.tuple_o.loop (g['_loopfunc'], c.lo, c.hi)
1265 
1266  return True
1267 
1268 
1269 # Dictionary of command handlers.
1270 # Should return True if cmd was handled.
1271 _cmddict = {'d': draw,
1272  'draw' : draw,
1273  'scan' : scan,
1274  'loop' : loop,
1275  }
1276 
1277 
1278 def cmd (s):
1279  """Process a command S.
1280 
1281  Returns True if the command was handled, False otherwise.
1282  See the header comments for the command syntax.
1283  """
1284 
1285  ssplit = s.split (None, 1)
1286 
1287  if len(ssplit) < 2:
1288  return False
1289 
1290  cmd, args = ssplit
1291 
1292  func = _cmddict.get (cmd)
1293  if func:
1294  return func (args)
1295 
1296  return False
1297 
1298 
1299 
1300 
1306 
1307 #
1308 # Hook holding the original value of the exception hook.
1309 # But be careful not to overwrite this if this file is reread.
1310 #
1311 if '_orig_ehook' not in globals():
1312  _orig_ehook = None
1313 
1314 
1315 def _excepthook (exctype, value, traceb):
1316  """Exception hook used by pydraw to process drawing commands."""
1317 
1318  # If it's a syntax error, try interpreting as a drawing command.
1319  if isinstance (value, SyntaxError):
1320  val = value.text
1321  if val[-1] == '\n':
1322  val = val[:-1] #pragma: NO COVER
1323  if cmd (val):
1324  # Success --- update root stuff and return.
1325  # (This will swallow the original syntax error.)
1326  ROOT.gInterpreter.EndOfLineAction()
1327  return
1328 
1329  # No luck --- pass it on to the original exception handler.
1330  _orig_ehook (exctype, value, traceb)
1331 
1332 
1333 def cmdhook():
1334  """Enable entering drawing commands directly at the python prompt."""
1335 
1336  # Store the old value of the exception hook (only if we haven't
1337  # done so already).
1338  global _orig_ehook
1339  if _orig_ehook is None:
1340  _orig_ehook = sys.excepthook
1341 
1342  # Install our handler.
1343  sys.excepthook = _excepthook
1344  return
1345 
1346 
1347 
1348 
1349 # import ROOT
1350 # import string
1351 # import sys
1352 # import exceptions
1353 # import copy
1354 # from PyAnalysisUtils.draw_obj import draw_obj, get_canvas
1355 
1356 # try:
1357 # ScatterH2 = ROOT.RootUtils.ScatterH2
1358 # except AttributeError:
1359 # ScatterH2 = ROOT.TH2F
1360 # print ("WARNING: RootUtils::ScatterH2 not available; using TH2F instead")
1361 
1362 # kCanRebin = ROOT.TH1.kCanRebin
1363 
1364 # _last_hist = None
1365 # #_marker_style = 3
1366 # #_marker_size = 0.5
1367 
1368 # _evtvar = 'e'
1369 
1370 
1371 
1372 
1373 
1374 
1375 # from array import array
1376 # class hist_filler:
1377 # def __init__ (self, hist, nbuf=100):
1378 # self.hist = hist
1379 # self.filln = hist.FillN
1380 # self.nbuf = nbuf
1381 # self.xarr = array ('d', 100*[0.])
1382 # self.warr = array ('d', 100*[1.])
1383 # self.i = [0]
1384 
1385 # self.xlist = 100*[0.]
1386 # return
1387 # def get_filler (self):
1388 # def fill (x,i=self.i,nbuf=self.nbuf,xarr=self.xarr,flush=self.flush):
1389 # ii = i[0]
1390 # if ii == nbuf:
1391 # flush()
1392 # ii = i[0]
1393 # xarr[ii] = x
1394 # i[0] = ii + 1
1395 # return
1396 # return fill
1397 # def flush (self):
1398 # #print (self.i, self.xarr)
1399 # self.filln (self.i[0], self.xarr, self.warr)
1400 # self.i[0] = 0
1401 # return
1402 
1403 # ##############################################################################
1404 # # Here are the command handlers.
python.pydraw.draw
def draw(arg)
Definition: pydraw.py:1133
python.pydraw._Loopvar.ids
ids
Definition: pydraw.py:584
python.pydraw.TreeLoopWrapper
Definition: pydraw.py:515
python.pydraw._get_hist
def _get_hist(ndim, args, hname, htitle)
Definition: pydraw.py:1076
python.pydraw.Draw_Cmd._mung_loop
def _mung_loop(self, s1, s2)
Definition: pydraw.py:826
python.pydraw._Bins
Definition: pydraw.py:994
python.pydraw.Draw_Cmd._loopdict
_loopdict
Definition: pydraw.py:647
python.pydraw.Draw_Cmd.exprs
exprs
Definition: pydraw.py:707
python.pydraw.Draw_Cmd._limdict
_limdict
Definition: pydraw.py:646
python.pydraw.Draw_Cmd._make_func
def _make_func(self, payload, extargs='')
Definition: pydraw.py:940
python.pydraw._untokenize
def _untokenize(tokens)
Definition: pydraw.py:389
python.pydraw.scan
def scan(arg)
Definition: pydraw.py:1213
python.pydraw.Draw_Cmd._mung_expr
def _mung_expr(self, s)
Definition: pydraw.py:931
python.pydraw._Loopvar.name
name
Definition: pydraw.py:583
python.pydraw.TreeLoopWrapper.__init__
def __init__(self, tree)
Definition: pydraw.py:522
python.pydraw._Loopvar.itname
def itname(self, id)
Definition: pydraw.py:588
python.pydraw.Draw_Cmd
Definition: pydraw.py:610
python.pydraw._excepthook
def _excepthook(exctype, value, traceb)
Definition: pydraw.py:1315
python.pydraw.Draw_Cmd._mung_expr_dollar
def _mung_expr_dollar(self, s)
Definition: pydraw.py:869
python.pydraw.Draw_Cmd._mung_expr_ids
def _mung_expr_ids(self, s)
Definition: pydraw.py:901
python.pydraw.TreeLoopWrapper._tree
_tree
Definition: pydraw.py:524
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
python.pydraw.AthenaLoopWrapper._sg
_sg
Definition: pydraw.py:550
python.pydraw.AthenaLoopWrapper._app
_app
Definition: pydraw.py:549
python.pydraw._scan_print
def _scan_print(i, *args)
Definition: pydraw.py:1198
python.pydraw.Draw_Cmd._iddict
_iddict
Definition: pydraw.py:645
python.draw_obj.get_canvas
def get_canvas(cname="c1")
Definition: draw_obj.py:273
python.pydraw.AthenaLoopWrapper
Definition: pydraw.py:538
python.pydraw.cmdhook
def cmdhook()
Definition: pydraw.py:1333
python.pydraw.Draw_Cmd._mung_index
def _mung_index(self, s1, s2)
Definition: pydraw.py:782
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
python.pydraw.Draw_Cmd.errstr
errstr
Definition: pydraw.py:643
python.pydraw.Draw_Cmd.tuple_o
tuple_o
Definition: pydraw.py:690
hist_file_dump.f
f
Definition: hist_file_dump.py:135
python.pydraw._Loopvar.dumname
def dumname(self)
Definition: pydraw.py:593
python.pydraw._Loopvar.add_id
def add_id(self, id)
Definition: pydraw.py:597
python.pydraw.AthenaLoopWrapper.__init__
def __init__(self, app=None)
Definition: pydraw.py:544
python.pydraw.Draw_Cmd.lo
lo
Definition: pydraw.py:766
python.pydraw._sanitize_hname
def _sanitize_hname(s)
Definition: pydraw.py:376
python.pydraw.loop
def loop(arg)
Definition: pydraw.py:1242
DerivationFramework::TriggerMatchingUtils::sorted
std::vector< typename T::value_type > sorted(T begin, T end)
Helper function to create a sorted vector from an unsorted one.
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
python.pydraw._hasCanRebin
def _hasCanRebin(h)
Definition: pydraw.py:350
python.pydraw.AthenaLoopWrapper.__getattr__
def __getattr__(self, v)
Definition: pydraw.py:564
python.pydraw.TreeLoopWrapper.loop
def loop(self, f, looplo=0, loophi=sys.maxsize)
Definition: pydraw.py:527
python.pydraw._Loopvar
Definition: pydraw.py:570
python.pydraw._setCanRebin
def _setCanRebin(h)
Definition: pydraw.py:348
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
python.pydraw._Loopvar.__init__
def __init__(self, name)
Definition: pydraw.py:581
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:79
python.pydraw.Draw_Cmd.excstr
excstr
Definition: pydraw.py:654
python.pydraw.Draw_Cmd.stmts
stmts
Definition: pydraw.py:698
python.pydraw._find_outer
def _find_outer(haystack, needle, ignore_delim=False)
Definition: pydraw.py:434
python.pydraw.Draw_Cmd.tuple
tuple
Definition: pydraw.py:765
python.pydraw.Draw_Cmd._tupleparse
def _tupleparse(self, s)
Definition: pydraw.py:659
python.pydraw.Draw_Cmd._mung_n
def _mung_n(self, s1, s2)
Definition: pydraw.py:812
python.pydraw.Draw_Cmd.sel
sel
Definition: pydraw.py:705
python.pydraw.AthenaLoopWrapper.loop
def loop(self, f, looplo=0, loophi=sys.maxsize)
Definition: pydraw.py:554
get
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition: hcg.cxx:127
python.pydraw._get_bins
def _get_bins(args, ndim, axis)
Definition: pydraw.py:1004
python.pydraw.Draw_Cmd.hi
hi
Definition: pydraw.py:767
python.pydraw.Draw_Cmd._mung_id
def _mung_id(self, id)
Definition: pydraw.py:771
python.pydraw.Draw_Cmd.__init__
def __init__(self, s)
Definition: pydraw.py:639
pickleTool.object
object
Definition: pickleTool.py:30
str
Definition: BTagTrackIpAccessor.cxx:11
python.pydraw.Draw_Cmd.histspec
histspec
Definition: pydraw.py:669
python.pydraw._Loopvar.get_ids
def get_ids(self)
Definition: pydraw.py:605
python.pydraw.Draw_Cmd._parserange
def _parserange(self, tuple)
Definition: pydraw.py:734
python.pydraw.cmd
def cmd(s)
Definition: pydraw.py:1278
python.pydraw._Loopvar.explicit
explicit
Definition: pydraw.py:585
python.pydraw._split_outer
def _split_outer(haystack, needle)
Definition: pydraw.py:490