def plot_variation(baseline_maps, up_maps, down_maps, h1_name, fulltitle, savename, outdir, ftype='pdf'): matplotlib.rcParams['font.family'] = 'sans-serif' matplotlib.rcParams['mathtext.fontset'] = 'stixsans' gridspec_kw = dict(left=0.04, right=0.966, wspace=0.32) fig, axes = plt.subplots(nrows=1, ncols=3, gridspec_kw=gridspec_kw, sharex=False, sharey=False, figsize=(15, 5)) asymmetry_hist = (h1_map.hist - h0_map.hist) / np.sqrt(h0_map.hist) asymmetry_to_plot = Map(name='asymmetry', hist=asymmetry_hist, binning=h0_map.binning) asymmetrylabel = ( r'$\left(N_{%s}-N_{%s}\right)' r'/\sqrt{N_{%s}}$' % (text2tex(h1_name), text2tex(h0_name), text2tex(h0_name))) vmax = max(np.nanmax(h0_map.hist), np.nanmax(h1_map.hist)) h0_map.plot(fig=fig, ax=axes[0], title='Hypothesis 0: $%s$' % text2tex(h0_name), cmap=plt.cm.afmhot, vmax=vmax) h1_map.plot(fig=fig, ax=axes[1], title='Hypothesis 1: $%s$' % text2tex(h1_name), cmap=plt.cm.afmhot, vmax=vmax) asymmetry_to_plot.plot(fig=fig, ax=axes[2], title='Asymmetry', symm=True, cmap=plt.cm.seismic) plt.subplots_adjust(bottom=0.12, top=0.8) plt.suptitle(fulltitle, size='xx-large') if savename != '' and savename[-1] != '_': savename += '_' fname = '%s%s_%s_asymmetry.pdf' % (savename, h0_name, h1_name) fname = fname.replace(' ', '_') mkdir(outdir, warn=False) fig.savefig(os.path.join(outdir, fname)) plt.close(fig.number)
def _compute_outputs(self, inputs=None): """Compute histograms for output channels.""" logging.debug('Entering fit._compute_outputs') if not isinstance(inputs, Data): raise AssertionError('inputs is not a Data object, instead is ' 'type {0}'.format(type(inputs))) self.weight_hash = deepcopy(inputs.metadata['weight_hash']) logging.trace('{0} fit weight_hash = ' '{1}'.format(inputs.metadata['name'], self.weight_hash)) logging.trace('{0} fit fit_hash = ' '{1}'.format(inputs.metadata['name'], self.fit_hash)) self._data = inputs self.reweight() if self.output_events: return self._data outputs = [] if self.neutrinos: trans_nu_data = self._data.transform_groups( self._output_nu_groups ) for fig in trans_nu_data.iterkeys(): outputs.append( trans_nu_data.histogram( kinds=fig, binning=self.output_binning, weights_col='pisa_weight', errors=True, name=str(NuFlavIntGroup(fig)), ) ) if self.muons: outputs.append( self._data.histogram( kinds='muons', binning=self.output_binning, weights_col='pisa_weight', errors=True, name='muons', tex=text2tex('muons') ) ) if self.noise: outputs.append( self._data.histogram( kinds='noise', binning=self.output_binning, weights_col='pisa_weight', errors=True, name='noise', tex=text2tex('noise') ) ) return MapSet(maps=outputs, name=self._data.metadata['name'])
def plot_1d_projection(self, map, plot_axis, **kwargs): """plot map projected on plot_axis""" r_vmin = kwargs.pop('r_vmin', None) r_vmax = kwargs.pop('r_vmax', None) axis = plt.gca() plt_binning = map.binning[plot_axis] hist = self.project_1d(map, plot_axis) if map.tex == 'data': axis.errorbar(plt_binning.weighted_centers.m, unp.nominal_values(hist), yerr=unp.std_devs(hist), fmt='o', markersize='4', label=tex_dollars(text2tex('data')), color='k', ecolor='k', mec='k', **kwargs) else: axis.hist(inf2finite(plt_binning.weighted_centers.m), weights=unp.nominal_values(hist), bins=inf2finite(plt_binning.bin_edges.m), histtype='step', lw=1.5, label=tex_dollars(text2tex(map.tex)), color=self.color, **kwargs) axis.bar(plt_binning.bin_edges.m[:-1], 2 * unp.std_devs(hist), bottom=unp.nominal_values(hist) - unp.std_devs(hist), width=plt_binning.bin_widths.m, alpha=0.25, linewidth=0, color=self.color, **kwargs) axis.set_xlabel(tex_dollars(plt_binning.label)) if self.label: axis.set_ylabel(tex_dollars(text2tex(self.label))) if plt_binning.is_log: axis.set_xscale('log') if self.log: axis.set_yscale('log') else: axis.set_ylim(0, np.max(unp.nominal_values(hist)) * 1.4) axis.set_xlim( inf2finite(plt_binning.bin_edges.m)[0], inf2finite(plt_binning.bin_edges.m)[-1]) if self.grid: plt.grid(True, which="both", ls='-', alpha=0.2)
def plot_xsec(self, map_set, ylim=None, logx=True): from pisa.utils import fileio zero_np_element = np.array([0]) for map in map_set: binning = map.binning if 'true_energy' in binning.names: energy_binning = binning.true_energy elif 'reco_energy' in binning.names: energy_binning = binning.reco_energy else: dim_idx = binning.index('energy', use_basenames=True) energy_binning = binning.dims[dim_idx] fig = plt.figure(figsize=self.size) fig.suptitle(map.name, y=0.95) ax = fig.add_subplot(111) ax.grid(b=True, which='major') ax.grid(b=True, which='minor', linestyle=':') plt.xlabel(tex_dollars(energy_binning.label), size=18) plt.ylabel(tex_dollars(text2tex(self.label)), size=18) if self.log: ax.set_yscale('log') if logx: ax.set_xscale('log') if ylim: ax.set_ylim(ylim) ax.set_xlim(np.min(energy_binning.bin_edges.m), np.max(energy_binning.bin_edges.m)) hist = map.hist array_element = np.hstack((hist, zero_np_element)) ax.step(energy_binning.bin_edges.m, array_element, where='post') fileio.mkdir(self.outdir) fig.savefig(self.outdir + '/' + map.name + '.png', bbox_inches='tight', dpi=150)
def plot_1d_ratio(self, maps, plot_axis, **kwargs): """make a ratio plot for a 1d projection""" r_vmin = kwargs.pop('r_vmin', None) r_vmax = kwargs.pop('r_vmax', None) axis = plt.gca() map0 = maps[0] plt_binning = map0.binning[plot_axis] hist = self.project_1d(map0, plot_axis) hist0 = unp.nominal_values(hist) # TODO: should this be used somewhere? err0 = unp.std_devs(hist) axis.set_xlim( inf2finite(plt_binning.bin_edges.m)[0], inf2finite(plt_binning.bin_edges.m)[-1]) maximum = 1.0 minimum = 1.0 self.reset_colors() for map in maps: self.next_color() hist = self.project_1d(map, plot_axis) hist1 = unp.nominal_values(hist) err1 = unp.std_devs(hist) ratio = np.zeros_like(hist0) ratio_error = np.zeros_like(hist0) for i, hist0i in enumerate(hist0): if hist1[i] == 0 and hist0i == 0: ratio[i] = 1. ratio_error[i] = 1. elif hist1[i] != 0 and hist0i == 0: logging.warning('deviding non 0 by 0 for ratio') ratio[i] = 0. ratio_error[i] = 1. else: ratio[i] = hist1[i] / hist0i ratio_error[i] = err1[i] / hist0i minimum = min(minimum, ratio[i]) maximum = max(maximum, ratio[i]) if map.tex == 'data': axis.errorbar(plt_binning.weighted_centers.m, ratio, yerr=ratio_error, fmt='o', markersize='4', label=tex_dollars(text2tex('data')), color='k', ecolor='k', mec='k') else: _ = axis.hist(inf2finite(plt_binning.weighted_centers.m), weights=ratio, bins=inf2finite(plt_binning.bin_edges.m), histtype='step', lw=1.5, label=tex_dollars(text2tex(map.tex)), color=self.color) axis.bar(plt_binning.bin_edges.m[:-1], 2 * ratio_error, bottom=ratio - ratio_error, width=plt_binning.bin_widths.m, alpha=0.25, linewidth=0, color=self.color) if self.grid: plt.grid(True, which="both", ls='-', alpha=0.2) self.fig.subplots_adjust(hspace=0) axis.set_ylabel(tex_dollars(text2tex('ratio'))) axis.set_xlabel(tex_dollars(plt_binning.label)) # Calculate nice scale: if r_vmin is not None and r_vmax is not None: axis.set_ylim(1 - r_vmin, 1 + r_vmax) else: off = max(maximum - 1, 1 - minimum) axis.set_ylim(1 - 1.2 * off, 1 + 1.2 * off)
def plot_2d_map(self, map, cmap=None, **kwargs): """plot map or transform on current axis in 2d""" vmin = kwargs.pop('vmin', None) vmax = kwargs.pop('vmax', None) axis = plt.gca() if isinstance(map, BinnedTensorTransform): binning = map.input_binning elif isinstance(map, Map): binning = map.binning else: raise TypeError('Unhandled `map` type %s' % map.__class__.__name__) dims = binning.dims bin_centers = binning.weighted_centers bin_edges = binning.bin_edges linlog = all([(d.is_log or d.is_lin) for d in binning]) zmap = map.nominal_values if self.log: zmap = np.log10(zmap) if self.symmetric: vmax = np.max(np.abs(np.ma.masked_invalid(zmap))) vmin = -vmax if cmap is None: cmap = CMAP_DIV else: if vmax is None: vmax = np.max(zmap[np.isfinite(zmap)]) if vmin is None: vmin = np.min(zmap[np.isfinite(zmap)]) if cmap is None: cmap = CMAP_SEQ extent = [ np.min(bin_edges[0].m), np.max(bin_edges[0].m), np.min(bin_edges[1].m), np.max(bin_edges[1].m) ] # Only lin or log can be handled by imshow...otherise use colormesh # TODO: fix imshow for log-scaled energy vs. lin-scaled coszen, or # remove this code altogether if False: #linlog: # Needs to be transposed for imshow _ = plt.imshow(zmap.T, origin='lower', interpolation='nearest', extent=extent, aspect='auto', cmap=cmap, vmin=vmin, vmax=vmax, **kwargs) else: x, y = np.meshgrid(bin_edges[0], bin_edges[1]) pcol = plt.pcolormesh(x, y, np.ma.masked_invalid(zmap.T), vmin=vmin, vmax=vmax, cmap=cmap, linewidth=0, rasterized=True, **kwargs) pcol.set_edgecolor('face') if self.annotate: for i in range(len(bin_centers[0])): for j in range(len(bin_centers[1])): bin_x = bin_centers[0][i].m bin_y = bin_centers[1][j].m plt.annotate('%.1f' % (zmap[i, j]), xy=(bin_x, bin_y), xycoords=('data', 'data'), xytext=(bin_x, bin_y), textcoords='data', va='top', ha='center', size=7) axis.set_xlabel(tex_dollars(dims[0].label)) axis.set_ylabel(tex_dollars(dims[1].label)) axis.set_xlim(extent[0:2]) axis.set_ylim(extent[2:4]) # TODO: use log2 scale & integer tick labels if too few major gridlines # result from default log10 scale if dims[0].is_log: axis.set_xscale('log') if dims[1].is_log: axis.set_yscale('log') if self.log: col_bar = plt.colorbar(format=r'$10^{%.1f}$') else: col_bar = plt.colorbar() if self.label: col_bar.set_label(tex_dollars(text2tex(self.label)))
def histogram(self, kinds, binning, binning_cols=None, weights_col=None, errors=False, name=None, tex=None, **kwargs): """Histogram the events of all `kinds` specified, with `binning` and optionally applying `weights`. Parameters ---------- kinds : string, sequence of NuFlavInt, or NuFlavIntGroup binning : OneDimBinning, MultiDimBinning or sequence of arrays (one array per binning dimension) binning_cols : string or sequence of strings Bin only these dimensions, ignoring other dimensions in `binning` weights_col : None or string Column to use for weighting the events errors : bool Whether to attach errors to the resulting Map name : None or string Name to give to resulting Map. If None, a default is derived from `kinds` and `weights_col`. tex : None or string TeX label to give to the resulting Map. If None, default is dereived from the `name` specified or the derived default. **kwargs : Keyword args passed to Map object Returns ------- Map : numpy ndarray with as many dimensions as specified by `binning` argument """ # TODO: make able to take integer for `binning` and--in combination # with units in the Data columns--generate an appropriate # MultiDimBinning object, attach this and return the package as a Map. if isinstance(kinds, basestring): kinds = [kinds] if 'muons' not in kinds and 'noise' not in kinds: kinds = self._parse_flavint_groups(kinds) kinds = kinds[0] if isinstance(binning_cols, basestring): binning_cols = [binning_cols] assert weights_col is None or isinstance(weights_col, basestring) # TODO: units of columns, and convert bin edges if necessary if isinstance(binning, OneDimBinning): binning = MultiDimBinning([binning]) elif isinstance(binning, MultiDimBinning): pass elif (isinstance(binning, Iterable) and not isinstance(binning, Sequence)): binning = list(binning) elif isinstance(binning, Sequence): pass else: raise TypeError('Unhandled type %s for `binning`.' % type(binning)) if isinstance(binning, Sequence): raise NotImplementedError( 'Simle sequences not handled at this time. Please specify a' ' OneDimBinning or MultiDimBinning object for `binning`.') # assert len(binning_cols) == len(binning) # bin_edges = binning # TODO: units support for Data will mean we can do `m_as(...)` here! bin_edges = [edges.magnitude for edges in binning.bin_edges] if binning_cols is None: binning_cols = binning.names else: assert set(binning_cols).issubset(set(binning.names)) # Extract the columns' data into a list of array(s) for histogramming sample = [self[kinds][colname] for colname in binning_cols] err_weights = None hist_weights = None if weights_col is not None: hist_weights = self[kinds][weights_col] if errors: err_weights = np.square(hist_weights) hist, edges = np.histogramdd(sample=sample, weights=hist_weights, bins=bin_edges) if errors: sumw2, edges = np.histogramdd(sample=sample, weights=err_weights, bins=bin_edges) hist = unp.uarray(hist, np.sqrt(sumw2)) if name is None: if tex is None: try: tex = kinds.tex # TODO: specify specific exception(s) except: tex = r'{0}'.format(kinds) if weights_col is not None: tex += r', \; {\rm weights} =' + text2tex(weights_col) name = str(kinds) if weights_col is not None: name += ', weights=' + weights_col if tex is None: tex = text2tex(name) return Map(name=name, hist=hist, binning=binning, tex=tex, **kwargs)