def find_input_file(self, search_dirs): if self._input_file: utils.debug("searching for input_file={} defined for series".format(self._input_file)) e = InputFileNotFoundError(self._input_file, search_dirs) self._input_file = find(self._input_file, search_dirs) if not self._input_file: raise e
def find_input_files(self, search_dirs): if self._input_file: utils.debug("searching for input_file={} defined at top level of spec".format(self._input_file)) e = InputFileNotFoundError(self._input_file, search_dirs) self._input_file = find(self._input_file, search_dirs) if not self._input_file: raise e for plot in self.subplots: plot.find_input_files(search_dirs)
def configure_xaxis(ax, axis_spec): if "lim" in axis_spec: ax.set_xlim(axis_spec["lim"]) if "label" in axis_spec: ax.set_xlabel(axis_spec["label"]) if "type" in axis_spec: value = axis_spec["type"] utils.debug("seting x axis type: {}".format(value)) ax.set_xscale(value, basex=2)
def main(ctx, debug, include, quiet): # This is needed if main is called via setuptools entrypoint if ctx.obj is None: ctx.obj = {} utils.DEBUG = debug utils.QUIET = quiet ctx.obj["INCLUDE"] = include utils.debug("Running: {}".format(" ".join(sys.argv)))
def generate_plot(plot_spec): if "bar" == plot_spec.ty(): utils.debug("Generating bar plot") return generate_bar(plot_spec) elif "errorbar" == plot_spec.ty(): utils.debug("Generating errorbar plot") return generate_errorbar(plot_spec) else: utils.halt("Unrecognized plot type: {}".format(plot_spec.ty()))
def save(fig, path): utils.debug("saving bokeh figure: {}".format(path)) if path.endswith(".png"): export_png(fig, filename=path) elif path.endswith(".svg"): export_svgs(fig, filename=path) elif path.endswith(".html"): bokeh.io.output_file(path) bokeh.io.save(fig) else: utils.error("unsupported bokeh output type {}".format(path))
def generator_regplot(ax, ax_spec): series_specs = ax_spec.series for i, series_spec in enumerate(series_specs): file_path = series_spec.input_file() label = series_spec.label_or(str(i)) regex = series_spec.regex() yscale = series_spec.yscale() xscale = series_spec.xscale() x_field = series_spec.xfield() y_field = series_spec.yfield() utils.debug("series {}: opening {}".format(i, file_path)) with GoogleBenchmark(file_path) as g: stats = g.keep_name_regex(regex).keep_stats() df = stats.stats_dataframe(x_field, y_field) df = df.sort_values(by=["x_mean"]) x = df.loc[:, "x_mean"] y = df.loc[:, "y_mean"] e = df.loc[:, "y_stddev"] x *= xscale y *= yscale e *= yscale color = series_spec.color_or(styles.colors[i]) # Draw scatter plot of values ax.errorbar( x, y, e, capsize=3, ecolor=color, linestyle='None', label=None) # compute a fit line and show z, _ = np.polyfit(x, y, 1, w=1. / e, cov=True) slope, intercept = z[0], z[1] ax.plot( x, x * slope + intercept, color=color, label=label + ": {:.2f}".format(slope) + " us/fault") if "title" in ax_spec: ax.set_title(ax_spec["title"]) if "yaxis" in ax_spec: configure_yaxis(ax, ax_spec["yaxis"]) if "xaxis" in ax_spec: configure_xaxis(ax, ax_spec["xaxis"]) ax.legend(loc="best") ax.grid(True) return ax
def generate(figure_spec): fig = generate_subplots(figure_spec) # Set the figure size # fig.autofmt_xdate() if "size" in figure_spec: size = figure_spec["size"] utils.debug("Using figsize {}".format(size)) fig.set_size_inches(size) fig.set_tight_layout(True) return fig
def __init__(self, spec, spec_path=None): SpecificationBase.__init__(self, parent=None, spec=spec) input_file_mixin.__init__(self, None, spec) regex_mixin.__init__(self, None, spec) xfield_mixin.__init__(self, None, spec) yfield_mixin.__init__(self, None, spec) xscale_mixin.__init__(self, None, spec) yscale_mixin.__init__(self, None, spec) if "subplots" in spec: self.subplots = [ PlotSpecification(self, s) for s in spec["subplots"] ] else: utils.debug("subplot not in spec") self.subplots = [PlotSpecification(self, spec)] self.subplots[0]["pos"] = (1, 1) self.size = spec.get("size", None) self.type_str = spec.get("type", None) self.output_spec = spec.get("output", None) self.spec_path = spec_path # path of file this spec came from, if any
def generate(figure_spec): # figure out the size of the grid num_x = max([int(spec["pos"][0]) for spec in figure_spec.subplots]) num_y = max([int(spec["pos"][1]) for spec in figure_spec.subplots]) grid = [[None for i in range(num_x)] for j in range(num_y)] utils.debug("grid: {}".format(grid)) for plot_spec in figure_spec.subplots: # propagate fields down to children if children don't override for k in ["yaxis", "xaxis"]: if k in figure_spec: utils.propagate_key_if_missing(figure_spec, k, plot_spec) pos = plot_spec["pos"] fig = generate_plot(plot_spec) grid[pos[1] - 1][pos[0] - 1] = fig grid = gridplot(grid, merge_tools=False) return grid
def spec(ctx, output, output_prefix, spec): """Create a figure from a spec file.""" include = ctx.obj["INCLUDE"] # load YAML spec file figure_spec = Specification.load_yaml(spec) # apply include directories if include: utils.debug("searching dirs {}".format(include)) figure_spec.find_input_files(include) # output path from command line or spec if output: utils.debug("output path from command line: {}".format(output)) backend_str = backend.infer_from_path(output) utils.debug("inferred backend: {}".format(backend_str)) output_specs = [(output, backend_str)] else: output_specs = figure_spec.output_specs() # prepend prefix to output_path if output_prefix: output_specs = [(os.path.join(output_prefix, path), backend_str) for path, backend_str in output_specs] for (path, backend_str) in output_specs: utils.debug("prefixed output path: {}".format(path)) # determine the figures that need to be constructed jobs = backend.construct_jobs(figure_spec, output_specs) utils.debug("{} jobs to run".format(len(jobs))) # run the jobs for job in jobs: backend.run(job)
def deps(ctx, output, spec, target): """Create a Makefile dependence""" utils.debug("Loading {}".format(spec)) figure_spec = Specification.load_yaml(spec) include_dirs = ctx.obj["INCLUDE"] utils.debug("Searching for input_file values in: {}".format(include_dirs)) try: figure_spec.find_input_files(include_dirs) except InputFileNotFoundError as e: utils.error(str(e)) sys.exit(-1) utils.debug("Saving deps to {}".format(output)) figure_spec.save_makefile_deps(output, target)
def generator_errorbar(ax, ax_cfg): series_specs = ax_cfg.series for i, series_spec in enumerate(series_specs): file_path = series_spec.input_file() label = series_spec.label_or(None) regex = series_spec.regex() yscale = series_spec.yscale() xscale = series_spec.xscale() x_field = series_spec.xfield() y_field = series_spec.yfield() linestyle = series_spec.linestyle() utils.debug("series {}: linestyle: {}".format(i, linestyle)) utils.debug("series {}: opening {}".format(i, file_path)) with GoogleBenchmark(file_path) as g: stats = g.keep_name_regex(regex).keep_stats() df = stats.stats_dataframe(x_field, y_field) df = df.sort_values(by=["x_mean"]) x = df.loc[:, "x_mean"] y = df.loc[:, "y_mean"] e = df.loc[:, "y_stddev"] x *= xscale y *= yscale e *= yscale alpha = series_spec.alpha() color = series_spec.color_or(styles.colors[i]) utils.debug("series {}: color = {} alpha = {}".format(i, color, alpha)) ax.errorbar(x, y, e, capsize=3, label=label, color=color, linestyle=linestyle) if "title" in ax_cfg: ax.set_title(ax_cfg["title"]) if "yaxis" in ax_cfg: configure_yaxis(ax, ax_cfg["yaxis"]) if "xaxis" in ax_cfg: configure_xaxis(ax, ax_cfg["xaxis"]) ax.legend(loc="best") ax.grid(True) return ax
def generator_bar(ax, ax_cfg): bar_width = ax_cfg.get("bar_width", 0.8) series_specs = ax_cfg.series utils.debug("Number of series: {}".format(len(series_specs))) df = pd.DataFrame() for i, series_spec in enumerate(series_specs): input_path = series_spec.input_file() label = series_spec.label_or(str(i)) regex = series_spec.regex() y_field = series_spec.yfield() x_field = series_spec.xfield() y_scale = series_spec.yscale() x_scale = series_spec.xscale() input_path = series_spec.input_file() utils.require(input_path, "input_file should have been defined") utils.require(y_field, "yfield should have been defined") utils.require(x_field, "xfield should have been defined") utils.debug("series {}: Opening {}".format(i, input_path)) utils.debug("series {}: filter regex is {}".format(i, regex)) utils.debug("series {}: x field: {}".format(i, x_field)) utils.debug("series {}: y field: {}".format(i, y_field)) if x_scale != 1: utils.debug("series {}: xscale: {}".format(i, x_scale)) if y_scale != 1: utils.debug("series {}: yscale: {}".format(i, y_scale)) with GoogleBenchmark(input_path) as b: matches = b.keep_name_regex(regex) for entry in matches.benchmarks: utils.debug("name {} matched regex {}".format(entry["name"], regex)) series_df = matches.xy_dataframe(x_field, y_field) if series_df.dtypes[x_field] == np.object: utils.debug("Not scaling non-numeric x data by {}".format(x_scale)) else: series_df.loc[:, x_field] *= x_scale series_df.loc[:, y_field] *= y_scale series_df = series_df.rename(columns={y_field: label}) series_df = series_df.set_index(x_field) # FIXME: this could be resolved with join? # https://stackoverflow.com/questions/27719407/pandas-concat-valueerror-shape-of-passed-values-is-blah-indices-imply-blah2 if not series_df.index.is_unique: utils.warn( "multiple benchmark results with identical {} values. The plot might be weird.".format( x_field)) df = pd.concat([df, series_df], axis=1, sort=False) df = df.sort_index() df.plot.bar(ax=ax) if "xaxis" in ax_cfg: configure_yaxis(ax, ax_cfg["yaxis"]) if "yaxis" in ax_cfg: configure_xaxis(ax, ax_cfg["xaxis"]) if "title" in ax_cfg: ax.set_title(ax_cfg["title"]) ax.legend(loc="best") return ax
def generate_errorbar(errorbar_spec): x_type = errorbar_spec.get("xaxis", {}).get("type", "auto") y_type = errorbar_spec.get("yaxis", {}).get("type", "auto") # Create the figure fig = figure( title=errorbar_spec["title"], x_axis_type=x_type, y_axis_type=y_type, plot_width=808, plot_height=int(500 / 2.0), toolbar_location='above', sizing_mode='scale_width') if "xaxis" in errorbar_spec: configure_xaxis(fig, errorbar_spec["xaxis"]) if "yaxis" in errorbar_spec: configure_yaxis(fig, errorbar_spec["yaxis"]) # Read all the series data df = pd.DataFrame() for i, series_spec in enumerate(errorbar_spec.series): label = series_spec.label_or(str(i)) color = series_spec.color_or(styles.colors[i]) utils.debug("series \"{}\": color {}".format(label, color)) input_path = series_spec.input_file() regex = series_spec.regex() x_field = series_spec.xfield() y_field = series_spec.yfield() x_scale = series_spec.xscale() y_scale = series_spec.yscale() utils.debug("Opening {}".format(input_path)) with GoogleBenchmark(input_path) as b: df = b.keep_name_regex(regex) \ .keep_stats() \ .stats_dataframe(x_field, y_field) if not df.size: utils.warn("Empty stats dataframe for path={} and x_field={} and y_field={}".format(input_path, x_field, y_field)) df.loc[:, 'x_mean'] *= x_scale df.loc[:, 'x_median'] *= x_scale df.loc[:, 'x_stddev'] *= x_scale df.loc[:, 'y_mean'] *= y_scale df.loc[:, 'y_median'] *= y_scale df.loc[:, 'y_stddev'] *= y_scale df = df.sort_values(by=['x_mean']) fig.line(x=df.loc[:, "x_mean"], y=df.loc[:, "y_mean"], color=color, legend=label) df.loc[:, "lower"] = df.loc[:, 'y_mean'] - df.loc[:, 'y_stddev'] df.loc[:, "upper"] = df.loc[:, 'y_mean'] + df.loc[:, 'y_stddev'] error_source = ColumnDataSource(df) whisker = Whisker( source=error_source, base='x_mean', upper="upper", lower="lower", line_color=color) whisker.upper_head.line_color = color whisker.lower_head.line_color = color fig.add_layout(whisker) fig.legend.location = "top_left" fig.legend.click_policy = "hide" return fig
def save(fig, path): utils.debug("saving matplotlib figure: {}".format(path)) fig.savefig(path, clip_on=False, transparent=False)
def generate_bar(bar_spec): x_axis_label = bar_spec.get("xaxis", {}).get("label", "") y_axis_label = bar_spec.get("yaxis", {}).get("label", "") x_axis_tick_rotation = bar_spec.get("xaxis", {}).get("tick_rotation", 90) # convert x axis tick rotation to radians x_axis_tick_rotation = x_axis_tick_rotation / 360.0 * 2 * math.pi x_type = bar_spec.get("xaxis", {}).get("type", "auto") y_type = bar_spec.get("yaxis", {}).get("type", "auto") # Read all the series data df = pd.DataFrame() for i, series_spec in enumerate(bar_spec.series): input_path = series_spec.input_file() y_scale = series_spec.yscale() x_scale = series_spec.xscale() regex = series_spec.regex() utils.debug("Using regex {}".format(regex)) x_field = series_spec.xfield() y_field = series_spec.yfield() label = series_spec.label_or(str(i)) utils.debug("Opening {}".format(input_path)) with GoogleBenchmark(input_path) as b: new_df = b.keep_name_regex(regex).xy_dataframe(x_field, y_field) new_df.loc[:, x_field] *= x_scale new_df.loc[:, y_field] *= y_scale new_df = new_df.rename(columns={y_field: label}) new_df = new_df.set_index(x_field) df = pd.concat([df, new_df], axis=1, sort=False) # convert index to a string df.index = df.index.map(str) source = ColumnDataSource(data=df) source.data[x_field] = map(str, source.data[x_field]) # Figure out the unique x values that we'll need to plot x_range = list(df.index) utils.debug("x_range contains {} unique values".format(len(x_range))) # Create the figure fig = figure( title=bar_spec["title"], x_axis_label=x_axis_label, y_axis_label=y_axis_label, x_axis_type=x_type, y_axis_type=y_type, x_range=x_range, plot_width=800, plot_height=int(300), toolbar_location='above', ) # offset each series group_width = 1.0 / ( len(bar_spec.series) + 1 ) # each group of bars is 1 wide, leave 1 bar-width between groups bar_width = group_width * 0.95 # small gap between bars # plot the bars for i, series_spec in enumerate(bar_spec.series): color = series_spec.color_or(styles.colors[i]) dodge_amount = -0.5 + (i + 1) * group_width utils.debug("{}".format(dodge_amount)) fig.vbar( x=dodge(x_field, dodge_amount, range=fig.x_range), top=series_spec["label"], width=bar_width, source=source, color=color) fig.xaxis.major_label_orientation = x_axis_tick_rotation return fig