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:
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.)
20 In addition, this style of query may be somewhat
21 easier to type interactively.
27 Here are some examples of plotting commands to give you the flavor:
30 d tt.ele_pt$i; 50 0 100*gev
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
36 To use these commands, you can pass them as strings to pydraw.cmd:
38 from pydraw import cmd
41 Alternatively, if you execute the cmdhook function, you can type them
44 from pydraw import cmdhook
48 (Note that this second form doesn't work in general for code that's read
55 The general syntax for drawing a histogram looks like this:
57 d TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR] [; HISTSPEC]
59 These pieces are explained in more detail below.
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:
70 d (trees.tt[1])[:100].ele_pt$i
72 Optionally, this can include a slice-like notation
73 to restrict the rows to which the draw applies:
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
80 i and j can be expressions as well.
82 The tuple object should contain a method like this:
84 def loop (self, func, looplo, loophi)
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).
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.
96 Thus, you can make plots from within Athena like this:
98 d theApp.ElectronAODCollection$i.eta()
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.
107 To plot a simple numeric variable from the tuple, just give its name.
112 will plot the variable `foo' from each row of the tuple. You can of course
113 also use more complicated expressions:
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:
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.)
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
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:
141 d tt.ele$i.pt() if $i<4
143 (This uses a selection clause. This is to be described later, but the meaning
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:
151 will iterate min(len(ele),len(muo)) times.
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:
159 d tt.(ele$i+ele$j).m() if $i>$j
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
167 Note that one can do something similar just using standard python
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:
176 d tt.ele[0].pt() if len(ele)>0
178 You can also use $nCONT as an abbreviation for len(CONT):
180 d tt.ele[0].pt() if $nele>0
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.)
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.
197 You can select items to be filled using a boolean expression, set off
198 with an `if' keyword:
200 d tt.ele$i.pt() if abs(ele$i.eta())<2
202 All dummy variables are common between the variable expressions
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:
214 d tt.ele=ElectronAODCollection@ele$i.eta() if ele$i.pt()>100*gev
217 Histogram specifications
218 ------------------------
220 Histogram specifications follow a semicolon. They can have the forms:
224 NX XLO XHI OPTIONS...
225 NX XLO XHI NY YLO YHI OPTIONS...
228 For the first form, specifying ! reuses the same histogram that was used
231 For the second form, specifying >>NAME looks in the global dictionary
232 for a histogram NAME and uses that.
234 Otherwise, a new histogram is created. The binning for this histogram
235 may be specified by NX XLO XHI and NY YLO YHI.
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.
243 The last histogram to have been drawn is available is pydraw.last_hist.
249 The scan command is very similar to draw:
251 scan TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR]
253 Instead of drawing a histogram, scan prints out a table of the expression
256 The formatting of the data printed by scan is currently pretty rudimentary.
257 This should probably be improved.
263 There is also a loop command:
265 loop TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR]
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.
276 The general interface to execute one of these commands is the `cmd' function,
277 which takes the command as a string:
279 from pydraw import cmd
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:
285 from pydraw import draw
288 Finally, if you call the function cmdhook(), then you can give the commands
289 directly on the python command line:
291 from pydraw import cmdhook
298 - No way to specify an event weight when filling a histogram using
301 - Hoist selection code out of the dummy index loops, when they don't
302 depend on the index? For example,
306 gets implemented like:
312 but it would be more efficient to pull the selection out of the loop.
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.
332 from StringIO
import StringIO
334 from io
import StringIO
335 from PyAnalysisUtils.draw_obj
import draw_obj, get_canvas
339 ScatterH2 = ROOT.RootUtils.ScatterH2
340 except AttributeError:
341 ScatterH2 = ROOT.TH2F
342 print (
"WARNING: RootUtils::ScatterH2 not available; using TH2F instead")
348 h.SetBit (ROOT.TH1.kCanRebin)
350 return h.TestBit (ROOT.TH1.kCanRebin)
351 except AttributeError:
353 h.GetXaxis().SetCanExtend(
True)
355 return h.GetXaxis().CanExtend()
363 _globals = sys.modules[
'__main__'].__dict__
367 _idchars = string.ascii_letters + string.digits +
'_'
376 """Name a string safe to use as a histogram name.
378 Root does bad things if you put / in a histogram name, so we remove them.
380 >>> print (_sanitize_hname('foo'))
382 >>> print (_sanitize_hname('foo/bar'))
385 return s.replace (
'/',
' DIV ')
389 """Transform tokens back into Python source code.
391 Each element returned by the iterable must be a token sequence
392 with at least two elements, a token number and token value.
394 Unlike tokenize.untokenize(), this does not handle multiple lines.
395 It also tries not to add unneeded spaces.
398 >>> from tokenize import generate_tokens, untokenize
401 ... from StringIO import StringIO
403 ... from io import StringIO
404 >>> def untokenize1(tt):
406 ... if tt[-1][0]==0: tt=tt[:-1]
407 ... return untokenize(tt)
408 >>> untokenize1(generate_tokens(StringIO('1+1').readline))
410 >>> _untokenize(generate_tokens(StringIO('1+1').readline))
412 >>> untokenize1(generate_tokens(StringIO('foo$i>2*h').readline))
414 >>> _untokenize(generate_tokens(StringIO('foo$i>2*h').readline))
419 toks_append = toks.append
421 toknum, tokval = tok[:2]
422 tokval = tokval.strip()
423 if toknum
in (token.NAME, token.NUMBER):
425 tokval =
' ' + tokval
434 """Look for NEEDLE in HAYSTACK (token-based. Return pair (HEAD, TAIL).
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).
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.
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", ";")
458 >>> _find_outer ("a '$' b", '$')
460 >>> _find_outer ("a $ b", '$')
462 >>> _find_outer ("(head.tail1).tail2", ".", True)
463 ('(head', 'tail1).tail2')
464 >>> _find_outer ('a; 1 -1 1', ';')
467 tlist = tokenize.generate_tokens (StringIO(haystack).readline)
470 for (i, (tnum, val, a, b, c))
in enumerate (tlist):
471 if tnum != token.STRING
and not pend
and val == needle:
474 return (haystack[:col1].strip(),
475 haystack[col2:].strip())
483 elif pend
and val == pend[-1]:
485 head.append ((tnum, val))
486 return (haystack,
None)
490 """Split HAYSTACK at the delimiters NEEDLE, as in _find_outer.
493 >>> _split_outer ("a,(b,c),d", ",")
495 >>> _split_outer ("a,,b", ",")
497 >>> _split_outer ("a", ",")
499 >>> #_split_outer ("", ",")
504 (head, tail) = _find_outer (haystack, needle)
515 """Wrapper for TTree, supplying a loop method.
517 This class wraps a TTree class and provides a loop method
518 that will work with pydraw.
522 """Make a wrapper for a tree."""
526 def loop (self, f, looplo=0, loophi=sys.maxsize):
527 """Call f(i,tree) on rows [looplo, loophi)"""
529 loophi = min (loophi, tree.GetEntries())
530 getentry = tree.GetEntry
531 for i
in range(looplo, loophi):
538 """Wrapper for the Athena event loop, supplying a loop method.
540 This class wraps an application manager object and provides a loop method
541 that will work with pydraw.
544 from AthenaPython
import PyAthena
546 from AthenaCommon.AppMgr
import theApp
549 self.
_sg = PyAthena.py_svc(
'StoreGateSvc')
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())
556 getentry = self.
_app.seekEvent
557 for i
in range(looplo, loophi):
564 if not v.startswith(
'_'):
566 raise AttributeError()
570 """Holds information about a dummy loop variable.
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
581 """Initialize given the name."""
588 """Return the iterator variable for this dummy and loop identifier ID.
590 return "_it_%s_%s" % (self.
name, id)
593 """Return the dummy variable name for this dummy."""
594 return "_dum_" + self.
name
597 """Notice this this dummy is used with loop identifier ID.
599 Return the iterator variable.
605 """Return the list of loop identifiers with which we've been used."""
606 return list (self.
ids)
610 """Holds information used to implement a draw/scan/loop command.
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:
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.
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.
639 """Initialize from a draw string. See above for more details."""
650 except Exception
as e:
659 """Parse a draw string. See above for more details."""
662 (s, self.
histspec) = _find_outer (s,
';')
675 self.
errstr =
"Empty draw string."
679 (tuple, s) = _find_outer (s,
'.')
681 self.
errstr =
"Missing period in tuple specification."
703 (self.expr_orig, self.sel_orig) = _find_outer (s,
"if")
707 _split_outer (self.expr_orig,
':')]
712 if hasattr (self.
tuple_o,
'loop'):
715 elif (hasattr (self.
tuple_o,
'GetEntry')
and
716 hasattr (self.
tuple_o,
'GetEntries')):
719 elif (hasattr (self.
tuple_o,
'size')
and
720 hasattr (self.
tuple_o,
'seekEvent')):
726 " doesn't have a correct interface.")
734 """Parse the range part of a draw string.
736 See above for more details.
737 Fills self.tuple, self.lo, self.hi.
741 (tuple, tail) = _find_outer (tuple,
'[')
743 g = copy.copy (_globals)
745 pos = tail.find (
':')
746 pos2 = tail.find (
']')
750 slo = tail[:pos2].strip()
752 lo = int (eval (slo, g))
755 slo = tail[:pos].strip()
757 lo = int (eval (slo, g))
758 shi = tail[pos+1:pos2].strip()
760 hi = int (eval (shi, g))
762 if tuple[0] ==
'(' and tuple[-1] ==
')':
763 tuple = tuple[1:-1].strip()
771 """Given a loop identifier (`foo' in `foo$i'), return the identifier
772 used to reference it in loop functions.
782 """Handle an explicit index reference; i.e., `foo$2'.
784 S1 and S2 are pieces of the string before and after the `$'.
785 Returns the modified string.
788 while pos2 < len(s2)
and s2[pos2]
in string.digits:
797 s = (
"[%d]" % (i-1)) + s2[pos2:]
799 while pos2 >= 0
and s1[pos2]
in _idchars:
806 s = s1[:pos2] + self.
_mung_id (id) + s
812 """Handle a length reference; i.e., `$nfoo'.
814 S1 and S2 are pieces of the string before and after the `$'.
815 Returns the modified string.
818 while pos2 < len(s2)
and s2[pos2]
in _idchars:
821 s = s1 + (
" len(%s)" % self.
_mung_id(id)) + s2[pos2:]
826 """Handle use of a dummy loop variable, such as foo$i.
828 S1 and S2 are pieces of the string before and after the `$'.
829 Returns the modified string.
834 while pos2 < len(s2)
and s2[pos2]
in _idchars:
837 self.
errstr =
"Bad loop var"
848 if len(s1) > 0
and s1[-1]
in _idchars:
851 while pos3 >= 0
and s1[pos3]
in _idchars:
854 assert (len(s1) - pos3 >= 1)
858 s = s1[:pos3] + ll.add_id(id) + s2[pos2:]
863 s = s1 + (
"%s" % ll.dumname()) + s2[pos2:]
869 """Process $ constructions in string S.
871 Returns the modified string.
877 (s1, s2) = _find_outer (s[pos:],
'$',
True)
882 if s2[0]
in string.digits:
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'))):
890 elif s2[0]
in string.ascii_letters:
895 pos = pos + len(s1)+1
901 """Perform id substitution in S.
903 For identifiers in S that are attributes of our tuple,
904 replace them with references to the tuple attribute
907 Returns the modified string.
912 tlist = tokenize.generate_tokens (StringIO(s).readline)
915 for tnum, val, a, b, c
in tlist:
916 if tnum == token.NAME
and not afterDot:
917 if hasattr (self.
tuple_o, val):
920 out.append ((tnum, val))
923 if tnum == token.OP
and val ==
'.':
927 return _untokenize (out)
931 """Process $ constructions and id substitution in string S.
933 Returns the modified string.
940 """Create the text for the function to process this query.
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.
950 limsel =
' and '.join ([
"len(%s)>=%d" % (self.
_iddict[p[0]], p[1])
955 sel = limsel +
" and (" + sel +
")"
957 ftext =
"def _loopfunc(_i, %s%s):\n" % (_evtvar, extargs)
959 ftext +=
" %s = %s.%s\n" % (id2, _evtvar, id1)
966 vars = l.itname (ids[0])
969 vars =
"(" +
','.
join([l.itname (id)
for id
in ids]) +
")"
970 lists = (
"zip(" +
','.
join([self.
_iddict[id]
for id
in ids])
973 vars =
"(%s,%s)" % (l.dumname(), vars)
974 lists =
"enumerate(%s)" % lists
975 ftext +=
' '*indent +
"for %s in %s:\n" % (vars, lists)
979 ftext +=
' '*indent + s +
'\n'
981 if sel
and sel !=
'1':
982 ftext +=
' '*indent +
"if (%s):\n" % sel
985 ftext +=
' '*indent +
"%s\n" % payload
994 """Holds the results of _get_bins. Defined attributes:
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.
1008 >>> from PyAnalysisUtils import pydraw
1009 >>> pydraw._globals = globals()
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)
1015 >>> b = _get_bins ([], 1, 0)
1016 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1018 >>> b = _get_bins (["!", "10"], 1, 0)
1019 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1021 >>> b = _get_bins (["!", "!", "10"], 1, 0)
1022 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1025 >>> b = _get_bins (["50", "0", "2*scale"], 1, 0)
1026 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1028 >>> b = _get_bins ([], 2, 0)
1029 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1031 >>> b = _get_bins ([], 2, 1)
1032 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1034 >>> b = _get_bins ([], 2, 2)
1035 Traceback (most recent call last):
1040 g = copy.copy (_globals)
1045 if len(args) >= 1
and args[0] !=
'!' and len(args[0]) > 0:
1046 bins.nbins = int (eval (args[0], g))
1051 if len(args) >= 2
and args[1] !=
'!' and len(args[1]) > 0:
1052 bins.lo = float (eval (args[1], g))
1055 if len(args) >= 3
and args[2] !=
'!' and len(args[2]) > 0:
1056 bins.hi = float (eval (args[2], g))
1059 if bins.hi <= bins.lo:
1062 bins.hi = bins.lo + 1
1064 bins.lo = ROOT.gPad.GetUxmin()
1065 bins.hi = ROOT.gPad.GetUxmax()
1067 bins.lo = ROOT.gPad.GetUymin()
1068 bins.hi = ROOT.gPad.GetUymax()
1076 """Create a new histogram from options.
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.
1085 xbins = _get_bins (args, ndim, 0)
1090 ybins = _get_bins (args[3:], ndim, 1)
1091 rebin = rebin
or ybins.rebin
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":
1102 options =
' '.join (args[i:])
1106 hold = ROOT.gROOT.FindObject (hname)
1108 ROOT.gROOT.Remove (hold)
1112 hist = ROOT.TProfile (hname, htitle, xbins.nbins, xbins.lo, xbins.hi)
1114 hist.SetMinimum (ybins.lo)
1115 hist.SetMaximum (ybins.hi)
1117 hist = ROOT.TH1F (hname, htitle, xbins.nbins, xbins.lo, xbins.hi)
1119 hist = ScatterH2 (hname, htitle,
1120 xbins.nbins, xbins.lo, xbins.hi,
1121 ybins.nbins, ybins.lo, ybins.hi)
1122 if hasattr (hist,
'scatter'):
1129 return (hist, options)
1133 """Process a draw command.
1135 ARG is the command arguments (without the command word itself).
1136 See the header comments for the command syntax.
1148 if len (c.exprs) == 1:
1150 payload =
"_hfill (%s)" % c.exprs[0]
1153 payload =
"_hfill ((%s),(%s))" % (c.exprs[0], c.exprs[1])
1156 htitle =
"%s.%s" % (c.tuple, c.expr_orig)
1158 htitle = htitle +
'{%s}' % c.sel_orig
1162 if len(c.histspec) >= 1
and c.histspec[0] ==
"!" and last_hist
is not None:
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:])
1170 (hist, options) = _get_hist (ndim, c.histspec,
1178 g = copy.copy (_globals)
1179 g[
'_hfill'] = hist.Fill
1180 ftext = c._make_func (payload,
', _hfill = _hfill')
1184 c.tuple_o.loop (g[
'_loopfunc'], c.lo, c.hi)
1187 if _hasCanRebin (hist):
1188 hist.LabelsDeflate (
"X")
1190 hist.LabelsDeflate (
"Y")
1193 draw_obj (hist, options)
1198 """Helper to print out one row of a scan.
1200 I is the row number and ARGS is a tuple of the column values."""
1204 if isinstance(a, six.integer_types):
1213 """Process a scan command.
1215 ARG is the command arguments (without the command word itself).
1216 See the header comments for the command syntax.
1225 payload =
"_print (_i, %s)" % \
1226 ','.join ([
'(%s)'%e
for e
in c.exprs])
1230 g = copy.copy (_globals)
1231 g[
'_print'] = _scan_print
1232 ftext = c._make_func (payload,
', _print = _print')
1236 c.tuple_o.loop (g[
'_loopfunc'], c.lo, c.hi)
1242 """Process a loop command.
1244 ARG is the command arguments (without the command word itself).
1245 See the header comments for the command syntax.
1254 payload =
"(%s,)" %
','.join (c.exprs)
1258 g = copy.copy (_globals)
1259 ftext = c._make_func (payload)
1263 c.tuple_o.loop (g[
'_loopfunc'], c.lo, c.hi)
1270 _cmddict = {
'd': draw,
1278 """Process a command S.
1280 Returns True if the command was handled, False otherwise.
1281 See the header comments for the command syntax.
1284 ssplit = s.split (
None, 1)
1291 func = _cmddict.get (cmd)
1310 if '_orig_ehook' not in globals():
1315 """Exception hook used by pydraw to process drawing commands."""
1318 if isinstance (value, SyntaxError):
1325 ROOT.gInterpreter.EndOfLineAction()
1329 _orig_ehook (exctype, value, traceb)
1333 """Enable entering drawing commands directly at the python prompt."""
1338 if _orig_ehook
is None:
1339 _orig_ehook = sys.excepthook
1342 sys.excepthook = _excepthook