Browse Source

Document interpolation and add a larger stroke width on active

pull/242/head
Florian Mounier 10 years ago
parent
commit
09480b58e3
  1. 13
      demo/moulinrouge/__init__.py
  2. 4
      pygal/_compat.py
  3. 8
      pygal/adapters.py
  4. 1
      pygal/colors.py
  5. 1
      pygal/css/style.css
  6. 9
      pygal/etree.py
  7. 63
      pygal/interpolate.py

13
demo/moulinrouge/__init__.py

@ -98,7 +98,11 @@ def create_app():
@app.route("/svg/<type>/<series>/<config>") @app.route("/svg/<type>/<series>/<config>")
def svg(type, series, config): def svg(type, series, config):
graph = getattr(pygal, type)(pickle.loads(b64decode(str(config)))) module = '.'.join(type.split('.')[:-1])
name = type.split('.')[-1]
from importlib import import_module
graph = getattr(import_module(module), name)(
pickle.loads(b64decode(str(config))))
for title, values in pickle.loads(b64decode(str(series))): for title, values in pickle.loads(b64decode(str(series))):
graph.add(title, values) graph.add(title, values)
return graph.render_response() return graph.render_response()
@ -196,10 +200,13 @@ def create_app():
config.human_readable = True config.human_readable = True
config.interpolate = interpolate config.interpolate = interpolate
config.style = style config.style = style
config.x_labels = [random_label() for i in range(data)]
svgs = [] svgs = []
for chart in pygal.CHARTS: for chart in pygal.CHARTS:
type = chart.__name__ type = '.'.join((chart.__module__, chart.__name__))
if chart._dual:
config.x_labels = None
else:
config.x_labels = [random_label() for i in range(data)]
svgs.append({'type': type, svgs.append({'type': type,
'series': xy_series if type == 'XY' else other_series, 'series': xy_series if type == 'XY' else other_series,
'config': b64encode(pickle.dumps(config))}) 'config': b64encode(pickle.dumps(config))})

4
pygal/_compat.py

@ -16,6 +16,10 @@
# #
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>. # along with pygal. If not, see <http://www.gnu.org/licenses/>.
"""
Various hacks for transparent python 2 / python 3 support
"""
import sys import sys
from collections import Iterable from collections import Iterable
import time import time

8
pygal/adapters.py

@ -24,6 +24,7 @@ from decimal import Decimal
def positive(x): def positive(x):
"""Return zero if value is negative"""
if x is None: if x is None:
return return
if x < 0: if x < 0:
@ -32,16 +33,21 @@ def positive(x):
def not_zero(x): def not_zero(x):
"""Return None if value is zero"""
if x == 0: if x == 0:
return return
return x return x
def none_to_zero(x): def none_to_zero(x):
return x or 0 """Return 0 if value is None"""
if x is None:
return 0
return x
def decimal_to_float(x): def decimal_to_float(x):
"""Cast Decimal values to float"""
if isinstance(x, Decimal): if isinstance(x, Decimal):
return float(x) return float(x)
return x return x

1
pygal/colors.py

@ -150,6 +150,7 @@ _clamp = lambda x: max(0, min(100, x))
def _adjust(hsl, attribute, percent): def _adjust(hsl, attribute, percent):
"""Internal adjust function"""
hsl = list(hsl) hsl = list(hsl)
if attribute > 0: if attribute > 0:
hsl[attribute] = _clamp(hsl[attribute] + percent) hsl[attribute] = _clamp(hsl[attribute] + percent)

1
pygal/css/style.css

@ -97,6 +97,7 @@
{{ id }}.reactive.active, {{ id }}.reactive.active,
{{ id }}.active .reactive { {{ id }}.active .reactive {
fill-opacity: {{ style.opacity_hover }}; fill-opacity: {{ style.opacity_hover }};
stroke-width: 4;
} }
{{ id }}.series text { {{ id }}.series text {

9
pygal/etree.py

@ -16,10 +16,17 @@
# #
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>. # along with pygal. If not, see <http://www.gnu.org/licenses/>.
"""
Wrapper for seemless lxml.etree / xml.etree usage
depending on whether lxml is installed or not.
"""
import os import os
class Etree(object): class Etree(object):
"""Etree wrapper using lxml.etree or standard xml.etree"""
def __init__(self): def __init__(self):
from xml.etree import ElementTree as _py_etree from xml.etree import ElementTree as _py_etree
self._py_etree = _py_etree self._py_etree = _py_etree
@ -42,10 +49,12 @@ class Etree(object):
return object.__getattribute__(self, attr) return object.__getattribute__(self, attr)
def to_lxml(self): def to_lxml(self):
"""Force lxml.etree to be used"""
self._etree = self._lxml_etree self._etree = self._lxml_etree
self.lxml = True self.lxml = True
def to_etree(self): def to_etree(self):
"""Force xml.etree to be used"""
self._etree = self._py_etree self._etree = self._py_etree
self.lxml = False self.lxml = False

63
pygal/interpolate.py

@ -17,7 +17,11 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>. # along with pygal. If not, see <http://www.gnu.org/licenses/>.
""" """
Interpolation Interpolation functions
These functions takes two lists of points x and y and
returns an iterator over the interpolation between all these points
with `precision` interpolated points between each of them
""" """
from __future__ import division from __future__ import division
@ -25,6 +29,11 @@ from math import sin
def quadratic_interpolate(x, y, precision=250, **kwargs): def quadratic_interpolate(x, y, precision=250, **kwargs):
"""
Interpolate x, y using a quadratic algorithm
https://en.wikipedia.org/wiki/Spline_(mathematics)
"""
n = len(x) - 1 n = len(x) - 1
delta_x = [x2 - x1 for x1, x2 in zip(x, x[1:])] delta_x = [x2 - x1 for x1, x2 in zip(x, x[1:])]
delta_y = [y2 - y1 for y1, y2 in zip(y, y[1:])] delta_y = [y2 - y1 for y1, y2 in zip(y, y[1:])]
@ -51,6 +60,10 @@ def quadratic_interpolate(x, y, precision=250, **kwargs):
def cubic_interpolate(x, y, precision=250, **kwargs): def cubic_interpolate(x, y, precision=250, **kwargs):
"""
Interpolate x, y using a cubic algorithm
https://en.wikipedia.org/wiki/Spline_interpolation
"""
n = len(x) - 1 n = len(x) - 1
# Spline equation is a + bx + cx² + dx³ # Spline equation is a + bx + cx² + dx³
# ie: Spline part i equation is a[i] + b[i]x + c[i]x² + d[i]x³ # ie: Spline part i equation is a[i] + b[i]x + c[i]x² + d[i]x³
@ -91,6 +104,25 @@ def cubic_interpolate(x, y, precision=250, **kwargs):
def hermite_interpolate(x, y, precision=250, def hermite_interpolate(x, y, precision=250,
type='cardinal', c=None, b=None, t=None): type='cardinal', c=None, b=None, t=None):
"""
Interpolate x, y using the hermite method.
See https://en.wikipedia.org/wiki/Cubic_Hermite_spline
This interpolation is configurable and contain 4 subtypes:
* Catmull Rom
* Finite Difference
* Cardinal
* Kochanek Bartels
The cardinal subtype is customizable with a parameter:
* c: tension (0, 1)
This last type is also customizable using 3 parameters:
* c: continuity (-1, 1)
* b: bias (-1, 1)
* t: tension (-1, 1)
"""
n = len(x) - 1 n = len(x) - 1
m = [1] * (n + 1) m = [1] * (n + 1)
w = [1] * (n + 1) w = [1] * (n + 1)
@ -148,6 +180,10 @@ def hermite_interpolate(x, y, precision=250,
def lagrange_interpolate(x, y, precision=250, **kwargs): def lagrange_interpolate(x, y, precision=250, **kwargs):
"""
Interpolate x, y using Lagrange polynomials
https://en.wikipedia.org/wiki/Lagrange_polynomial
"""
n = len(x) - 1 n = len(x) - 1
delta_x = [x2 - x1 for x1, x2 in zip(x, x[1:])] delta_x = [x2 - x1 for x1, x2 in zip(x, x[1:])]
for i in range(n + 1): for i in range(n + 1):
@ -170,7 +206,10 @@ def lagrange_interpolate(x, y, precision=250, **kwargs):
def trigonometric_interpolate(x, y, precision=250, **kwargs): def trigonometric_interpolate(x, y, precision=250, **kwargs):
"""As per http://en.wikipedia.org/wiki/Trigonometric_interpolation""" """
Interpolate x, y using trigonometric
As per http://en.wikipedia.org/wiki/Trigonometric_interpolation
"""
n = len(x) - 1 n = len(x) - 1
delta_x = [x2 - x1 for x1, x2 in zip(x, x[1:])] delta_x = [x2 - x1 for x1, x2 in zip(x, x[1:])]
for i in range(n + 1): for i in range(n + 1):
@ -191,12 +230,6 @@ def trigonometric_interpolate(x, y, precision=250, **kwargs):
s += y[k] * p s += y[k] * p
yield X, s yield X, s
"""
These functions takes two lists of points x and y and
returns an iterator over the interpolation between all these points
with `precision` interpolated points between each of them
"""
INTERPOLATIONS = { INTERPOLATIONS = {
'quadratic': quadratic_interpolate, 'quadratic': quadratic_interpolate,
'cubic': cubic_interpolate, 'cubic': cubic_interpolate,
@ -213,4 +246,18 @@ if __name__ == '__main__':
xy.add('normal', points) xy.add('normal', points)
xy.add('quadratic', quadratic_interpolate(*zip(*points))) xy.add('quadratic', quadratic_interpolate(*zip(*points)))
xy.add('cubic', cubic_interpolate(*zip(*points))) xy.add('cubic', cubic_interpolate(*zip(*points)))
xy.add('lagrange', lagrange_interpolate(*zip(*points)))
xy.add('trigonometric', trigonometric_interpolate(*zip(*points)))
xy.add('hermite catmul_rom', hermite_interpolate(
*zip(*points), type='catmul_rom'))
xy.add('hermite finite_difference', hermite_interpolate(
*zip(*points), type='finite_difference'))
xy.add('hermite cardinal -.5', hermite_interpolate(
*zip(*points), type='cardinal', c=-.5))
xy.add('hermite cardinal .5', hermite_interpolate(
*zip(*points), type='cardinal', c=.5))
xy.add('hermite kochanek_bartels .5 .75 -.25', hermite_interpolate(
*zip(*points), type='kochanek_bartels', c=.5, b=.75, t=-.25))
xy.add('hermite kochanek_bartels .25 -.75 .5', hermite_interpolate(
*zip(*points), type='kochanek_bartels', c=.25, b=-.75, t=.5))
xy.render_in_browser() xy.render_in_browser()

Loading…
Cancel
Save