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