Changeset 170

Show
Ignore:
Timestamp:
03/18/09 15:35:07 (3 years ago)
Author:
lgs
Message:

Implement different color schemes. Fixes #29

Location:
trunk
Files:
2 added
3 modified

Legend:

Unmodified
Added
Removed
  • trunk/pycha/chart.py

    r169 r170  
    1717 
    1818import copy 
     19import inspect 
    1920import math 
    2021 
     
    121122        colorSchemeClass = ColorScheme.getColorScheme(name, None) 
    122123        if colorSchemeClass is None: 
    123             raise ValueError('Color scheme is invalid!') 
    124  
     124            raise ValueError('Color scheme "%s" is invalid!' % name) 
     125 
     126        # Remove invalid args before calling the constructor 
    125127        kwargs = dict(self.options.colorScheme.args) 
     128        validArgs = inspect.getargspec(colorSchemeClass.__init__)[0] 
     129        kwargs = dict([(k, v) for k, v in kwargs.items() if k in validArgs]) 
    126130        self.colorScheme = colorSchemeClass(keys, **kwargs) 
    127131 
     
    672676    colorScheme=Option( 
    673677        name='gradient', 
    674         args=Option(initialColor=DEFAULT_COLOR), 
     678        args=Option( 
     679            initialColor=DEFAULT_COLOR, 
     680            colors=[], 
     681            ), 
    675682    ), 
    676683    title=None, 
  • trunk/pycha/color.py

    r169 r170  
    1616# You should have received a copy of the GNU Lesser General Public License 
    1717# along with PyCha.  If not, see <http://www.gnu.org/licenses/>. 
     18 
     19import math 
    1820 
    1921DEFAULT_COLOR = '#3c581a' 
     
    4547    b = int(hexstring[digits*2+1:digits*3+1], 16) 
    4648    return r / top, g / top, b / top 
     49 
     50 
     51def rgb2hsv(r, g, b): 
     52    """Converts a RGB color into a HSV one 
     53 
     54    See http://en.wikipedia.org/wiki/HSV_color_space 
     55    """ 
     56    maximum = max(r, g, b) 
     57    minimum = min(r, g, b) 
     58    if maximum == minimum: 
     59        h = 0.0 
     60    elif maximum == r: 
     61        h = 60.0 * ((g - b) / (maximum - minimum)) + 360.0 
     62        if h >= 360.0: 
     63            h -= 360.0 
     64    elif maximum == g: 
     65        h = 60.0 * ((b - r) / (maximum - minimum)) + 120.0 
     66    elif maximum == b: 
     67        h = 60.0 * ((r - g) / (maximum - minimum)) + 240.0 
     68 
     69    if maximum == 0.0: 
     70        s = 0.0 
     71    else: 
     72        s = 1.0 - (minimum / maximum) 
     73 
     74    v = maximum 
     75 
     76    return h, s, v 
     77 
     78 
     79def hsv2rgb(h, s, v): 
     80    """Converts a HSV color into a RGB one 
     81 
     82    See http://en.wikipedia.org/wiki/HSV_color_space 
     83    """ 
     84    hi = int(math.floor(h / 60.0)) % 6 
     85    f = (h / 60.0) - hi 
     86    p = v * (1 - s) 
     87    q = v * (1 - f * s) 
     88    t = v * (1 - (1 - f) * s) 
     89 
     90    if hi == 0: 
     91        r, g, b = v, t, p 
     92    elif hi == 1: 
     93        r, g, b = q, v, p 
     94    elif hi == 2: 
     95        r, g, b = p, v, t 
     96    elif hi == 3: 
     97        r, g, b = p, q, v 
     98    elif hi == 4: 
     99        r, g, b = t, p, v 
     100    elif hi == 5: 
     101        r, g, b = v, p, q 
     102 
     103    return r, g, b 
    47104 
    48105 
     
    112169        for i, key in enumerate(keys): 
    113170            self[key] = lighten(r, g, b, light * i) 
     171 
     172 
     173class FixedColorScheme(ColorScheme): 
     174    """In this color scheme fixed colors are used. 
     175 
     176    These colors are provided as a list argument in the constructor. 
     177    """ 
     178 
     179    def __init__(self, keys, colors=[]): 
     180        super(FixedColorScheme, self).__init__(keys) 
     181 
     182        if len(keys) != len(colors): 
     183            raise ValueError("You must provide as many colors as datasets " 
     184                             "for the fixed color scheme") 
     185 
     186        for i, key in enumerate(keys): 
     187            self[key] = hex2rgb(colors[i]) 
     188 
     189 
     190class RainbowColorScheme(ColorScheme): 
     191 
     192    def __init__(self, keys, initialColor=DEFAULT_COLOR): 
     193        super(RainbowColorScheme, self).__init__(keys) 
     194        if initialColor in basicColors: 
     195            initialColor = basicColors[initialColor] 
     196 
     197        r, g, b = hex2rgb(initialColor) 
     198        h, s, v = rgb2hsv(r, g, b) 
     199 
     200        angleDelta = 360.0 / (len(keys) + 1) 
     201        for key in keys: 
     202            self[key] = hsv2rgb(h, s, v) 
     203            h += angleDelta 
     204            if h >= 360.0: 
     205                h -= 360.0 
  • trunk/tests/color.py

    r169 r170  
    5757        self.assertEqual(1, color[2]) 
    5858 
     59    def test_rgb2hsv_and_hsv2rgb(self): 
     60        for rgb, hsv in (((1.0, 0.0, 0.0), (0.0, 1.0, 1.0)), 
     61                         ((1.0, 0.5, 0.0), (30.0, 1.0, 1.0)), 
     62                         ((1.0, 1.0, 0.0), (60.0, 1.0, 1.0)), 
     63                         ((0.5, 1.0, 0.0), (90.0, 1.0, 1.0)), 
     64                         ((0.0, 1.0, 0.0), (120.0, 1.0, 1.0)), 
     65                         ((0.0, 1.0, 0.5), (150.0, 1.0, 1.0)), 
     66                         ((0.0, 1.0, 1.0), (180.0, 1.0, 1.0)), 
     67                         ((0.0, 0.5, 1.0), (210.0, 1.0, 1.0)), 
     68                         ((0.0, 0.0, 1.0), (240.0, 1.0, 1.0)), 
     69                         ((0.5, 0.0, 1.0), (270.0, 1.0, 1.0)), 
     70                         ((1.0, 0.0, 1.0), (300.0, 1.0, 1.0)), 
     71                         ((1.0, 0.0, 0.5), (330.0, 1.0, 1.0)), 
     72                         ((0.375, 0.5, 0.25), (90.0, 0.5, 0.5)), 
     73                         ((0.21875, 0.25, 0.1875), (90.0, 0.25, 0.25))): 
     74            self._assertColors(pycha.color.rgb2hsv(*rgb), hsv, 5) 
     75            self._assertColors(pycha.color.hsv2rgb(*hsv), rgb, 5) 
     76 
    5977    def test_lighten(self): 
    6078        r, g, b = (1.0, 1.0, 0.0) 
     
    8098                          pycha.color.ColorScheme.getColorScheme('foo')) 
    8199 
     100    def test_FixedColorScheme(self): 
     101        keys = range(3) 
     102        colors = ((1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)) 
     103        scheme = pycha.color.FixedColorScheme(keys, colors) 
     104        self._assertColors(scheme[0], (1.0, 0.0, 0.0), 1) 
     105        self._assertColors(scheme[1], (0.0, 1.0, 0.0), 3) 
     106        self._assertColors(scheme[2], (0.0, 0.0, 1.0), 3) 
     107 
    82108    def test_GradientColorScheme(self): 
    83109        keys = range(5) 
    84         scheme = pycha.color.GradientColorScheme(keys, "000000") 
     110        scheme = pycha.color.GradientColorScheme(keys, "#000000") 
    85111        self._assertColors(scheme[0], (0.0, 0.0, 0.0), 3) 
    86112        self._assertColors(scheme[1], (0.1, 0.1, 0.1), 3) 
     
    108134        self.assertNotAlmostEqual(color[2], 1.0, 4) 
    109135 
     136    def test_RainbowColorScheme(self): 
     137        keys = range(5) 
     138        scheme = pycha.color.GradientColorScheme(keys, "#ff0000") 
     139        self._assertColors(scheme[0], (1.0, 0.0, 0.0), 3) 
     140        self._assertColors(scheme[1], (1.0, 0.1, 0.1), 3) 
     141        self._assertColors(scheme[2], (1.0, 0.2, 0.2), 3) 
     142        self._assertColors(scheme[3], (1.0, 0.3, 0.3), 3) 
     143        self._assertColors(scheme[4], (1.0, 0.4, 0.4), 3) 
     144 
    110145 
    111146def test_suite():