ATLAS Offline Software
pydraw.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2025 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 from io import StringIO #pragma: NO COVER
331 from PyAnalysisUtils.draw_obj import draw_obj, get_canvas
332 
333 
334 try:
335  ScatterH2 = ROOT.RootUtils.ScatterH2
336 except AttributeError: #pragma: NO COVER
337  ScatterH2 = ROOT.TH2F #pragma: NO COVER
338  print ("WARNING: RootUtils::ScatterH2 not available; using TH2F instead") #pragma: NO COVER
339 
340 
341 try:
342  ROOT.TH1.kCanRebin
343  def _setCanRebin (h): #pragma: NO COVER
344  h.SetBit (ROOT.TH1.kCanRebin) #pragma: NO COVER
345  def _hasCanRebin (h): #pragma: NO COVER
346  return h.TestBit (ROOT.TH1.kCanRebin) #pragma: NO COVER
347 except AttributeError: #pragma: NO COVER
348  def _setCanRebin (h): #pragma: NO COVER
349  h.GetXaxis().SetCanExtend(True) #pragma: NO COVER
350  def _hasCanRebin (h): #pragma: NO COVER
351  return h.GetXaxis().CanExtend() #pragma: NO COVER
352 
353 
354 # The last histogram we made.
355 last_hist = None
356 
357 
358 # Dictionary in which to find global names.
359 _globals = sys.modules['__main__'].__dict__
360 
361 
362 # Characters that are legal in identifiers.
363 _idchars = string.ascii_letters + string.digits + '_'
364 
365 # This is what's used as the event formal argument in the generated functions.
366 _evtvar = '_ev'
367 
368 # Set this to true to dump out the generated function bodies.
369 _debug = False
370 
372  """Name a string safe to use as a histogram name.
373 
374  Root does bad things if you put / in a histogram name, so we remove them.
375  Examples:
376  >>> print (_sanitize_hname('foo'))
377  foo
378  >>> print (_sanitize_hname('foo/bar'))
379  foo DIV bar
380  """
381  return s.replace ('/', ' DIV ')
382 
383 
384 def _untokenize (tokens):
385  """Transform tokens back into Python source code.
386 
387  Each element returned by the iterable must be a token sequence
388  with at least two elements, a token number and token value.
389 
390  Unlike tokenize.untokenize(), this does not handle multiple lines.
391  It also tries not to add unneeded spaces.
392 
393  Examples:
394  >>> from tokenize import generate_tokens, untokenize
395  >>> from io import StringIO
396  >>> def untokenize1(tt):
397  ... tt=list(tt)
398  ... if tt[-1][0]==0: tt=tt[:-1]
399  ... return untokenize(tt)
400  >>> untokenize1(generate_tokens(StringIO('1+1').readline))
401  '1+1'
402  >>> _untokenize(generate_tokens(StringIO('1+1').readline))
403  '1+1'
404  >>> untokenize1(generate_tokens(StringIO('foo$i>2*h').readline))
405  'foo$i>2*h'
406  >>> _untokenize(generate_tokens(StringIO('foo$i>2*h').readline))
407  'foo$i>2*h'
408  """
409  lastname = False
410  toks = []
411  toks_append = toks.append
412  for tok in tokens:
413  toknum, tokval = tok[:2]
414  tokval = tokval.strip()
415  if toknum in (token.NAME, token.NUMBER):
416  if lastname:
417  tokval = ' ' + tokval
418  lastname = True
419  else:
420  lastname = False
421  toks_append (tokval)
422  return ''.join(toks)
423 
424 
425 def _find_outer (haystack, needle, ignore_delim = False):
426  """Look for NEEDLE in HAYSTACK (token-based. Return pair (HEAD, TAIL).
427 
428  HAYSTACK and NEEDLE are both strings. Look for a token in HAYSTACK with
429  a value matching NEEDLE that is outside of any paired delimiters.
430  Also ignores things in strings.
431  If IGNORE_DELIM is True, then we do find things inside delimiters
432  (strings are still ignored).
433 
434  Returns a pair (HEAD, TAIL) of the pieces of the string before and
435  after NEEDLE. If there is no match, returns (HAYSTACK, None).
436  Note that whitespace and formatting in HEAD and TAIL may differ
437  from the original string.
438 
439  Examples:
440  >>> _find_outer ("head.tail1.tail2", ".")
441  ('head', 'tail1.tail2')
442  >>> _find_outer ("(head.tail1).tail2", ".")
443  ('(head.tail1)', 'tail2')
444  >>> _find_outer ("[a for a in foo if good(a)] if bar", "if")
445  ('[a for a in foo if good(a)]', 'bar')
446  >>> _find_outer ("(a [b {c . d } ] ) . e", ".")
447  ('(a [b {c . d } ] )', 'e')
448  >>> _find_outer ("a.b", ";")
449  ('a.b', None)
450  >>> _find_outer ("a '$' b", '$')
451  ("a '$' b", None)
452  >>> _find_outer ("a $ b", '$')
453  ('a', 'b')
454  >>> _find_outer ("(head.tail1).tail2", ".", True)
455  ('(head', 'tail1).tail2')
456  >>> _find_outer ('a; 1 -1 1', ';')
457  ('a', '1 -1 1')
458 """
459  tlist = tokenize.generate_tokens (StringIO(haystack).readline)
460  pend = []
461  head = []
462  for (i, (tnum, val, a, b, c)) in enumerate (tlist):
463  if tnum != token.STRING and not pend and val == needle:
464  col1 = a[1]
465  col2 = b[1]
466  return (haystack[:col1].strip(),
467  haystack[col2:].strip())
468  if not ignore_delim:
469  if val == '(':
470  pend.append (')')
471  elif val == '[':
472  pend.append (']')
473  elif val == '{':
474  pend.append ('}')
475  elif pend and val == pend[-1]:
476  pend.pop()
477  head.append ((tnum, val))
478  return (haystack, None)
479 
480 
481 def _split_outer (haystack, needle):
482  """Split HAYSTACK at the delimiters NEEDLE, as in _find_outer.
483 
484  Examples:
485  >>> _split_outer ("a,(b,c),d", ",")
486  ['a', '(b,c)', 'd']
487  >>> _split_outer ("a,,b", ",")
488  ['a', '', 'b']
489  >>> _split_outer ("a", ",")
490  ['a']
491  >>> #_split_outer ("", ",")
492  []
493 """
494  out = []
495  while True:
496  (head, tail) = _find_outer (haystack, needle)
497  head = head.strip()
498  out.append (head)
499  if tail is None:
500  break
501  else:
502  haystack = tail
503  return out
504 
505 
507  """Wrapper for TTree, supplying a loop method.
508 
509  This class wraps a TTree class and provides a loop method
510  that will work with pydraw.
511 """
512 
513  def __init__ (self, tree):
514  """Make a wrapper for a tree."""
515  self._tree = tree
516  return
517 
518  def loop (self, f, looplo=0, loophi=sys.maxsize):
519  """Call f(i,tree) on rows [looplo, loophi)"""
520  tree = self._tree
521  loophi = min (loophi, tree.GetEntries())
522  getentry = tree.GetEntry
523  for i in range(looplo, loophi):
524  getentry(i)
525  f(i, tree)
526  return
527 
528 
530  """Wrapper for the Athena event loop, supplying a loop method.
531 
532  This class wraps an application manager object and provides a loop method
533  that will work with pydraw.
534 """
535  def __init__ (self, app=None):
536  from AthenaPython import PyAthena #pragma: NO COVER
537  if app is None: #pragma: NO COVER
538  from AthenaCommon.AppMgr import theApp #pragma: NO COVER
539  app = theApp #pragma: NO COVER
540  self._app = app #pragma: NO COVER
541  self._sg = PyAthena.py_svc('StoreGateSvc') #pragma: NO COVER
542  return #pragma: NO COVER
543 
544 
545  def loop (self, f, looplo=0, loophi=sys.maxsize):
546  """Call f(i,tree) on rows [looplo, loophi)"""
547  loophi = min (loophi, self._app.size()) #pragma: NO COVER
548  getentry = self._app.seekEvent #pragma: NO COVER
549  for i in range(looplo, loophi): #pragma: NO COVER
550  getentry(i) #pragma: NO COVER
551  f(i, self) #pragma: NO COVER
552  return #pragma: NO COVER
553 
554 
555  def __getattr__ (self, v):
556  if not v.startswith('_'): #pragma: NO COVER
557  return self._sg[v] #pragma: NO COVER
558  raise AttributeError() #pragma: NO COVER
559 
560 
562  """Holds information about a dummy loop variable.
563 
564  Attributes:
565  name - The name of the dummy variable.
566  ids - Set of loop identifiers (`foo' in `foo$i') with which
567  this dummy has been used.
568  explicit - Set to true if this variable is ever used on its own
569  (just $i)
570  """
571 
572  def __init__ (self, name):
573  """Initialize given the name."""
574  self.name = name
575  self.ids = set()
576  self.explicit = 0
577  return
578 
579  def itname (self, id):
580  """Return the iterator variable for this dummy and loop identifier ID.
581  """
582  return "_it_%s_%s" % (self.name, id)
583 
584  def dumname (self):
585  """Return the dummy variable name for this dummy."""
586  return "_dum_" + self.name
587 
588  def add_id (self, id):
589  """Notice this this dummy is used with loop identifier ID.
590 
591  Return the iterator variable.
592  """
593  self.ids.add (id)
594  return self.itname (id)
595 
596  def get_ids (self):
597  """Return the list of loop identifiers with which we've been used."""
598  return list (self.ids)
599 
600 
602  """Holds information used to implement a draw/scan/loop command.
603 
604  Pass the draw string to the constructor. See the file-level comments
605  for details on the syntax of this. This will define the
606  following attributes:
607 
608  errstr - If set to a string, there was an error.
609  Should be None if everything's ok.
610  tuple - The name of the tuple object.
611  tuple_o - Tuple object.
612  lo - The lower bound for row iteration.
613  hi - The upper bound for row iteration.
614  stmts - List of additional statements.
615  exprs - List of draw expressions.
616  sel - Selection expression or None.
617  sel_orig - Untransformed selection expression or None.
618  expr_orig- Untransformed plotting expression.
619  histspec - The text following `;', split into space-separated words.
620 
621  Other attributes:
622  _iddict - Map from loop identifiers (`foo' in `foo$i')
623  to temp variables used to reference
624  them in the loop function.
625  _limdict - Map from loop identifiers (`foo' in `foo$2')
626  to the largest explicit index seen.
627  _loopdict - Map of loop dummy variable names to _Loopvar instances.
628 """
629 
630  def __init__ (self, s):
631  """Initialize from a draw string. See above for more details."""
632 
633  # Assume no error.
634  self.errstr = None
635 
636  self._iddict = {}
637  self._limdict = {}
638  self._loopdict = {}
639 
640  try:
641  self._tupleparse (s)
642  except Exception as e:
643  import traceback
644  self.errstr = str(e)
645  self.excstr = traceback.format_exc()
646  return
647 
648 
649 
650  def _tupleparse (self, s):
651  """Parse a draw string. See above for more details."""
652 
653  # Split off the histspec.
654  (s, self.histspec) = _find_outer (s, ';')
655 
656  # ??? Don't split at spaces in delimiters.
657  # _find_outer doesn't really work for this since it operates
658  # on the tokenized string, in which whitespace doesn't appear.
659  if self.histspec is None:
660  self.histspec = []
661  else:
662  self.histspec = self.histspec.split ()
663 
664  # Gotta have something.
665  s = s.strip()
666  if not s:
667  self.errstr = "Empty draw string."
668  return
669 
670  # Split off the tuple part --- before the first period.
671  (tuple, s) = _find_outer (s, '.')
672  if not s:
673  self.errstr = "Missing period in tuple specification."
674  return
675 
676  # Handle a range specification on the sample.
677  self._parserange (tuple)
678 
679  # Try to find the sample.
680  try:
681  self.tuple_o = eval (self.tuple, _globals)
682  except NameError:
683  self.tuple_o = None
684  if not self.tuple_o:
685  self.errstr = "Can't find sample " + self.tuple
686  return
687 
688  # Look for additional statements.
689  self.stmts = _split_outer (s, '@')
690  s = self.stmts[-1]
691  del self.stmts[-1]
692  self.stmts = [self._mung_expr(x) for x in self.stmts]
693 
694  # Split off the selection.
695  (self.expr_orig, self.sel_orig) = _find_outer (s, "if")
696  self.sel = self._mung_expr (self.sel_orig)
697 
698  self.exprs = [self._mung_expr(x) for x in
699  _split_outer (self.expr_orig, ':')]
700 
701  # Check the interface of the sample. If it doesn't have
702  # the loop interface but has the root tree interface,
703  # use a wrapper.
704  if hasattr (self.tuple_o, 'loop'):
705  # Ok --- has the loop interface.
706  pass
707  elif (hasattr (self.tuple_o, 'GetEntry') and
708  hasattr (self.tuple_o, 'GetEntries')):
709  # Has the TTree interface. Use a wrapper.
710  self.tuple_o = TreeLoopWrapper (self.tuple_o)
711  elif (hasattr (self.tuple_o, 'size') and
712  hasattr (self.tuple_o, 'seekEvent')): #pragma: NO COVER
713  # Has the appmgr interface. Use a wrapper.
714  self.tuple_o = AthenaLoopWrapper (self.tuple_o) #pragma: NO COVER
715  else:
716  # An error --- complain.
717  self.errstr = ("Sample " + self.tuple +
718  " doesn't have a correct interface.")
719  return
720 
721  return
722 
723 
724 
725  def _parserange (self, tuple):
726  """Parse the range part of a draw string.
727 
728  See above for more details.
729  Fills self.tuple, self.lo, self.hi.
730  """
731  lo = 0
732  hi = sys.maxsize
733  (tuple, tail) = _find_outer (tuple, '[')
734  if tail:
735  g = copy.copy (_globals)
736 
737  pos = tail.find (':')
738  pos2 = tail.find (']')
739  if pos2 < 0:
740  pos2 = len (tail) #pragma: NO COVER
741  if pos < 0:
742  slo = tail[:pos2].strip()
743  if len (slo) > 0:
744  lo = int (eval (slo, g))
745  hi = lo + 1
746  else:
747  slo = tail[:pos].strip()
748  if len (slo) > 0:
749  lo = int (eval (slo, g))
750  shi = tail[pos+1:pos2].strip()
751  if len (shi) > 0:
752  hi = int (eval (shi, g))
753 
754  if tuple[0] == '(' and tuple[-1] == ')':
755  tuple = tuple[1:-1].strip()
756  self.tuple = tuple
757  self.lo = lo
758  self.hi = hi
759  return
760 
761 
762  def _mung_id (self, id):
763  """Given a loop identifier (`foo' in `foo$i'), return the identifier
764  used to reference it in loop functions.
765  """
766  out = self._iddict.get (id)
767  if not out:
768  out = '_e_' + id
769  self._iddict[id] = out
770  return out
771 
772 
773  def _mung_index (self, s1, s2):
774  """Handle an explicit index reference; i.e., `foo$2'.
775 
776  S1 and S2 are pieces of the string before and after the `$'.
777  Returns the modified string.
778  """
779  pos2 = 0
780  while pos2 < len(s2) and s2[pos2] in string.digits:
781  pos2 += 1
782  if pos2 == 0:
783  self.errstr = "Bad index"
784  return ''
785  i = int (s2[:pos2])
786  if i < 1:
787  self.errstr = "Bad index"
788  return ''
789  s = ("[%d]" % (i-1)) + s2[pos2:]
790  pos2 = len(s1)-1
791  while pos2 >= 0 and s1[pos2] in _idchars:
792  pos2 -= 1
793  pos2 += 1
794  if pos2 == len(s1):
795  self.errstr = "Bad index"
796  return ''
797  id = s1[pos2:]
798  s = s1[:pos2] + self._mung_id (id) + s
799  self._limdict[id] = max (i, self._limdict.get(id, 0))
800  return s
801 
802 
803  def _mung_n (self, s1, s2):
804  """Handle a length reference; i.e., `$nfoo'.
805 
806  S1 and S2 are pieces of the string before and after the `$'.
807  Returns the modified string.
808  """
809  pos2 = 1
810  while pos2 < len(s2) and s2[pos2] in _idchars:
811  pos2 += 1
812  id = s2[1:pos2]
813  s = s1 + (" len(%s)" % self._mung_id(id)) + s2[pos2:]
814  return s
815 
816 
817  def _mung_loop (self, s1, s2):
818  """Handle use of a dummy loop variable, such as foo$i.
819 
820  S1 and S2 are pieces of the string before and after the `$'.
821  Returns the modified string.
822  """
823 
824  # Scan after the $ to find the dummy variable.
825  pos2 = 0
826  while pos2 < len(s2) and s2[pos2] in _idchars:
827  pos2 += 1
828  if pos2 == 0:
829  self.errstr = "Bad loop var"
830  return ''
831  loopvar = s2[:pos2]
832 
833  # Look it up. Make a new _Loopvar object if it's not in the map.
834  ll = self._loopdict.get (loopvar)
835  if not ll:
836  ll = _Loopvar(loopvar)
837  self._loopdict[loopvar] = ll
838 
839  # Is the $ after an identifier?
840  if len(s1) > 0 and s1[-1] in _idchars:
841  # Yes --- find the identifier.
842  pos3 = len(s1)-1
843  while pos3 >= 0 and s1[pos3] in _idchars:
844  pos3 -= 1
845  pos3 += 1
846  assert (len(s1) - pos3 >= 1)
847  id = s1[pos3:]
848 
849  # Replace with the iterator.
850  s = s1[:pos3] + ll.add_id(id) + s2[pos2:]
851  self._mung_id (id)
852  else:
853  # Explicit use of the dummy.
854  # Replace with the dummy name and note that it was used explicitly.
855  s = s1 + ("%s" % ll.dumname()) + s2[pos2:]
856  ll.explicit = 1
857  return s
858 
859 
860  def _mung_expr_dollar (self, s):
861  """Process $ constructions in string S.
862 
863  Returns the modified string.
864  """
865  if not s:
866  return s
867  pos = 0
868  while 1:
869  (s1, s2) = _find_outer (s[pos:], '$', True)
870  if s2 is None:
871  break
872  snew = None
873  if len(s2) > 0:
874  if s2[0] in string.digits:
875  snew = self._mung_index (s1, s2)
876  elif (s2[0] == 'n' and
877  (not (len(s1) > 0 and s1[-1] in _idchars) or
878  s1.endswith (' and') or
879  s1.endswith (' or') or
880  s1.endswith ('not'))):
881  snew = self._mung_n (s1, s2)
882  elif s2[0] in string.ascii_letters:
883  snew = self._mung_loop (s1, s2)
884  s = s[:pos]
885  if snew is None:
886  snew = s1 + '$' + s2
887  pos = pos + len(s1)+1
888  s = s + snew
889  return s
890 
891 
892  def _mung_expr_ids (self, s):
893  """Perform id substitution in S.
894 
895  For identifiers in S that are attributes of our tuple,
896  replace them with references to the tuple attribute
897  (using _mung_id).
898 
899  Returns the modified string.
900  """
901  if not s:
902  return s
903 
904  tlist = tokenize.generate_tokens (StringIO(s).readline)
905  out = []
906  afterDot = False
907  for tnum, val, a, b, c in tlist:
908  if tnum == token.NAME and not afterDot:
909  if hasattr (self.tuple_o, val):
910  val = self._mung_id (val)
911  #val = _evtvar + '.' + val
912  out.append ((tnum, val))
913  # Don't mung names after a period. We may have attributes
914  # with the same names as variables in the tuple.
915  if tnum == token.OP and val == '.':
916  afterDot = True
917  else:
918  afterDot = False
919  return _untokenize (out)
920 
921 
922  def _mung_expr (self, s):
923  """Process $ constructions and id substitution in string S.
924 
925  Returns the modified string.
926  """
927  s = self._mung_expr_dollar (s)
928  return self._mung_expr_ids (s)
929 
930 
931  def _make_func (self, payload, extargs = ''):
932  """Create the text for the function to process this query.
933 
934  PAYLOAD is the payload expression to plug in.
935  EXTARGS is an additional string to add to the end of the
936  function's argument list (to set default values, for example).
937  Returns the function definition as a string.
938  """
939 
940  sel = self.sel
941  if self._limdict:
942  limsel = ' and '.join (["len(%s)>=%d" % (self._iddict[p[0]], p[1])
943  for p in self._limdict.items()])
944  if not sel:
945  sel = limsel
946  else:
947  sel = limsel + " and (" + sel + ")"
948 
949  ftext = "def _loopfunc(_i, %s%s):\n" % (_evtvar, extargs)
950  for (id1, id2) in sorted(self._iddict.items()):
951  ftext += " %s = %s.%s\n" % (id2, _evtvar, id1)
952  indent = 2
953 
954  for (i,l) in sorted(self._loopdict.items()):
955  ids = sorted(l.get_ids())
956  assert (not not ids)
957  if len(ids) == 1:
958  vars = l.itname (ids[0])
959  lists = self._iddict[ids[0]]
960  else:
961  vars = "(" + ','.join([l.itname (id) for id in ids]) + ")"
962  lists = ("zip(" + ','.join([self._iddict[id] for id in ids])
963  + ")")
964  if l.explicit:
965  vars = "(%s,%s)" % (l.dumname(), vars)
966  lists = "enumerate(%s)" % lists
967  ftext += ' '*indent + "for %s in %s:\n" % (vars, lists)
968  indent += 2
969 
970  for s in self.stmts:
971  ftext += ' '*indent + s + '\n'
972 
973  if sel and sel != '1':
974  ftext += ' '*indent + "if (%s):\n" % sel
975  indent += 2
976 
977  ftext += ' '*indent + "%s\n" % payload
978 
979  if _debug:
980  print (ftext)
981 
982  return ftext
983 
984 
985 class _Bins(object):
986  """Holds the results of _get_bins. Defined attributes:
987 
988  nbins
989  lo
990  hi
991  rebin
992  """
993 
994 
995 def _get_bins (args, ndim, axis):
996  """Parse bin specifications from split list of arguments ARGS.
997  NDIM is 1 or 2, and AXIS is 0 or 1, for the x or y axis.
998 
999  Examples:
1000  >>> from PyAnalysisUtils import pydraw
1001  >>> pydraw._globals = globals()
1002  >>> import ROOT
1003  >>> ROOT.gPad.Range(0, 1,2,3)
1004  >>> b = _get_bins (["50", "10", "100"], 1, 0)
1005  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1006  50 10.0 100.0 0
1007  >>> b = _get_bins ([], 1, 0)
1008  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1009  50 0 1 1
1010  >>> b = _get_bins (["!", "10"], 1, 0)
1011  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1012  50 10.0 11.0 1
1013  >>> b = _get_bins (["!", "!", "10"], 1, 0)
1014  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1015  50 0 10.0 0
1016  >>> scale = 10
1017  >>> b = _get_bins (["50", "0", "2*scale"], 1, 0)
1018  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1019  50 0.0 20.0 0
1020  >>> b = _get_bins ([], 2, 0)
1021  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1022  50 0.0 2.0 1
1023  >>> b = _get_bins ([], 2, 1)
1024  >>> print (b.nbins, b.lo, b.hi, b.rebin)
1025  50 1.0 3.0 1
1026  >>> b = _get_bins ([], 2, 2)
1027  Traceback (most recent call last):
1028  ...
1029  AssertionError
1030  """
1031 
1032  g = copy.copy (_globals)
1033 
1034  bins = _Bins()
1035 
1036  bins.nbins = 0
1037  if len(args) >= 1 and args[0] != '!' and len(args[0]) > 0:
1038  bins.nbins = int (eval (args[0], g))
1039  if bins.nbins <= 0:
1040  bins.nbins = 50
1041 
1042  bins.lo = 0
1043  if len(args) >= 2 and args[1] != '!' and len(args[1]) > 0:
1044  bins.lo = float (eval (args[1], g))
1045 
1046  bins.hi = 0
1047  if len(args) >= 3 and args[2] != '!' and len(args[2]) > 0:
1048  bins.hi = float (eval (args[2], g))
1049 
1050  bins.rebin = 0
1051  if bins.hi <= bins.lo:
1052  bins.rebin = 1
1053  if ndim == 1:
1054  bins.hi = bins.lo + 1
1055  elif axis == 0:
1056  bins.lo = ROOT.gPad.GetUxmin()
1057  bins.hi = ROOT.gPad.GetUxmax()
1058  elif axis == 1:
1059  bins.lo = ROOT.gPad.GetUymin()
1060  bins.hi = ROOT.gPad.GetUymax()
1061  else:
1062  assert 0
1063 
1064  return bins
1065 
1066 
1067 def _get_hist (ndim, args, hname, htitle):
1068  """Create a new histogram from options.
1069 
1070  NDIM is the dimensionality of the histogram (1 or 2).
1071  ARGS is a list of the arguments given to specify the histogram.
1072  HNAME and HTITLE are the histogram name and title, respectively.
1073  """
1074  get_canvas()
1075 
1076  # Get the x-axis bin specifications.
1077  xbins = _get_bins (args, ndim, 0)
1078  rebin = xbins.rebin
1079 
1080  # Get the y-axis bin specifications.
1081  if ndim >= 2:
1082  ybins = _get_bins (args[3:], ndim, 1)
1083  rebin = rebin or ybins.rebin
1084 
1085  profile = 0
1086  # Look for drawing options.
1087  options = ''
1088  for i in range (0, len(args)):
1089  if args[i][0] in string.ascii_letters:
1090  for j in range (i, len(args)):
1091  if ndim == 2 and args[j].lower() == "prof":
1092  profile = 1
1093  args[j] = ''
1094  options = ' '.join (args[i:])
1095  break
1096 
1097  # Delete any old object of the same name.
1098  hold = ROOT.gROOT.FindObject (hname)
1099  if hold:
1100  ROOT.gROOT.Remove (hold)
1101 
1102  # Create the histogram.
1103  if profile:
1104  hist = ROOT.TProfile (hname, htitle, xbins.nbins, xbins.lo, xbins.hi)
1105  if not ybins.rebin:
1106  hist.SetMinimum (ybins.lo)
1107  hist.SetMaximum (ybins.hi)
1108  elif ndim == 1:
1109  hist = ROOT.TH1F (hname, htitle, xbins.nbins, xbins.lo, xbins.hi)
1110  elif ndim == 2:
1111  hist = ScatterH2 (hname, htitle,
1112  xbins.nbins, xbins.lo, xbins.hi,
1113  ybins.nbins, ybins.lo, ybins.hi)
1114  if hasattr (hist, 'scatter'):
1115  hist.scatter (1)
1116 
1117  # Automatic rebinning?
1118  if rebin:
1119  _setCanRebin (hist)
1120 
1121  return (hist, options)
1122 
1123 
1124 def draw (arg):
1125  """Process a draw command.
1126 
1127  ARG is the command arguments (without the command word itself).
1128  See the header comments for the command syntax.
1129  """
1130 
1131  global last_hist
1132 
1133  # Initial parsing of the arguments.
1134  c = Draw_Cmd (arg)
1135  if c.errstr:
1136  print (c.errstr)
1137  return False
1138 
1139  # Construct the expression to use to fill the histogram.
1140  if len (c.exprs) == 1:
1141  ndim = 1
1142  payload = "_hfill (%s)" % c.exprs[0]
1143  else:
1144  ndim = 2
1145  payload = "_hfill ((%s),(%s))" % (c.exprs[0], c.exprs[1])
1146 
1147  # Construct the histogram title.
1148  htitle = "%s.%s" % (c.tuple, c.expr_orig)
1149  if c.sel_orig:
1150  htitle = htitle + '{%s}' % c.sel_orig
1151 
1152  # Make the histogram.
1153  # If it's `!', then we just use the last one.
1154  if len(c.histspec) >= 1 and c.histspec[0] == "!" and last_hist is not None:
1155  hist = last_hist
1156  options = ' '.join (c.histspec[1:])
1157  elif len(c.histspec) >= 1 and c.histspec[0][:2] == '>>':
1158  hname = c.histspec[0][2:]
1159  hist = _globals.get (hname)
1160  options = ' '.join (c.histspec[1:])
1161  else:
1162  (hist, options) = _get_hist (ndim, c.histspec,
1163  _sanitize_hname(c.tuple+'.'+c.expr_orig), htitle)
1164 
1165  # Remember it.
1166  last_hist = hist
1167 
1168  # Generate the function.
1169  # It will be defined as _loopfunc in g.
1170  g = copy.copy (_globals)
1171  g['_hfill'] = hist.Fill
1172  ftext = c._make_func (payload, ', _hfill = _hfill')
1173  exec (ftext, g)
1174 
1175  # Execute the loop over the data.
1176  c.tuple_o.loop (g['_loopfunc'], c.lo, c.hi)
1177 
1178  # Adjust binning, if requested.
1179  if _hasCanRebin (hist):
1180  hist.LabelsDeflate ("X")
1181  if ndim > 1:
1182  hist.LabelsDeflate ("Y")
1183 
1184  # Draw the histogram.
1185  draw_obj (hist, options)
1186  return True
1187 
1188 
1189 def _scan_print (i, *args):
1190  """Helper to print out one row of a scan.
1191 
1192  I is the row number and ARGS is a tuple of the column values."""
1193 
1194  s = '%6d' % i
1195  for a in args:
1196  if isinstance(a, int):
1197  s += ' %8d' % a
1198  else:
1199  s += ' %8g' % a
1200  print (s)
1201  return
1202 
1203 
1204 def scan (arg):
1205  """Process a scan command.
1206 
1207  ARG is the command arguments (without the command word itself).
1208  See the header comments for the command syntax.
1209  """
1210 
1211  # Initial parsing of the arguments.
1212  c = Draw_Cmd (arg)
1213  if c.errstr:
1214  print (c.errstr)
1215  return False
1216 
1217  payload = "_print (_i, %s)" % \
1218  ','.join (['(%s)'%e for e in c.exprs])
1219 
1220  # Generate the function.
1221  # It will be defined as _loopfunc in g.
1222  g = copy.copy (_globals)
1223  g['_print'] = _scan_print
1224  ftext = c._make_func (payload, ', _print = _print')
1225  exec (ftext, g)
1226 
1227  # Execute the loop over the data.
1228  c.tuple_o.loop (g['_loopfunc'], c.lo, c.hi)
1229 
1230  return True
1231 
1232 
1233 def loop (arg):
1234  """Process a loop command.
1235 
1236  ARG is the command arguments (without the command word itself).
1237  See the header comments for the command syntax.
1238  """
1239 
1240  # Initial parsing of the arguments.
1241  c = Draw_Cmd (arg)
1242  if c.errstr:
1243  print (c.errstr)
1244  return False
1245 
1246  payload = "(%s,)" % ','.join (c.exprs)
1247 
1248  # Generate the function.
1249  # It will be defined as _loopfunc in g.
1250  g = copy.copy (_globals)
1251  ftext = c._make_func (payload)
1252  exec (ftext, g)
1253 
1254  # Execute the loop over the data.
1255  c.tuple_o.loop (g['_loopfunc'], c.lo, c.hi)
1256 
1257  return True
1258 
1259 
1260 # Dictionary of command handlers.
1261 # Should return True if cmd was handled.
1262 _cmddict = {'d': draw,
1263  'draw' : draw,
1264  'scan' : scan,
1265  'loop' : loop,
1266  }
1267 
1268 
1269 def cmd (s):
1270  """Process a command S.
1271 
1272  Returns True if the command was handled, False otherwise.
1273  See the header comments for the command syntax.
1274  """
1275 
1276  ssplit = s.split (None, 1)
1277 
1278  if len(ssplit) < 2:
1279  return False
1280 
1281  cmd, args = ssplit
1282 
1283  func = _cmddict.get (cmd)
1284  if func:
1285  return func (args)
1286 
1287  return False
1288 
1289 
1290 
1291 
1297 
1298 #
1299 # Hook holding the original value of the exception hook.
1300 # But be careful not to overwrite this if this file is reread.
1301 #
1302 if '_orig_ehook' not in globals():
1303  _orig_ehook = None
1304 
1305 
1306 def _excepthook (exctype, value, traceb):
1307  """Exception hook used by pydraw to process drawing commands."""
1308 
1309  # If it's a syntax error, try interpreting as a drawing command.
1310  if isinstance (value, SyntaxError):
1311  val = value.text
1312  if val[-1] == '\n':
1313  val = val[:-1] #pragma: NO COVER
1314  if cmd (val):
1315  # Success --- update root stuff and return.
1316  # (This will swallow the original syntax error.)
1317  ROOT.gInterpreter.EndOfLineAction()
1318  return
1319 
1320  # No luck --- pass it on to the original exception handler.
1321  _orig_ehook (exctype, value, traceb)
1322 
1323 
1324 def cmdhook():
1325  """Enable entering drawing commands directly at the python prompt."""
1326 
1327  # Store the old value of the exception hook (only if we haven't
1328  # done so already).
1329  global _orig_ehook
1330  if _orig_ehook is None:
1331  _orig_ehook = sys.excepthook
1332 
1333  # Install our handler.
1334  sys.excepthook = _excepthook
1335  return
1336 
1337 
1338 
1339 
1340 # import ROOT
1341 # import string
1342 # import sys
1343 # import exceptions
1344 # import copy
1345 # from PyAnalysisUtils.draw_obj import draw_obj, get_canvas
1346 
1347 # try:
1348 # ScatterH2 = ROOT.RootUtils.ScatterH2
1349 # except AttributeError:
1350 # ScatterH2 = ROOT.TH2F
1351 # print ("WARNING: RootUtils::ScatterH2 not available; using TH2F instead")
1352 
1353 # kCanRebin = ROOT.TH1.kCanRebin
1354 
1355 # _last_hist = None
1356 # #_marker_style = 3
1357 # #_marker_size = 0.5
1358 
1359 # _evtvar = 'e'
1360 
1361 
1362 
1363 
1364 
1365 
1366 # from array import array
1367 # class hist_filler:
1368 # def __init__ (self, hist, nbuf=100):
1369 # self.hist = hist
1370 # self.filln = hist.FillN
1371 # self.nbuf = nbuf
1372 # self.xarr = array ('d', 100*[0.])
1373 # self.warr = array ('d', 100*[1.])
1374 # self.i = [0]
1375 
1376 # self.xlist = 100*[0.]
1377 # return
1378 # def get_filler (self):
1379 # def fill (x,i=self.i,nbuf=self.nbuf,xarr=self.xarr,flush=self.flush):
1380 # ii = i[0]
1381 # if ii == nbuf:
1382 # flush()
1383 # ii = i[0]
1384 # xarr[ii] = x
1385 # i[0] = ii + 1
1386 # return
1387 # return fill
1388 # def flush (self):
1389 # #print (self.i, self.xarr)
1390 # self.filln (self.i[0], self.xarr, self.warr)
1391 # self.i[0] = 0
1392 # return
1393 
1394 # ##############################################################################
1395 # # Here are the command handlers.
python.pydraw.draw
def draw(arg)
Definition: pydraw.py:1124
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:575
python.pydraw.TreeLoopWrapper
Definition: pydraw.py:506
python.pydraw._get_hist
def _get_hist(ndim, args, hname, htitle)
Definition: pydraw.py:1067
python.pydraw.Draw_Cmd._mung_loop
def _mung_loop(self, s1, s2)
Definition: pydraw.py:817
python.pydraw._Bins
Definition: pydraw.py:985
python.pydraw.Draw_Cmd._loopdict
_loopdict
Definition: pydraw.py:638
python.pydraw.Draw_Cmd.exprs
exprs
Definition: pydraw.py:698
python.pydraw.Draw_Cmd._limdict
_limdict
Definition: pydraw.py:637
python.pydraw.Draw_Cmd._make_func
def _make_func(self, payload, extargs='')
Definition: pydraw.py:931
python.pydraw._untokenize
def _untokenize(tokens)
Definition: pydraw.py:384
python.pydraw.scan
def scan(arg)
Definition: pydraw.py:1204
python.pydraw.Draw_Cmd._mung_expr
def _mung_expr(self, s)
Definition: pydraw.py:922
python.pydraw._Loopvar.name
name
Definition: pydraw.py:574
python.pydraw.TreeLoopWrapper.__init__
def __init__(self, tree)
Definition: pydraw.py:513
python.pydraw._Loopvar.itname
def itname(self, id)
Definition: pydraw.py:579
python.pydraw.Draw_Cmd
Definition: pydraw.py:601
python.pydraw._excepthook
def _excepthook(exctype, value, traceb)
Definition: pydraw.py:1306
python.pydraw.Draw_Cmd._mung_expr_dollar
def _mung_expr_dollar(self, s)
Definition: pydraw.py:860
python.pydraw.Draw_Cmd._mung_expr_ids
def _mung_expr_ids(self, s)
Definition: pydraw.py:892
python.pydraw.TreeLoopWrapper._tree
_tree
Definition: pydraw.py:515
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
python.pydraw.AthenaLoopWrapper._sg
_sg
Definition: pydraw.py:541
python.pydraw.AthenaLoopWrapper._app
_app
Definition: pydraw.py:540
python.pydraw._scan_print
def _scan_print(i, *args)
Definition: pydraw.py:1189
python.pydraw.Draw_Cmd._iddict
_iddict
Definition: pydraw.py:636
python.draw_obj.get_canvas
def get_canvas(cname="c1")
Definition: draw_obj.py:274
python.pydraw.AthenaLoopWrapper
Definition: pydraw.py:529
python.pydraw.cmdhook
def cmdhook()
Definition: pydraw.py:1324
python.pydraw.Draw_Cmd._mung_index
def _mung_index(self, s1, s2)
Definition: pydraw.py:773
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:194
python.pydraw.Draw_Cmd.errstr
errstr
Definition: pydraw.py:634
python.pydraw.Draw_Cmd.tuple_o
tuple_o
Definition: pydraw.py:681
hist_file_dump.f
f
Definition: hist_file_dump.py:140
python.pydraw._Loopvar.dumname
def dumname(self)
Definition: pydraw.py:584
python.pydraw._Loopvar.add_id
def add_id(self, id)
Definition: pydraw.py:588
python.pydraw.AthenaLoopWrapper.__init__
def __init__(self, app=None)
Definition: pydraw.py:535
python.pydraw.Draw_Cmd.lo
lo
Definition: pydraw.py:757
python.pydraw._sanitize_hname
def _sanitize_hname(s)
Definition: pydraw.py:371
python.pydraw.loop
def loop(arg)
Definition: pydraw.py:1233
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:345
python.pydraw.AthenaLoopWrapper.__getattr__
def __getattr__(self, v)
Definition: pydraw.py:555
python.pydraw.TreeLoopWrapper.loop
def loop(self, f, looplo=0, loophi=sys.maxsize)
Definition: pydraw.py:518
python.pydraw._Loopvar
Definition: pydraw.py:561
python.pydraw._setCanRebin
def _setCanRebin(h)
Definition: pydraw.py:343
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:572
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:71
python.pydraw.Draw_Cmd.excstr
excstr
Definition: pydraw.py:645
python.pydraw.Draw_Cmd.stmts
stmts
Definition: pydraw.py:689
python.pydraw._find_outer
def _find_outer(haystack, needle, ignore_delim=False)
Definition: pydraw.py:425
python.pydraw.Draw_Cmd.tuple
tuple
Definition: pydraw.py:756
python.pydraw.Draw_Cmd._tupleparse
def _tupleparse(self, s)
Definition: pydraw.py:650
python.pydraw.Draw_Cmd._mung_n
def _mung_n(self, s1, s2)
Definition: pydraw.py:803
python.pydraw.Draw_Cmd.sel
sel
Definition: pydraw.py:696
python.pydraw.AthenaLoopWrapper.loop
def loop(self, f, looplo=0, loophi=sys.maxsize)
Definition: pydraw.py:545
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:995
python.pydraw.Draw_Cmd.hi
hi
Definition: pydraw.py:758
python.pydraw.Draw_Cmd._mung_id
def _mung_id(self, id)
Definition: pydraw.py:762
python.pydraw.Draw_Cmd.__init__
def __init__(self, s)
Definition: pydraw.py:630
pickleTool.object
object
Definition: pickleTool.py:29
str
Definition: BTagTrackIpAccessor.cxx:11
python.pydraw.Draw_Cmd.histspec
histspec
Definition: pydraw.py:660
python.pydraw._Loopvar.get_ids
def get_ids(self)
Definition: pydraw.py:596
python.pydraw.Draw_Cmd._parserange
def _parserange(self, tuple)
Definition: pydraw.py:725
python.pydraw.cmd
def cmd(s)
Definition: pydraw.py:1269
python.pydraw._Loopvar.explicit
explicit
Definition: pydraw.py:576
python.pydraw._split_outer
def _split_outer(haystack, needle)
Definition: pydraw.py:481