diff --git a/.pylintrc b/.pylintrc
index 940c3e7..242f3c7 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -33,7 +33,7 @@ load-plugins=
# can either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once).
-disable=W0142
+disable=I0011,W0142,C0102
[REPORTS]
@@ -133,7 +133,7 @@ module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
const-rgx=(([A-Za-z_][A-Za-z0-9_]*)|(__.*__))$
# Regular expression which should only match correct class names
-class-rgx=[A-Z_][a-zA-Z0-9]+$
+class-rgx=[a-zA-Z_][a-zA-Z0-9]+$
# Regular expression which should only match correct function names
function-rgx=[a-z_][a-z0-9_]{2,30}$
@@ -148,7 +148,7 @@ attr-rgx=[a-z_][a-z0-9_]{0,30}$
argument-rgx=[a-z_][a-z0-9_]{0,30}$
# Regular expression which should only match correct variable names
-variable-rgx=[a-z_][a-z0-9_]{0,30}$
+variable-rgx=[A-Za-z_][a-z0-9_]{0,30}$
# Regular expression which should only match correct list comprehension /
# generator expression variable names
diff --git a/pygal/graph/base.py b/pygal/graph/base.py
index 855d48f..7e9e64e 100644
--- a/pygal/graph/base.py
+++ b/pygal/graph/base.py
@@ -42,8 +42,8 @@ class BaseGraph(object):
"""Add a serie to this graph"""
self.series.append(Serie(title, values, len(self.series)))
- def _init(self):
- """Init the graph"""
+ def reinit(self):
+ """(Re-)Init the graph"""
self.margin = Margin(*([20] * 4))
self._box = Box()
@@ -191,13 +191,13 @@ class BaseGraph(object):
def _render(self):
"""Make the graph internally"""
- self._init()
- self.svg._init()
+ self.reinit()
+ self.svg.reinit()
if self._has_data():
self._draw()
- self.svg._pre_render(False)
+ self.svg.pre_render(False)
else:
- self.svg._pre_render(True)
+ self.svg.pre_render(True)
def render(self, is_unicode=False):
"""Render the graph, and return the svg string"""
diff --git a/pygal/svg.py b/pygal/svg.py
index 8a49f93..64c1a46 100644
--- a/pygal/svg.py
+++ b/pygal/svg.py
@@ -16,11 +16,16 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see .
+"""
+Svg helper
+
+"""
+
from __future__ import division
import io
import os
from lxml import etree
-from pygal.util import template
+from pygal.util import template, coord_format
from pygal import __version__
@@ -30,8 +35,11 @@ class Svg(object):
def __init__(self, graph):
self.graph = graph
+ self.root = None
+ self.defs = None
- def _init(self):
+ def reinit(self):
+ """(Re-)initialization"""
self.root = etree.Element(
"{%s}svg" % self.ns,
nsmap={
@@ -45,6 +53,7 @@ class Svg(object):
self.defs = self.node(tag='defs')
def add_style(self, css):
+ """Add the css to the svg"""
style = self.node(self.defs, 'style', type='text/css')
with io.open(css, encoding='utf-8') as f:
templ = template(
@@ -55,6 +64,7 @@ class Svg(object):
style.text = templ
def add_script(self, js):
+ """Add the js to the svg"""
script = self.node(self.defs, 'script', type='text/javascript')
with io.open(js, encoding='utf-8') as f:
templ = template(
@@ -65,6 +75,7 @@ class Svg(object):
script.text = templ
def node(self, parent=None, tag='g', attrib=None, **extras):
+ """Make a new svg node"""
if parent is None:
parent = self.root
attrib = attrib or {}
@@ -80,6 +91,7 @@ class Svg(object):
return etree.SubElement(parent, tag, attrib)
def transposable_node(self, parent=None, tag='g', attrib=None, **extras):
+ """Make a new svg node which can be transposed if horizontal"""
if self.graph._horizontal:
for key1, key2 in (('x', 'y'), ('width', 'height')):
attr1 = extras.get(key1, None)
@@ -87,24 +99,23 @@ class Svg(object):
extras[key1], extras[key2] = attr2, attr1
return self.node(parent, tag, attrib, **extras)
- def format(self, xy):
- return '%f %f' % xy
-
def line(self, node, coords, close=False, **kwargs):
+ """Draw a svg line"""
if len(coords) < 2:
return
root = 'M%s L%s Z' if close else 'M%s L%s'
origin_index = 0
while None in coords[origin_index]:
origin_index += 1
- origin = self.format(coords[origin_index])
- line = ' '.join([self.format(c)
+ origin = coord_format(coords[origin_index])
+ line = ' '.join([coord_format(c)
for c in coords[origin_index + 1:]
if None not in c])
self.node(node, 'path',
d=root % (origin, line), **kwargs)
- def _pre_render(self, no_data=False):
+ def pre_render(self, no_data=False):
+ """Last things to do before rendering"""
self.add_style(self.graph.base_css or os.path.join(
os.path.dirname(__file__), 'css', 'graph.css'))
self.add_script(self.graph.base_js or os.path.join(
@@ -122,6 +133,7 @@ class Svg(object):
no_data.text = self.graph.no_data_text
def render(self, is_unicode=False):
+ """Last thing to do before rendering"""
svg = etree.tostring(
self.root, pretty_print=True,
xml_declaration=not self.graph.disable_xml_declaration,
diff --git a/pygal/util.py b/pygal/util.py
index 1a9ad3f..a1e2793 100644
--- a/pygal/util.py
+++ b/pygal/util.py
@@ -16,6 +16,11 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see .
+"""
+Various utils
+
+"""
+
from __future__ import division
from decimal import Decimal
from math import floor, pi, log, log10
@@ -23,10 +28,12 @@ ORDERS = u"yzafpnµm kMGTPEZY"
def float_format(number):
+ """Format a float to a precision of 3, without zeroes or dots"""
return ("%.3f" % number).rstrip('0').rstrip('.')
def humanize(number):
+ """Format a number to engineer scale"""
order = number and int(floor(log(abs(number)) / log(1000)))
human_readable = ORDERS.split(" ")[int(order > 0)]
if order == 0 or order > len(human_readable):
@@ -42,37 +49,43 @@ def is_major(number):
def round_to_int(number, precision):
+ """Round a number to a precision"""
precision = int(precision)
rounded = (int(number) + precision / 2) // precision * precision
return rounded
def round_to_float(number, precision):
+ """Round a float to a precision"""
rounded = Decimal(str(floor((number + precision / 2) // precision))
) * Decimal(str(precision))
return float(rounded)
def round_to_scale(number, precision):
+ """Round a number or a float to a precision"""
if precision < 1:
return round_to_float(number, precision)
return round_to_int(number, precision)
def cut(list_, index=0):
+ """Cut a list by index or arg"""
if isinstance(index, int):
- cut = lambda x: x[index]
+ cut_ = lambda x: x[index]
else:
- cut = lambda x: getattr(x, index)
- return map(cut, list_)
+ cut_ = lambda x: getattr(x, index)
+ return map(cut_, list_)
-def rad(deg):
- return pi * deg / 180
+def rad(degrees):
+ """Convert degrees in radiants"""
+ return pi * degrees / 180
-def deg(deg):
- return 180 * deg / pi
+def deg(radiants):
+ """Convert radiants in degrees"""
+ return 180 * radiants / pi
def _swap_curly(string):
@@ -92,19 +105,25 @@ def template(string, **kwargs):
"""Format a string using double braces"""
return _swap_curly(string).format(**kwargs)
+
+def coord_format(xy):
+ """Format x y coords to svg"""
+ return '%f %f' % xy
+
swap = lambda tuple_: tuple(reversed(tuple_))
ident = lambda x: x
# Stolen from brownie http://packages.python.org/Brownie/
class cached_property(object):
+ """Optimize a static property"""
def __init__(self, getter, doc=None):
self.getter = getter
self.__module__ = getter.__module__
self.__name__ = getter.__name__
self.__doc__ = doc or getter.__doc__
- def __get__(self, obj, type=None):
+ def __get__(self, obj, type_=None):
if obj is None:
return self
value = obj.__dict__[self.__name__] = self.getter(obj)
diff --git a/pygal/view.py b/pygal/view.py
index 66bdc9b..9e865ec 100644
--- a/pygal/view.py
+++ b/pygal/view.py
@@ -136,6 +136,7 @@ class LogView(View):
self.log10_ymin = log10(self.box.ymin)
self.box.fix(False)
+ # pylint: enable-msg=W0231
def y(self, y):
"""Project y"""
if y == None or y <= 0: