Browse Source

Add human readable option

pull/8/head
Florian Mounier 13 years ago
parent
commit
66b30f0f3a
  1. 1
      demo/moulinrouge/__init__.py
  2. 8
      demo/simple_test.py
  3. 2
      pygal/config.py
  4. 4
      pygal/graph/bar.py
  5. 3
      pygal/graph/base.py
  6. 4
      pygal/graph/line.py
  7. 4
      pygal/graph/radar.py
  8. 2
      pygal/graph/stackedbar.py
  9. 4
      pygal/graph/xy.py
  10. 30
      pygal/test/test_util.py
  11. 25
      pygal/util.py

1
demo/moulinrouge/__init__.py

@ -118,6 +118,7 @@ def create_app():
config.width = width
config.height = height
config.fill = True
config.human_readable = True
config.style = styles[style]
config.x_labels = [random_label() for i in range(data)]
svgs = []

8
demo/simple_test.py

@ -74,10 +74,10 @@ with open('out-horizontalstackedbar.svg', 'w') as f:
line = Line(Config(y_scale=.0005, style=NeonStyle,
interpolate='univariate'))
rng = range(-30, 31, 10)
line.add('test1', [cos(x / 10.) for x in rng])
line.add('test2', [sin(x / 10.) for x in rng])
line.add('test3', [cos(x / 10.) - sin(x / 10.) for x in rng])
rng = range(-30, 31, 5)
line.add('test1', [1000 ** cos(x / 10.) for x in rng])
line.add('test2', [1000 ** sin(x / 10.) for x in rng])
line.add('test3', [1000 ** (cos(x / 10.) - sin(x / 10.)) for x in rng])
line.x_labels = map(str, rng)
line.title = "Line test"
with open('out-line.svg', 'w') as f:

2
pygal/config.py

@ -32,6 +32,8 @@ class Config(object):
# Scale order range
x_scale = 1
y_scale = 1
# Display values in human readable format (ie: 12.4M)
human_readable = False
# If set to a filename, this will replace the default css
base_css = None
# or default js

4
pygal/graph/bar.py

@ -86,7 +86,7 @@ class Bar(Graph):
y=y - shift,
id="reactive-%s" % tag,
class_='reactive-text'
).text = str(values[i][1][1])
).text = self.format(values[i][1][1])
return stack_vals
def _compute(self):
@ -101,7 +101,7 @@ class Bar(Graph):
self._x_ranges = zip(x_pos, x_pos[1:])
self._x_labels = self.x_labels and zip(self.x_labels, [
sum(x_range) / 2. for x_range in self._x_ranges])
self._y_labels = zip(map(str, y_pos), y_pos)
self._y_labels = zip(map(self.format, y_pos), y_pos)
def _plot(self):
for serie in self.series:

3
pygal/graph/base.py

@ -1,6 +1,6 @@
from pygal.serie import Serie
from pygal.view import Margin, Box
from pygal.util import round_to_scale, cut, rad
from pygal.util import round_to_scale, cut, rad, humanize
from pygal.svg import Svg
from pygal.config import Config
from pygal.util import cached_property
@ -18,6 +18,7 @@ class BaseGraph(object):
self.margin = Margin(*([20] * 4))
self._x_labels = self._y_labels = None
self._box = Box()
self.format = humanize if self.human_readable else str
def __getattr__(self, attr):
if attr in dir(self.config):

4
pygal/graph/line.py

@ -25,7 +25,7 @@ class Line(Graph):
"""Line graph"""
def _get_value(self, values, i):
return str(values[i][1])
return self.format(values[i][1])
@cached_property
def _values(self):
@ -92,7 +92,7 @@ class Line(Graph):
) if not self.y_labels else map(int, self.y_labels)
self._x_labels = self.x_labels and zip(self.x_labels, self._x_pos)
self._y_labels = zip(map(str, self._y_pos), self._y_pos)
self._y_labels = zip(map(self.format, self._y_pos), self._y_pos)
def _plot(self):
for serie in self.series:

4
pygal/graph/radar.py

@ -30,7 +30,7 @@ class Radar(Line):
return values
def _get_value(self, values, i):
return str(values[i][0])
return self.format(values[i][0])
@cached_property
def _values(self):
@ -124,5 +124,5 @@ class Radar(Line):
self._box.ymin, self._box.ymax, self.y_scale, max_scale=8
) if not self.y_labels else map(int, self.y_labels)
self._x_labels = self.x_labels and zip(self.x_labels, self._x_pos)
self._y_labels = zip(map(str, self._y_pos), self._y_pos)
self._y_labels = zip(map(self.format, self._y_pos), self._y_pos)
self._box.xmin = self._box.ymin = - self._box.ymax

2
pygal/graph/stackedbar.py

@ -42,7 +42,7 @@ class StackedBar(Bar):
self._x_labels = self.x_labels and zip(self.x_labels, [
sum(x_range) / 2 for x_range in self._x_ranges])
self._y_labels = zip(map(str, y_pos), y_pos)
self._y_labels = zip(map(self.format, y_pos), y_pos)
def _plot(self):
stack_vals = [[0, 0] for i in range(self._length)]

4
pygal/graph/xy.py

@ -60,5 +60,5 @@ class XY(Line):
x_pos = self._pos(self._box.xmin, self._box.xmax, self.x_scale)
y_pos = self._pos(self._box.ymin, self._box.ymax, self.y_scale)
self._x_labels = zip(map(str, x_pos), x_pos)
self._y_labels = zip(map(str, y_pos), y_pos)
self._x_labels = zip(map(self.format, x_pos), x_pos)
self._y_labels = zip(map(self.format, y_pos), y_pos)

30
pygal/test/test_util.py

@ -16,7 +16,8 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>.
from pygal.util import round_to_int, round_to_float, _swap_curly, template
from pygal.util import (
round_to_int, round_to_float, _swap_curly, template, humanize)
from pytest import raises
@ -73,3 +74,30 @@ def test_format():
obj.c = '3'
assert template('foo {{ o.a }} {{o.b}}-{{o.c}}',
o=obj) == 'foo 1 True-3'
def test_humanize():
assert humanize(1) == '1'
assert humanize(10) == '10'
assert humanize(12.5) == '12.5'
assert humanize(1000) == '1k'
assert humanize(5000) == '5k'
assert humanize(100000) == '100k'
assert humanize(1253) == '1.253k'
assert humanize(1250) == '1.25k'
assert humanize(0.1) == '100m'
assert humanize(0.01) == '10m'
assert humanize(0.001) == '1m'
assert humanize(0.002) == '2m'
assert humanize(0.0025) == '2.5m'
assert humanize(0.0001) == u'100µ'
assert humanize(0.000123) == u'123µ'
assert humanize(0.00001) == u'10µ'
assert humanize(0.000001) == u''
assert humanize(0.0000001) == u'100n'
assert humanize(0.0000000001) == u'100p'
assert humanize(0) == '0'
assert humanize(-1337) == '-1.337k'
assert humanize(-.000000042) == '-42n'

25
pygal/util.py

@ -17,7 +17,30 @@
# You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
from math import floor, pi
from math import floor, pi, log, ceil
def float_format(number):
return ("%.3f" % number).rstrip('0').rstrip('.')
def humanize(number):
if number == 0:
return '0'
order = int(floor(log(abs(number)) / log(1000)))
if order > 0:
human_readable = "kMGTPEZY"
if order > len(human_readable):
return str(number)
elif order < 0:
human_readable = u"yzafpnµm "
if order > len(human_readable):
return str(number)
else:
return str(number)
return (
float_format(number / float(1000 ** int(order))) +
human_readable[int(order) - 1])
def round_to_int(number, precision):

Loading…
Cancel
Save