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.
330 from io
import StringIO
331 from PyAnalysisUtils.draw_obj
import draw_obj, get_canvas
335 ScatterH2 = ROOT.RootUtils.ScatterH2
336 except AttributeError:
337 ScatterH2 = ROOT.TH2F
338 print (
"WARNING: RootUtils::ScatterH2 not available; using TH2F instead")
344 h.SetBit (ROOT.TH1.kCanRebin)
346 return h.TestBit (ROOT.TH1.kCanRebin)
347 except AttributeError:
349 h.GetXaxis().SetCanExtend(
True)
351 return h.GetXaxis().CanExtend()
359 _globals = sys.modules[
'__main__'].__dict__
363 _idchars = string.ascii_letters + string.digits +
'_'
372 """Name a string safe to use as a histogram name.
374 Root does bad things if you put / in a histogram name, so we remove them.
376 >>> print (_sanitize_hname('foo'))
378 >>> print (_sanitize_hname('foo/bar'))
381 return s.replace (
'/',
' DIV ')
385 """Transform tokens back into Python source code.
387 Each element returned by the iterable must be a token sequence
388 with at least two elements, a token number and token value.
390 Unlike tokenize.untokenize(), this does not handle multiple lines.
391 It also tries not to add unneeded spaces.
394 >>> from tokenize import generate_tokens, untokenize
395 >>> from io import StringIO
396 >>> def untokenize1(tt):
398 ... if tt[-1][0]==0: tt=tt[:-1]
399 ... return untokenize(tt)
400 >>> untokenize1(generate_tokens(StringIO('1+1').readline))
402 >>> _untokenize(generate_tokens(StringIO('1+1').readline))
404 >>> untokenize1(generate_tokens(StringIO('foo$i>2*h').readline))
406 >>> _untokenize(generate_tokens(StringIO('foo$i>2*h').readline))
411 toks_append = toks.append
413 toknum, tokval = tok[:2]
414 tokval = tokval.strip()
415 if toknum
in (token.NAME, token.NUMBER):
417 tokval =
' ' + tokval
426 """Look for NEEDLE in HAYSTACK (token-based. Return pair (HEAD, TAIL).
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).
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.
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", ";")
450 >>> _find_outer ("a '$' b", '$')
452 >>> _find_outer ("a $ b", '$')
454 >>> _find_outer ("(head.tail1).tail2", ".", True)
455 ('(head', 'tail1).tail2')
456 >>> _find_outer ('a; 1 -1 1', ';')
459 tlist = tokenize.generate_tokens (StringIO(haystack).readline)
462 for (i, (tnum, val, a, b, c))
in enumerate (tlist):
463 if tnum != token.STRING
and not pend
and val == needle:
466 return (haystack[:col1].strip(),
467 haystack[col2:].strip())
475 elif pend
and val == pend[-1]:
477 head.append ((tnum, val))
478 return (haystack,
None)
482 """Split HAYSTACK at the delimiters NEEDLE, as in _find_outer.
485 >>> _split_outer ("a,(b,c),d", ",")
487 >>> _split_outer ("a,,b", ",")
489 >>> _split_outer ("a", ",")
491 >>> #_split_outer ("", ",")
496 (head, tail) = _find_outer (haystack, needle)
507 """Wrapper for TTree, supplying a loop method.
509 This class wraps a TTree class and provides a loop method
510 that will work with pydraw.
514 """Make a wrapper for a tree."""
518 def loop (self, f, looplo=0, loophi=sys.maxsize):
519 """Call f(i,tree) on rows [looplo, loophi)"""
521 loophi = min (loophi, tree.GetEntries())
522 getentry = tree.GetEntry
523 for i
in range(looplo, loophi):
530 """Wrapper for the Athena event loop, supplying a loop method.
532 This class wraps an application manager object and provides a loop method
533 that will work with pydraw.
536 from AthenaPython
import PyAthena
538 from AthenaCommon.AppMgr
import theApp
541 self.
_sg = PyAthena.py_svc(
'StoreGateSvc')
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())
548 getentry = self.
_app.seekEvent
549 for i
in range(looplo, loophi):
556 if not v.startswith(
'_'):
558 raise AttributeError()
562 """Holds information about a dummy loop variable.
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
573 """Initialize given the name."""
580 """Return the iterator variable for this dummy and loop identifier ID.
582 return "_it_%s_%s" % (self.
name, id)
585 """Return the dummy variable name for this dummy."""
586 return "_dum_" + self.
name
589 """Notice this this dummy is used with loop identifier ID.
591 Return the iterator variable.
597 """Return the list of loop identifiers with which we've been used."""
598 return list (self.
ids)
602 """Holds information used to implement a draw/scan/loop command.
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:
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.
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.
631 """Initialize from a draw string. See above for more details."""
642 except Exception
as e:
651 """Parse a draw string. See above for more details."""
654 (s, self.
histspec) = _find_outer (s,
';')
667 self.
errstr =
"Empty draw string."
671 (tuple, s) = _find_outer (s,
'.')
673 self.
errstr =
"Missing period in tuple specification."
695 (self.expr_orig, self.sel_orig) = _find_outer (s,
"if")
699 _split_outer (self.expr_orig,
':')]
704 if hasattr (self.
tuple_o,
'loop'):
707 elif (hasattr (self.
tuple_o,
'GetEntry')
and
708 hasattr (self.
tuple_o,
'GetEntries')):
711 elif (hasattr (self.
tuple_o,
'size')
and
712 hasattr (self.
tuple_o,
'seekEvent')):
718 " doesn't have a correct interface.")
726 """Parse the range part of a draw string.
728 See above for more details.
729 Fills self.tuple, self.lo, self.hi.
733 (tuple, tail) = _find_outer (tuple,
'[')
735 g = copy.copy (_globals)
737 pos = tail.find (
':')
738 pos2 = tail.find (
']')
742 slo = tail[:pos2].strip()
744 lo = int (eval (slo, g))
747 slo = tail[:pos].strip()
749 lo = int (eval (slo, g))
750 shi = tail[pos+1:pos2].strip()
752 hi = int (eval (shi, g))
754 if tuple[0] ==
'(' and tuple[-1] ==
')':
755 tuple = tuple[1:-1].strip()
763 """Given a loop identifier (`foo' in `foo$i'), return the identifier
764 used to reference it in loop functions.
774 """Handle an explicit index reference; i.e., `foo$2'.
776 S1 and S2 are pieces of the string before and after the `$'.
777 Returns the modified string.
780 while pos2 < len(s2)
and s2[pos2]
in string.digits:
789 s = (
"[%d]" % (i-1)) + s2[pos2:]
791 while pos2 >= 0
and s1[pos2]
in _idchars:
798 s = s1[:pos2] + self.
_mung_id (id) + s
804 """Handle a length reference; i.e., `$nfoo'.
806 S1 and S2 are pieces of the string before and after the `$'.
807 Returns the modified string.
810 while pos2 < len(s2)
and s2[pos2]
in _idchars:
813 s = s1 + (
" len(%s)" % self.
_mung_id(id)) + s2[pos2:]
818 """Handle use of a dummy loop variable, such as foo$i.
820 S1 and S2 are pieces of the string before and after the `$'.
821 Returns the modified string.
826 while pos2 < len(s2)
and s2[pos2]
in _idchars:
829 self.
errstr =
"Bad loop var"
840 if len(s1) > 0
and s1[-1]
in _idchars:
843 while pos3 >= 0
and s1[pos3]
in _idchars:
846 assert (len(s1) - pos3 >= 1)
850 s = s1[:pos3] + ll.add_id(id) + s2[pos2:]
855 s = s1 + (
"%s" % ll.dumname()) + s2[pos2:]
861 """Process $ constructions in string S.
863 Returns the modified string.
869 (s1, s2) = _find_outer (s[pos:],
'$',
True)
874 if s2[0]
in string.digits:
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'))):
882 elif s2[0]
in string.ascii_letters:
887 pos = pos + len(s1)+1
893 """Perform id substitution in S.
895 For identifiers in S that are attributes of our tuple,
896 replace them with references to the tuple attribute
899 Returns the modified string.
904 tlist = tokenize.generate_tokens (StringIO(s).readline)
907 for tnum, val, a, b, c
in tlist:
908 if tnum == token.NAME
and not afterDot:
909 if hasattr (self.
tuple_o, val):
912 out.append ((tnum, val))
915 if tnum == token.OP
and val ==
'.':
919 return _untokenize (out)
923 """Process $ constructions and id substitution in string S.
925 Returns the modified string.
932 """Create the text for the function to process this query.
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.
942 limsel =
' and '.join ([
"len(%s)>=%d" % (self.
_iddict[p[0]], p[1])
947 sel = limsel +
" and (" + sel +
")"
949 ftext =
"def _loopfunc(_i, %s%s):\n" % (_evtvar, extargs)
951 ftext +=
" %s = %s.%s\n" % (id2, _evtvar, id1)
958 vars = l.itname (ids[0])
961 vars =
"(" +
','.
join([l.itname (id)
for id
in ids]) +
")"
962 lists = (
"zip(" +
','.
join([self.
_iddict[id]
for id
in ids])
965 vars =
"(%s,%s)" % (l.dumname(), vars)
966 lists =
"enumerate(%s)" % lists
967 ftext +=
' '*indent +
"for %s in %s:\n" % (vars, lists)
971 ftext +=
' '*indent + s +
'\n'
973 if sel
and sel !=
'1':
974 ftext +=
' '*indent +
"if (%s):\n" % sel
977 ftext +=
' '*indent +
"%s\n" % payload
986 """Holds the results of _get_bins. Defined attributes:
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.
1000 >>> from PyAnalysisUtils import pydraw
1001 >>> pydraw._globals = globals()
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)
1007 >>> b = _get_bins ([], 1, 0)
1008 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1010 >>> b = _get_bins (["!", "10"], 1, 0)
1011 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1013 >>> b = _get_bins (["!", "!", "10"], 1, 0)
1014 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1017 >>> b = _get_bins (["50", "0", "2*scale"], 1, 0)
1018 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1020 >>> b = _get_bins ([], 2, 0)
1021 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1023 >>> b = _get_bins ([], 2, 1)
1024 >>> print (b.nbins, b.lo, b.hi, b.rebin)
1026 >>> b = _get_bins ([], 2, 2)
1027 Traceback (most recent call last):
1032 g = copy.copy (_globals)
1037 if len(args) >= 1
and args[0] !=
'!' and len(args[0]) > 0:
1038 bins.nbins = int (eval (args[0], g))
1043 if len(args) >= 2
and args[1] !=
'!' and len(args[1]) > 0:
1044 bins.lo = float (eval (args[1], g))
1047 if len(args) >= 3
and args[2] !=
'!' and len(args[2]) > 0:
1048 bins.hi = float (eval (args[2], g))
1051 if bins.hi <= bins.lo:
1054 bins.hi = bins.lo + 1
1056 bins.lo = ROOT.gPad.GetUxmin()
1057 bins.hi = ROOT.gPad.GetUxmax()
1059 bins.lo = ROOT.gPad.GetUymin()
1060 bins.hi = ROOT.gPad.GetUymax()
1068 """Create a new histogram from options.
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.
1077 xbins = _get_bins (args, ndim, 0)
1082 ybins = _get_bins (args[3:], ndim, 1)
1083 rebin = rebin
or ybins.rebin
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":
1094 options =
' '.join (args[i:])
1098 hold = ROOT.gROOT.FindObject (hname)
1100 ROOT.gROOT.Remove (hold)
1104 hist = ROOT.TProfile (hname, htitle, xbins.nbins, xbins.lo, xbins.hi)
1106 hist.SetMinimum (ybins.lo)
1107 hist.SetMaximum (ybins.hi)
1109 hist = ROOT.TH1F (hname, htitle, xbins.nbins, xbins.lo, xbins.hi)
1111 hist = ScatterH2 (hname, htitle,
1112 xbins.nbins, xbins.lo, xbins.hi,
1113 ybins.nbins, ybins.lo, ybins.hi)
1114 if hasattr (hist,
'scatter'):
1121 return (hist, options)
1125 """Process a draw command.
1127 ARG is the command arguments (without the command word itself).
1128 See the header comments for the command syntax.
1140 if len (c.exprs) == 1:
1142 payload =
"_hfill (%s)" % c.exprs[0]
1145 payload =
"_hfill ((%s),(%s))" % (c.exprs[0], c.exprs[1])
1148 htitle =
"%s.%s" % (c.tuple, c.expr_orig)
1150 htitle = htitle +
'{%s}' % c.sel_orig
1154 if len(c.histspec) >= 1
and c.histspec[0] ==
"!" and last_hist
is not None:
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:])
1162 (hist, options) = _get_hist (ndim, c.histspec,
1170 g = copy.copy (_globals)
1171 g[
'_hfill'] = hist.Fill
1172 ftext = c._make_func (payload,
', _hfill = _hfill')
1176 c.tuple_o.loop (g[
'_loopfunc'], c.lo, c.hi)
1179 if _hasCanRebin (hist):
1180 hist.LabelsDeflate (
"X")
1182 hist.LabelsDeflate (
"Y")
1185 draw_obj (hist, options)
1190 """Helper to print out one row of a scan.
1192 I is the row number and ARGS is a tuple of the column values."""
1196 if isinstance(a, int):
1205 """Process a scan command.
1207 ARG is the command arguments (without the command word itself).
1208 See the header comments for the command syntax.
1217 payload =
"_print (_i, %s)" % \
1218 ','.join ([
'(%s)'%e
for e
in c.exprs])
1222 g = copy.copy (_globals)
1223 g[
'_print'] = _scan_print
1224 ftext = c._make_func (payload,
', _print = _print')
1228 c.tuple_o.loop (g[
'_loopfunc'], c.lo, c.hi)
1234 """Process a loop command.
1236 ARG is the command arguments (without the command word itself).
1237 See the header comments for the command syntax.
1246 payload =
"(%s,)" %
','.join (c.exprs)
1250 g = copy.copy (_globals)
1251 ftext = c._make_func (payload)
1255 c.tuple_o.loop (g[
'_loopfunc'], c.lo, c.hi)
1262 _cmddict = {
'd': draw,
1270 """Process a command S.
1272 Returns True if the command was handled, False otherwise.
1273 See the header comments for the command syntax.
1276 ssplit = s.split (
None, 1)
1283 func = _cmddict.get (cmd)
1302 if '_orig_ehook' not in globals():
1307 """Exception hook used by pydraw to process drawing commands."""
1310 if isinstance (value, SyntaxError):
1317 ROOT.gInterpreter.EndOfLineAction()
1321 _orig_ehook (exctype, value, traceb)
1325 """Enable entering drawing commands directly at the python prompt."""
1330 if _orig_ehook
is None:
1331 _orig_ehook = sys.excepthook
1334 sys.excepthook = _excepthook