Completed
Push — master ( 5dce03...efda8a )
by Ionel Cristian
01:05
created

src.pytest_benchmark.Plot   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 23
Duplicated Lines 0 %
Metric Value
dl 0
loc 23
rs 10
wmc 6

3 Methods

Rating   Name   Duplication   Size   Complexity  
A src.pytest_benchmark.CustomBox._box_points() 0 2 1
A src.pytest_benchmark.CustomBox._tooltip_data() 0 3 1
A src.pytest_benchmark.CustomBox._format() 0 10 2
1
import py
2
3
from .utils import TIME_UNITS
4
from .utils import slugify
5
6
try:
7
    from pygal.graph.box import Box
8
    from pygal.graph.box import is_list_like
9
    from pygal.style import DefaultStyle
10
except ImportError as exc:
11
    raise ImportError(exc.args, "Please install pygal and pygaljs or pytest-benchmark[histogram]")
12
13
14
class CustomBox(Box):
15
    def _box_points(self, serie, _):
16
        return serie, [serie[0], serie[6]]
17
18
    def _format(self, x):
19
        sup = super(CustomBox, self)._format
20
        if is_list_like(x):
21
            return "Min: {0[0]:.4f}\n" \
22
                   "Q1-1.5IQR: {0[1]:.4f}\n" \
23
                   "Q1: {0[2]:.4f}\nMedian: {0[3]:.4f}\nQ3: {0[4]:.4f}\n" \
24
                   "Q3+1.5IQR: {0[5]:.4f}\n" \
25
                   "Max: {0[6]:.4f}".format(x[:7]), x[7]
26
        else:
27
            return sup(x)
28
29
    def _tooltip_data(self, node, value, x, y, classes=None, xlabel=None):
30
        super(CustomBox, self)._tooltip_data(node, value[0], x, y, classes=classes, xlabel=None)
31
        self.svg.node(node, 'desc', class_="x_label").text = value[1]
32
33
34
def make_plot(benchmarks, title, adjustment):
35
    class Style(DefaultStyle):
36
        colors = ["#000000" if row["path"] else DefaultStyle.colors[1]
37
                  for row in benchmarks]
38
        font_family = 'Consolas, "Deja Vu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace'
39
40
    minimum = int(min(row["min"] * adjustment for row in benchmarks))
41
    maximum = int(max(
42
        min(row["max"], row["hd15iqr"]) * adjustment
43
        for row in benchmarks
44
    ) + 1)
45
46
    try:
47
        import pygaljs
48
    except ImportError:
49
        opts = {}
50
    else:
51
        opts = {
52
            "js": [
53
                pygaljs.uri("2.0.x", "pygal-tooltips.js")
54
            ]
55
        }
56
    print(["{0[name]}".format(row) for row in benchmarks])
57
    plot = CustomBox(
58
        box_mode='tukey',
59
        x_label_rotation=-90,
60
        x_labels=["{0[name]}".format(row) for row in benchmarks],
61
        show_legend=False,
62
        title=title,
63
        x_title="Trial",
64
        y_title="Duration",
65
        style=Style,
66
        min_scale=20,
67
        max_scale=20,
68
        truncate_label=50,
69
        range=(minimum, maximum),
70
        zero=minimum,
71
        css=[
72
            "file://style.css",
73
            "file://graph.css",
74
            """inline:
75
                .tooltip .value {
76
                    font-size: 1em !important;
77
                }
78
                .axis text {
79
                    font-size: 9px !important;
80
                }
81
            """
82
        ],
83
        **opts
84
    )
85
86
    for row in benchmarks:
87
        serie = [row[field] * adjustment for field in ["min", "ld15iqr", "q1", "median", "q3", "hd15iqr", "max"]]
88
        serie.append(row["path"])
89
        plot.add("{0[fullname]} - {0[rounds]} rounds".format(row), serie)
90
    return plot
91
92
93
def make_histogram(output_prefix, name, benchmarks, unit, adjustment):
94
    if name:
95
        path = "{0}-{1}.svg".format(output_prefix, slugify(name))
96
        title = "Speed in {0} of {1}".format(TIME_UNITS[unit], name)
97
    else:
98
        path = "{0}.svg".format(output_prefix)
99
        title = "Speed in {0}".format(TIME_UNITS[unit])
100
101
    output_file = py.path.local(path).ensure()
102
103
    plot = make_plot(
104
        benchmarks=benchmarks,
105
        title=title,
106
        adjustment=adjustment,
107
    )
108
    plot.render_to_file(str(output_file))
109
    return output_file
110