![]() |
ATLAS Offline Software
|
Classes | |
| class | _Bins |
| class | _Loopvar |
| class | AthenaLoopWrapper |
| class | Draw_Cmd |
| class | TreeLoopWrapper |
Functions | |
| _setCanRebin (h) | |
| _hasCanRebin (h) | |
| _sanitize_hname (s) | |
| _untokenize (tokens) | |
| _find_outer (haystack, needle, ignore_delim=False) | |
| _split_outer (haystack, needle) | |
| _get_bins (args, ndim, axis) | |
| _get_hist (ndim, args, hname, htitle) | |
| draw (arg) | |
| _scan_print (i, *args) | |
| scan (arg) | |
| loop (arg) | |
| cmd (s) | |
| _excepthook (exctype, value, traceb) | |
| cmdhook () | |
Variables | |
| ScatterH2 = ROOT.RootUtils.ScatterH2 | |
| last_hist = None | |
| _globals = sys.modules['__main__'].__dict__ | |
| str | _idchars = string.ascii_letters + string.digits + '_' |
| str | _evtvar = '_ev' |
| bool | _debug = False |
| dict | _cmddict |
| _orig_ehook = None | |
| The stuff here sets things up so that after calling cmdhook(), the user can enter drawing commands directly at the python prompt. | |
Interactive python commands for plotting from a tuple-like object.
This module provides in python functionality similar to TTree::Draw
and TTree::Scan. The major conceptual differences are:
- All expressions are written in python (and not the specialized
TTree::Draw language).
- This can be applied to any type of object providing a simple loop
interface (explained below), not just to TTree's. (A TTree will work;
there is also a wrapper for the Athena event loop.)
In addition, this style of query may be somewhat
easier to type interactively.
Quick start
===========
Here are some examples of plotting commands to give you the flavor:
d tt.metx
d tt.ele_pt$i; 50 0 100*gev
d tt.metx:mety
d tt[100:1000].muo$i.pt() if abs(muo.eta)<2
d tt.(ele$i+ele$j).m() if $i<$j; same
scan tt.metx:mety
To use these commands, you can pass them as strings to pydraw.cmd:
from pydraw import cmd
cmd('d tt.metx')
Alternatively, if you execute the cmdhook function, you can type them
directly:
from pydraw import cmdhook
cmdhook()
d tt.metx
(Note that this second form doesn't work in general for code that's read
from a file.)
Draw syntax
===========
The general syntax for drawing a histogram looks like this:
d TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR] [; HISTSPEC]
These pieces are explained in more detail below.
Tuple specifications
--------------------
The object on which the draw operation is to be performed is given
by TUPLESPEC. This should be the name of some object in the python
global dictionary. Note that if the expression for the tuple
itself contains a period or brackets, you'll need to enclose it in parentheses:
d (trees.tt[1])[:100].ele_pt$i
Optionally, this can include a slice-like notation
to restrict the rows to which the draw applies:
tuple[i:j] --- process rows i <= n < j
tuple[:j] --- process rows n < j
tuple[i:] --- process rows n >= i
tuple[i] --- process row i
i and j can be expressions as well.
The tuple object should contain a method like this:
def loop (self, func, looplo, loophi)
This function should loop over rows [looplo, loophi) and
call func on each. func will take two arguments, the first
being the row number and the second being the event object
(which may just be the tuple itself).
If a method named loop is not available, but GetEntry and GetEntries
methods are available, then those will be used instead.
Similarly, if size and seekEvent are available, a wrapper
appropriate for the Athena event loop will be used.
Thus, you can make plots from within Athena like this:
d theApp.ElectronAODCollection$i.eta()
Expressions
-----------
Once a tuple is specified, one then needs to specify what to plot.
This is done with an arbitrary python expression, with some extensions.
To plot a simple numeric variable from the tuple, just give its name.
For example:
d tt.foo
will plot the variable `foo' from each row of the tuple. You can of course
also use more complicated expressions:
d tt.r*cos(phi)
In the common case, though, the members of the tuple will be vectors
of numbers of objects over which you want to iterate. You can iterate
plotting over such a vector by specifying a dummy index. This is an
identifier starting with a dollar sign:
d tt.pt_e$i
(Making the dummy indices explicit was a deliberate change from the
implicit iteration of root/paw. Such implicit iteration sometimes
caused confusion about just what was being iterated over, and also
when people needed to distinguish between accessing attributes
of a container and attributes of the contained objects.)
This will automatically step $i over the contents of the vector pt_e,
plotting each one. The vector being iterated over may contain objects
as well as numbers:
d tt.ele$i.pt()
Note that the limits of the iteration are handled automatically.
The index $i can also be used in contexts other than that of an index.
For example, to limit the iteration in the above example to the first
four items, one can use:
d tt.ele$i.pt() if $i<4
(This uses a selection clause. This is to be described later, but the meaning
should be obvious.)
If a dummy index is used for more than one vector, the iteration limit
will be taken from whichever vector is smaller. For example:
d tt.ele$i+muo$i
will iterate min(len(ele),len(muo)) times.
Multiple dummy indices may be used. In that case, all possible index
combinations are used (a simple nested loop). If there is a symmetry
involved, a selection clause may be used to eliminate duplicates.
For example (given an appropriate ele definition), this will plot the
invariant masses of all electron pairs:
d tt.(ele$i+ele$j).m() if $i>$j
One can also reference individual elements of a vector using the
notation $N. Here, the indexing is 1-based (so $1 is the first element).
Example: to plot the pt of the leading electron
d tt.ele$1.pt()
Note that one can do something similar just using standard python
indexing directly:
d tt.ele[0].pt()
This, however, will crash if ele is empty; if the $N form is used,
an implicit selection is added to ensure that the index is in range.
Thus, the proper equivalent of the $N-form example is:
d tt.ele[0].pt() if len(ele)>0
You can also use $nCONT as an abbreviation for len(CONT):
d tt.ele[0].pt() if $nele>0
Names used in expressions will be looked up first in the tuple object,
then in the global dictionary. Note that the lookup in the tuple happens
before looping starts, so all needed variables must already be present
in the tuple. If you want to refer to the tuple object itself,
you can use the special variable `_ev'. (This can be changed by assigning
a string to pydraw._evtvar.)
Multiple expressions may be given, separated by `:'. For drawing histograms,
you can give two expressions, for the x and y axis expressions. For scanning
tuples (see below), you give the list of expressions to be scanned.
Selections
----------
You can select items to be filled using a boolean expression, set off
with an `if' keyword:
d tt.ele$i.pt() if abs(ele$i.eta())<2
All dummy variables are common between the variable expressions
and the selection.
Statements
----------
You can specify arbitrary Python expressions to be executed before looping
starts. These come before the variables expressions, and are delimited
with `@'. This is useful mostly for defining short aliases for tuple
variables. For example:
d tt.ele=ElectronAODCollection@ele$i.eta() if ele$i.pt()>100*gev
Histogram specifications
------------------------
Histogram specifications follow a semicolon. They can have the forms:
! OPTIONS...
>>NAME OPTIONS...
NX XLO XHI OPTIONS...
NX XLO XHI NY YLO YHI OPTIONS...
OPTIONS...
For the first form, specifying ! reuses the same histogram that was used
for the last plot.
For the second form, specifying >>NAME looks in the global dictionary
for a histogram NAME and uses that.
Otherwise, a new histogram is created. The binning for this histogram
may be specified by NX XLO XHI and NY YLO YHI.
Plotting options may also be given. The special option `prof' means
to create a profile histogram. Otherwise, root drawing options may
be used. This package uses PyAnalysisUtils.draw_obj to draw the
histograms, so the extra options supported by that function may
also be used. See draw_obj.py for details.
The last histogram to have been drawn is available is pydraw.last_hist.
Scan syntax
===========
The scan command is very similar to draw:
scan TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR]
Instead of drawing a histogram, scan prints out a table of the expression
values.
The formatting of the data printed by scan is currently pretty rudimentary.
This should probably be improved.
Loop syntax
===========
There is also a loop command:
loop TUPLESPEC.[STMT@ ...]EXPR[:EXPR] [if EXPR]
Loop will evaluate the given expressions in the same manner as draw and scan,
but the results of this are ignored. So it only makes sense to use loop
to evaluate expressions for their side effects. This can be used,
for example, to call a function that fills some large set of histograms.
Running commands
================
The general interface to execute one of these commands is the `cmd' function,
which takes the command as a string:
from pydraw import cmd
cmd ('d tt.foo')
Each command is also implemented by a single function, which may be called
directly. The command name should not be included in this case:
from pydraw import draw
draw ('tt.foo')
Finally, if you call the function cmdhook(), then you can give the commands
directly on the python command line:
from pydraw import cmdhook
cmdhook()
d tt.foo
Bugs/stuff missing
==================
- No way to specify an event weight when filling a histogram using
the draw command.
- Hoist selection code out of the dummy index loops, when they don't
depend on the index? For example,
d tt.foo$i if ht>100
gets implemented like:
for _it_foo in foo:
if _ev.ht>100:
Fill(_it_foo)
but it would be more efficient to pull the selection out of the loop.
- In an expr like d em.foo$i if em.bar$i>1
then foo always gets evaluated even if the condition is false.
- Scan formatting.
|
protected |
Exception hook used by pydraw to process drawing commands.
Definition at line 1306 of file pydraw.py.
|
protected |
Look for NEEDLE in HAYSTACK (token-based. Return pair (HEAD, TAIL).
HAYSTACK and NEEDLE are both strings. Look for a token in HAYSTACK with
a value matching NEEDLE that is outside of any paired delimiters.
Also ignores things in strings.
If IGNORE_DELIM is True, then we do find things inside delimiters
(strings are still ignored).
Returns a pair (HEAD, TAIL) of the pieces of the string before and
after NEEDLE. If there is no match, returns (HAYSTACK, None).
Note that whitespace and formatting in HEAD and TAIL may differ
from the original string.
Examples:
>>> _find_outer ("head.tail1.tail2", ".")
('head', 'tail1.tail2')
>>> _find_outer ("(head.tail1).tail2", ".")
('(head.tail1)', 'tail2')
>>> _find_outer ("[a for a in foo if good(a)] if bar", "if")
('[a for a in foo if good(a)]', 'bar')
>>> _find_outer ("(a [b {c . d } ] ) . e", ".")
('(a [b {c . d } ] )', 'e')
>>> _find_outer ("a.b", ";")
('a.b', None)
>>> _find_outer ("a '$' b", '$')
("a '$' b", None)
>>> _find_outer ("a $ b", '$')
('a', 'b')
>>> _find_outer ("(head.tail1).tail2", ".", True)
('(head', 'tail1).tail2')
>>> _find_outer ('a; 1 -1 1', ';')
('a', '1 -1 1')
Definition at line 425 of file pydraw.py.
|
protected |
Parse bin specifications from split list of arguments ARGS.
NDIM is 1 or 2, and AXIS is 0 or 1, for the x or y axis.
Examples:
>>> from PyAnalysisUtils import pydraw
>>> pydraw._globals = globals()
>>> import ROOT
>>> ROOT.gPad.Range(0, 1,2,3)
>>> b = _get_bins (["50", "10", "100"], 1, 0)
>>> print (b.nbins, b.lo, b.hi, b.rebin)
50 10.0 100.0 0
>>> b = _get_bins ([], 1, 0)
>>> print (b.nbins, b.lo, b.hi, b.rebin)
50 0 1 1
>>> b = _get_bins (["!", "10"], 1, 0)
>>> print (b.nbins, b.lo, b.hi, b.rebin)
50 10.0 11.0 1
>>> b = _get_bins (["!", "!", "10"], 1, 0)
>>> print (b.nbins, b.lo, b.hi, b.rebin)
50 0 10.0 0
>>> scale = 10
>>> b = _get_bins (["50", "0", "2*scale"], 1, 0)
>>> print (b.nbins, b.lo, b.hi, b.rebin)
50 0.0 20.0 0
>>> b = _get_bins ([], 2, 0)
>>> print (b.nbins, b.lo, b.hi, b.rebin)
50 0.0 2.0 1
>>> b = _get_bins ([], 2, 1)
>>> print (b.nbins, b.lo, b.hi, b.rebin)
50 1.0 3.0 1
>>> b = _get_bins ([], 2, 2)
Traceback (most recent call last):
...
AssertionError
Definition at line 995 of file pydraw.py.
|
protected |
Create a new histogram from options. NDIM is the dimensionality of the histogram (1 or 2). ARGS is a list of the arguments given to specify the histogram. HNAME and HTITLE are the histogram name and title, respectively.
Definition at line 1067 of file pydraw.py.
|
protected |
|
protected |
Name a string safe to use as a histogram name.
Root does bad things if you put / in a histogram name, so we remove them.
Examples:
>>> print (_sanitize_hname('foo'))
foo
>>> print (_sanitize_hname('foo/bar'))
foo DIV bar
Definition at line 371 of file pydraw.py.
|
protected |
Helper to print out one row of a scan. I is the row number and ARGS is a tuple of the column values.
Definition at line 1189 of file pydraw.py.
|
protected |
|
protected |
Split HAYSTACK at the delimiters NEEDLE, as in _find_outer.
Examples:
>>> _split_outer ("a,(b,c),d", ",")
['a', '(b,c)', 'd']
>>> _split_outer ("a,,b", ",")
['a', '', 'b']
>>> _split_outer ("a", ",")
['a']
>>> #_split_outer ("", ",")
[]
Definition at line 481 of file pydraw.py.
|
protected |
Transform tokens back into Python source code.
Each element returned by the iterable must be a token sequence
with at least two elements, a token number and token value.
Unlike tokenize.untokenize(), this does not handle multiple lines.
It also tries not to add unneeded spaces.
Examples:
>>> from tokenize import generate_tokens, untokenize
>>> from io import StringIO
>>> def untokenize1(tt):
... tt=list(tt)
... if tt[-1][0]==0: tt=tt[:-1]
... return untokenize(tt)
>>> untokenize1(generate_tokens(StringIO('1+1').readline))
'1+1'
>>> _untokenize(generate_tokens(StringIO('1+1').readline))
'1+1'
>>> untokenize1(generate_tokens(StringIO('foo$i>2*h').readline))
'foo$i>2*h'
>>> _untokenize(generate_tokens(StringIO('foo$i>2*h').readline))
'foo$i>2*h'
Definition at line 384 of file pydraw.py.
| python.pydraw.cmd | ( | s | ) |
Process a command S. Returns True if the command was handled, False otherwise. See the header comments for the command syntax.
Definition at line 1269 of file pydraw.py.
| python.pydraw.cmdhook | ( | ) |
Enable entering drawing commands directly at the python prompt.
Definition at line 1324 of file pydraw.py.
| python.pydraw.draw | ( | arg | ) |
Process a draw command. ARG is the command arguments (without the command word itself). See the header comments for the command syntax.
Definition at line 1124 of file pydraw.py.
| python.pydraw.loop | ( | arg | ) |
Process a loop command. ARG is the command arguments (without the command word itself). See the header comments for the command syntax.
Definition at line 1233 of file pydraw.py.
| python.pydraw.scan | ( | arg | ) |
Process a scan command. ARG is the command arguments (without the command word itself). See the header comments for the command syntax.
Definition at line 1204 of file pydraw.py.
|
protected |
|
protected |
|
protected |
|
protected |