3 # Copyright (c) 2012 Pierre-Francois Carpentier <carpentier.pf@gmail.com>
5 # https://github.com/kakwa/py-ascii-graph/
7 # Permission is hereby granted, free of charge, to any person obtaining
8 # a copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sublicense, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
15 # The above copyright notice and this permission notice shall be
16 # included in all copies or substantial portions of the Software.
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 from __future__
import unicode_literals
32 def __init__(self
, line_length
=79, min_graph_length
=50,
34 """Constructor of Pyasciigraph
36 :param int line_length: the max number of char on a line
37 if any line cannot be shorter,
38 it will go over this limit
39 :param int min_graph_length: the min number of char used by the graph
40 :param int separator_length: the length of field separator
42 self
.line_length
= line_length
43 self
.separator_length
= separator_length
44 self
.min_graph_length
= min_graph_length
49 return codecs
.unicode_escape_decode(x
)[0]
53 def _get_maximum(self
, data
):
55 all_max
['value_max_length'] = 0
56 all_max
['info_max_length'] = 0
57 all_max
['max_value'] = 0
59 for (info
, value
) in data
:
60 if value
> all_max
['max_value']:
61 all_max
['max_value'] = value
63 if len(info
) > all_max
['info_max_length']:
64 all_max
['info_max_length'] = len(info
)
66 if len(str(value
)) > all_max
['value_max_length']:
67 all_max
['value_max_length'] = len(str(value
))
70 def _gen_graph_string(self
, value
, max_value
, graph_length
, start_value
):
72 number_of_square
= int(value
* graph_length
)
74 number_of_square
= int(value
* graph_length
/ max_value
)
75 number_of_space
= int(start_value
- number_of_square
)
76 return '█' * number_of_square
+ self
._u(' ') * number_of_space
78 def _console_size(self
):
80 return int(os
.environ
.get('COLUMNS', TERMSIZE
)) - 1
82 def _gen_info_string(self
, info
, start_info
, line_length
, info_before
):
83 number_of_space
= (line_length
- start_info
- len(info
))
85 return self
._u(' ') * number_of_space
+ info
87 return info
+ self
._u(' ') * number_of_space
89 def _gen_value_string(self
, value
, start_value
, start_info
, unit
, count
):
91 v
= str("%0.02f" % value
)
93 # we don't want to add .00 to count values (only integers)
95 number_space
= start_info
-\
100 return ' ' * number_space
+\
102 ' ' * self
.separator_length
104 def _sanitize_string(self
, string
):
105 # get the type of a unicode string
106 unicode_type
= type(self
._u('t'))
107 input_type
= type(string
)
108 if input_type
is str:
109 if sys
.version_info
.major
< 3: # pragma: no cover
113 elif input_type
is unicode_type
:
115 elif input_type
is int or input_type
is float:
116 if sys
.version_info
.major
< 3: # pragma: no cover
122 def _sanitize_data(self
, data
):
125 ret
.append((self
._sanitize
_string
(item
[0]), item
[1]))
128 def graph(self
, label
, data
, sort
=0, with_value
=True, unit
="",
129 info_before
=False, count
=False):
130 """function generating the graph
132 :param string label: the label of the graph
133 :param iterable data: the data (list of tuple (info, value))
134 info must be "castable" to a unicode string
135 value must be an int or a float
136 :param int sort: flag sorted
137 0: not sorted (same order as given) (default)
140 :param boolean with_value: flag printing value
141 True: print the numeric value (default)
142 False: don't print the numeric value
143 :rtype: a list of strings (each lines)
147 san_data
= self
._sanitize
_data
(data
)
148 san_label
= self
._sanitize
_string
(label
)
151 san_data
= sorted(san_data
, key
=lambda value
: value
[1],
154 san_data
= sorted(san_data
, key
=lambda value
: value
[1],
157 all_max
= self
._get
_maximum
(san_data
)
159 real_line_length
= max(self
.line_length
, len(label
))
161 min_line_length
= self
.min_graph_length
+\
162 2 * self
.separator_length
+\
163 all_max
['value_max_length'] +\
164 all_max
['info_max_length']
166 if min_line_length
< real_line_length
:
167 # calcul of where to start info
168 start_info
= self
.line_length
-\
169 all_max
['info_max_length']
170 # calcul of where to start value
171 start_value
= start_info
-\
172 self
.separator_length
-\
173 all_max
['value_max_length']
174 # calcul of where to end graph
175 graph_length
= start_value
-\
176 self
.separator_length
178 # calcul of where to start value
179 start_value
= self
.min_graph_length
+\
180 self
.separator_length
181 # calcul of where to start info
182 start_info
= start_value
+\
183 all_max
['value_max_length'] +\
184 self
.separator_length
185 # calcul of where to end graph
186 graph_length
= self
.min_graph_length
187 # calcul of the real line length
188 real_line_length
= min_line_length
190 real_line_length
= min(real_line_length
, self
._console
_size
())
191 result
.append(san_label
)
192 result
.append(self
._u('#') * real_line_length
)
194 for item
in san_data
:
198 graph_string
= self
._gen
_graph
_string
(
200 all_max
['max_value'],
205 value_string
= self
._gen
_value
_string
(
208 start_info
, unit
, count
)
212 info_string
= self
._gen
_info
_string
(
215 real_line_length
, info_before
)
217 new_line
= info_string
+ " " + graph_string
+ value_string
219 new_line
= graph_string
+ value_string
+ info_string
220 result
.append(new_line
)
224 if __name__
== '__main__':
225 test
= [('long_label', 423), ('sl', 1234), ('line3', 531),
226 ('line4', 200), ('line5', 834)]
227 graph
= Pyasciigraph()
228 for line
in graph
.graph('test print', test
):
This page took 0.070697 seconds and 5 git commands to generate.