def main(return_outputs=False): """Main; call as script with `return_outputs=False` or interactively with `return_outputs=True`""" from pisa.utils.plotter import Plotter args = parse_args() set_verbosity(args.v) plot_formats = [] if args.pdf: plot_formats.append('pdf') if args.png: plot_formats.append('png') distribution_maker = DistributionMaker(pipelines=args.pipeline) # pylint: disable=redefined-outer-name if args.select is not None: distribution_maker.select_params(args.select) outputs = distribution_maker.get_outputs(return_sum=args.return_sum) # pylint: disable=redefined-outer-name if args.outdir: # TODO: unique filename: append hash (or hash per pipeline config) fname = 'distribution_maker_outputs.json.bz2' mkdir(args.outdir) fpath = expand(os.path.join(args.outdir, fname)) to_file(outputs, fpath) if args.outdir and plot_formats: my_plotter = Plotter(outdir=args.outdir, fmt=plot_formats, log=False, annotate=False) for num, output in enumerate(outputs): my_plotter.plot_2d_array(output, fname='dist_output_%d' % num) if return_outputs: return distribution_maker, outputs
def test_standard_plots(xsec_file, outdir='./'): from pisa.utils.plotter import Plotter xsec = genie.get_combined_xsec(xsec_file) e_bins = MultiDimBinning( [OneDimBinning(name='true_energy', tex=r'E_\nu', num_bins=150, domain=(1E-1, 1E3)*ureg.GeV, is_log=True)] ) xsec.compute_maps(e_bins) logging.info('Making plots for genie xsec_maps') plot_obj = Plotter(outdir=outdir, stamp='Cross-Section', fmt='png', log=True, size=(12, 8), label=r'Cross-Section ($m^{2}$)') maps = xsec.return_mapset() plot_obj.plot_xsec(maps, ylim=(1E-43, 1E-37))
def test_per_e_plot(xsec_file, outdir='./'): from pisa.utils.plotter import Plotter xsec = genie.get_combined_xsec(xsec_file) e_bins = MultiDimBinning( [OneDimBinning(name='true_energy', tex=r'E_\nu', num_bins=200, domain=(1E-1, 1E3)*ureg.GeV, is_log=True)] ) xsec.compute_maps(e_bins) xsec.scale_maps(1/e_bins.true_energy.bin_widths.magnitude) logging.info('Making plots for genie xsec_maps per energy') plot_obj = Plotter(outdir=outdir, stamp='Cross-Section / Energy', fmt='png', log=False, size=(12, 8), label=r'Cross-Section / Energy ($m^{2} GeV^{-1}$)') maps = xsec.return_mapset() plot_obj.plot_xsec(maps, ylim=(3.5E-41, 3E-40))
def main(return_outputs=False): """Main; call as script with `return_outputs=False` or interactively with `return_outputs=True`""" from pisa.utils.plotter import Plotter args = parse_args() set_verbosity(args.v) plot_formats = [] if args.pdf: plot_formats.append('pdf') if args.png: plot_formats.append('png') detectors = Detectors(args.pipeline,shared_params=args.shared_params) Names = detectors.det_names if args.select is not None: detectors.select_params(args.select) outputs = detectors.get_outputs(return_sum=args.return_sum) #outputs = outputs[0].fluctuate( # method='poisson', random_state=get_random_state([0, 0, 0])) if args.outdir: # TODO: unique filename: append hash (or hash per pipeline config) fname = 'detectors_outputs.json.bz2' mkdir(args.outdir) fpath = expand(os.path.join(args.outdir, fname)) to_file(outputs, fpath) if args.outdir and plot_formats: my_plotter = Plotter( outdir=args.outdir, fmt=plot_formats, log=False, annotate=False ) for num, output in enumerate(outputs): if args.return_sum: my_plotter.plot_2d_array( output, fname=Names[num] ) else: for out in output: my_plotter.plot_2d_array( out, fname=Names[num] ) if return_outputs: return detectors, outputs
def main(return_outputs=False): """Run unit tests if `pipeline.py` is called as a script.""" from pisa.utils.plotter import Plotter args = parse_args() set_verbosity(args.v) # Even if user specifies an integer on command line, it comes in as a # string. Try to convert to int (e.g. if `'1'` is passed to indicate the # second stage), and -- if successful -- use this as `args.only_stage`. # Otherwise, the string value passed will be used (e.g. `'osc'` could be # passed). try: only_stage_int = int(args.only_stage) except (ValueError, TypeError): pass else: args.only_stage = only_stage_int if args.outdir: mkdir(args.outdir) else: if args.pdf or args.png: raise ValueError("No --outdir provided, so cannot save images.") # Most basic parsing of the pipeline config (parsing only to this level # allows for simple strings to be specified as args for updating) bcp = PISAConfigParser() bcp.read(args.pipeline) # Update the config with any args specified on command line if args.arg is not None: for arg_list in args.arg: if len(arg_list) < 2: raise ValueError( 'Args must be formatted as: "section arg=val". Got "%s"' " instead." % " ".join(arg_list)) section = arg_list[0] remainder = " ".join(arg_list[1:]) eq_split = remainder.split("=") newarg = eq_split[0].strip() value = ("=".join(eq_split[1:])).strip() logging.debug('Setting config section "%s" arg "%s" = "%s"', section, newarg, value) try: bcp.set(section, newarg, value) except NoSectionError: logging.error( 'Invalid section "%s" specified. Must be one of %s', section, bcp.sections(), ) raise # Instantiate the pipeline pipeline = Pipeline(bcp) # pylint: disable=redefined-outer-name if args.select is not None: pipeline.select_params(args.select, error_on_missing=True) if args.only_stage is None: stop_idx = args.stop_after_stage try: stop_idx = int(stop_idx) except (TypeError, ValueError): pass if isinstance(stop_idx, str): stop_idx = pipeline.index(stop_idx) outputs = pipeline.get_outputs(idx=stop_idx) # pylint: disable=redefined-outer-name if stop_idx is not None: stop_idx += 1 indices = slice(0, stop_idx) else: assert args.stop_after_stage is None idx = pipeline.index(args.only_stage) stage = pipeline[idx] indices = slice(idx, idx + 1) # Create dummy inputs if necessary inputs = None if hasattr(stage, "input_binning"): logging.warning( "Stage requires input, so building dummy" " inputs of random numbers, with random state set to the input" " index according to alphabetical ordering of input names and" " filled in alphabetical ordering of dimension names.") input_maps = [] tmp = deepcopy(stage.input_binning) alphabetical_binning = tmp.reorder_dimensions(sorted(tmp.names)) for input_num, input_name in enumerate(sorted(stage.input_names)): # Create a new map with all 3's; name according to the input hist = np.full(shape=alphabetical_binning.shape, fill_value=3.0) input_map = Map(name=input_name, binning=alphabetical_binning, hist=hist) # Apply Poisson fluctuations to randomize the values in the map input_map.fluctuate(method="poisson", random_state=input_num) # Reorder dimensions according to user's original binning spec input_map.reorder_dimensions(stage.input_binning) input_maps.append(input_map) inputs = MapSet(maps=input_maps, name="ones", hash=1) outputs = stage.run(inputs=inputs) for stage in pipeline[indices]: if not args.outdir: break stg_svc = stage.stage_name + "__" + stage.service_name fbase = os.path.join(args.outdir, stg_svc) if args.intermediate or stage == pipeline[indices][-1]: stage.outputs.to_json(fbase + "__output.json.bz2") # also only plot if args intermediate or last stage if args.intermediate or stage == pipeline[indices][-1]: formats = OrderedDict(png=args.png, pdf=args.pdf) if isinstance(stage.outputs, Data): # TODO(shivesh): plots made here will use the most recent # "pisa_weight" column and so all stages will have identical plots # (one workaround is to turn on "memcache_deepcopy") # TODO(shivesh): intermediate stages have no output binning if stage.output_binning is None: logging.debug("Skipping plot of intermediate stage %s", stage) continue outputs = stage.outputs.histogram_set( binning=stage.output_binning, nu_weights_col="pisa_weight", mu_weights_col="pisa_weight", noise_weights_col="pisa_weight", mapset_name=stg_svc, errors=True, ) try: for fmt, enabled in formats.items(): if not enabled: continue my_plotter = Plotter( stamp="Event rate", outdir=args.outdir, fmt=fmt, log=False, annotate=args.annotate, ) my_plotter.ratio = True my_plotter.plot_2d_array(outputs, fname=stg_svc + "__output", cmap="RdBu") except ValueError as exc: logging.error( "Failed to save plot to format %s. See exception" " message below", fmt, ) traceback.format_exc() logging.exception(exc) logging.warning("I can't go on, I'll go on.") if return_outputs: return pipeline, outputs
def main(): args = parse_args() set_verbosity(args.v) if args.plot: import matplotlib as mpl mpl.use('pdf') import matplotlib.pyplot as plt from pisa.utils.plotter import Plotter cfg = from_file(args.fit_settings) sys_list = cfg.get('general', 'sys_list').replace(' ', '').split(',') stop_idx = cfg.getint('general', 'stop_after_stage') for sys in sys_list: # Parse info for given systematic nominal = cfg.getfloat(sys, 'nominal') degree = cfg.getint(sys, 'degree') force_through_nominal = cfg.getboolean(sys, 'force_through_nominal') runs = eval(cfg.get(sys, 'runs')) #print "runs ", runs smooth = cfg.get(sys, 'smooth') x_values = np.array(sorted(runs)) # Build fit function if force_through_nominal: function = "lambda x, *p: np.polynomial.polynomial.polyval(x, [1.] + list(p))" else: function = "lambda x, *p: np.polynomial.polynomial.polyval(x, list(p))" # Add free parameter for constant term degree += 1 fit_fun = eval(function) # Instantiate template maker template_maker = Pipeline(args.template_settings) if not args.set_param == '': for one_set_param in args.set_param: p_name, value = one_set_param.split("=") #print "p_name,value= ", p_name, " ", value value = parse_quantity(value) value = value.n * value.units param = template_maker.params[p_name] #print "old ", p_name, "value = ", param.value param.value = value #print "new ", p_name, "value = ", param.value template_maker.update_params(param) inputs = {} map_names = None # Get sys templates for run in runs: for key, val in cfg.items('%s:%s'%(sys, run)): if key.startswith('param.'): _, pname = key.split('.') param = template_maker.params[pname] try: value = parse_quantity(val) param.value = value.n * value.units except ValueError: value = parse_string_literal(val) param.value = value param.set_nominal_to_current_value() template_maker.update_params(param) # Retreive maps template = template_maker.get_outputs(idx=stop_idx) if map_names is None: map_names = [m.name for m in template] inputs[run] = {} for m in template: inputs[run][m.name] = m.hist # Numpy acrobatics: arrays = {} for name in map_names: arrays[name] = [] for x in x_values: arrays[name].append( inputs[x][name] / unp.nominal_values(inputs[nominal][name]) ) a = np.array(arrays[name]) arrays[name] = np.rollaxis(a, 0, len(a.shape)) # Shift to get deltas x_values -= nominal # Binning object (assuming they're all the same) binning = template.maps[0].binning shape = [d.num_bins for d in binning] + [degree] shape_small = [d.num_bins for d in binning] outputs = {} errors = {} for name in map_names: # Now actualy perform some fits outputs[name] = np.ones(shape) errors[name] = np.ones(shape) for idx in np.ndindex(*shape_small): y_values = unp.nominal_values(arrays[name][idx]) y_sigma = unp.std_devs(arrays[name][idx]) if np.any(y_sigma): popt, pcov = curve_fit(fit_fun, x_values, y_values, sigma=y_sigma, p0=np.ones(degree)) else: popt, pcov = curve_fit(fit_fun, x_values, y_values, p0=np.ones(degree)) perr = np.sqrt(np.diag(pcov)) for k, p in enumerate(popt): outputs[name][idx][k] = p errors[name][idx][k] = perr[k] # TODO(philippeller): the below block of code will fail # Maybe plot #if args.plot: # fig_num = i + nx * j # if fig_num == 0: # fig = plt.figure(num=1, figsize=( 4*nx, 4*ny)) # subplot_idx = nx*(ny-1-j)+ i + 1 # plt.subplot(ny, nx, subplot_idx) # #plt.snameter(x_values, y_values, color=plt_colors[name]) # plt.gca().errorbar(x_values, y_values, yerr=y_sigma, # fmt='o', color=plt_colors[name], # ecolor=plt_colors[name], # mec=plt_colors[name]) # # Plot nominal point again in black # plt.snameter([0.0], [1.0], color='k') # f_values = fit_fun(x_values, *popt) # fun_plot, = plt.plot(x_values, f_values, # color=plt_colors[name]) # plt.ylim(np.min(unp.nominal_values(arrays[name]))*0.9, # np.max(unp.nominal_values(arrays[name]))*1.1) # if i > 0: # plt.setp(plt.gca().get_yticklabels(), visible=False) # if j > 0: # plt.setp(plt.gca().get_xticklabels(), visible=False) if smooth == 'gauss': for name in map_names: for d in range(degree): outputs[name][...,d] = gaussian_filter(outputs[name][...,d],sigma=1) if smooth == 'gauss_pid': for name in map_names: split_idx = binning.names.index('pid') tot = len(binning)-1 for d in range(degree): for p in range(len(binning['pid'])): outputs[name][...,p,d] = gaussian_filter( np.swapaxes(outputs[name], split_idx, tot)[...,p,d], sigma=1 ) outputs[name] = np.swapaxes(outputs[name], split_idx, tot) # Save the raw ones anyway outputs['pname'] = sys outputs['nominal'] = nominal outputs['function'] = function outputs['map_names'] = map_names outputs['binning_hash'] = binning.hash to_file(outputs, '%s/%s_sysfits_%s_%s.json'%(args.out_dir, sys, args.tag, smooth)) if args.plot: for d in range(degree): maps = [] for name in map_names: maps.append(Map(name='%s_raw'%name, hist=outputs[name][...,d], binning=binning)) maps = MapSet(maps) my_plotter = Plotter( stamp='', outdir=args.out_dir, fmt='pdf', log=False, label='' ) my_plotter.plot_2d_array( maps, fname='%s_%s_%s_%s'%(sys, args.tag, d, smooth), )
def test_kde_histogramdd(): """Unit tests for kde_histogramdd""" from argparse import ArgumentParser from shutil import rmtree from tempfile import mkdtemp from pisa import ureg from pisa.core.map import Map, MapSet from pisa.utils.log import logging, set_verbosity from pisa.utils.plotter import Plotter parser = ArgumentParser() parser.add_argument("-v", action="count", default=None, help="set verbosity level") args = parser.parse_args() set_verbosity(args.v) temp_dir = mkdtemp() try: my_plotter = Plotter( stamp="", outdir=temp_dir, fmt="pdf", log=False, annotate=False, symmetric=False, ratio=True, ) b1 = OneDimBinning(name="coszen", num_bins=20, is_lin=True, domain=[-1, 1], tex=r"\cos(\theta)") b2 = OneDimBinning(name="energy", num_bins=10, is_log=True, domain=[1, 80] * ureg.GeV, tex=r"E") b3 = OneDimBinning(name="pid", num_bins=2, bin_edges=[0, 1, 2], tex=r"pid") binning = b1 * b2 * b3 # now let's generate some toy data N = 100000 cz = np.random.normal(1, 1.2, N) # cut away coszen outside -1, 1 cz = cz[(cz >= -1) & (cz <= 1)] e = np.random.normal(30, 20, len(cz)) pid = np.random.uniform(0, 2, len(cz)) data = np.array([cz, e, pid]).T # make numpy histogram for validation bins = [unp.nominal_values(b.bin_edges) for b in binning] raw_hist, _ = np.histogramdd(data, bins=bins) # get KDE'ed histo hist = kde_histogramdd( data, binning, bw_method="silverman", coszen_name="coszen", oversample=10, use_cuda=True, stack_pid=True, ) # put into mapsets and plot m1 = Map(name="KDE", hist=hist, binning=binning) m2 = Map(name="raw", hist=raw_hist, binning=binning) with np.errstate(divide="ignore", invalid="ignore"): m3 = m2 / m1 m3.name = "hist/KDE" m3.tex = m3.name m4 = m1 - m2 m4.name = "KDE - hist" m4.tex = m4.name ms = MapSet([m1, m2, m3, m4]) my_plotter.plot_2d_array(ms, fname="test_kde", cmap="summer") except: rmtree(temp_dir) raise else: logging.warning("Inspect and manually clean up output(s) saved to %s" % temp_dir)
def compare(outdir, ref, ref_label, test, test_label, asymm_max=None, asymm_min=None, combine=None, diff_max=None, diff_min=None, fract_diff_max=None, fract_diff_min=None, json=False, pdf=False, png=False, ref_abs=False, ref_param_selections=None, sum=None, test_abs=False, test_param_selections=None): """Compare two entities. The result each entity specification is formatted into a MapSet and stored to disk, so that e.g. re-running a DistributionMaker is unnecessary to reproduce the results. Parameters ---------- outdir : string Store output plots to this directory ref : string or array of strings Pipeline settings config file that generates reference output, or a stored map or map set. Multiple pipelines, maps, or map sets are supported ref_abs : bool Use the absolute value of the reference plot for comparisons ref_label : string Label for reference ref_param-selections : string Param selections to apply to ref pipeline config(s). Not applicable if ref specifies stored map or map sets test : string or array of strings Pipeline settings config file that generates test output, or a stored map or map set. Multiple pipelines, maps, or map sets are supported test_abs : bool Use the absolute value of the test plot for comparisons test_label : string Label for test test_param_selections : None or string Param selections to apply to test pipeline config(s). Not applicable if test specifies stored map or map sets combine : None or string or array of strings Combine by wildcard string, where string globbing (a la command line) uses asterisk for any number of wildcard characters. Use single quotes such that asterisks do not get expanded by the shell. Multiple combine strings supported sum : None or int Sum over (and hence remove) the specified axis or axes. I.e., project the map onto remaining (unspecified) axis or axes json : bool Save output maps in compressed json (json.bz2) format pdf : bool Save plots in PDF format. If neither this nor png is specified, no plots are produced png : bool Save plots in PNG format. If neither this nor pdf is specfied, no plots are produced diff_min : None or float Difference plot vmin; if you specify only one of diff_min or diff_max, symmetric limits are automatically used (min = -max) diff_max : None or float Difference plot max; if you specify only one of diff_min or diff_max, symmetric limits are automatically used (min = -max) fract_diff_min : None or float Fractional difference plot vmin; if you specify only one of fract_diff_min or fract_diff_max, symmetric limits are automatically used (min = -max) fract_diff_max : None or float Fractional difference plot max; if you specify only one of fract_diff_min or fract_diff_max, symmetric limits are automatically used (min = -max) asymm_min : None or float Asymmetry plot vmin; if you specify only one of asymm_min or asymm_max, symmetric limits are automatically used (min = -max) asymm_max : None or float Fractional difference plot max; if you specify only one of asymm_min or asymm_max, symmetric limits are automatically used (min = -max) Returns ------- summary_stats : dict Dictionary containing a summary for each h Map processed diff : MapSet MapSet of the difference - (Test - Ref) fract_diff : MapSet MapSet of the fractional difference - (Test - Ref) / Ref asymm : MapSet MapSet of the asymmetric fraction difference or pull - (Test - Ref) / sqrt(Ref) """ ref_plot_label = ref_label if ref_abs and not ref_label.startswith('abs'): ref_plot_label = 'abs(%s)' % ref_plot_label test_plot_label = test_label if test_abs and not test_label.startswith('abs'): test_plot_label = 'abs(%s)' % test_plot_label plot_formats = [] if pdf: plot_formats.append('pdf') if png: plot_formats.append('png') diff_symm = True if diff_min is not None and diff_max is None: diff_max = -diff_min diff_symm = False if diff_max is not None and diff_min is None: diff_min = -diff_max diff_symm = False fract_diff_symm = True if fract_diff_min is not None and fract_diff_max is None: fract_diff_max = -fract_diff_min fract_diff_symm = False if fract_diff_max is not None and fract_diff_min is None: fract_diff_min = -fract_diff_max fract_diff_symm = False asymm_symm = True if asymm_max is not None and asymm_min is None: asymm_min = -asymm_max asymm_symm = False if asymm_min is not None and asymm_max is None: asymm_max = -asymm_min asymm_symm = False outdir = os.path.expanduser(os.path.expandvars(outdir)) mkdir(outdir) # Get the reference distribution(s) into the form of a test MapSet p_ref = None ref_source = None if isinstance(ref, Map): p_ref = MapSet(ref) ref_source = MAP_SOURCE_STR elif isinstance(ref, MapSet): p_ref = ref ref_source = MAPSET_SOURCE_STR elif isinstance(ref, Pipeline): if ref_param_selections is not None: ref.select_params(ref_param_selections) p_ref = ref.get_outputs() ref_source = PIPELINE_SOURCE_STR elif isinstance(ref, DistributionMaker): if ref_param_selections is not None: ref.select_params(ref_param_selections) p_ref = ref.get_outputs() ref_source = DISTRIBUTIONMAKER_SOURCE_STR else: if len(ref) == 1: try: ref_pipeline = Pipeline(config=ref[0]) except: pass else: ref_source = PIPELINE_SOURCE_STR if ref_param_selections is not None: ref_pipeline.select_params(ref_param_selections) p_ref = ref_pipeline.get_outputs() else: try: ref_dmaker = DistributionMaker(pipelines=ref) except: pass else: ref_source = DISTRIBUTIONMAKER_SOURCE_STR if ref_param_selections is not None: ref_dmaker.select_params(ref_param_selections) p_ref = ref_dmaker.get_outputs() if p_ref is None: try: p_ref = [Map.from_json(f) for f in ref] except: pass else: ref_source = MAP_SOURCE_STR p_ref = MapSet(p_ref) if p_ref is None: assert ref_param_selections is None assert len(ref) == 1, 'Can only handle one MapSet' try: p_ref = MapSet.from_json(ref[0]) except: pass else: ref_source = MAPSET_SOURCE_STR if p_ref is None: raise ValueError( 'Could not instantiate the reference Pipeline, DistributionMaker,' ' Map, or MapSet from ref value(s) %s' % ref) ref = p_ref logging.info('Reference map(s) derived from a ' + ref_source) # Get the test distribution(s) into the form of a test MapSet p_test = None test_source = None if isinstance(test, Map): p_test = MapSet(test) test_source = MAP_SOURCE_STR elif isinstance(test, MapSet): p_test = test test_source = MAPSET_SOURCE_STR elif isinstance(test, Pipeline): if test_param_selections is not None: test.select_params(test_param_selections) p_test = test.get_outputs() test_source = PIPELINE_SOURCE_STR elif isinstance(test, DistributionMaker): if test_param_selections is not None: test.select_params(test_param_selections) p_test = test.get_outputs() test_source = DISTRIBUTIONMAKER_SOURCE_STR else: if len(test) == 1: try: test_pipeline = Pipeline(config=test[0]) except: pass else: test_source = PIPELINE_SOURCE_STR if test_param_selections is not None: test_pipeline.select_params(test_param_selections) p_test = test_pipeline.get_outputs() else: try: test_dmaker = DistributionMaker(pipelines=test) except: pass else: test_source = DISTRIBUTIONMAKER_SOURCE_STR if test_param_selections is not None: test_dmaker.select_params(test_param_selections) p_test = test_dmaker.get_outputs() if p_test is None: try: p_test = [Map.from_json(f) for f in test] except: pass else: test_source = MAP_SOURCE_STR p_test = MapSet(p_test) if p_test is None: assert test_param_selections is None assert len(test) == 1, 'Can only handle one MapSet' try: p_test = MapSet.from_json(test[0]) except: pass else: test_source = MAPSET_SOURCE_STR if p_test is None: raise ValueError( 'Could not instantiate the test Pipeline, DistributionMaker, Map,' ' or MapSet from test value(s) %s' % test) test = p_test logging.info('Test map(s) derived from a ' + test_source) if combine is not None: ref = ref.combine_wildcard(combine) test = test.combine_wildcard(combine) if isinstance(ref, Map): ref = MapSet([ref]) if isinstance(test, Map): test = MapSet([test]) if sum is not None: ref = ref.sum(sum) test = test.sum(sum) # Set the MapSet names according to args passed by user ref.name = ref_label test.name = test_label # Save to disk the maps being plotted (excluding optional aboslute value # operations) if json: refmaps_path = os.path.join(outdir, 'maps__%s.json.bz2' % ref_label) to_file(ref, refmaps_path) testmaps_path = os.path.join(outdir, 'maps__%s.json.bz2' % test_label) to_file(test, testmaps_path) if set(test.names) != set(ref.names): raise ValueError('Test map names %s do not match ref map names %s.' % (sorted(test.names), sorted(ref.names))) # Aliases to save keystrokes def masked(x): return np.ma.masked_invalid(x.nominal_values) def zero_to_nan(map): newmap = deepcopy(map) mask = np.isclose(newmap.nominal_values, 0, rtol=0, atol=EPSILON) newmap.hist[mask] = np.nan return newmap reordered_test = [] new_ref = [] diff_maps = [] fract_diff_maps = [] asymm_maps = [] summary_stats = {} for ref_map in ref: test_map = test[ref_map.name].reorder_dimensions(ref_map.binning) if ref_abs: ref_map = abs(ref_map) if test_abs: test_map = abs(test_map) diff_map = test_map - ref_map fract_diff_map = (test_map - ref_map) / zero_to_nan(ref_map) asymm_map = (test_map - ref_map) / zero_to_nan(ref_map**0.5) abs_fract_diff_map = np.abs(fract_diff_map) new_ref.append(ref_map) reordered_test.append(test_map) diff_maps.append(diff_map) fract_diff_maps.append(fract_diff_map) asymm_maps.append(asymm_map) min_ref = np.min(masked(ref_map)) max_ref = np.max(masked(ref_map)) min_test = np.min(masked(test_map)) max_test = np.max(masked(test_map)) total_ref = np.sum(masked(ref_map)) total_test = np.sum(masked(test_map)) mean_ref = np.mean(masked(ref_map)) mean_test = np.mean(masked(test_map)) max_abs_fract_diff = np.max(masked(abs_fract_diff_map)) mean_abs_fract_diff = np.mean(masked(abs_fract_diff_map)) median_abs_fract_diff = np.median(masked(abs_fract_diff_map)) mean_fract_diff = np.mean(masked(fract_diff_map)) min_fract_diff = np.min(masked(fract_diff_map)) max_fract_diff = np.max(masked(fract_diff_map)) std_fract_diff = np.std(masked(fract_diff_map)) mean_diff = np.mean(masked(diff_map)) min_diff = np.min(masked(diff_map)) max_diff = np.max(masked(diff_map)) std_diff = np.std(masked(diff_map)) median_diff = np.nanmedian(masked(diff_map)) mad_diff = np.nanmedian(masked(np.abs(diff_map))) median_fract_diff = np.nanmedian(masked(fract_diff_map)) mad_fract_diff = np.nanmedian(masked(np.abs(fract_diff_map))) min_asymm = np.min(masked(fract_diff_map)) max_asymm = np.max(masked(fract_diff_map)) total_asymm = np.sqrt(np.sum(masked(asymm_map)**2)) summary_stats[test_map.name] = OrderedDict([ ('min_ref', min_ref), ('max_ref', max_ref), ('total_ref', total_ref), ('mean_ref', mean_ref), ('min_test', min_test), ('max_test', max_test), ('total_test', total_test), ('mean_test', mean_test), ('max_abs_fract_diff', max_abs_fract_diff), ('mean_abs_fract_diff', mean_abs_fract_diff), ('median_abs_fract_diff', median_abs_fract_diff), ('min_fract_diff', min_fract_diff), ('max_fract_diff', max_fract_diff), ('mean_fract_diff', mean_fract_diff), ('std_fract_diff', std_fract_diff), ('median_fract_diff', median_fract_diff), ('mad_fract_diff', mad_fract_diff), ('min_diff', min_diff), ('max_diff', max_diff), ('mean_diff', mean_diff), ('std_diff', std_diff), ('median_diff', median_diff), ('mad_diff', mad_diff), ('min_asymm', min_asymm), ('max_asymm', max_asymm), ('total_asymm', total_asymm), ]) logging.info('Map %s...', ref_map.name) logging.info(' Ref map(s):') logging.info(' min :' + ('%.2f' % min_ref).rjust(12)) logging.info(' max :' + ('%.2f' % max_ref).rjust(12)) logging.info(' total :' + ('%.2f' % total_ref).rjust(12)) logging.info(' mean :' + ('%.2f' % mean_ref).rjust(12)) logging.info(' Test map(s):') logging.info(' min :' + ('%.2f' % min_test).rjust(12)) logging.info(' max :' + ('%.2f' % max_test).rjust(12)) logging.info(' total :' + ('%.2f' % total_test).rjust(12)) logging.info(' mean :' + ('%.2f' % mean_test).rjust(12)) logging.info(' Absolute fract. diff., abs((Test - Ref) / Ref):') logging.info(' max : %.4e', max_abs_fract_diff) logging.info(' mean : %.4e', mean_abs_fract_diff) logging.info(' median: %.4e', median_abs_fract_diff) logging.info(' Fractional difference, (Test - Ref) / Ref:') logging.info(' min : %.4e', min_fract_diff) logging.info(' max : %.4e', max_fract_diff) logging.info(' mean : %.4e +/- %.4e', mean_fract_diff, std_fract_diff) logging.info(' median: %.4e +/- %.4e', median_fract_diff, mad_fract_diff) logging.info(' Difference, Test - Ref:') logging.info(' min : %.4e', min_diff) logging.info(' max : %.4e', max_diff) logging.info(' mean : %.4e +/- %.4e', mean_diff, std_diff) logging.info(' median: %.4e +/- %.4e', median_diff, mad_diff) logging.info(' Asymmetry, (Test - Ref) / sqrt(Ref)') logging.info(' min : %.4e', min_asymm) logging.info(' max : %.4e', max_asymm) logging.info(' total : %.4e (sum in quadrature)', total_asymm) logging.info('') ref = MapSet(new_ref) test = MapSet(reordered_test) diff = MapSet(diff_maps) fract_diff = MapSet(fract_diff_maps) asymm = MapSet(asymm_maps) if json: diff.to_json( os.path.join( outdir, 'diff__%s__%s.json.bz2' % (test_plot_label, ref_plot_label))) fract_diff.to_json( os.path.join( outdir, 'fract_diff__%s___%s.json.bz2' % (test_plot_label, ref_plot_label))) asymm.to_json( os.path.join( outdir, 'asymm__%s___%s.json.bz2' % (test_plot_label, ref_plot_label))) to_file( summary_stats, os.path.join( outdir, 'stats__%s__%s.json.bz2' % (test_plot_label, ref_plot_label))) for plot_format in plot_formats: # Plot the raw distributions plotter = Plotter(stamp='', outdir=outdir, fmt=plot_format, log=False, annotate=False, symmetric=False, ratio=False) plotter.plot_2d_array(ref, fname='distr__%s' % ref_plot_label) plotter.plot_2d_array(test, fname='distr__%s' % test_plot_label) # Plot the difference (test - ref) plotter = Plotter(stamp='', outdir=outdir, fmt=plot_format, log=False, annotate=False, symmetric=diff_symm, ratio=False) plotter.label = '%s - %s' % (test_plot_label, ref_plot_label) plotter.plot_2d_array( test - ref, fname='diff__%s__%s' % (test_plot_label, ref_plot_label), #vmin=diff_min, vmax=diff_max ) # Plot the fractional difference (test - ref)/ref plotter = Plotter(stamp='', outdir=outdir, fmt=plot_format, log=False, annotate=False, symmetric=fract_diff_symm, ratio=True) plotter.label = ('(%s-%s)/%s' % (test_plot_label, ref_plot_label, ref_plot_label)) plotter.plot_2d_array( (test - ref) / MapSet([zero_to_nan(r) for r in ref]), fname='fract_diff__%s__%s' % (test_plot_label, ref_plot_label), #vmin=fract_diff_min, vmax=fract_diff_max ) # Plot the asymmetry (test - ref)/sqrt(ref) plotter = Plotter(stamp='', outdir=outdir, fmt=plot_format, log=False, annotate=False, symmetric=asymm_symm, ratio=True) plotter.label = (r'$(%s - %s)/\sqrt{%s}$' % (test_plot_label, ref_plot_label, ref_plot_label)) plotter.plot_2d_array( (test - ref) / MapSet([zero_to_nan(r**0.5) for r in ref]), fname='asymm__%s__%s' % (test_plot_label, ref_plot_label), #vmin=asymm_min, vmax=asymm_max ) return summary_stats, diff, fract_diff, asymm