Browse Source

Support colors in rgb / rgba for parametric styles

pull/146/head
Florian Mounier 11 years ago
parent
commit
60daf6442c
  1. 1
      CHANGELOG
  2. 77
      pygal/colors.py
  3. 20
      pygal/ghost.py
  4. 64
      pygal/test/test_colors.py

1
CHANGELOG

@ -3,6 +3,7 @@ V 1.5.0 UNRELEASED
Add half pie (thanks philt2001)
Make lxml an optionnal dependency (huge speed boost in pypy)
Add render_table (WIP)
Support colors in rgb / rgba for parametric styles
V 1.4.6
Add support for \n separated multiline titles (thanks sirlark)

77
pygal/colors.py

@ -79,27 +79,78 @@ def hsl_to_rgb(h, s, l):
return r, g, b
def adjust(color, attribute, percent):
assert color[0] == '#', '#rrggbb and #rgb format are supported'
def parse_color(color):
r = g = b = a = type = None
if color.startswith('#'):
color = color[1:]
assert len(color) in (3, 6), '#rrggbb and #rgb format are supported'
if len(color) == 3:
color = [a for b in zip(color, color) for a in b]
bound = lambda x: max(0, min(100, x))
def _adjust(hsl):
type = '#rgb'
color = color + 'f'
if len(color) == 4:
type = type or '#rgba'
color = ''.join([c * 2 for c in color])
if len(color) == 6:
type = type or '#rrggbb'
color = color + 'ff'
assert len(color) == 8
type = type or '#rrggbbaa'
r, g, b, a = [
int(''.join(c), 16) for c in zip(color[::2], color[1::2])]
a /= 255
elif color.startswith('rgb('):
type = 'rgb'
color = color[4:-1]
r, g, b, a = [int(c) for c in color.split(',')] + [1]
elif color.startswith('rgba('):
type = 'rgba'
color = color[5:-1]
r, g, b, a = [int(c) for c in color.split(',')[:-1]] + [
float(color.split(',')[-1])]
return r, g, b, a, type
def unparse_color(r, g, b, a, type):
if type == '#rgb':
# Don't lose precision on rgb shortcut
if r % 17 == 0 and g % 17 == 0 and b % 17 == 0:
return '#%x%x%x' % (r / 17, g / 17, b / 17)
type = '#rrggbb'
if type == '#rgba':
if r % 17 == 0 and g % 17 == 0 and b % 17 == 0:
return '#%x%x%x%x' % (r / 17, g / 17, b / 17, a * 15)
type = '#rrggbbaa'
if type == '#rrggbb':
return '#%02x%02x%02x' % (r, g, b)
if type == '#rrggbbaa':
return '#%02x%02x%02x%02x' % (r, g, b, a * 255)
if type == 'rgb':
return 'rgb(%d, %d, %d)' % (r, g, b)
if type == 'rgba':
return 'rgba(%d, %d, %d, %g)' % (r, g, b, a)
_clamp = lambda x: max(0, min(100, x))
def _adjust(hsl, attribute, percent):
hsl = list(hsl)
if attribute > 0:
hsl[attribute] = bound(hsl[attribute] + percent)
hsl[attribute] = _clamp(hsl[attribute] + percent)
else:
hsl[attribute] += percent
return hsl
return '#%02x%02x%02x' % hsl_to_rgb(
*_adjust(
rgb_to_hsl(*map(lambda x: int(''.join(x), 16),
zip(color[::2], color[1::2])))))
def adjust(color, attribute, percent):
r, g, b, a, type = parse_color(color)
r, g, b = hsl_to_rgb(*_adjust(rgb_to_hsl(r, g, b), attribute, percent))
return unparse_color(r, g, b, a, type)
def rotate(color, percent):

20
pygal/ghost.py

@ -111,8 +111,8 @@ class Ghost(object):
.make_instance(overrides=kwargs)
.render(is_unicode=is_unicode))
def render_tree(self):
return self.make_instance().render_tree()
def render_tree(self, **kwargs):
return self.make_instance(overrides=kwargs).render_tree()
def render_table(self, **kwargs):
# Import here to avoid lxml import
@ -130,29 +130,29 @@ class Ghost(object):
from pyquery import PyQuery as pq
return pq(self.render(), parser='html')
def render_in_browser(self):
def render_in_browser(self, **kwargs):
"""Render the graph, open it in your browser with black magic"""
try:
from lxml.html import open_in_browser
except ImportError:
raise ImportError('You must install lxml to use render in browser')
open_in_browser(self.render_tree(), encoding='utf-8')
open_in_browser(self.render_tree(**kwargs), encoding='utf-8')
def render_response(self):
def render_response(self, **kwargs):
"""Render the graph, and return a Flask response"""
from flask import Response
return Response(self.render(), mimetype='image/svg+xml')
return Response(self.render(**kwargs), mimetype='image/svg+xml')
def render_to_file(self, filename):
def render_to_file(self, filename, **kwargs):
"""Render the graph, and write it to filename"""
with io.open(filename, 'w', encoding='utf-8') as f:
f.write(self.render(is_unicode=True))
f.write(self.render(is_unicode=True, **kwargs))
def render_to_png(self, filename=None, dpi=72):
def render_to_png(self, filename=None, dpi=72, **kwargs):
"""Render the graph, convert it to png and write it to filename"""
import cairosvg
return cairosvg.svg2png(
bytestring=self.render(), write_to=filename, dpi=dpi)
bytestring=self.render(**kwargs), write_to=filename, dpi=dpi)
def render_sparktext(self, relative_to=None):
"""Make a mini text sparkline from chart"""

64
pygal/test/test_colors.py

@ -1,21 +1,55 @@
from __future__ import division
from pygal.colors import (
parse_color, unparse_color,
rgb_to_hsl, hsl_to_rgb, darken, lighten, saturate, desaturate, rotate)
def test_parse_color():
assert parse_color('#123') == (17, 34, 51, 1., '#rgb')
assert parse_color('#cdf') == (204, 221, 255, 1., '#rgb')
assert parse_color('#a3d7') == (170, 51, 221, 119 / 255, '#rgba')
assert parse_color('#584b4f') == (88, 75, 79, 1., '#rrggbb')
assert parse_color('#8cbe22') == (140, 190, 34, 1., '#rrggbb')
assert parse_color('#16cbf055') == (22, 203, 240, 1 / 3, '#rrggbbaa')
assert parse_color('rgb(134, 67, 216)') == (134, 67, 216, 1., 'rgb')
assert parse_color('rgb(0, 111, 222)') == (0, 111, 222, 1., 'rgb')
assert parse_color('rgba(237, 83, 48, .8)') == (237, 83, 48, .8, 'rgba')
assert parse_color('rgba(0, 1, 0, 0.1223)') == (0, 1, 0, .1223, 'rgba')
def test_unparse_color():
assert unparse_color(17, 34, 51, 1., '#rgb') == '#123'
assert unparse_color(204, 221, 255, 1., '#rgb') == '#cdf'
assert unparse_color(170, 51, 221, 119 / 255, '#rgba') == '#a3d7'
assert unparse_color(88, 75, 79, 1., '#rrggbb') == '#584b4f'
assert unparse_color(140, 190, 34, 1., '#rrggbb') == '#8cbe22'
assert unparse_color(22, 203, 240, 1 / 3, '#rrggbbaa') == '#16cbf055'
assert unparse_color(134, 67, 216, 1., 'rgb') == 'rgb(134, 67, 216)'
assert unparse_color(0, 111, 222, 1., 'rgb') == 'rgb(0, 111, 222)'
assert unparse_color(237, 83, 48, .8, 'rgba') == 'rgba(237, 83, 48, 0.8)'
assert unparse_color(0, 1, 0, .1223, 'rgba') == 'rgba(0, 1, 0, 0.1223)'
def test_darken():
assert darken('#800', 20) == '#220000'
assert darken('#800', 0) == '#880000'
assert darken('#800', 20) == '#200'
assert darken('#800e', 20) == '#200e'
assert darken('#800', 0) == '#800'
assert darken('#ffffff', 10) == '#e6e6e6'
assert darken('#000000', 10) == '#000000'
assert darken('#f3148a', 25) == '#810747'
assert darken('#f3148aab', 25) == '#810747ab'
assert darken('#121212', 1) == '#0f0f0f'
assert darken('#999999', 100) == '#000000'
assert darken('#99999999', 100) == '#00000099'
assert darken('#1479ac', 8) == '#105f87'
assert darken('rgb(136, 0, 0)', 20) == 'rgb(34, 0, 0)'
assert darken('rgba(20, 121, 172, .13)', 8) == 'rgba(16, 95, 135, 0.13)'
def test_lighten():
assert lighten('#800', 20) == '#ee0000'
assert lighten('#800', 0) == '#880000'
assert lighten('#800', 20) == '#e00'
assert lighten('#800', 0) == '#800'
assert lighten('#ffffff', 10) == '#ffffff'
assert lighten('#000000', 10) == '#1a1a1a'
assert lighten('#f3148a', 25) == '#f98dc6'
@ -25,26 +59,26 @@ def test_lighten():
def test_saturate():
assert saturate('#000', 20) == '#000000'
assert saturate('#fff', 20) == '#ffffff'
assert saturate('#8a8', 100) == '#33ff33'
assert saturate('#000', 20) == '#000'
assert saturate('#fff', 20) == '#fff'
assert saturate('#8a8', 100) == '#3f3'
assert saturate('#855', 20) == '#9e3f3f'
def test_desaturate():
assert desaturate('#000', 20) == '#000000'
assert desaturate('#fff', 20) == '#ffffff'
assert desaturate('#8a8', 100) == '#999999'
assert desaturate('#000', 20) == '#000'
assert desaturate('#fff', 20) == '#fff'
assert desaturate('#8a8', 100) == '#999'
assert desaturate('#855', 20) == '#726b6b'
def test_rotate():
assert rotate('#000', 45) == '#000000'
assert rotate('#fff', 45) == '#ffffff'
assert rotate('#000', 45) == '#000'
assert rotate('#fff', 45) == '#fff'
assert rotate('#811', 45) == '#886a11'
assert rotate('#8a8', 360) == '#88aa88'
assert rotate('#8a8', 0) == '#88aa88'
assert rotate('#8a8', -360) == '#88aa88'
assert rotate('#8a8', 360) == '#8a8'
assert rotate('#8a8', 0) == '#8a8'
assert rotate('#8a8', -360) == '#8a8'
def test_hsl_to_rgb_part_0():

Loading…
Cancel
Save