"""
Define some
"""
from __future__ import print_function
from builtins import range
from builtins import object
from copy import deepcopy as copy
import numpy as n
import numpy as np
import dashi as d
import pylab as p
import matplotlib.ticker
from .colors import get_color_palette
from .canvases import YStackedCanvas
from ..utils.logger import Logger
d.visual()
###############################################
[docs]def adjust_minor_ticks(axis, which="x"):
"""
Decorate the x-axis with a reasonable set of
minor x-ticks
Args:
axis (matplotlib.axis): The axis to decorate
Keyword Args:
which (str): either "x", "y" or "both"
Returns:
matplotlib.axis
"""
assert which in ("x", "y", "both"), "Unable to find {} axis!".format(which)
axes_to_modify = [which]
if which == "both":
axes_to_modify = ["x", "y"]
for which in axes_to_modify:
minor_tick_space = getattr(axis, "{}axis".format(which)).get_ticklocs()
#minor_tick_space = axis.xaxis.get_ticklocs()
minor_tick_space = (minor_tick_space[1] - minor_tick_space[0])/10.
if minor_tick_space < 0.1:
Logger.debug("Adjusting for small numbers in tick spacing, tickspace detectected {}".format(minor_tick_space))
minor_tick_space = 0.1
getattr(axis, "{}axis".format(which)).set_minor_locator(matplotlib.ticker.MultipleLocator(minor_tick_space))
#axis.xaxis.set_minor_locator(matplotlib.ticker.MultipleLocator(minor_tick_space))
return axis
###############################################
[docs]def create_arrow(ax, x_0, y_0, dx, dy, length,\
width = .1, shape="right",\
fc="k", ec="k",\
alpha=1., log=False):
"""
Create an arrow object for plots. This is typically a large
arrow, which can used to indicate a region in the plot which
is excluded by a cut.
Args:
ax (matplotlib.axes._subplots.AxesSubplot): The axes where the arrow
will be attached to
x_0 (float): x-origin of the arrow
y_0 (float): y-origin of the arrow
dx (float): x length of the arrow
dy (float): y length of the arrow
length (float): additional scaling parameter to scale
the length of the arrow
Keyword Args:
width (float): thickness of arrow
shape (str): either "full", "left" or "right"
fc (str): facecolor
ec (str): edgecolor
alpha (float): 0 -1 alpha value of the arrow
log (bool): I for logscale, the proportions of the arrow will be adjusted accorginly.
Returns:
matplotlib.axes._subplots.AxesSubplot
"""
head_starts_at_zero = False
head_width = width*5
head_length = length*0.1
if log: # slightly bigger arrow
head_width = width*6
head_length = length*0.2
arrow_params={'length_includes_head':False,\
'shape':shape,\
'head_starts_at_zero':head_starts_at_zero}
arr = ax.arrow(x_0, y_0, dx*length,\
dy*length, fc=fc, ec=ec,\
alpha=alpha, width=width,\
head_width=head_width,\
head_length=head_length,\
**arrow_params)
return ax
###############################################
[docs]def meshgrid(xs, ys):
"""
Create x and y data for matplotlib pcolormesh and
similar plotting functions.
Args:
xs (np.ndarray): 1d x bins
ys (np.ndarray): 2d y bins
Returns:
tuple (np.ndarray, np.ndarray, np.ndarray): 2d X and 2d Y matrices as well as a placeholder for the Z array
"""
xlen = len(xs)
ylen = len(ys)
allx, ally = [], []
# prepare xs
for __ in range(ylen):
allx.append(xs)
allx = np.array(allx)
allx = allx.T
# prepare ys
for __ in range(xlen):
ally.append(ys)
ally = np.array(ally)
zs = np.zeros([xlen, ylen])
return allx, ally, zs
###############################################
[docs]def line_plot(quantities,
bins=None,
xlabel='',
add_ratio=None,
ratiolabel='',
colors=None,
figure_factory=None):
"""
Args:
quantities:
Keyword Args:
bins:
xlabel:
add_ratio (tuple): (["data1"],["data2"])
ratiolabel (str):
colors:
figure_factory (callable): Factory function returning matpltolib.Figure
Returns:
"""
# FIXME XXX under development
raise NotImplementedError
if add_ratio is not None:
canvas = YStackedCanvas(subplot_yheights=(0.2, 0.7),
space_between_plots=0.0)
ax0 = canvas.select_axes(-1)
data = np.array(quantities[add_ratio[0]]) / np.array(quantities[add_ratio[1]])
data = data * 100
thebins = np.array(bins[add_ratio[0]])
bin_size = abs(thebins[1] - thebins[0]) / 2 * np.ones(len(thebins))
thebins = thebins + bin_size
ax0.plot(thebins, data, color='gray')
ax0.scatter(thebins, data, marker='o', s=50, color='gray')
ax0.grid(1)
ax0.set_ylabel(ratiolabel)
ax0.spines['top'].set_visible(False)
ax0.spines['bottom'].set_visible(False)
ax0.spines['right'].set_visible(False)
ax = canvas.select_axes(0)
lgax = ax0
else:
if figure_factory is None:
fig = p.figure()
else:
fig = figure_factory()
ax = fig.gca()
lgax = ax
for reconame in quantities:
thebins = np.array(bins[reconame])
bin_size = abs(thebins[1] - thebins[0]) / 2 * np.ones(len(thebins))
thebins = thebins + bin_size
label = reconame.replace('-', '')
if colors is not None:
ax.plot(thebins, quantities[reconame], label=label, color=colors[reconame])
ax.scatter(thebins, quantities[reconame], marker='o', s=50, c=colors[reconame])
else:
ax.plot(thebins, quantities[reconame], label=label)
ax.scatter(thebins, quantities[reconame], marker='o', s=50)
legend_kwargs = {'bbox_to_anchor': [0.0, 1.0, 1.0, 0.102],'loc': 3,
'frameon': False,
'ncol': 2,
'borderaxespad': 0,
'mode': 'expand',
'handlelength': 2,
'numpoints': 1
}
if len(quantities.keys()) == 3:
legend_kwargs['ncol'] = 3
ax.grid(1)
ax.set_ylabel('$\\cos(\\Psi)$')
ax.set_xlabel(xlabel)
sb.despine()
if add_ratio:
ax.spines['top'].set_visible(False)
ax0.spines['bottom'].set_visible(False)
ax0.spines['left'].set_visible(False)
legend_kwargs['bbox_to_anchor'] = [0, 1.3, 1.0, 0.102]
ax.legend(**legend_kwargs)
p.subplots_adjust(hspace=0.2)
return canvas.figure
ax.legend(**legend_kwargs)
return fig
###############################################
[docs]class VariableDistributionPlot(object):
"""
A plot which shows the distribution of a certain variable.
Cuts can be indicated with lines and arrows. This class defines
(and somehow enforces) a certain style.
"""
def __init__(self, cuts=None,\
color_palette="dark",\
bins=None,\
xlabel=None):
"""
Keyword Args:
bins (array-like): desired binning, if None use default
cuts (HErmes.selection.cut.Cut):
color_palette (str): use this palette for the plotting
xlabel (str): descriptive string for x-label
"""
self.histograms = {}
self.histratios = {}
self.cumuls = {}
self.plotratio = False
self.plotcumul = False
self.canvas = None
self.label = ''
self.name = ''
self.bins = bins
if cuts is None:
cuts = []
self.cuts = cuts
if isinstance(color_palette, str):
self.color_palette = get_color_palette(color_palette)
else:
self.color_palette = color_palette
self.plot_options = dict()
[docs] def add_cuts(self, cut):
"""
Add a cut to the the plot which can be indicated by an arrow
Args:
cuts (HErmes.selection.cuts.Cut):
Returns:
None
"""
self.cuts.append(cut)
[docs] def add_data(self, variable_data,\
name, bins=None,\
weights=None, label=''):
"""
Histogram the added data and store internally
Args:
name (string): the name of a category
variable_data (array): the actual data
Keyword Args:
bins (array): histogram binning
weights (array): weights for the histogram
label (str): A label for the data when plotted
"""
if bins is None:
bins = self.bins
if weights is None:
self.histograms[name] = d.factory.hist1d(variable_data, bins)
else:
self.histograms[name] = d.factory.hist1d(variable_data, bins, weights=weights)
self.label = label
self.name = name
[docs] def add_variable(self, category,
variable_name,
external_weights=None,
transform=None):
"""
Convenience interface if data is sorted in categories already
Args:
category (HErmese.variables.category.Category): Get variable from this category
variable_name (string): The name of the variable
Keyword Args:
external_weights (np.ndarray): Supply an array for weighting. This will OVERIDE ANY INTERNAL WEIGHTING MECHANISM and use the supplied weights.
transform (callable): Apply transformation todata
"""
if category.plot_options:
self.plot_options[category.name] = copy(category.plot_options)
if self.bins is None:
self.bins = category.vardict[variable_name].bins
self.name = variable_name
if external_weights is None:
Logger.warning("Internal weighting mechanism is broken at the moment, FIXME!")
#weights = category.weights
#if len(weights) == 0:
# weights = None
weights = None
else:
weights = external_weights
if transform is None: transform = lambda x : x
self.add_data(transform(category.get(variable_name)),\
category.name,\
self.bins, weights=weights,\
label=category.vardict[variable_name].label)
[docs] def add_cumul(self, name):
"""
Add a cumulative distribution to the plto
Args:
name (str): the name of the category
"""
assert name in self.histograms, "Need to add data first"
self.cumuls[name] = self.histograms[name].normalized()
[docs] def indicate_cut(self, ax, arrow=True):
"""
If cuts are given, indicate them by lines
Args:
ax (pylab.axes): axes to draw on
"""
vmin, vmax = ax.get_ylim()
hmin, hmax = ax.get_xlim()
for cut in self.cuts:
for name, (operator, value) in cut:
# there might be more than one
# cut which should be
# drawn on this plot
# so go through ALL of them.
if name != self.name:
continue
Logger.debug('Found cut! {0} on {1}'.format(name,value))
width = vmax/50.
# create a line a cut position
ax.vlines(value, ymin=vmin, ymax=vmax, linestyle=':')
length = (hmax - hmin)*0.1
# mark part of the plot as "forbidden"
# and create arrow if desired
if operator in ('>','>='):
shape = 'right'
ax.axvspan(value, hmax,\
facecolor=self.color_palette["prohibited"],\
alpha=0.5)
else:
shape = 'left'
ax.axvspan(hmin, value,\
facecolor=self.color_palette["prohibited"],\
alpha=0.5)
if arrow:
ax = create_arrow(ax, value, vmax*0.1,\
-1., 0, length, width=width,\
shape=shape, log=True)
[docs] def add_ratio(self, nominator, denominator,\
total_ratio=None, total_ratio_errors=None, \
log=False, label="data/$\Sigma$ bg"):
"""
Add a ratio plot to the canvas
Args:
nominator (list or str): name(s) of the categorie(s) which
will be the nominator in the ratio
denominator (list or str): name(s) of the categorie(s) which
will be the nominator in the ratio
Keyword Args:
total_ratio (bool): Indicate the total ratio with a line in the plot
total_ratio_errors (bool): Draw error region around total ratio
log (bool): draw ratio plot in log-scale
label (str): y-label for the ratio plot
"""
if not isinstance(nominator, list):
nominator = [nominator]
if not isinstance(denominator, list):
denominator = [denominator]
name = "".join(nominator) + "_" + "".join(denominator)
first_nominator = nominator.pop()
nominator_hist = self.histograms[first_nominator]
nominator_ws = self.histograms[first_nominator].stats.weightsum
for name in nominator:
nominator_hist += self.histograms[name]
nominator_ws += self.histograms[name].stats.weightsum
first_denominator = denominator.pop()
denominator_hist = self.histograms[first_denominator]
denominator_ws = self.histograms[first_denominator].stats.weightsum
for name in denominator:
denominator_hist += self.histograms[name]
denominator_ws += self.histograms[name].stats.weightsum
nominator_hist.normalized()
denominator_hist.normalized()
ratio = d.histfuncs.histratio(nominator_hist, denominator_hist,\
log=False, ylabel=label)
if total_ratio is None:
total_ratio = nominator_ws/denominator_ws
Logger.info("Calculated scalar ratio of {:4.2f} from histos".format(total_ratio))
#ratio.y[ratio.y > 0] = ratio.y[ratio.y > 0] + total_ratio -1
self.histratios[name] = (ratio, total_ratio, total_ratio_errors,\
label)
return name
def _draw_distribution(self, ax, name,
log=True,\
cumulative=False,
normalized=False,
ylabel="rate/bin [1/s]"):
"""
Paint the histograms!
Args:
Keyword Args:
normalized (bool): draw by number of events normalized distribution
"""
try:
cfg = copy(self.plot_options[name])
except KeyError:
Logger.warn("No plot configuration available for {}".format(name))
cfg = {"histotype": "line",
"label": name,
"linestyle" : {"color": "k",
"linewidth": 3
}
}
log = False
if "linestyle" in cfg:
color = cfg["linestyle"].pop('color')
if isinstance(color, int):
color = self.color_palette[color]
if 'scatterstyle' in cfg:
scattercolor = cfg["scatterstyle"].pop('color')
if isinstance(scattercolor,int):
scattercolor = self.color_palette[scattercolor]
if cumulative:
histograms = self.cumuls
log = False
else:
histograms = self.histograms
if normalized and not cumulative:
histograms[name] = histograms[name].normalized()
if cfg['histotype'] == 'scatter':
histograms[name].scatter(log=log,cumulative=cumulative,\
label=cfg["label"],\
color=scattercolor, **cfg["scatterstyle"])
elif cfg['histotype'] == "line":
# apply th alpha only to the "fill" setting
linecfg = copy(cfg["linestyle"])
if "alpha" in linecfg:
linecfg.pop("alpha")
linecfg["filled"] = False
if "filled" in cfg["linestyle"]:
histograms[name].line(log=log, cumulative=cumulative,\
label=cfg["label"], color=color,\
**linecfg)
histograms[name].line(log=log, cumulative=cumulative,\
label=None, color=color,\
**cfg["linestyle"])
else:
histograms[name].line(log=log, cumulative=cumulative,\
label=cfg["label"], color=color,\
**cfg["linestyle"])
elif cfg['histotype'] == "overlay":
histograms[name].line(log=log, cumulative=cumulative,\
label=cfg["label"], color=color,\
**cfg["linestyle"])
histograms[name].scatter(log=log, cumulative=cumulative,\
color=scattercolor,\
**cfg["scatterstyle"])
if cumulative:
ax.set_ylabel('fraction')
else:
ax.set_ylabel(ylabel)
def _draw_histratio(self, name, axes, ylim=(0.1,2.5)):
"""
Plot one of the ratios
Returns:
tuple (float,float) : the min and max of the ratio
"""
ratio,total_ratio,total_ratio_errors,label = self.histratios[name]
ratio.scatter(c="k", marker="o", markersize=3)
axes.hlines(total_ratio,axes.get_xlim()[0],axes.get_xlim()[1],linestyle="--")
if total_ratio_errors is not None:
axes.hlines(total_ratio + total_ratio_errors,axes.get_xlim()[0],axes.get_xlim()[1],linestyle=":")
axes.hlines(total_ratio - total_ratio_errors,axes.get_xlim()[0],axes.get_xlim()[1],linestyle=":")
xs = n.linspace(axes.get_xlim()[0],axes.get_xlim()[1],200)
axes.fill_between(xs,total_ratio - total_ratio_errors,\
total_ratio + total_ratio_errors,\
facecolor="grey", alpha=0.3)
#axes.set_ylim(ylim)
axes.set_ylabel(label)
axes.grid(1)
if not ratio.y is None:
if not ratio.yerr is None:
ymin = min(ratio.y - ratio.yerr)
ymax = max(ratio.y + ratio.yerr)
ymin -= (0.1*ymin)
ymax += (0.1*ymax)
return ymin, ymax
else:
ymin = min(ratio.y)
ymax = max(ration.y)
ymin -= (0.1*ymin)
ymax += (0.1*ymax)
return ymin, ymax
else:
return 0,0
def _locate_axes(self, combined_cumul, combined_ratio, combined_distro):
axes_locator = []
if self.cumuls:
if combined_cumul:
axes_locator.append((0, "c"))
else:
axes_locator += [(x,"c") for x in range(len(self.cumuls))]
if self.histratios:
if combined_ratio:
if axes_locator:
axes_locator.append((axes_locator[-1] + 1,"r"))
else:
axes_locator.append((0,"r"))
else:
if axes_locator:
axes_locator +=[(x+ len(axes_locator),"r") for x in range(len(self.histratios))]
if self.histograms:
if combined_distro:
if axes_locator:
axes_locator.append((axes_locator[-1] + 1,"h"))
else:
axes_locator.append((0,"h"))
else:
if axes_locator:
axes_locator +=[(x+ len(axes_locator),"h") for x in range(len(self.histograms))]
return axes_locator
[docs] def plot(self,
axes_locator=((0, "c",.2), (1, "r",.2), (2, "h",.5)),\
combined_distro=True,\
combined_ratio=True,\
combined_cumul=True,
normalized=True,
log=True,
legendwidth = 1.5,
ylabel="rate/bin [1/s]",
figure_factory=None):
"""
Create the plot
Keyword Args:
heights:
axes_locator:
combined_distro:
combined_ratio:
combined_cumul:
log:
normalized (bool):
Returns:
"""
Logger.info("Found {} distributions".format(len(self.histograms)))
Logger.info("Found {} ratios".format(len(self.histratios)))
Logger.info("Found {} cumulative distributions".format(len(self.cumuls)))
if not axes_locator:
axes_locator = self._locate_axes(combined_cumul,\
combined_ratio,\
combined_distro)
# calculate the amount of needed axes
# assert len(axes_locator) == len(heights), "Need to specify exactly as many heights as plots you want to have"
heights = [k[2] for k in axes_locator]
self.canvas = YStackedCanvas(subplot_yheights=heights,\
figure_factory=figure_factory)
cu_axes = [x for x in axes_locator if x[1] == "c"]
h_axes = [x for x in axes_locator if x[1] == "h"]
r_axes = [x for x in axes_locator if x[1] == "r"]
maxheights = []
minheights = []
for ax in cu_axes:
cur_ax = self.canvas.select_axes(ax[0])
if combined_cumul:
for k in list(self.cumuls.keys()):
self._draw_distribution(cur_ax, k, cumulative=True,log=log, ylabel=ylabel)
break
else:
k = self.cumuls[list(self.cumuls.keys())[ax[0]]]
self._draw_distribution(cur_ax,cumulative=True,log=log, ylabel=ylabel)
for ax in r_axes:
cur_ax = self.canvas.select_axes(ax[0])
if combined_ratio:
for k in list(self.histratios.keys()):
ymin, ymax = self._draw_histratio(k,cur_ax)
ymin -= (ymin*0.1)
ymax += (ymax*0.1)
cur_ax.set_ylim(ymin,ymax)
# FIXME: good tick spacing
#major_tick_space = 1
#minor_tick_space = 0.1
## in case there are too many ticks
#nticks = float(ymax - ymin)/major_tick_space
#while nticks > 4:
# major_tick_space += 1
##if ymax - ymin < 1:
## major_tick_space =
#cur_ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(minor_tick_space))
break
else:
k = self.histratios[list(self.histratios.keys())[ax[0]]]
ymin, ymax = self._draw_histratio(k,cur_ax)
ymin -= (ymin*0.1)
ymax += (ymax*0.1)
cur_ax.set_ylim(ymin,ymax)
for ax in h_axes:
cur_ax = self.canvas.select_axes(ax[0])
if combined_distro:
for k in list(self.histograms.keys()):
Logger.debug("drawing..{}".format(k))
self._draw_distribution(cur_ax,k,log=log, normalized=normalized, ylabel=ylabel)
break
else:
k = self.histograms[list(self.histograms.keys())[ax[0]]]
ymax, ymin = self._draw_distribution(cur_ax,k,log=log, normalized=normalized, ylabel=ylabel)
cur_ax.set_ylim(ymin=ymin - 0.1*ymin,ymax=1.1*ymax)
cur_ax.grid(True)
lgax = self.canvas.select_axes(-1) # most upper one
ncol = 2 if len(self.histograms) <= 4 else 3
legend_kwargs = {"bbox_to_anchor": [0., 1.0, 1., .102],
"loc": 3,
"frameon": True,
"ncol": ncol,
"framealpha": 1.,
"borderaxespad": 0,
"mode": "expand",
"handlelength": 2,
"numpoints": 1}
lg = lgax.legend(**legend_kwargs)
if lg is not None:
lg.get_frame().set_linewidth(legendwidth)
lg.get_frame().set_edgecolor("k")
else:
Logger.warn("Can not set legendwidth!")
# plot the cuts
if self.cuts:
for ax in h_axes:
cur_ax = self.canvas.select_axes(ax[0])
self.indicate_cut(cur_ax, arrow=True)
for ax in r_axes + cu_axes:
cur_ax = self.canvas.select_axes(ax[0])
self.indicate_cut(cur_ax, arrow=False)
# cleanup
leftplotedge, rightplotedge, minplotrange, maxplotrange = self.optimal_plotrange_histo(self.histograms.values())
maxplotrange += (maxplotrange*0.1)
if log:
if maxplotrange < 1:
minplotrange -= (minplotrange*0.01)
else:
minplotrange = 0 # will be switched to symlog by default
for ax in h_axes:
self.canvas.select_axes(ax[0]).set_ylim(ymin=minplotrange, ymax=maxplotrange)
self.canvas.select_axes(ax[0]).set_xlim(xmin=leftplotedge, xmax=rightplotedge)
if log:
if maxplotrange < 1:
self.canvas.select_axes(ax[0]).set_yscale("log")
else:
self.canvas.select_axes(ax[0]).set_yscale("symlog")
for ax in cu_axes:
self.canvas.select_axes(ax[0]).set_xlim(xmin=leftplotedge, xmax=rightplotedge)
for ax in r_axes:
self.canvas.select_axes(ax[0]).set_xlim(xmin=leftplotedge, xmax=rightplotedge)
self.canvas.eliminate_lower_yticks()
# set the label on the lowest axes
self.canvas.axes[0].set_xlabel(self.label)
minor_tick_space = self.canvas.axes[0].xaxis.get_ticklocs()
minor_tick_space = (minor_tick_space[1] - minor_tick_space[0])/10.
if minor_tick_space < 0.1:
Logger.debug("Adjusting for small numbers in tick spacing, tickspace detectected {}".format(minor_tick_space))
minor_tick_space = 0.1
self.canvas.axes[0].xaxis.set_minor_locator(matplotlib.ticker.MultipleLocator(minor_tick_space))
for x in self.canvas.axes[1:]:
p.setp(x.get_xticklabels(), visible=False)
p.setp(x.get_xticklines(), visible=False)
x.xaxis.set_tick_params(which="both",\
length=0,\
width=0,\
bottom=False,\
labelbottom=False)
for x in self.canvas.figure.axes:
x.spines["right"].set_visible(True)
for ax in h_axes:
#self.canvas.select_axes(ax[0]).ticklabel_format(useOffset=False, style='plain', axis="y")
self.canvas.select_axes(ax[0]).get_yaxis().get_offset_text().set_x(-0.1)
[docs] @staticmethod
def optimal_plotrange_histo(histograms):
"""
Get most suitable x and y limits for a bunc of histograms
Args:
histograms (list(d.factory.hist1d)): The histograms in question
Returns:
tuple (float, float, float, float): xmin, xmax, ymin, ymax
"""
leftplotedge = n.inf
rightplotedge = -n.inf
minplotrange = n.inf
maxplotrange = -n.inf
for h in histograms:
if not h.bincontent.any():
continue
if h.bincenters[h.bincontent > 0][0] < leftplotedge:
leftplotedge = h.bincenters[h.bincontent > 0][0]
leftplotedge -= h.binwidths[0]
if h.bincenters[h.bincontent > 0][-1] > rightplotedge:
rightplotedge = h.bincenters[h.bincontent > 0][-1]
rightplotedge += h.binwidths[0]
if min(h.bincontent[h.bincontent > 0]) < minplotrange:
minplotrange = min(h.bincontent[h.bincontent > 0])
if max(h.bincontent[h.bincontent > 0]) > maxplotrange:
maxplotrange = max(h.bincontent[h.bincontent > 0])
return leftplotedge, rightplotedge, minplotrange, maxplotrange
[docs] def add_legend(self, **kwargs):
"""
Add a legend to the plot. If no kwargs are passed,
use some reasonable default.
Keyword Args:
will be passed to pylab.legend
"""
if not kwargs:
kwargs = {"bbox_to_anchor": (0.,1.0, 1., .102),\
"loc" : 3, "ncol" :3,\
"mode": "expand",\
"framealpha": 1,\
"borderaxespad": 0.,\
"handlelength": 2,\
"numpoints": 1}
self.canvas.global_legend(**kwargs)
# #######################################################
#
# def error_distribution_plot(h,
# xlabel = r"$\log(E_{rec}/E_{ref})$",
# name = "E",
# median = False):
# """
#
#
# Args:
# h:
# xlabel:
# name:
# median:
#
# Returns:
#
# """
# par = HistoFitter(h, Gauss)
# fig = p.figure(figsize=(6,4),dpi=350)
# ax = fig.gca()
# if not median: ax.plot(h.bincenters, Gauss(par,h.bincenters),color="k",lw=2)
# h.line(filled=True,color="k",lw=2,fc="grey",alpha=.5)#hatch="//")
# h.line(color="k",lw=2)
# ax.grid(1)
# ax.set_ylim(ymax=1.1*max(h.bincontent))
# ax.set_xlim(xmin=h.bincenters[0],xmax=h.bincenters[-1])
# ax.set_xlabel(xlabel)
# ax.set_ylabel("Normalized bincount")
# if median: ax.vlines(h.stats.median,0,1.1*max(h.bincontent),linestyles="dashed")
# textstr ="Gaussian fit:\n"
# textstr += "$\mu$ = " + "%4.3f" %par[1] + "\n" + "$\sigma$ = " + "%4.2f" %par[2]
# if median:
# textstr = "Median:\n %4.3f" %h.stats.median
# CreateTextbox(ax,textstr,boxstyle="square",xcoord=.65,fontsize=16,alpha=.9)
# #Thesisize(ax)
# #print h.bincontent[h.bincenters > -.1][h.bincenters < .1].cumsum()[-1]
#
# #ChisquareTest(h,Gauss(par,h.bincenters),xmin=-.001,xmax=.001)
# #savename = Multisavefig(plotdir_stat,"parameter-reso-" + name,3,orientation="portrait",pad_inches=.3,bbox_inches="tight")[0]#pad_inches=.5,bbox_inche s="tight")[0]
# return fig
#
# ####################################################
#
# def HistoFitter(histo,func,startmean=0,startsigma=.2):
#
# def error(p,x,y):
# return n.sqrt((func(p,x) - y)**2)
#
# #print histo.bincontent.std()
# histo.stats.mean
# p0 = [max(histo.bincontent),histo.stats.mean,histo.stats.var]
# output = optimize.leastsq(error,p0,args=(histo.bincenters,histo.bincontent),full_output=1)
# par = output[0]
# covar = output[1]
# rchisquare = scipy.stats.chisquare(1*histo.bincontent,f_exp=(1*func(par,histo.bincenters)))[0]/(1*(len(histo.bincenters) -len(par)))
# #print par,covar
# #print "chisquare/ndof",rchisquare
# #print histo.bincontent[:10], func(par,histo.bincenters)[:10]
# #print "ks2_samp", scipy.stats.ks_2samp(histo.bincontent,func(par,histo.bincenters))
# return par
#
# #####################################################
#
# def create_textbox(ax, textstr, boxstyle="round",\
# facecolor="white", alpha=.7,\
# xcoord=0.05, ycoord=0.95, fontsize=14):
# """
# Create a textbox on a given axis
#
# Args:
# ax:
# textstr:
# boxstyle:
# facecolor:
# alpha:
# xcoord:
# ycoord:
# fontsize:
#
# Returns:
# the given ax object
# """
# props = dict(boxstyle=boxstyle, facecolor=facecolor, alpha=alpha)
# # place a text box in upper left in axes coords
# ax.text(xcoord, ycoord, textstr,\
# transform=ax.transAxes,\
# fontsize=fontsize,\
# verticalalignment='top', bbox=props)
# return ax
#
# ######################################################
#
# def ChisquareTest(histo, fit, xmin=-.2, xmax=.2, ndof=3):
# data = histo.bincontent[histo.bincenters > xmin][histo.bincenters < xmax]
# fit = fit[histo.bincenters > xmin][histo.bincenters < xmax]
# #print data,fit
# print (scipy.stats.chisquare(data,f_exp=fit)[0]/(len(fit) - ndof))
# print (scipy.stats.ks_2samp(data,fit))
# print (scipy.stats.anderson(data))