CustomBox   A
last analyzed

Complexity

Total Complexity 6

Size/Duplication

Total Lines 25
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 10
c 0
b 0
f 0
wmc 6

4 Methods

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