import py from .compat import Iterable from .utils import TIME_UNITS from .utils import slugify try: from pygal.graph.box import Box from pygal.style import DefaultStyle except ImportError as exc: raise ImportError(exc.args, "Please install pygal and pygaljs or pytest-benchmark[histogram]") class CustomBox(Box): def _box_points(self, serie, _): return serie, [serie[0], serie[6]] def _value_format(self, x): return "Min: {0[0]:.4f}\n" \ "Q1-1.5IQR: {0[1]:.4f}\n" \ "Q1: {0[2]:.4f}\nMedian: {0[3]:.4f}\nQ3: {0[4]:.4f}\n" \ "Q3+1.5IQR: {0[5]:.4f}\n" \ "Max: {0[6]:.4f}".format(x[:7]) def _format(self, x, *args): sup = super(CustomBox, self)._format if args: val = x.values else: val = x if isinstance(val, Iterable): return self._value_format(val), val[7] else: return sup(x, *args) def _tooltip_data(self, node, value, x, y, classes=None, xlabel=None): super(CustomBox, self)._tooltip_data(node, value[0], x, y, classes=classes, xlabel=None) self.svg.node(node, 'desc', class_="x_label").text = value[1] def make_plot(benchmarks, title, adjustment): class Style(DefaultStyle): colors = ["#000000" if row["path"] else DefaultStyle.colors[1] for row in benchmarks] font_family = 'Consolas, "Deja Vu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace' minimum = int(min(row["min"] * adjustment for row in benchmarks)) maximum = int(max( min(row["max"], row["hd15iqr"]) * adjustment for row in benchmarks ) + 1) try: import pygaljs except ImportError: opts = {} else: opts = { "js": [ pygaljs.uri("2.0.x", "pygal-tooltips.js") ] } plot = CustomBox( box_mode='tukey', x_label_rotation=-90, x_labels=["{0[name]}".format(row) for row in benchmarks], show_legend=False, title=title, x_title="Trial", y_title="Duration", style=Style, min_scale=20, max_scale=20, truncate_label=50, range=(minimum, maximum), zero=minimum, css=[ "file://style.css", "file://graph.css", """inline: .tooltip .value { font-size: 1em !important; } .axis text { font-size: 9px !important; } """ ], **opts ) for row in benchmarks: serie = [row[field] * adjustment for field in ["min", "ld15iqr", "q1", "median", "q3", "hd15iqr", "max"]] serie.append(row["path"]) plot.add("{0[fullname]} - {0[rounds]} rounds".format(row), serie) return plot def make_histogram(output_prefix, name, benchmarks, unit, adjustment): if name: path = "{0}-{1}.svg".format(output_prefix, slugify(name)) title = "Speed in {0} of {1}".format(TIME_UNITS[unit], name) else: path = "{0}.svg".format(output_prefix) title = "Speed in {0}".format(TIME_UNITS[unit]) output_file = py.path.local(path).ensure() plot = make_plot( benchmarks=benchmarks, title=title, adjustment=adjustment, ) plot.render_to_file(str(output_file)) return output_file