def __coordinateToIndex(self, coordinates): col, row = map(int, coordinates) if row > len(self.rows): raise IndexError, "invalid row %d" % row if col > self.rows[row]: raise IndexError, "invalid column %d" % col return sum(self.rows[: row]) + col
def __init__(self, rows, **style): """Create a layout. For example, 'BrickLayout((2, 2, 1))' creates a layout of three rows with two cells in the top and center rows and one cell in the bottom row. 'rows' -- A sequence of rows. Each row is a sequence of numbers specifying how many cells in each row. The number of rows is the length of the sequence.""" rows = map(int, rows) num_figures = sum(rows) self.rows = modified.List(rows) self.figures = modified.List(num_figures * ( None, )) Layout.__init__(self, style) self.watch_modified.append(self.figures)
def chiSquareFit1D(histogram, function, variable_name, parameters, min_count=7, range=None): """Perform a one-dimensional chi-square fit of a PDF to a histogram. Performs a chi-square fit of PDF 'function' to a one-dimensional histogram. The chi-square is computed using Simpson's rule (three-point gaussian quadrature) to integrate the PDF for comparison with histogram bins. Bin errors in 'histogram' are ignored; 1/sqrt(N) gaussian couning errors are always used. Therefore, histogram contents should be positive integers (though zero and small bins are handled; see the 'min_count' parameter below). 'histogram' -- The histogram to fit to. 'function' -- The PDF. May be an 'Expression' object or a callable. 'variable_name' -- The name of the variable in 'function' corresponding to the dependent quantity in 'histogram' (i.e. the quantity along the histogram axis). 'parameters' -- A sequence of parameters to fit. Each may be simply a variable name in 'function', or a sequence '(name, initial_value, step_size, bound_low, bound_hi)'. 'min_count' -- The minimum value for bins in the fit. Bins which contain a smaller value than this are coalesced with neighboring bins until all bins contain at least this value. returns -- A 'Result' object.""" # We'll use this for minimization. import hep.minimize import hep.cernlib.minuit axis = histogram.axis function = hep.expr.asExpression(function) parameters = hep.minimize.normalizeParameters(parameters) num_floating = sum([ 1 for p in parameters if p[2] is not None ]) # Construct the list of bin samples, coalescing bins as necessary. samples = [] # Figure out which bins are included in the fit. if range is None: bins = hep.hist.AxisIterator(axis) else: lo, hi = range bins = xrange(axis(lo), axis(hi)) # Loop over bins. x0 = None for bin in bins: range = axis.getBinRange(bin) # Are we carrying a bin whose contents don't satisfy the minimum # so far? if x0 is None: # No. Start a new bin x0, x1 = range value = histogram.getBinContent(bin) else: # Yes. Make sure we are adjacent. assert x1 == range[0] # Coalesce this bin with the carried one. x1 = range[1] value += histogram.getBinContent(bin) # Doe the bin we're carrying have enough in it? if value >= min_count: # Yes it does. Use it as a sample. samples.append(((x0, x1), value, )) x0 = None # If we're still carrying a bin, it must not have enough in it. But # we have to do something with it. if x0 is not None: # Are there any samples at all so far? if len(samples) > 0: # Yes there are. Coalesce the bin we're carrying with the # last one. (last_x0, last_x1), last_value = samples.pop(-1) assert last_x1 == x0 samples.append(((last_x0, x1), last_value + value, )) else: # No samples. The whole histogram doesn't have enough in it # to satisfy the minimum criterion. Oh well, just use one # sample. samples.append(((x0, x1), value, )) # Construct the chi-square function. chi_sq = ChiSquare1D(function, variable_name, samples) # Minimize it. result = hep.cernlib.minuit.minimize(chi_sq, parameters) # Store the number of degrees of freedom. dof = len(samples) - num_floating result.degrees_of_freedom = dof # Compute the chi-square probability. result.chi_square_probability = \ dof > 0 and hep.num.chiSquareCDF(result.minimum, dof) or None # Substitute the fit parameter values into 'function' and store # that. result.expression = hep.expr.substitute(function, **result.values) # Construct a function suitable for plotting. Scale the PDF by the # bin size, for sensible comparison to the histogram. bin_size = (axis.range[1] - axis.range[0]) / axis.number_of_bins scaled_expr = hep.expr.Multiply( result.expression, hep.expr.Constant(bin_size)) notes = "Results of fit to '%s'\n" % str(function) notes += " $\chi^2$ / DOF = %.2f / %d\n" \ % (result.minimum, result.degrees_of_freedom, ) if result.chi_square_probability is not None: notes += " $P_{\chi^2}$ = %.3f\n" % result.chi_square_probability for name, value in result.values.items(): notes += " %s = %.4f ± %.4f\n" \ % (name, value, result.errors[name]) result.function = hep.hist.Function1D( scaled_expr, arg_name=variable_name, axis=hep.hist.Axis(axis.type, range=axis.range), notes=notes) return result