9 from __future__
import print_function
11 """Interactive python commands for plotting from a tuple-like object.
12 This module provides in python functionality similar to TTree::Draw
13 and TTree::Scan. The major conceptual differences are:
15 - All expressions are written in python (and not the specialized
16 TTree::Draw language).
17 - This can be applied to any type of object providing a simple loop
18 interface (explained below), not just to TTree's. (A TTree will work;
19 there is also a wrapper for the Athena event loop.)
21 In addition, this style of query may be somewhat
22 easier to type interactively.
28 Here are some examples of plotting commands to give you the flavor:
31 d tt.ele_pt$i; 50 0 100*gev
33 d tt[100:1000].muo$i.pt() if abs(muo.eta)<2
34 d tt.(ele$i+ele$j).m() if $i<$j; same
37 To use these commands, you can pass them as strings to pydraw.cmd:
39 from pydraw import cmd
42 Alternatively, if you execute the cmdhook function, you can type them
45 from pydraw import cmdhook
49 (Note that this second form doesn't work in general for code that's read
56 The general syntax for drawing a histogram looks like this:
58 d TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR] [; HISTSPEC]
60 These pieces are explained in more detail below.
66 The object on which the draw operation is to be performed is given
67 by TUPLESPEC. This should be the name of some object in the python
68 global dictionary. Note that if the expression for the tuple
69 itself contains a period or brackets, you'll need to enclose it in parentheses:
71 d (trees.tt[1])[:100].ele_pt$i
73 Optionally, this can include a slice-like notation
74 to restrict the rows to which the draw applies:
76 tuple[i:j] --- process rows i <= n < j
77 tuple[:j] --- process rows n < j
78 tuple[i:] --- process rows n >= i
79 tuple[i] --- process row i
81 i and j can be expressions as well.
83 The tuple object should contain a method like this:
85 def loop (self, func, looplo, loophi)
87 This function should loop over rows [looplo, loophi) and
88 call func on each. func will take two arguments, the first
89 being the row number and the second being the event object
90 (which may just be the tuple itself).
92 If a method named loop is not available, but GetEntry and GetEntries
93 methods are available, then those will be used instead.
94 Similarly, if size and seekEvent are available, a wrapper
95 appropriate for the Athena event loop will be used.
97 Thus, you can make plots from within Athena like this:
99 d theApp.ElectronAODCollection$i.eta()
105 Once a tuple is specified, one then needs to specify what to plot.
106 This is done with an arbitrary python expression, with some extensions.
108 To plot a simple numeric variable from the tuple, just give its name.
113 will plot the variable `foo' from each row of the tuple. You can of course
114 also use more complicated expressions:
118 In the common case, though, the members of the tuple will be vectors
119 of numbers of objects over which you want to iterate. You can iterate
120 plotting over such a vector by specifying a dummy index. This is an
121 identifier starting with a dollar sign:
125 (Making the dummy indices explicit was a deliberate change from the
126 implicit iteration of root/paw. Such implicit iteration sometimes
127 caused confusion about just what was being iterated over, and also
128 when people needed to distinguish between accessing attributes
129 of a container and attributes of the contained objects.)
131 This will automatically step $i over the contents of the vector pt_e,
132 plotting each one. The vector being iterated over may contain objects
137 Note that the limits of the iteration are handled automatically.
138 The index $i can also be used in contexts other than that of an index.
139 For example, to limit the iteration in the above example to the first
140 four items, one can use:
142 d tt.ele$i.pt() if $i<4
144 (This uses a selection clause. This is to be described later, but the meaning
147 If a dummy index is used for more than one vector, the iteration limit
148 will be taken from whichever vector is smaller. For example:
152 will iterate min(len(ele),len(muo)) times.
154 Multiple dummy indices may be used. In that case, all possible index
155 combinations are used (a simple nested loop). If there is a symmetry
156 involved, a selection clause may be used to eliminate duplicates.
157 For example (given an appropriate ele definition), this will plot the
158 invariant masses of all electron pairs:
160 d tt.(ele$i+ele$j).m() if $i>$j
162 One can also reference individual elements of a vector using the
163 notation $N. Here, the indexing is 1-based (so $1 is the first element).
164 Example: to plot the pt of the leading electron
168 Note that one can do something similar just using standard python
173 This, however, will crash if ele is empty; if the $N form is used,
174 an implicit selection is added to ensure that the index is in range.
175 Thus, the proper equivalent of the $N-form example is:
177 d tt.ele[0].pt() if len(ele)>0
179 You can also use $nCONT as an abbreviation for len(CONT):
181 d tt.ele[0].pt() if $nele>0
183 Names used in expressions will be looked up first in the tuple object,
184 then in the global dictionary. Note that the lookup in the tuple happens
185 before looping starts, so all needed variables must already be present
186 in the tuple. If you want to refer to the tuple object itself,
187 you can use the special variable `_ev'. (This can be changed by assigning
188 a string to pydraw._evtvar.)
190 Multiple expressions may be given, separated by `:'. For drawing histograms,
191 you can give two expressions, for the x and y axis expressions. For scanning
192 tuples (see below), you give the list of expressions to be scanned.
198 You can select items to be filled using a boolean expression, set off
199 with an `if' keyword:
201 d tt.ele$i.pt() if abs(ele$i.eta())<2
203 All dummy variables are common between the variable expressions
210 You can specify arbitrary Python expressions to be executed before looping
211 starts. These come before the variables expressions, and are delimited
212 with `@'. This is useful mostly for defining short aliases for tuple
213 variables. For example:
215 d tt.ele=ElectronAODCollection@ele$i.eta() if ele$i.pt()>100*gev
218 Histogram specifications
219 ------------------------
221 Histogram specifications follow a semicolon. They can have the forms:
225 NX XLO XHI OPTIONS...
226 NX XLO XHI NY YLO YHI OPTIONS...
229 For the first form, specifying ! reuses the same histogram that was used
232 For the second form, specifying >>NAME looks in the global dictionary
233 for a histogram NAME and uses that.
235 Otherwise, a new histogram is created. The binning for this histogram
236 may be specified by NX XLO XHI and NY YLO YHI.
238 Plotting options may also be given. The special option `prof' means
239 to create a profile histogram. Otherwise, root drawing options may
240 be used. This package uses PyAnalysisUtils.draw_obj to draw the
241 histograms, so the extra options supported by that function may
242 also be used. See draw_obj.py for details.
244 The last histogram to have been drawn is available is pydraw.last_hist.
250 The scan command is very similar to draw:
252 scan TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR]
254 Instead of drawing a histogram, scan prints out a table of the expression
257 The formatting of the data printed by scan is currently pretty rudimentary.
258 This should probably be improved.
264 There is also a loop command:
266 loop TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR]
268 Loop will evaluate the given expressions in the same manner as draw and scan,
269 but the results of this are ignored. So it only makes sense to use loop
270 to evaluate expressions for their side effects. This can be used,
271 for example, to call a function that fills some large set of histograms.
277 The general interface to execute one of these commands is the `cmd' function,
278 which takes the command as a string:
280 from pydraw import cmd
283 Each command is also implemented by a single function, which may be called
284 directly. The command name should not be included in this case:
286 from pydraw import draw
289 Finally, if you call the function cmdhook(), then you can give the commands
290 directly on the python command line:
292 from pydraw import cmdhook
299 - No way to specify an event weight when filling a histogram using
302 - Hoist selection code out of the dummy index loops, when they don't
303 depend on the index? For example,
307 gets implemented like:
313 but it would be more efficient to pull the selection out of the loop.
315 - In an expr like d em.foo$i if em.bar$i>1
316 then foo always gets evaluated even if the condition is false.
333 from StringIO
import StringIO
335 from io
import StringIO
336 from PyAnalysisUtils.draw_obj
import draw_obj, get_canvas
340 ScatterH2 = ROOT.RootUtils.ScatterH2
341 except AttributeError:
342 ScatterH2 = ROOT.TH2F
343 print (
"WARNING: RootUtils::ScatterH2 not available; using TH2F instead")
349 h.SetBit (ROOT.TH1.kCanRebin)
351 return h.TestBit (ROOT.TH1.kCanRebin)
352 except AttributeError:
354 h.GetXaxis().SetCanExtend(
True)
356 return h.GetXaxis().CanExtend()
364 _globals = sys.modules[
'__main__'].__dict__
368 _idchars = string.ascii_letters + string.digits +
'_'
377 """Name a string safe to use as a histogram name.
379 Root does bad things if you put / in a histogram name, so we remove them.
381 >>> print (_sanitize_hname('foo'))
383 >>> print (_sanitize_hname('foo/bar'))
386 return s.replace (
'/',
' DIV ')
390 """Transform tokens back into Python source code.
392 Each element returned by the iterable must be a token sequence
393 with at least two elements, a token number and token value.
395 Unlike tokenize.untokenize(), this does not handle multiple lines.
396 It also tries not to add unneeded spaces.
399 >>> from tokenize import generate_tokens, untokenize
402 ... from StringIO import StringIO
404 ... from io import StringIO
405 >>> def untokenize1(tt):
407 ... if tt[-1][0]==0: tt=tt[:-1]
408 ... return untokenize(tt)
409 >>> untokenize1(generate_tokens(StringIO('1+1').readline))
411 >>> _untokenize(generate_tokens(StringIO('1+1').readline))
413 >>> untokenize1(generate_tokens(StringIO('foo$i>2*h').readline))
415 >>> _untokenize(generate_tokens(StringIO('foo$i>2*h').readline))
420 toks_append = toks.append
422 toknum, tokval = tok[:2]
423 tokval = tokval.strip()
424 if toknum
in (token.NAME, token.NUMBER):
426 tokval =
' ' + tokval
435 """Look for NEEDLE in HAYSTACK (token-based. Return pair (HEAD, TAIL).
437 HAYSTACK and NEEDLE are both strings. Look for a token in HAYSTACK with
438 a value matching NEEDLE that is outside of any paired delimiters.
439 Also ignores things in strings.
440 If IGNORE_DELIM is True, then we do find things inside delimiters
441 (strings are still ignored).
443 Returns a pair (HEAD, TAIL) of the pieces of the string before and
444 after NEEDLE. If there is no match, returns (HAYSTACK, None).
445 Note that whitespace and formatting in HEAD and TAIL may differ
446 from the original string.
449 >>> _find_outer ("head.tail1.tail2", ".")
450 ('head', 'tail1.tail2')
451 >>> _find_outer ("(head.tail1).tail2", ".")
452 ('(head.tail1)', 'tail2')
453 >>> _find_outer ("[a for a in foo if good(a)] if bar", "if")
454 ('[a for a in foo if good(a)]', 'bar')
455 >>> _find_outer ("(a [b {c . d } ] ) . e", ".")
456 ('(a [b {c . d } ] )', 'e')
457 >>> _find_outer ("a.b", ";")
459 >>> _find_outer ("a '$' b", '$')
461 >>> _find_outer ("a $ b", '$')
463 >>> _find_outer ("(head.tail1).tail2", ".", True)
464 ('(head', 'tail1).tail2')
465 >>> _find_outer ('a; 1 -1 1', ';')
468 tlist = tokenize.generate_tokens (StringIO(haystack).readline)
471 for (i, (tnum, val, a, b, c))
in enumerate (tlist):
472 if tnum != token.STRING
and not pend
and val == needle:
475 return (haystack[:col1].strip(),
476 haystack[col2:].strip())
484 elif pend
and val == pend[-1]:
486 head.append ((tnum, val))
487 return (haystack,
None)
491 """Split HAYSTACK at the delimiters NEEDLE, as in _find_outer.
494 >>> _split_outer ("a,(b,c),d", ",")
496 >>> _split_outer ("a,,b", ",")
498 >>> _split_outer ("a", ",")
500 >>> #_split_outer ("", ",")
505 (head, tail) = _find_outer (haystack, needle)
516 """Wrapper for TTree, supplying a loop method.
518 This class wraps a TTree class and provides a loop method
519 that will work with pydraw.
523 """Make a wrapper for a tree."""
527 def loop (self, f, looplo=0, loophi=sys.maxsize):
528 """Call f(i,tree) on rows [looplo, loophi)"""
530 loophi = min (loophi, tree.GetEntries())
531 getentry = tree.GetEntry
532 for i
in range(looplo, loophi):
539 """Wrapper for the Athena event loop, supplying a loop method.
541 This class wraps an application manager object and provides a loop method
542 that will work with pydraw.
545 from AthenaPython
import PyAthena
547 from AthenaCommon.AppMgr
import theApp
550 self.
_sg = PyAthena.py_svc(
'StoreGateSvc')
554 def loop (self, f, looplo=0, loophi=sys.maxsize):
555 """Call f(i,tree) on rows [looplo, loophi)"""
556 loophi = min (loophi, self.
_app.
size())
557 getentry = self.
_app.seekEvent
558 for i
in range(looplo, loophi):
565 if not v.startswith(
'_'):
567 raise AttributeError()
571 """Holds information about a dummy loop variable.
574 name - The name of the dummy variable.
575 ids - Set of loop identifiers (`foo' in `foo$i') with which
576 this dummy has been used.
577 explicit - Set to true if this variable is ever used on its own
582 """Initialize given the name."""
589 """Return the iterator variable for this dummy and loop identifier ID.
591 return "_it_%s_%s" % (self.
name, id)
594 """Return the dummy variable name for this dummy."""
595 return "_dum_" + self.
name
598 """Notice this this dummy is used with loop identifier ID.
600 Return the iterator variable.
606 """Return the list of loop identifiers with which we've been used."""
607 return list (self.
ids)
611 """Holds information used to implement a draw/scan/loop command.
613 Pass the draw string to the constructor. See the file-level comments
614 for details on the syntax of this. This will define the
615 following attributes:
617 errstr - If set to a string, there was an error.
618 Should be None if everything's ok.
619 tuple - The name of the tuple object.
620 tuple_o - Tuple object.
621 lo - The lower bound for row iteration.
622 hi - The upper bound for row iteration.
623 stmts - List of additional statements.
624 exprs - List of draw expressions.
625 sel - Selection expression or None.
626 sel_orig - Untransformed selection expression or None.
627 expr_orig- Untransformed plotting expression.
628 histspec - The text following `;', split into space-separated words.
631 _iddict - Map from loop identifiers (`foo' in `foo$i')
632 to temp variables used to reference
633 them in the loop function.
634 _limdict - Map from loop identifiers (`foo' in `foo$2')
635 to the largest explicit index seen.
636 _loopdict - Map of loop dummy variable names to _Loopvar instances.
640 """Initialize from a draw string. See above for more details."""
651 except Exception
as e:
660 """Parse a draw string. See above for more details."""
663 (s, self.
histspec) = _find_outer (s,
';')
676 self.
errstr =
"Empty draw string."
680 (tuple, s) = _find_outer (s,
'.')
682 self.
errstr =
"Missing period in tuple specification."
704 (self.expr_orig, self.sel_orig) = _find_outer (s,
"if")
708 _split_outer (self.expr_orig,
':')]
713 if hasattr (self.
tuple_o,
'loop'):
716 elif (hasattr (self.
tuple_o,
'GetEntry')
and
717 hasattr (self.
tuple_o,
'GetEntries')):
720 elif (hasattr (self.
tuple_o,
'size')
and
721 hasattr (self.
tuple_o,
'seekEvent')):
727 " doesn't have a correct interface.")
735 """Parse the range part of a draw string.
737 See above for more details.
738 Fills self.tuple, self.lo, self.hi.
742 (tuple, tail) = _find_outer (tuple,
'[')
744 g = copy.copy (_globals)
746 pos = tail.find (
':')
747 pos2 = tail.find (
']')
751 slo = tail[:pos2].strip()
753 lo = int (eval (slo, g))
756 slo = tail[:pos].strip()
758 lo = int (eval (slo, g))
759 shi = tail[pos+1:pos2].strip()
761 hi = int (eval (shi, g))
763 if tuple[0] ==
'(' and tuple[-1] ==
')':
764 tuple = tuple[1:-1].strip()
772 """Given a loop identifier (`foo' in `foo$i'), return the identifier
773 used to reference it in loop functions.
783 """Handle an explicit index reference; i.e., `foo$2'.
785 S1 and S2 are pieces of the string before and after the `$'.
786 Returns the modified string.
789 while pos2 < len(s2)
and s2[pos2]
in string.digits:
798 s = (
"[%d]" % (i-1)) + s2[pos2:]
800 while pos2 >= 0
and s1[pos2]
in _idchars:
807 s = s1[:pos2] + self.
_mung_id (id) + s
813 """Handle a length reference; i.e., `$nfoo'.
815 S1 and S2 are pieces of the string before and after the `$'.
816 Returns the modified string.
819 while pos2 < len(s2)
and s2[pos2]
in _idchars:
822 s = s1 + (
" len(%s)" % self.
_mung_id(id)) + s2[pos2:]
827 """Handle use of a dummy loop variable, such as foo$i.
829 S1 and S2 are pieces of the string before and after the `$'.
830 Returns the modified string.
835 while pos2 < len(s2)
and s2[pos2]
in _idchars:
838 self.
errstr =
"Bad loop var"
849 if len(s1) > 0
and s1[-1]
in _idchars:
852 while pos3 >= 0
and s1[pos3]
in _idchars:
855 assert (len(s1) - pos3 >= 1)
859 s = s1[:pos3] + ll.add_id(id) + s2[pos2:]
864 s = s1 + (
"%s" % ll.dumname()) + s2[pos2:]
870 """Process $ constructions in string S.
872 Returns the modified string.
878 (s1, s2) = _find_outer (s[pos:],
'$',
True)
883 if s2[0]
in string.digits:
885 elif (s2[0] ==
'n' and
886 (
not (len(s1) > 0
and s1[-1]
in _idchars)
or
887 s1.endswith (
' and')
or
888 s1.endswith (
' or')
or
889 s1.endswith (
'not'))):
891 elif s2[0]
in string.ascii_letters:
896 pos = pos + len(s1)+1
902 """Perform id substitution in S.
904 For identifiers in S that are attributes of our tuple,
905 replace them with references to the tuple attribute
908 Returns the modified string.
913 tlist = tokenize.generate_tokens (StringIO(s).readline)
916 for tnum, val, a, b, c
in tlist:
917 if tnum == token.NAME
and not afterDot:
918 if hasattr (self.
tuple_o, val):
921 out.append ((tnum, val))
924 if tnum == token.OP
and val ==
'.':
928 return _untokenize (out)
932 """Process $ constructions and id substitution in string S.
934 Returns the modified string.
941 """Create the text for the function to process this query.
943 PAYLOAD is the payload expression to plug in.
944 EXTARGS is an additional string to add to the end of the
945 function's argument list (to set default values, for example).
946 Returns the function definition as a string.
951 limsel =
' and '.join ([
"len(%s)>=%d" % (self.
_iddict[p[0]], p[1])
956 sel = limsel +
" and (" + sel +
")"
958 ftext =
"def _loopfunc(_i, %s%s):\n" % (_evtvar, extargs)
960 ftext +=
" %s = %s.%s\n" % (id2, _evtvar, id1)
967 vars = l.itname (ids[0])
970 vars =
"(" +
','.
join([l.itname (id)
for id
in ids]) +
")"
971 lists = (
"zip(" +
','.
join([self.
_iddict[id]
for id
in ids])
974 vars =
"(%s,%s)" % (l.dumname(), vars)
975 lists =
"enumerate(%s)" % lists
976 ftext +=
' '*indent +
"for %s in %s:\n" % (vars, lists)
980 ftext +=
' '*indent + s +
'\n'
982 if sel
and sel !=
'1':
983 ftext +=
' '*indent +
"if (%s):\n" % sel
986 ftext +=
' '*indent +
"%s\n" % payload
995 """Holds the results of _get_bins. Defined attributes:
1005 """Parse bin specifications from split list of arguments ARGS.
1006 NDIM is 1 or 2, and AXIS is 0 or 1, for the x or y axis.
1009 >>> from PyAnalysisUtils import pydraw
1010 >>> pydraw._globals = globals()
1012 >>> ROOT.gPad.Range(0, 1,2,3)
1013 >>> b = _get_bins (["50", "10", "100"], 1, 0)
1014 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1016 >>> b = _get_bins ([], 1, 0)
1017 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1019 >>> b = _get_bins (["!", "10"], 1, 0)
1020 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1022 >>> b = _get_bins (["!", "!", "10"], 1, 0)
1023 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1026 >>> b = _get_bins (["50", "0", "2*scale"], 1, 0)
1027 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1029 >>> b = _get_bins ([], 2, 0)
1030 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1032 >>> b = _get_bins ([], 2, 1)
1033 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1035 >>> b = _get_bins ([], 2, 2)
1036 Traceback (most recent call last):
1041 g = copy.copy (_globals)
1046 if len(args) >= 1
and args[0] !=
'!' and len(args[0]) > 0:
1047 bins.nbins = int (eval (args[0], g))
1052 if len(args) >= 2
and args[1] !=
'!' and len(args[1]) > 0:
1053 bins.lo = float (eval (args[1], g))
1056 if len(args) >= 3
and args[2] !=
'!' and len(args[2]) > 0:
1057 bins.hi = float (eval (args[2], g))
1060 if bins.hi <= bins.lo:
1063 bins.hi = bins.lo + 1
1065 bins.lo = ROOT.gPad.GetUxmin()
1066 bins.hi = ROOT.gPad.GetUxmax()
1068 bins.lo = ROOT.gPad.GetUymin()
1069 bins.hi = ROOT.gPad.GetUymax()
1077 """Create a new histogram from options.
1079 NDIM is the dimensionality of the histogram (1 or 2).
1080 ARGS is a list of the arguments given to specify the histogram.
1081 HNAME and HTITLE are the histogram name and title, respectively.
1086 xbins = _get_bins (args, ndim, 0)
1091 ybins = _get_bins (args[3:], ndim, 1)
1092 rebin = rebin
or ybins.rebin
1097 for i
in range (0, len(args)):
1098 if args[i][0]
in string.ascii_letters:
1099 for j
in range (i, len(args)):
1100 if ndim == 2
and args[j].lower() ==
"prof":
1103 options =
' '.join (args[i:])
1107 hold = ROOT.gROOT.FindObject (hname)
1109 ROOT.gROOT.Remove (hold)
1113 hist = ROOT.TProfile (hname, htitle, xbins.nbins, xbins.lo, xbins.hi)
1115 hist.SetMinimum (ybins.lo)
1116 hist.SetMaximum (ybins.hi)
1118 hist = ROOT.TH1F (hname, htitle, xbins.nbins, xbins.lo, xbins.hi)
1120 hist = ScatterH2 (hname, htitle,
1121 xbins.nbins, xbins.lo, xbins.hi,
1122 ybins.nbins, ybins.lo, ybins.hi)
1123 if hasattr (hist,
'scatter'):
1130 return (hist, options)
1134 """Process a draw command.
1136 ARG is the command arguments (without the command word itself).
1137 See the header comments for the command syntax.
1149 if len (c.exprs) == 1:
1151 payload =
"_hfill (%s)" % c.exprs[0]
1154 payload =
"_hfill ((%s),(%s))" % (c.exprs[0], c.exprs[1])
1157 htitle =
"%s.%s" % (c.tuple, c.expr_orig)
1159 htitle = htitle +
'{%s}' % c.sel_orig
1163 if len(c.histspec) >= 1
and c.histspec[0] ==
"!" and last_hist
is not None:
1165 options =
' '.join (c.histspec[1:])
1166 elif len(c.histspec) >= 1
and c.histspec[0][:2] ==
'>>':
1167 hname = c.histspec[0][2:]
1168 hist = _globals.get (hname)
1169 options =
' '.join (c.histspec[1:])
1171 (hist, options) = _get_hist (ndim, c.histspec,
1179 g = copy.copy (_globals)
1180 g[
'_hfill'] = hist.Fill
1181 ftext = c._make_func (payload,
', _hfill = _hfill')
1185 c.tuple_o.loop (g[
'_loopfunc'], c.lo, c.hi)
1188 if _hasCanRebin (hist):
1189 hist.LabelsDeflate (
"X")
1191 hist.LabelsDeflate (
"Y")
1194 draw_obj (hist, options)
1199 """Helper to print out one row of a scan.
1201 I is the row number and ARGS is a tuple of the column values."""
1205 if isinstance(a, six.integer_types):
1214 """Process a scan command.
1216 ARG is the command arguments (without the command word itself).
1217 See the header comments for the command syntax.
1226 payload =
"_print (_i, %s)" % \
1227 ','.join ([
'(%s)'%e
for e
in c.exprs])
1231 g = copy.copy (_globals)
1232 g[
'_print'] = _scan_print
1233 ftext = c._make_func (payload,
', _print = _print')
1237 c.tuple_o.loop (g[
'_loopfunc'], c.lo, c.hi)
1243 """Process a loop command.
1245 ARG is the command arguments (without the command word itself).
1246 See the header comments for the command syntax.
1255 payload =
"(%s,)" %
','.join (c.exprs)
1259 g = copy.copy (_globals)
1260 ftext = c._make_func (payload)
1264 c.tuple_o.loop (g[
'_loopfunc'], c.lo, c.hi)
1271 _cmddict = {
'd': draw,
1279 """Process a command S.
1281 Returns True if the command was handled, False otherwise.
1282 See the header comments for the command syntax.
1285 ssplit = s.split (
None, 1)
1292 func = _cmddict.get (cmd)
1311 if '_orig_ehook' not in globals():
1316 """Exception hook used by pydraw to process drawing commands."""
1319 if isinstance (value, SyntaxError):
1326 ROOT.gInterpreter.EndOfLineAction()
1330 _orig_ehook (exctype, value, traceb)
1334 """Enable entering drawing commands directly at the python prompt."""
1339 if _orig_ehook
is None:
1340 _orig_ehook = sys.excepthook
1343 sys.excepthook = _excepthook