117 lines
3.4 KiB
Python
117 lines
3.4 KiB
Python
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
|