Browse Source

Removes python subproject which has now been moved to filval-python

Caleb Fangmeier 6 years ago
parent
commit
8ec9c7a1be

+ 0 - 4
python/.flake8

@@ -1,4 +0,0 @@
-
-[flake8]
-ignore = E248, E241, E226, E402, E701, E402, E202
-max_line_length=120

+ 0 - 8
python/.gitignore

@@ -1,8 +0,0 @@
-figures/
-env/
-build/
-dist/
-
-__pycache__/
-.ipynb_checkpoints/
-*.egg-info/

+ 0 - 0
python/filval/__init__.py


+ 0 - 103
python/filval/graph_vals.py

@@ -1,103 +0,0 @@
-import pydotplus.graphviz as pdp
-
-
-def parse(str_in, alias=None):
-    """ Creates a call-tree for the supplied value name
-    """
-    str_in = "("+str_in+")"
-
-    functions = []
-    ends = {}
-    nests = {}
-    names = {}
-    styles = {}
-    parens = []
-    name = ""
-    name_start = 0
-    name_end = 0
-    for i, char in enumerate(str_in):
-        if char == "(":
-            nests[name_start] = []
-            if parens:
-                nests[parens[-1]].append(name_start)
-            names[name_start] = name  # save function name
-            styles[name_start] = {"shape": "ellipse"}
-            name = ""
-            parens.append(name_start)
-        elif char == ")":
-            if name:
-                ends[name_start] = name_end
-                names[name_start] = name
-                styles[name_start] = {"shape": "rectangle"}
-                nests[parens[-1]].append(name_start)
-                name = ""
-            ends[parens.pop()] = i
-        elif char in ",:":
-            if name:
-                ends[name_start] = name_end
-                names[name_start] = name
-                if char == ",":
-                    styles[name_start] = {"shape": "rectangle"}
-                else:
-                    styles[name_start] = {"shape": "invhouse"}
-                    functions.append(name)
-                nests[parens[-1]].append(name_start)
-                name = ""
-        else:
-            if not name:
-                name_start = i
-            name += char
-            name_end = i
-
-    # clean up duplicate sub-trees
-    text = {}
-    for start, end in ends.items():
-        s = str_in[start:end+1]
-        if s in text:
-            dup_id = text[s]
-            names.pop(start)
-            if start in nests:
-                nests.pop(start)
-            for l in nests.values():
-                for i in range(len(l)):
-                    if l[i] == start:
-                        l[i] = dup_id
-        else:
-            text[s] = start
-
-    names.pop(0)
-    nests.pop(0)
-
-    g = pdp.Dot()
-
-    for id_, name in names.items():
-        g.add_node(pdp.Node(str(id_), label=name, **styles[id_]))
-    for group_id, children in nests.items():
-        for child_id in children:
-            g.add_edge(pdp.Edge(str(group_id), str(child_id)))
-    if alias:
-        g.add_node(pdp.Node(alias, shape="plain", pos="0,0!"))
-    return g, functions
-
-
-if __name__ == '__main__':
-    import re
-    import sys
-    aliases = {}
-    ali_re = re.compile(r"ALIAS::\"([^\"]*)\" referring to \"([^\"]*)\"")
-
-    with open(sys.argv[1]) as f:
-        for line in f.readlines():
-            res = ali_re.findall(line)
-            if res:
-                aliases[res[0][1]] = res[0][0]
-                continue
-    for name, alias in aliases.items():
-        graph, _ = parse(name, alias)
-        fname = "val_graph_{}.gif".format(alias)
-        with open(fname, "wb") as f:
-            try:
-                f.write(graph.create_gif())
-            except Exception as e:
-                print(e)
-                print(graph.to_string())

+ 0 - 154
python/filval/histogram_utils.py

@@ -1,154 +0,0 @@
-'''
-    histogram_utils.py
-    The functions in this module use a representation of a histogram that is a
-    tuple containing an arr of N bin values, an array of N bin errors(symmetric)
-    and an array of N+1 bin edges(N lower edges + 1 upper edge).
-
-    For 2d histograms, It is similar, but the arrays are two dimensional and
-    there are separate arrays for x-edges and y-edges.
-'''
-
-import numpy as np
-from scipy.optimize import curve_fit
-
-
-def hist(th1, rescale_x=1.0, rescale_y=1.0):
-    nbins = th1.GetNbinsX()
-
-    edges = np.zeros(nbins+1, np.float32)
-    values = np.zeros(nbins, np.float32)
-    errors = np.zeros(nbins, np.float32)
-
-    for i in range(nbins):
-        edges[i] = th1.GetXaxis().GetBinLowEdge(i+1)
-        values[i] = th1.GetBinContent(i+1)
-        errors[i] = th1.GetBinError(i+1)
-
-    edges[nbins] = th1.GetXaxis().GetBinUpEdge(nbins)
-    edges *= rescale_x
-    values *= rescale_y
-    errors *= rescale_y
-    return values, errors, edges
-
-
-def hist_bin_centers(h):
-    _, _, edges = h
-    return (edges[:-1] + edges[1:])/2.0
-
-
-def hist2d(th2, rescale_x=1.0, rescale_y=1.0, rescale_z=1.0):
-    """ Converts TH2 object to something amenable to
-        plotting w/ matplotlab's pcolormesh.
-    """
-    nbins_x = th2.GetNbinsX()
-    nbins_y = th2.GetNbinsY()
-    print(nbins_x, nbins_y)
-    xs = np.zeros((nbins_y+1, nbins_x+1), np.float32)
-    ys = np.zeros((nbins_y+1, nbins_x+1), np.float32)
-    values = np.zeros((nbins_y, nbins_x), np.float32)
-    errors = np.zeros((nbins_y, nbins_x), np.float32)
-    for i in range(nbins_x):
-        for j in range(nbins_y):
-            xs[j][i] = th2.GetXaxis().GetBinLowEdge(i+1)
-            ys[j][i] = th2.GetYaxis().GetBinLowEdge(j+1)
-            values[j][i] = th2.GetBinContent(i+1, j+1)
-            errors[j][i] = th2.GetBinError(i+1, j+1)
-        xs[nbins_y][i] = th2.GetXaxis().GetBinUpEdge(i)
-        ys[nbins_y][i] = th2.GetYaxis().GetBinUpEdge(nbins_y)
-    for j in range(nbins_y+1):
-        xs[j][nbins_x] = th2.GetXaxis().GetBinUpEdge(nbins_x)
-        ys[j][nbins_x] = th2.GetYaxis().GetBinUpEdge(j)
-
-    xs *= rescale_x
-    ys *= rescale_y
-    values *= rescale_z
-    errors *= rescale_z
-
-    return values, errors, xs, ys
-
-
-def hist_slice(hist, range_):
-    values, errors, edges = hist
-    lim_low, lim_high = range_
-    slice_ = np.logical_and(edges[:-1] > lim_low, edges[1:] < lim_high)
-    last = len(slice_) - np.argmax(slice_[::-1])
-    return (values[slice_],
-            errors[slice_],
-            np.concatenate([edges[:-1][slice_], [edges[last]]]))
-
-
-def hist_add(*hists):
-    if len(hists) == 0:
-        return np.zeros(0)
-    vals, errs, edges = zip(*hists)
-    return np.sum(vals, axis=0), np.sqrt(np.sum([err*err for err in errs], axis=0)), edges[0]
-
-
-def hist_integral(hist, times_bin_width=True):
-    values, errors, edges = hist
-    if times_bin_width:
-        bin_widths = [abs(x2 - x1) for x1, x2 in zip(edges[:-1], edges[1:])]
-        return sum(val*width for val, width in zip(values, bin_widths))
-    else:
-        return sum(values)
-
-def hist_scale(hist, scale):
-    values, errors, edges = hist
-    return values*scale, errors*scale, edges
-
-def hist_normalize(hist, norm = 1):
-    scale = norm/np.sum(hist[0])
-    return hist_scale(hist, scale)
-
-
-
-def hist_mean(hist):
-    xs = hist_bin_centers(hist)
-    ys, _, _ = hist
-    return sum(x*y for x, y in zip(xs, ys)) / sum(ys)
-
-
-def hist_var(hist):
-    xs = hist_bin_centers(hist)
-    ys, _, _ = hist
-    mean = sum(x*y for x, y in zip(xs, ys)) / sum(ys)
-    mean2 = sum((x**2)*y for x, y in zip(xs, ys)) / sum(ys)
-    return mean2 - mean**2
-
-
-def hist_std(hist):
-    return np.sqrt(hist_var(hist))
-
-
-def hist_stats(hist):
-    return {'int': hist_integral(hist),
-            'sum': hist_integral(hist, False),
-            'mean': hist_mean(hist),
-            'var': hist_var(hist),
-            'std': hist_std(hist)}
-
-
-# def hist_slice2d(h, range_):
-#     values, errors, xs, ys = h
-
-#     last = len(slice_) - np.argmax(slice_[::-1])
-
-#     (xlim_low, xlim_high), (ylim_low, ylim_high) = range_
-#     slice_ = np.logical_and(xs[:-1, :-1] > xlim_low, xs[1:, 1:] < xlim_high,
-#                             ys[:-1, :-1] > ylim_low, ys[1:, 1:] < ylim_high)
-#     last = len(slice_) - np.argmax(slice_[::-1])
-#     return (values[slice_],
-#             errors[slice_],
-#             np.concatenate([edges[:-1][slice_], [edges[last]]]))
-
-
-def hist_fit(h, f, p0=None):
-    values, errors, edges = h
-    xs = hist_bin_centers(h)
-    # popt, pcov = curve_fit(f, xs, values, p0=p0, sigma=errors)
-    popt, pcov = curve_fit(f, xs, values, p0=p0)
-    return popt, pcov
-
-
-def hist_rebin(hist, range_, nbins):
-    raise NotImplementedError()

+ 0 - 375
python/filval/plotter.py

@@ -1,375 +0,0 @@
-#!/usr/bin/env python3
-
-from collections import defaultdict
-from itertools import zip_longest
-from io import BytesIO
-from base64 import b64encode
-import numpy as np
-import matplotlib.pyplot as plt
-from markdown import Markdown
-import latexipy as lp
-
-from filval.histogram_utils import (hist, hist2d, hist_bin_centers, hist_fit,
-                                    hist_normalize, hist_stats)
-
-__all__ = ['Plot',
-           'decl_plot',
-           'grid_plot',
-           'render_plots',
-           'generate_dashboard',
-           'hist_plot',
-           'hist_plot_stack',
-           'hist2d_plot',
-           'hists_to_table']
-
-
-class Plot:
-    def __init__(self, subplots, name, title=None, docs="N/A", arg_dicts=None):
-        self.subplots = subplots
-        self.name = name
-        self.title = title
-        self.docs = docs
-        self.arg_dicts = arg_dicts if arg_dicts is not None else {}
-
-
-MD = Markdown(extensions=['mdx_math'],
-              extension_configs={'mdx_math': {'enable_dollar_delimiter': True}})
-
-lp.latexify(params={'pgf.texsystem': 'pdflatex',
-                    'text.usetex': True,
-                    'font.family': 'serif',
-                    'pgf.preamble': [],
-                    'font.size': 15,
-                    'axes.labelsize': 15,
-                    'axes.titlesize': 13,
-                    'legend.fontsize': 13,
-                    'xtick.labelsize': 11,
-                    'ytick.labelsize': 11,
-                    'figure.dpi': 150,
-                    'savefig.transparent': False,
-                    },
-            new_backend='TkAgg')
-
-
-def _fn_call_to_dict(fn, *args, **kwargs):
-    from inspect import signature
-    from html import escape
-    pnames = list(signature(fn).parameters)
-    pvals = list(args) + list(kwargs.values())
-    return {escape(str(k)): escape(str(v)) for k, v in zip(pnames, pvals)}
-
-
-def _process_docs(fn):
-    from inspect import getdoc
-    raw = getdoc(fn)
-    if raw:
-        return MD.convert(raw)
-    else:
-        return None
-
-
-def decl_plot(fn):
-    from functools import wraps
-
-    @wraps(fn)
-    def f(*args, **kwargs):
-        txt = fn(*args, **kwargs)
-        argdict = _fn_call_to_dict(fn, *args, **kwargs)
-        docs = _process_docs(fn)
-        if not txt:
-            txt = ''
-        txt = MD.convert(txt)
-
-        return argdict, docs, txt
-
-    return f
-
-
-def generate_dashboard(plots, title, output='dashboard.html', template='dashboard.j2', source_file=None, ana_source=None):
-    from jinja2 import Environment, PackageLoader, select_autoescape
-    from os.path import join, isdir
-    from os import mkdir
-    from urllib.parse import quote
-
-    env = Environment(
-        loader=PackageLoader('filval', 'templates'),
-        autoescape=select_autoescape(['htm', 'html', 'xml']),
-    )
-    env.globals.update({'quote': quote,
-                        'enumerate': enumerate,
-                        'zip': zip,
-                        })
-
-    def get_by_n(objects, n=2):
-        objects = list(objects)
-        while objects:
-            yield objects[:n]
-            objects = objects[n:]
-
-    if source_file is not None:
-        with open(source_file, 'r') as this_file:
-            source = this_file.read()
-    else:
-        source = "# Not supplied!!"
-
-    if not isdir('output'):
-        mkdir('output')
-
-    with open(join('output', output), 'w') as tempout:
-        templ = env.get_template(template)
-        tempout.write(templ.render(
-            plots=get_by_n(plots, 3),
-            title=title,
-            source=source,
-            ana_source=ana_source
-        ))
-
-
-def _add_stats(hist, title=''):
-    fmt = r'''\begin{{eqnarray*}}
-\sum{{x_i}} &=& {sum:5.3f}                  \\
-\sum{{\Delta x_i \cdot x_i}} &=& {int:5.3G} \\
-\mu &=& {mean:5.3G}                         \\
-\sigma^2 &=& {var:5.3G}                     \\
-\sigma &=& {std:5.3G}
-\end{{eqnarray*}}'''
-
-    txt = fmt.format(**hist_stats(hist), title=title)
-    txt = txt.replace('\n', ' ')
-
-    plt.text(0.7, 0.9, txt,
-             bbox={'facecolor': 'white',
-                   'alpha': 0.7,
-                   'boxstyle': 'square,pad=0.8'},
-             transform=plt.gca().transAxes,
-             verticalalignment='top',
-             horizontalalignment='left',
-             size='small')
-    if title:
-        plt.text(0.72, 0.97, title,
-                 bbox={'facecolor': 'white',
-                       'alpha': 0.8},
-                 transform=plt.gca().transAxes,
-                 verticalalignment='top',
-                 horizontalalignment='left')
-
-
-def grid_plot(subplots):
-    if any(len(row) != len(subplots[0]) for row in subplots):
-        raise ValueError('make_plot requires a rectangular list-of-lists as '
-                         'input. Fill empty slots with None')
-
-    def calc_row_span(fig, row, col):
-        span = 1
-        for r in range(row + 1, len(fig)):
-            if fig[r][col] == 'FU':
-                span += 1
-            else:
-                break
-        return span
-
-    def calc_column_span(fig, row, col):
-        span = 1
-        for c in range(col + 1, len(fig[row])):
-            if fig[row][c] == 'FL':
-                span += 1
-            else:
-                break
-        return span
-
-    rows = len(subplots)
-    cols = len(subplots[0])
-
-    argdicts = defaultdict(list)
-    docs = defaultdict(list)
-    txts = defaultdict(list)
-    for i in range(rows):
-        for j in range(cols):
-            cell = subplots[i][j]
-            if cell in ('FL', 'FU', None):
-                continue
-            if not isinstance(cell, list):
-                cell = [cell]
-            column_span = calc_column_span(subplots, i, j)
-            row_span = calc_row_span(subplots, i, j)
-            plt.subplot2grid((rows, cols), (i, j),
-                             colspan=column_span, rowspan=row_span)
-            for plot in cell:
-                if len(plot) == 1:
-                    plot_fn, args, kwargs = plot[0], (), {}
-                elif len(plot) == 2:
-                    plot_fn, args, kwargs = plot[0], plot[1], {}
-                elif len(plot) == 3:
-                    plot_fn, args, kwargs = plot[0], plot[1], plot[2]
-                else:
-                    raise ValueError('Plot tuple must be of format (func), '
-                                     f'or (func, tuple), or (func, tuple, dict). Got {plot}')
-                this_args, this_docs, txt = plot_fn(*args, **kwargs)
-                argdicts[(i, j)].append(this_args)
-                docs[(i, j)].append(this_docs)
-                txts[(i, j)].append(txt)
-    return argdicts, docs, txts
-
-
-def render_plots(plots, exts=('png',), scale=1.0, to_disk=True):
-    for plot in plots:
-        print(f'Building plot {plot.name}')
-        plot.data = None
-        if to_disk:
-            with lp.figure(plot.name.replace(' ', '_'), directory='output/figures',
-                           exts=exts,
-                           size=(scale * 10, scale * 10)):
-                argdicts, docs, txts = grid_plot(plot.subplots)
-        else:
-            out = BytesIO()
-            with lp.mem_figure(out,
-                               ext=exts[0],
-                               size=(scale * 10, scale * 10)):
-                argdicts, docs, txts = grid_plot(plot.subplots)
-            out.seek(0)
-            plot.data = b64encode(out.read()).decode()
-        plot.argdicts = argdicts
-        plot.docs = docs
-        plot.txts = txts
-
-
-def add_decorations(axes, luminosity, energy):
-    cms_prelim = r'{\raggedright{}\textsf{\textbf{CMS}}\\ \emph{Preliminary}}'
-    axes.text(0.01, 0.98, cms_prelim,
-              horizontalalignment='left',
-              verticalalignment='top',
-              transform=axes.transAxes)
-
-    lumi = ""
-    energy_str = ""
-    if luminosity is not None:
-        lumi = r'${} \mathrm{{fb}}^{{-1}}$'.format(luminosity)
-    if energy is not None:
-        energy_str = r'({} TeV)'.format(energy)
-
-    axes.text(1, 1, ' '.join([lumi, energy_str]),
-              horizontalalignment='right',
-              verticalalignment='bottom',
-              transform=axes.transAxes)
-
-
-def hist_plot(h, *args, norm=None, include_errors=False,
-              log=False, xlim=None, ylim=None, fit=None,
-              grid=False, stats=False, **kwargs):
-    """ Plots a 1D ROOT histogram object using matplotlib """
-    from inspect import signature
-    if norm:
-        h = hist_normalize(h, norm)
-    values, errors, edges = h
-
-    scale = 1. if norm is None else norm / np.sum(values)
-    values = [val * scale for val in values]
-    errors = [val * scale for val in errors]
-
-    left, right = np.array(edges[:-1]), np.array(edges[1:])
-    x = np.array([left, right]).T.flatten()
-    y = np.array([values, values]).T.flatten()
-
-    ax = plt.gca()
-
-    ax.set_xlabel(kwargs.pop('xlabel', ''))
-    ax.set_ylabel(kwargs.pop('ylabel', ''))
-    title = kwargs.pop('title', '')
-    if xlim is not None:
-        ax.set_xlim(xlim)
-    if ylim is not None:
-        ax.set_ylim(ylim)
-    # elif not log:
-    #     axes.set_ylim((0, None))
-
-    ax.plot(x, y, *args, linewidth=1, **kwargs)
-    if include_errors:
-        ax.errorbar(hist_bin_centers(h), values, yerr=errors,
-                    color='k', marker=None, linestyle='None',
-                    barsabove=True, elinewidth=.7, capsize=1)
-    if log:
-        ax.set_yscale('log')
-    if fit:
-        f, p0 = fit
-        popt, pcov = hist_fit(h, f, p0)
-        fit_xs = np.linspace(x[0], x[-1], 100)
-        fit_ys = f(fit_xs, *popt)
-        ax.plot(fit_xs, fit_ys, '--g')
-        arglabels = list(signature(f).parameters)[1:]
-        label_txt = "\n".join('{:7s}={: 0.2G}'.format(label, value)
-                              for label, value in zip(arglabels, popt))
-        ax.text(0.60, 0.95, label_txt, va='top', transform=ax.transAxes,
-                fontsize='medium', family='monospace', usetex=False)
-    if stats:
-        _add_stats(h, title)
-    else:
-        ax.set_title(title)
-    ax.grid(grid, color='#E0E0E0')
-
-
-def hist2d_plot(h, **kwargs):
-    """ Plots a 2D ROOT histogram object using matplotlib """
-    try:
-        values, errors, xs, ys = h
-    except (TypeError, ValueError):
-        values, errors, xs, ys = hist2d(h)
-
-    plt.xlabel(kwargs.pop('xlabel', ''))
-    plt.ylabel(kwargs.pop('ylabel', ''))
-    plt.title(kwargs.pop('title', ''))
-    plt.pcolormesh(xs, ys, values, )
-    # axes.colorbar() TODO: Re-enable this
-
-
-def hist_plot_stack(hists: list, labels: list = None):
-    """
-    Creates a stacked histogram in the current axes.
-
-    :param hists: list of histogram
-    :param labels:
-    :return:
-    """
-    if len(hists) == 0:
-        return
-
-    if len(set([len(hist[0]) for hist in hists])) != 1:
-        raise ValueError("all histograms must have the same number of bins")
-    if labels is None:
-        labels = [None for _ in hists]
-    if len(labels) != len(hists):
-        raise ValueError("Label mismatch")
-
-    bottoms = [0 for _ in hists[0][0]]
-
-    for hist, label in zip(hists, labels):
-        centers = []
-        widths = []
-        heights = []
-        for left, right, content in zip(hist[2][:-1], hist[2][1:], hist[0]):
-            centers.append((right + left) / 2)
-            widths.append(right - left)
-            heights.append(content)
-
-        plt.bar(centers, heights, widths, bottoms, label=label)
-        for i, content in enumerate(hist[0]):
-            bottoms[i] += content
-
-
-def hists_to_table(hists, row_labels=(), column_labels=(), format="{:.2f}"):
-    table = ['<table class="table table-condensed">']
-    if column_labels:
-        table.append('<thead><tr>')
-        if row_labels:
-            table.append('<th></th>')
-        table.extend(f'<th>{label}</th>' for label in column_labels)
-        table.append('</tr></thead>')
-    table.append('<tbody>\n')
-    for row_label, (vals, *_) in zip_longest(row_labels, hists):
-        table.append('<tr>')
-        if row_label:
-            table.append(f'<td><strong>{row_label}</strong></td>')
-        table.extend(('<td>'+format.format(val)+'</td>') for val in vals)
-        table.append('</tr>\n')
-    table.append('</tbody></table>')
-    return ''.join(table)
-

+ 0 - 86
python/filval/result_set.py

@@ -1,86 +0,0 @@
-import ROOT
-
-from filval.plotter import hist_plot, hist2d_plot
-from numpy import ceil
-
-
-class ResultSet:
-
-    def __init__(self, sample_name, input_filename):
-        self.sample_name = sample_name
-        self.input_filename = input_filename
-        self.load_objects()
-
-        ResultSet.add_collection(self)
-
-    def load_objects(self):
-        file = ROOT.TFile.Open(self.input_filename)
-        l = file.GetListOfKeys()
-        self.map = {}
-        try:
-            self.values = dict(file.Get("_value_lookup"))
-        except Exception:
-            self.values = {}
-        for i in range(l.GetSize()):
-            name = l.At(i).GetName()
-            new_name = ":".join((self.sample_name, name))
-            obj = file.Get(name)
-            try:
-                obj.SetName(new_name)
-                obj.SetDirectory(0)  # disconnects Object from file
-            except AttributeError:
-                pass
-            if 'ROOT.vector<int>' in str(type(obj)) and '_count' in name:
-                obj = obj[0]
-            self.map[name] = obj
-            setattr(self, name, obj)
-        file.Close()
-
-        # Now add these histograms into the current ROOT directory (in memory)
-        # and remove old versions if needed
-        for obj in self.map.values():
-            try:
-                old_obj = ROOT.gDirectory.Get(obj.GetName())
-                ROOT.gDirectory.Remove(old_obj)
-                ROOT.gDirectory.Add(obj)
-            except AttributeError:
-                pass
-
-    @classmethod
-    def calc_shape(cls, n_plots):
-        if n_plots > 3:
-            return ceil(n_plots / 3), 3
-        else:
-            return 1, n_plots
-
-    def draw(self, figure=None, shape=None):
-        objs = [(name, obj) for name, obj in self.map.items() if isinstance(obj, ROOT.TH1)]
-        shape = self.calc_shape(len(objs))
-        if figure is None:
-            import matplotlib.pyplot as plt
-            figure = plt.gcf() if plt.gcf() is not None else plt.figure()
-        figure.clear()
-        for i, (name, obj) in enumerate(objs):
-            axes = figure.add_subplot(*shape, i+1)
-            if isinstance(obj, ROOT.TH2):
-                hist2d_plot(obj, title=obj.GetTitle(), axes=axes)
-            else:
-                hist_plot(obj, title=obj.GetTitle(), axes=axes)
-        figure.tight_layout()
-
-    @classmethod
-    def get_hist_set(cls, attrname):
-        return [(sample_name, getattr(h, attrname))
-                for sample_name, h in cls.collections.items()]
-
-    @classmethod
-    def add_collection(cls, hc):
-        if not hasattr(cls, "collections"):
-            cls.collections = {}
-        cls.collections[hc.sample_name] = hc
-
-    def __str__(self):
-        return self.sample_name+"@"+self.input_filename
-
-    def __repr__(self):
-        return f"<ResultSet: input_filename: {self.input_filename}>"

+ 0 - 127
python/filval/templates/dashboard.j2

@@ -1,127 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-  <title>{{ title }}</title>
-  <meta charset="utf-8">
-  <meta name="viewport" content="width=device-width, initial-scale=2">
-  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
-  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
-  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
-
-  <script src="https://tttt.fangmeier.tech/hl/shCore.js"         type="text/javascript"></script>
-  <script src="https://tttt.fangmeier.tech/hl/shBrushPython.js" type="text/javascript"></script>
-  <link href="https://tttt.fangmeier.tech/hl/shCore.css"          rel="stylesheet" type="text/css" />
-  <link href="https://tttt.fangmeier.tech/hl/shThemeDefault.css"  rel="stylesheet" type="text/css" />
-  <script src="https://tttt.fangmeier.tech/hl/shAutoloader.js" type="text/javascript"></script>
-
-<script type="text/x-mathjax-config">
-MathJax.Hub.Config({
-  config: ["MMLorHTML.js"],
-  jax: ["input/TeX", "output/HTML-CSS", "output/NativeMML"],
-  extensions: ["MathMenu.js", "MathZoom.js"]
-});
-</script>
-<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML-full"> </script>
-</head>
-<body>
-<div class="container-fluid">
-{% for r, plot_row in enumerate(plots) %}
-  <div class="row">
-  {% for c, plot in enumerate(plot_row) %}
-    <div class="col-md-4">
-      <div class="well">
-    {% if plot.title %}
-        <h3 class="text-center">{{ plot.title }}</h3>
-    {% endif %}
-        <div>
-          <a href="#" title="{{ plot.name }}">
-            <img src="data:img/png;base64,{{ plot.data }}" style="width:100%" class="thumbnail img-responsive">
-          </a>
-        </div>
-        <div class="caption">
-          <p class="text-center"> {{ plot.name }} </p>
-          <div class="panel-group" id="accordion{{ r }}{{ c }}">
-    {% for id, (i,j) in enumerate(plot.docs.keys()) %}
-            <div class="panel-heading">
-              <h4 class="panel-title">
-                <button data-toggle="collapse" data-parent="#accordion{{ r }}{{ c }}" class="btn btn-info" href="#collapse{{r}}-{{c}}-{{id}}">
-                  Plot at ({{ i+1 }}, {{ j+1 }})</button>
-              </h4>
-            </div>
-            <div id="collapse{{r}}-{{c}}-{{id}}" class="panel-collapse collapse">
-              <div class="panel-body">
-      {% for doc, argdict, txt in zip(plot.docs[(i,j)], plot.argdicts[(i,j)], plot.txts[(i,j)]) %}
-                <div class="text-left">{{ doc|safe }}</div>
-                <div class="text-left">{{ txt|safe }}</div>
-                <hr>
-                <p class="text-left"><strong>Plot Arguments</strong></p>
-                <table class="table table-hover">
-                  <tbody>
-        {% for key, val in argdict.items() %}
-                    <tr>
-                      <td>{{ key }}</td> <td>{{ val }}</td>
-                    </tr>
-        {% endfor %}
-                  </tbody>
-                </table>
-      {% endfor %}
-              </div>
-            </div>
-    {% endfor %}
-          </div>
-        </div>
-      </div>
-    </div>
-  {% endfor %}
-  </div>
-{% endfor %}
-  <div class="row">
-    <div class="col-12-lg">
-      <div class="panel-group" id="accordion">
-        <div class="panel-heading">
-          <h4 class="panel-title" style="text-align:center">
-            <button data-toggle="collapse" data-parent="#accordion" class="btn btn-default" href="#collapseSrc">Figure Source Code</button>
-            {% if ana_source %}
-            <a class="btn btn-default" href="{{ ana_source }}" target="_blank">Analysis Source Code</a>
-            {% endif %}
-          </h4>
-        </div>
-        <div id="collapseSrc" class="panel-collapse collapse">
-          <div class="panel-body">
-<script type="syntaxhighlighter" class="brush: python"><![CDATA[ {{ source|safe}} ]]></script>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-</div>
-<div id="myModal" class="modal fade" tabindex="-1" role="dialog">
-  <div class="modal-dialog modal-lg">
-    <div class="modal-content">
-      <div class="modal-header">
-        <button type="button" class="close" data-dismiss="modal">×</button>
-        <h3 class="modal-title">Heading</h3>
-      </div>
-      <div class="modal-body">
-
-      </div>
-   </div>
-  </div>
-</div>
-</body>
-<style>
-.modal-dialog {width:900px;}
-.thumbnail {margin-bottom:6px;}
-.modal-title {text-align:center;}
-</style>
-<script>
-$('.thumbnail').click(function(){
-    $('.modal-body').empty();
-    var title = $(this).parent('a').attr("title");
-    $('.modal-title').html(title);
-    $($(this).parents('div').html()).appendTo('.modal-body');
-    $('#myModal').modal({show:true});
-});
-SyntaxHighlighter.all()
-</script>
-</html>

+ 0 - 51
python/filval/utils.py

@@ -1,51 +0,0 @@
-import ROOT
-
-__all__ = ["pdg", "show_function", "show_value"]
-
-db = ROOT.TDatabasePDG()
-
-
-class PDGParticle:
-
-    def __init__(self, tPart):
-        self.pdgId = tPart.PdgCode()
-        self.name = tPart.GetName()
-        self.charge = tPart.Charge() / 3.0
-        self.mass = tPart.Mass()
-        self.spin = tPart.Spin()
-
-    def __repr__(self):
-        return (f"<PDGParticle {self.name}:"
-                f"pdgId={self.pdgId}, charge={self.charge}, mass={self.mass:5.4e} GeV, spin={self.spin}>")
-
-
-def pdg(pdg_id):
-    try:
-        return PDGParticle(db.GetParticle(pdg_id))
-    except ReferenceError:
-        raise ValueError(f"unknown pdgId: {pdg_id}")
-
-
-def show_function(dataset, fname):
-    from IPython.display import Markdown
-
-    def md_single(fname_):
-        impl = dataset._function_impl_lookup[fname_]
-        return '*{}*\n-----\n```cpp\n{}\n```\n\n---'.format(fname_, impl)
-    try:
-        return Markdown('\n'.join(md_single(fname_) for fname_ in iter(fname)))
-    except TypeError:
-        return Markdown(md_single(fname))
-
-
-def show_value(dataset, container):
-    from IPython.display import Image
-    from graph_vals import parse
-    if type(container) != str:
-        container = container.GetName().split(':')[1]
-    g, functions = parse(dataset.values[container], container)
-    try:
-        return Image(g.create_gif()), show_function(dataset, functions)
-    except Exception as e:
-        print(e)
-        print(g.to_string())

+ 0 - 10
python/requirements.txt

@@ -1,10 +0,0 @@
-numpy
-matplotlib
-latexipy
-ipython
-scipy
-jupyter
-pydotplus
-Jinja2
-Markdown
-python-markdown-math

+ 0 - 111
python/scripts/generate_class.py

@@ -1,111 +0,0 @@
-#!/usr/bin/env python3
-
-
-def generate_collection_class(obj_name, obj_attrs):
-    src = []
-
-    src += f'''\
-struct {obj_name};
-
-class {obj_name}Collection {{
-  public:
-    class iter {{
-      public:
-        iter(const {obj_name}Collection* collection, size_t idx)
-          :collection(collection), idx(idx) {{ }}
-        iter operator++() {{ ++idx; return *this; }}
-        bool operator!=(const iter & other) {{ return idx != other.idx; }}
-        const {obj_name} operator*() const;
-      private:
-        const {obj_name}Collection* collection;
-        size_t idx;
-    }};
-
-'''.splitlines()
-
-    for field in obj_attrs['fields']:
-        name = field['name']
-        type_ = field['type']
-        src.append(f'    Value<vector<{type_}>>* val_{name};')
-
-    src.append(f'\n    {obj_name}Collection() {{ }}\n')
-
-    src.append('    void init(TrackingDataSet& tds){')
-    for field in obj_attrs['fields']:
-        name = field['name']
-        type_ = field['type']
-        prefix = obj_attrs['treename_prefix']+'_'
-        src.append(f'        val_{name} = tds.track_branch_obj<vector<{type_}>>("{prefix}{name}");')
-    src.append('    }\n')
-    first_obj_name = list(obj_attrs['fields'])[0]['name']
-    src.append(f'    size_t size() const {{ return val_{first_obj_name}->get_value().size();}}\n')
-    src.append(f'    const {obj_name} operator[](size_t) const;')
-    src.append('    iter begin() const { return iter(this, 0); }')
-    src.append('    iter end() const { return iter(this, size()); }')
-    src.append('};')
-
-    src += f'''
-struct {obj_name} {{
-    const {obj_name}Collection* collection;
-    const size_t idx;
-    {obj_name}(const {obj_name}Collection* collection, const size_t idx)
-      :collection(collection), idx(idx) {{ }}\n
-'''.splitlines()
-
-    for field in obj_attrs['fields']:
-        name = field['name']
-        type_ = field['type']
-        src.append(f'    const {type_}& {name}() const {{return collection->val_{name}->get_value().at(idx);}}')
-    src.append('};')
-
-    src.append(f'''
-const {obj_name} {obj_name}Collection::iter::operator*() const {{
-    return {{collection, idx}};
-}}
-const {obj_name} {obj_name}Collection::operator[](size_t idx) const {{
-    return {{this, idx}};
-}}
-''')
-    return '\n'.join(src)
-
-
-def generate_header(input_filename, output_filename):
-    from datetime import datetime
-
-    return f'''\
-/** {output_filename} created on {datetime.now()} by generate_class.py
- * AVOID EDITING THIS FILE BY HAND!! Instead edit {input_filename} and re-run
- * generate_class.py
- */
-#include "filval/filval.hpp"
-#include "filval/root/filval.hpp"
-
-#include<cmath>
-
-#include "TrackingNtuple.h"
-
-using namespace std;
-using namespace fv;
-using namespace fv::root;
-
-typedef TreeDataSet<TrackingNtuple> TrackingDataSet;
-'''
-
-
-if __name__ == '__main__':
-    import argparse
-    import yaml
-    parser = argparse.ArgumentParser()
-    add = parser.add_argument
-    add('input_file', help='An input YAML file defining the objects to generate')
-
-    args = parser.parse_args()
-    classes = []
-    with open(args.input_file) as fi:
-        for obj, attrs in yaml.load(fi).items():
-            classes.append(generate_collection_class(obj, attrs))
-    output_filename = args.input_file.replace('.yaml', '.hpp')
-    with open(output_filename, 'w') as fo:
-        fo.write(generate_header(args.input_file, output_filename))
-        for class_ in classes:
-            fo.write(class_)

+ 0 - 76
python/scripts/merge.py

@@ -1,76 +0,0 @@
-#!env/bin/python
-import argparse
-import re
-import os
-import ROOT
-
-
-def merge_stl_obj(obj_key, output_file, input1, input_rest, merge_func=None):
-    """ Merges STL objects and saves the result into the output file, user
-        must supply the merging function.
-    """
-    obj = input1.Get(obj_key)
-    type_name_raw = str(type(obj))
-    try:
-        type_name = re.findall("<class 'ROOT.([^']+)'>", type_name_raw)[0]
-    except IndexError:
-        raise ValueError(f"Couldn't extract stl type name from {type_name_raw}")
-    if merge_func is not None:
-        for input_file in input_rest:
-            obj_ = input_file.Get(obj_key)
-            merge_func(obj, obj_)
-    output_file.WriteObjectAny(obj, type_name, obj_key)
-
-
-def merge_obj(obj_key, output_file, input1, input_rest):
-    obj = input1.Get(obj_key)
-    print('='*80)
-    print(f'Merging object {obj_key} of type {type(obj)}')
-    if isinstance(obj, ROOT.TH1):
-        obj.SetDirectory(output_file)  # detach from input file
-        for input_file in input_rest:
-            obj_ = input_file.Get(obj_key)
-            obj.Add(obj_)
-        obj.Write()
-    else:
-        print(f"I don't know how to merge object of type{type(obj)}, but "
-              "you can add a case in merge_obj to handle it!")
-
-
-def merge_files(input_filenames, output_filename, preserve=False):
-    print(f"Merging files {', '.join(input_filenames)} into {output_filename}")
-
-    input1, *input_rest = [ROOT.TFile.Open(input_file, "READ") for input_file in input_filenames]
-    output_file = ROOT.TFile.Open(output_filename, "RECREATE")
-    output_file.cd()
-
-    obj_keys = [k.GetName() for k in input1.GetListOfKeys()]
-    for obj_key in obj_keys:
-        if obj_key in {"_value_lookup", "_function_impl_lookup"}:
-            merge_stl_obj(obj_key, output_file, input1, [])
-        else:
-            merge_obj(obj_key, output_file, input1, input_rest)
-
-    for file_ in [input1, *input_rest, output_file]:
-        file_.Close()
-    print(f"Merge finished! Results have been saved into {output_filename}")
-    if preserve:
-        print("Preseve specified, leaving input files intact")
-    else:
-        print("Removing input files...", end='', flush=True)
-        for filename in input_filenames:
-            os.remove(filename)
-        print("Done!")
-
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser()
-
-    add = parser.add_argument
-
-    add('output_file')
-    add('input_files', nargs='+')
-    add('--preserve', '-p', action='store_true')
-
-    args = parser.parse_args()
-    merge_files(args.input_files, args.output_file, args.preserve)

+ 0 - 63
python/scripts/process_parallel.py

@@ -1,63 +0,0 @@
-#! /usr/bin/env python3
-from os import listdir
-from os.path import join, isdir
-import argparse
-import subprocess
-
-import multiprocessing
-from multiprocessing.pool import Pool
-
-from merge import merge_files
-
-
-def run_job(job_number, executable, files):
-    file_list = f'file_list_{job_number:02d}.txt'
-    with open(file_list, 'w') as f:
-        f.write("\n".join(files))
-
-    output_filename = f'output_{job_number:02d}.root'
-    ret = subprocess.run([executable, '-s', '-F', file_list,
-                          '-o', output_filename])
-    retcode = ret.returncode
-    if retcode != 0:
-        raise RuntimeError(f'Job {job_number} encountered errors!'
-                           f'(retcode: {retcode}), check log file.')
-    return (job_number, output_filename)
-
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser()
-    add = parser.add_argument
-
-    add('executable')
-    add('--jobs', '-j', type=int, default=multiprocessing.cpu_count())
-    add('--dir', '-d', default='./data')
-    add('--mergeinto', '-m', default='output.root')
-    args = parser.parse_args()
-
-    if not isdir(args.dir):
-        raise ValueError(f'Directory {args.dir} does not exist')
-
-    files = sorted([join(args.dir, fname) for fname in listdir(args.dir) if fname[-5:] == '.root'])
-
-    files_per_job = len(files) // args.jobs
-    job_files = [files[i::args.jobs] for i in range(args.jobs)]
-    output_files = []
-
-    def job_callback(args):
-        job_num, job_file = args
-        print(f'job {job_num} finished')
-        output_files.append(job_file)
-
-    with Pool(args.jobs) as pool:
-        print(f'Starting {args.jobs} processes to process {len(files)} files')
-        results = []
-        for i, files in enumerate(job_files):
-            results.append(pool.apply_async(run_job, (i, args.executable, files),
-                           callback=job_callback))
-        for result in results: result.get()
-        pool.close()
-        pool.join()
-        print('Finished processing nTuples.')
-    print('Begin merging job files')
-    merge_files(output_files, args.mergeinto)

+ 0 - 18
python/setup.py

@@ -1,18 +0,0 @@
-from setuptools import setup
-
-with open('requirements.txt') as req:
-    install_requires = [l.strip() for l in req.readlines()]
-
-setup(
-    name='filval',
-    version='0.1',
-    install_requires=install_requires,
-    dependency_links=[
-        "git+ssh://git@github.com/cfangmeier/latexipy.git#egg=latexipy"
-    ],
-    packages=['filval'],
-    scripts=['scripts/merge.py',
-             'scripts/process_parallel.py'
-             ],
-    package_data={'filval': ['templates/*.j2']},
-)