Style: fix minor pep8 style issues
[deliverable/lttng-analyses.git] / lttnganalyses / cli / termgraph.py
1 # The MIT License (MIT)
2 #
3 # Copyright (C) 2016 - Antoine Busque <abusque@efficios.com>
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 # SOFTWARE.
22
23 from collections import namedtuple
24
25
26 GraphDatum = namedtuple('GraphDatum', ['value', 'value_str'])
27 BarGraphDatum = namedtuple('BarGraphDatum', ['value', 'value_str', 'label'])
28 FreqGraphDatum = namedtuple(
29 'FreqGraphDatum', ['value', 'value_str', 'lower_bound']
30 )
31
32
33 class Graph():
34 MAX_GRAPH_WIDTH = 80
35 BAR_CHAR = '█'
36 HR_CHAR = '#'
37
38 def __init__(self, data, get_value, get_value_str, title, unit):
39 self._data = data
40 self._get_value = get_value
41 self._title = title
42 self._unit = unit
43 self._max_value = 0
44 self._max_value_len = 0
45
46 if get_value_str is not None:
47 self._get_value_str_cb = get_value_str
48 else:
49 self._get_value_str_cb = Graph._get_value_str_default
50
51 def _transform_data(self, data):
52 graph_data = []
53
54 for datum in data:
55 graph_datum = self._get_graph_datum(datum)
56
57 if graph_datum.value > self._max_value:
58 self._max_value = graph_datum.value
59 if len(graph_datum.value_str) > self._max_value_len:
60 self._max_value_len = len(graph_datum.value_str)
61
62 graph_data.append(graph_datum)
63
64 return graph_data
65
66 def _get_value_str(self, value):
67 return self._get_value_str_cb(value)
68
69 def _get_graph_datum(self, datum):
70 value = self._get_value(datum)
71 value_str = self._get_value_str(value)
72
73 return GraphDatum(value, value_str)
74
75 def _print_header(self):
76 if self._title:
77 print(self._title)
78
79 def _print_separator(self):
80 print(self.HR_CHAR * self.MAX_GRAPH_WIDTH)
81
82 def _print_body(self):
83 raise NotImplementedError()
84
85 def print_graph(self):
86 if not self._data:
87 return
88
89 self._print_header()
90 self._print_separator()
91 self._print_body()
92 print()
93
94 @staticmethod
95 def _get_value_str_default(value):
96 if isinstance(value, float):
97 value_str = '{:0.02f}'.format(value)
98 else:
99 value_str = str(value)
100
101 return value_str
102
103
104 class BarGraph(Graph):
105 def __init__(self, data, get_value, get_label, get_value_str=None,
106 title=None, label_header=None, unit=None):
107 super().__init__(data, get_value, get_value_str, title, unit)
108
109 self._get_label = get_label
110 self._label_header = label_header
111 self._data = self._transform_data(self._data)
112
113 def _get_graph_datum(self, datum):
114 value = self._get_value(datum)
115 value_str = self._get_value_str(value)
116 label = self._get_label(datum)
117
118 return BarGraphDatum(value, value_str, label)
119
120 def _get_value_str(self, value):
121 value_str = super()._get_value_str(value)
122 if self._unit:
123 value_str += ' ' + self._unit
124
125 return value_str
126
127 def _get_graph_header(self):
128 if not self._label_header:
129 return self._title
130
131 title_len = len(self._title)
132 space_width = (
133 self.MAX_GRAPH_WIDTH - title_len + 1 + self._max_value_len + 1
134 )
135
136 return self._title + ' ' * space_width + self._label_header
137
138 def _print_header(self):
139 header = self._get_graph_header()
140 print(header)
141
142 def _get_bar_str(self, datum):
143 if self._max_value == 0:
144 bar_width = 0
145 else:
146 bar_width = int(self.MAX_GRAPH_WIDTH * datum.value /
147 self._max_value)
148 space_width = self.MAX_GRAPH_WIDTH - bar_width
149 bar_str = self.BAR_CHAR * bar_width + ' ' * space_width
150
151 return bar_str
152
153 def _print_body(self):
154 for datum in self._data:
155 bar_str = self._get_bar_str(datum)
156 value_padding = ' ' * (self._max_value_len - len(datum.value_str))
157 print(bar_str, value_padding + datum.value_str, datum.label)
158
159
160 class FreqGraph(Graph):
161 LOWER_BOUND_WIDTH = 8
162
163 def __init__(self, data, get_value, get_lower_bound,
164 get_value_str=None, title=None, unit=None):
165 super().__init__(data, get_value, get_value_str, title, unit)
166
167 self._get_lower_bound = get_lower_bound
168 self._data = self._transform_data(self._data)
169
170 def _get_graph_datum(self, datum):
171 value = self._get_value(datum)
172 value_str = self._get_value_str(value)
173 lower_bound = self._get_lower_bound(datum)
174
175 return FreqGraphDatum(value, value_str, lower_bound)
176
177 def _print_header(self):
178 header = self._title
179 if self._unit:
180 header += ' ({})'.format(self._unit)
181
182 print(header)
183
184 def _get_bar_str(self, datum):
185 max_width = self.MAX_GRAPH_WIDTH - self.LOWER_BOUND_WIDTH
186 if self._max_value == 0:
187 bar_width = 0
188 else:
189 bar_width = int(max_width * datum.value / self._max_value)
190 space_width = max_width - bar_width
191 bar_str = self.BAR_CHAR * bar_width + ' ' * space_width
192
193 return bar_str
194
195 def _print_body(self):
196 for datum in self._data:
197 bound_str = FreqGraph._get_bound_str(datum)
198 bar_str = self._get_bar_str(datum)
199 value_padding = ' ' * (self._max_value_len - len(datum.value_str))
200 print(bound_str, bar_str, value_padding + datum.value_str)
201
202 @staticmethod
203 def _get_bound_str(datum):
204 return '{:>7.03f}'.format(datum.lower_bound)
This page took 0.033592 seconds and 5 git commands to generate.