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