/+junk/pygooglechart-py3k

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/%2Bjunk/pygooglechart-py3k

« back to all changes in this revision

Viewing changes to pygooglechart.py

  • Committer: gak
  • Date: 2008-08-23 08:24:07 UTC
  • Revision ID: git-v1:62a852b162ce05f4126ffc3c7c594d06c8d6f5dc

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
 
4
4
http://pygooglechart.slowchop.com/
5
5
 
6
 
Copyright 2007-2009 Gerald Kaszuba
 
6
Copyright 2007-2008 Gerald Kaszuba
7
7
 
8
8
This program is free software: you can redistribute it and/or modify
9
9
it under the terms of the GNU General Public License as published by
19
19
along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
20
 
21
21
"""
22
 
from __future__ import division
23
22
 
24
23
import os
25
24
import urllib
33
32
# Helper variables and functions
34
33
# -----------------------------------------------------------------------------
35
34
 
36
 
__version__ = '0.3.0'
 
35
__version__ = '0.2.1'
37
36
__author__ = 'Gerald Kaszuba'
38
37
 
39
38
reo_colour = re.compile('^([A-Fa-f0-9]{2,2}){3,4}$')
85
84
class UnknownChartType(PyGoogleChartException):
86
85
    pass
87
86
 
88
 
class UnknownCountryCodeException(PyGoogleChartException):
89
 
    pass
90
87
 
91
88
# Data Classes
92
89
# -----------------------------------------------------------------------------
103
100
    def float_scale_value(cls, value, range):
104
101
        lower, upper = range
105
102
        assert(upper > lower)
106
 
        scaled = (value - lower) * (cls.max_value / (upper - lower))
 
103
        scaled = (value - lower) * (float(cls.max_value) / (upper - lower))
107
104
        return scaled
108
105
 
109
106
    @classmethod
165
162
                else:
166
163
                    raise DataOutOfRangeException()
167
164
            encoded_data.append(','.join(sub_data))
168
 
        return 'chd=t:' + '%7c'.join(encoded_data)
 
165
        return 'chd=t:' + '|'.join(encoded_data)
169
166
 
170
167
    @classmethod
171
168
    def scale_value(cls, value, range):
260
257
        self.values = [str(a) for a in values]
261
258
 
262
259
    def __repr__(self):
263
 
        return '%i:%%7c%s' % (self.axis_index, '%7c'.join(self.values))
 
260
        return '%i:|%s' % (self.axis_index, '|'.join(self.values))
264
261
 
265
262
 
266
263
class RangeAxis(Axis):
304
301
        self.height = height
305
302
        self.data = []
306
303
        self.set_title(title)
307
 
        self.set_title_style(None, None)
308
304
        self.set_legend(legend)
309
305
        self.set_legend_position(None)
310
306
        self.set_colours(colours)
332
328
        self.markers = []
333
329
        self.line_styles = {}
334
330
        self.grid = None
335
 
        self.title_colour = None
336
 
        self.title_font_size = None
337
331
 
338
332
    # URL generation
339
333
    # -------------------------------------------------------------------------
351
345
        # optional arguments
352
346
        if self.title:
353
347
            url_bits.append('chtt=%s' % self.title)
354
 
        if self.title_colour and self.title_font_size:
355
 
            url_bits.append('chts=%s,%s' % (self.title_colour, \
356
 
                self.title_font_size))
357
348
        if self.legend:
358
 
            url_bits.append('chdl=%s' % '%7c'.join(self.legend))
 
349
            url_bits.append('chdl=%s' % '|'.join(self.legend))
359
350
        if self.legend_position:
360
351
            url_bits.append('chdlp=%s' % (self.legend_position))
361
352
        if self.colours:
362
353
            url_bits.append('chco=%s' % ','.join(self.colours))            
363
354
        if self.colours_within_series:
364
 
            url_bits.append('chco=%s' % '%7c'.join(self.colours_within_series))
 
355
            url_bits.append('chco=%s' % '|'.join(self.colours_within_series))
365
356
        ret = self.fill_to_url()
366
357
        if ret:
367
358
            url_bits.append(ret)
378
369
                else:
379
370
                    values = ('1', )
380
371
                style.append(','.join(values))
381
 
            url_bits.append('chls=%s' % '%7c'.join(style))
 
372
            url_bits.append('chls=%s' % '|'.join(style))
382
373
        if self.grid:
383
374
            url_bits.append('chg=%s' % self.grid)
384
375
        return url_bits
404
395
        else:
405
396
            self.title = None
406
397
 
407
 
    def set_title_style(self, colour=None, font_size=None):
408
 
        if not colour is None:
409
 
            _check_colour(colour)
410
 
        if not colour and not font_size:
411
 
            return
412
 
        self.title_colour = colour or '333333'
413
 
        self.title_font_size = font_size or 13.5
414
 
 
415
398
    def set_legend(self, legend):
416
399
        """legend needs to be a list, tuple or None"""
417
400
        assert(isinstance(legend, list) or isinstance(legend, tuple) or
464
447
        assert(angle >= 0 and angle <= 90)
465
448
        assert(len(args) % 2 == 0)
466
449
        args = list(args)  # args is probably a tuple and we need to mutate
467
 
        for a in xrange(int(len(args) / 2)):
 
450
        for a in xrange(len(args) / 2):
468
451
            col = args[a * 2]
469
452
            offset = args[a * 2 + 1]
470
453
            _check_colour(col)
491
474
                areas.append('%s,%s,%s' % (area, self.fill_types[area], \
492
475
                    self.fill_area[area]))
493
476
        if areas:
494
 
            return 'chf=' + '%7c'.join(areas)
 
477
            return 'chf=' + '|'.join(areas)
495
478
 
496
479
    # Data
497
480
    # -------------------------------------------------------------------------
620
603
 
621
604
    def set_axis_labels(self, axis_type, values):
622
605
        assert(axis_type in Axis.TYPES)
623
 
        values = [urllib.quote(str(a)) for a in values]
 
606
        values = [urllib.quote(a) for a in values]
624
607
        axis_index = len(self.axis)
625
608
        axis = LabelAxis(axis_index, axis_type, values)
626
609
        self.axis.append(axis)
670
653
        url_bits = []
671
654
        url_bits.append('chxt=%s' % ','.join(available_axis))
672
655
        if label_axis:
673
 
            url_bits.append('chxl=%s' % '%7c'.join(label_axis))
 
656
            url_bits.append('chxl=%s' % '|'.join(label_axis))
674
657
        if range_axis:
675
 
            url_bits.append('chxr=%s' % '%7c'.join(range_axis))
 
658
            url_bits.append('chxr=%s' % '|'.join(range_axis))
676
659
        if positions:
677
 
            url_bits.append('chxp=%s' % '%7c'.join(positions))
 
660
            url_bits.append('chxp=%s' % '|'.join(positions))
678
661
        if styles:
679
 
            url_bits.append('chxs=%s' % '%7c'.join(styles))
 
662
            url_bits.append('chxs=%s' % '|'.join(styles))
680
663
        return '&'.join(url_bits)
681
664
 
682
665
    # Markers, Ranges and Fill area (chm)
683
666
    # -------------------------------------------------------------------------
684
667
 
685
668
    def markers_to_url(self):        
686
 
        return 'chm=%s' % '%7c'.join([','.join(a) for a in self.markers])
 
669
        return 'chm=%s' % '|'.join([','.join(a) for a in self.markers])
687
670
 
688
671
    def add_marker(self, index, point, marker_type, colour, size, priority=0):
689
672
        self.markers.append((marker_type, colour, str(index), str(point), \
693
676
        self.markers.append(('r', colour, '0', str(start), str(stop)))
694
677
 
695
678
    def add_data_line(self, colour, data_set, size, priority=0):
696
 
        self.markers.append(('D', colour, str(data_set), '0', str(size), \
697
 
            str(priority)))
 
679
        self.markers.append(('D', colour, str(data_set), '0', str(size), str(priority)))
698
680
 
699
 
    def add_marker_text(self, string, colour, data_set, data_point, size, \
700
 
            priority=0):
701
 
        self.markers.append((str(string), colour, str(data_set), \
702
 
            str(data_point), str(size), str(priority)))        
 
681
    def add_marker_text(self, string, colour, data_set, data_point, size, priority=0):
 
682
        self.markers.append((str(string), colour, str(data_set), str(data_point), str(size), str(priority)))        
703
683
 
704
684
    def add_vertical_range(self, colour, start, stop):
705
685
        self.markers.append(('R', colour, '0', str(start), str(stop)))
905
885
    def get_url_bits(self, data_class=None):
906
886
        url_bits = Chart.get_url_bits(self, data_class=data_class)
907
887
        if self.pie_labels:
908
 
            url_bits.append('chl=%s' % '%7c'.join(self.pie_labels))
 
888
            url_bits.append('chl=%s' % '|'.join(self.pie_labels))
909
889
        return url_bits
910
890
 
911
891
    def annotated_data(self):
914
894
        for dataset in self.data:
915
895
            yield ('x', dataset)
916
896
 
917
 
    def scaled_data(self, data_class, x_range=None, y_range=None):
918
 
        if not x_range:
919
 
            x_range = [0, sum(self.data[0])]
920
 
        return Chart.scaled_data(self, data_class, x_range, self.y_range)
921
 
 
922
897
 
923
898
class PieChart2D(PieChart):
924
899
 
960
935
        Chart.__init__(self, *args, **kwargs)
961
936
        self.geo_area = 'world'
962
937
        self.codes = []
963
 
        self.__areas = ('africa', 'asia', 'europe', 'middle_east',
964
 
            'south_america', 'usa', 'world')
965
 
        self.__ccodes = (
966
 
            'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AN', 'AO', 'AQ', 'AR',
967
 
            'AS', 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF',
968
 
            'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BR', 'BS', 'BT',
969
 
            'BV', 'BW', 'BY', 'BZ', 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI',
970
 
            'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CX', 'CY', 'CZ',
971
 
            'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'EH', 'ER',
972
 
            'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD',
973
 
            'GE', 'GF', 'GG', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR',
974
 
            'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM', 'HN', 'HR', 'HT', 'HU',
975
 
            'ID', 'IE', 'IL', 'IM', 'IN', 'IO', 'IQ', 'IR', 'IS', 'IT', 'JE',
976
 
            'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KP', 'KR',
977
 
            'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT',
978
 
            'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK',
979
 
            'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV',
980
 
            'MW', 'MX', 'MY', 'MZ', 'NA', 'NC', 'NE', 'NF', 'NG', 'NI', 'NL',
981
 
            'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH',
982
 
            'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', 'PW', 'PY', 'QA', 'RE',
983
 
            'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH',
984
 
            'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'ST', 'SV', 'SY',
985
 
            'SZ', 'TC', 'TD', 'TF', 'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN',
986
 
            'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'UM', 'US', 'UY',
987
 
            'UZ', 'VA', 'VC', 'VE', 'VG', 'VI', 'VN', 'VU', 'WF', 'WS', 'YE',
988
 
            'YT', 'ZA', 'ZM', 'ZW')
989
 
        
 
938
 
990
939
    def type_to_url(self):
991
940
        return 'cht=t'
992
941
 
993
942
    def set_codes(self, codes):
994
 
        '''Set the country code map for the data.
995
 
        Codes given in a list.
996
 
 
997
 
        i.e. DE - Germany
998
 
             AT - Austria
999
 
             US - United States
1000
 
        '''
1001
 
 
1002
 
        codemap = ''
1003
 
        
1004
 
        for cc in codes:
1005
 
            cc = cc.upper()
1006
 
            if cc in self.__ccodes:
1007
 
                codemap += cc
1008
 
            else:
1009
 
                raise UnknownCountryCodeException(cc)
1010
 
            
1011
 
        self.codes = codemap
1012
 
 
1013
 
    def set_geo_area(self, area):
1014
 
        '''Sets the geo area for the map.
1015
 
 
1016
 
        * africa
1017
 
        * asia
1018
 
        * europe
1019
 
        * middle_east
1020
 
        * south_america
1021
 
        * usa
1022
 
        * world
1023
 
        '''
1024
 
        
1025
 
        if area in self.__areas:
1026
 
            self.geo_area = area
1027
 
        else:
1028
 
            raise UnknownChartType('Unknown chart type for maps: %s' %area)
 
943
        self.codes = codes
1029
944
 
1030
945
    def get_url_bits(self, data_class=None):
1031
946
        url_bits = Chart.get_url_bits(self, data_class=data_class)
1034
949
            url_bits.append('chld=%s' % ''.join(self.codes))
1035
950
        return url_bits
1036
951
 
1037
 
    def add_data_dict(self, datadict):
1038
 
        '''Sets the data and country codes via a dictionary.
1039
 
 
1040
 
        i.e. {'DE': 50, 'GB': 30, 'AT': 70}
1041
 
        '''
1042
 
 
1043
 
        self.set_codes(datadict.keys())
1044
 
        self.add_data(datadict.values())
1045
 
 
1046
952
 
1047
953
class GoogleOMeterChart(PieChart):
1048
954
    """Inheriting from PieChart because of similar labeling"""
1078
984
        if self.encoding:
1079
985
            url_bits.append('choe=%s' % self.encoding)
1080
986
        if self.ec_level:
1081
 
            url_bits.append('chld=%s%%7c%s' % (self.ec_level, self.margin))
 
987
            url_bits.append('chld=%s|%s' % (self.ec_level, self.margin))
1082
988
        return url_bits
1083
989
 
1084
990
    def set_encoding(self, encoding):