diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..940c3e7 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,249 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Profiled execution. +profile=no + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=test + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + + +[MESSAGES CONTROL] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# 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 + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html +output-format=colorized + +# Include message's id in output +include-ids=yes + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (RP0004). +comment=yes + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=no + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +# ignored-classes= + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. Python regular +# expressions are accepted. +generated-members= + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=79 + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the beginning of the name of dummy variables +# (i.e. not used). +dummy-variables-rgx=_ + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# List of builtins function names that should not be used, separated by a comma +bad-functions=apply,input + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +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]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-z0-9_]{0,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{0,30}$ + +# Regular expression which should only match correct argument names +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}$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,db,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__ + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + + +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods= + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__ + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=20 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branchs=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=10 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=0 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=80 + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/pygal/__init__.py b/pygal/__init__.py index 5572bcd..7f5037b 100644 --- a/pygal/__init__.py +++ b/pygal/__init__.py @@ -16,6 +16,10 @@ # # You should have received a copy of the GNU Lesser General Public License # along with pygal. If not, see . +""" +Pygal - A python svg graph plotting library + +""" __version__ = '0.9.21' @@ -30,7 +34,8 @@ from pygal.graph.pie import Pie from pygal.graph.radar import Radar from pygal.config import Config -"""List of all chart types""" + +#: List of all chart types CHARTS = [ Bar, HorizontalBar, StackedBar, HorizontalStackedBar, Line, StackedLine, XY, Pie, Radar] diff --git a/pygal/config.py b/pygal/config.py index 6679193..7438ffd 100644 --- a/pygal/config.py +++ b/pygal/config.py @@ -16,6 +16,12 @@ # # You should have received a copy of the GNU Lesser General Public License # along with pygal. If not, see . + +""" +Config module with all options +""" + + from pygal.style import DefaultStyle @@ -27,72 +33,73 @@ class Config(object): """Class holding config values""" _horizontal = False - # Graph width + #: Graph width width = 800 - # Graph height + #: Graph height height = 600 - # Display values in human readable format (ie: 12.4M) + #: Display values in human readable format (ie: 12.4M) human_readable = False - # Display values in logarithmic scale + #: Display values in logarithmic scale logarithmic = False - # If set to a filename, this will replace the default css + #: If set to a filename, this will replace the default css base_css = None - # or default js + #: or default js base_js = None - # Style holding values injected in css + #: Style holding values injected in css style = DefaultStyle - # Various font sizes + #: Various font sizes label_font_size = 10 value_font_size = 8 tooltip_font_size = 20 title_font_size = 16 legend_font_size = 14 - # Specify labels rotation angles in degrees + #: Specify labels rotation angles in degrees x_label_rotation = 0 y_label_rotation = 0 - # Set to false to remove legend + #: Set to false to remove legend show_legend = True - # Set to false to remove dots + #: Set to false to remove dots show_dots = True - # Size of legend boxes + #: Size of legend boxes legend_box_size = 12 - # X labels, must have same len than data. - # Leave it to None to disable x labels display. + #: X labels, must have same len than data. + #: Leave it to None to disable x labels display. x_labels = None - # You can specify explicit y labels (must be list(int)) + #: You can specify explicit y labels (must be list(int)) y_labels = None - # Graph title - # Leave it to None to disable title. + #: Graph title + #: Leave it to None to disable title. title = None - # Set this to the desired radius in px + #: Set this to the desired radius in px rounded_bars = False - # Always include x axis + #: Always include x axis include_x_axis = False - # Fill areas under lines + #: Fill areas under lines fill = False - # Line dots (set it to false to get a scatter plot) + #: Line dots (set it to false to get a scatter plot) stroke = True - # Interpolation, this requires scipy module - # May be any of ‘linear’, ’nearest’, ‘zero’, ‘slinear’, ‘quadratic, ‘cubic’ - # 'krogh', 'barycentric', 'univariate', or an integer specifying the order - # of the spline interpolator + #: Interpolation, this requires scipy module + #: May be any of 'linear', 'nearest', 'zero', 'slinear', 'quadratic, + #: 'cubic', 'krogh', 'barycentric', 'univariate', + #: or an integer specifying the order + #: of the spline interpolator interpolate = None - # Number of interpolated points between two values + #: Number of interpolated points between two values interpolation_precision = 250 - # Set the ordinate zero value (for filling) + #: Set the ordinate zero value (for filling) zero = 0 - # Text to display when no data is given + #: Text to display when no data is given no_data_text = "No data" - # Print values when graph is in non interactive mode + #: Print values when graph is in non interactive mode print_values = True - # Print zeroes when graph is in non interactive mode + #: Print zeroes when graph is in non interactive mode print_zeroes = False - # Animate tooltip steps (0 disable animation) + #: Animate tooltip steps (0 disable animation) animation_steps = 0 - # Don't write xml declaration and return unicode instead of string - # (usefull for writing output in html) + #: Don't write xml declaration and return unicode instead of string + #: (usefull for writing output in html) disable_xml_declaration = False - # Write width and height attributes + #: Write width and height attributes explicit_size = False def __init__(self, **kwargs): diff --git a/pygal/graph/bar.py b/pygal/graph/bar.py index ad032e9..76efa61 100644 --- a/pygal/graph/bar.py +++ b/pygal/graph/bar.py @@ -39,6 +39,17 @@ class Bar(Graph): for i, ((x, y), (X, Y)) in enumerate(view_values): if None in (x, y): continue + + # +-------+ + # | | + # | | + # | +-------+ + # | | | + # | | | + # | | | + # +-------+-------+ + # (x,y) (X,Y) + # # x and y are left range coords and X, Y right ones val = self._format(values[i][1][1]) if self._horizontal: diff --git a/pygal/interpolate.py b/pygal/interpolate.py index 86c1a61..bf47727 100644 --- a/pygal/interpolate.py +++ b/pygal/interpolate.py @@ -16,15 +16,21 @@ # # You should have received a copy of the GNU Lesser General Public License # along with pygal. If not, see . +""" +Interpolation using scipy +""" from pygal.util import ident + +scipy = None try: import scipy from scipy import interpolate -except: - scipy = None +except ImportError: + pass def interpolation(x, y, kind): + """Make the interpolation function""" assert scipy != None, 'You must have scipy installed to use interpolation' order = None if len(y) < len(x): diff --git a/pygal/serie.py b/pygal/serie.py index 6c65c15..05373ac 100644 --- a/pygal/serie.py +++ b/pygal/serie.py @@ -16,9 +16,13 @@ # # You should have received a copy of the GNU Lesser General Public License # along with pygal. If not, see . +""" +Little helpers for series +""" class Serie(object): + """Serie containing title, values and the graph serie index""" def __init__(self, title, values, index): self.title = title self.values = values @@ -26,6 +30,7 @@ class Serie(object): class Label(object): + """A label with his position""" def __init__(self, label, pos): self.label = label self.pos = pos diff --git a/pygal/style.py b/pygal/style.py index bb7f3dd..1f1e1fb 100644 --- a/pygal/style.py +++ b/pygal/style.py @@ -16,9 +16,13 @@ # # You should have received a copy of the GNU Lesser General Public License # along with pygal. If not, see . +""" +Charts styling +""" class Style(object): + """Styling class containing colors for the css generation""" def __init__(self, background='black', plot_background='#111', @@ -33,19 +37,21 @@ class Style(object): '#899ca1', '#f8f8f2', '#808384', '#bf4646', '#516083', '#f92672', '#82b414', '#fd971f', '#56c2d6', '#8c54fe', '#465457')): - self.background = background - self.plot_background = plot_background - self.foreground = foreground - self.foreground_light = foreground_light - self.foreground_dark = foreground_dark - self.opacity = opacity - self.opacity_hover = opacity_hover - self.transition = transition - self._colors = colors + self.background = background + self.plot_background = plot_background + self.foreground = foreground + self.foreground_light = foreground_light + self.foreground_dark = foreground_dark + self.opacity = opacity + self.opacity_hover = opacity_hover + self.transition = transition + self._colors = colors @property def colors(self): + """Get the css color list""" def color(tupl): + """Make a color css""" return ( '.color-{0} {{\n' ' stroke: {1};\n' diff --git a/pygal/view.py b/pygal/view.py index dd1c159..66bdc9b 100644 --- a/pygal/view.py +++ b/pygal/view.py @@ -16,11 +16,16 @@ # # You should have received a copy of the GNU Lesser General Public License # along with pygal. If not, see . +""" +Projection and bounding helpers +""" + from __future__ import division from math import sin, cos, log10 class Margin(object): + """Graph margin""" def __init__(self, top, right, bottom, left): self.top = top self.right = right @@ -29,14 +34,17 @@ class Margin(object): @property def x(self): + """Helper for total x margin""" return self.left + self.right @property def y(self): + """Helper for total y margin""" return self.top + self.bottom class Box(object): + """Chart boundings""" _margin = .02 def __init__(self): @@ -45,17 +53,21 @@ class Box(object): @property def width(self): + """Helper for box width""" return self.xmax - self.xmin @property def height(self): + """Helper for box height""" return self.ymax - self.ymin def swap(self): + """Return the box (for horizontal qraphs)""" self.xmin, self.ymin = self.ymin, self.xmin self.xmax, self.ymax = self.ymax, self.xmax def fix(self, with_margin=True): + """Correct box when no values and take margin in account""" if not self.width: self.xmax = self.xmin + 1 if not self.height: @@ -71,6 +83,7 @@ class Box(object): class View(object): + """Projection base class""" def __init__(self, width, height, box): self.width = width self.height = height @@ -78,23 +91,29 @@ class View(object): self.box.fix() def x(self, x): + """Project x""" if x == None: return None return self.width * (x - self.box.xmin) / self.box.width def y(self, y): + """Project y""" if y == None: return None return (self.height - self.height * (y - self.box.ymin) / self.box.height) def __call__(self, xy): + """Project x and y""" x, y = xy return (self.x(x), self.y(y)) class PolarView(View): + """Polar projection for pie like graphs""" + def __call__(self, rhotheta): + """Project rho and theta""" if None in rhotheta: return None, None rho, theta = rhotheta @@ -104,6 +123,9 @@ class PolarView(View): class LogView(View): + """Logarithmic projection """ + # Do not want to call the parent here + # pylint: disable-msg=W0231 def __init__(self, width, height, box): self.width = width self.height = height @@ -115,6 +137,7 @@ class LogView(View): self.box.fix(False) def y(self, y): + """Project y""" if y == None or y <= 0: return None return (self.height - self.height *