/+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)
349
345
        # optional arguments
350
346
        if self.title:
351
347
            url_bits.append('chtt=%s' % self.title)
352
 
        if self.title_colour and self.title_font_size:
353
 
            url_bits.append('chts=%s,%s' % (self.title_colour, \
354
 
                self.title_font_size))
355
348
        if self.legend:
356
 
            url_bits.append('chdl=%s' % '%7c'.join(self.legend))
 
349
            url_bits.append('chdl=%s' % '|'.join(self.legend))
357
350
        if self.legend_position:
358
351
            url_bits.append('chdlp=%s' % (self.legend_position))
359
352
        if self.colours:
360
353
            url_bits.append('chco=%s' % ','.join(self.colours))            
361
354
        if self.colours_within_series:
362
 
            url_bits.append('chco=%s' % '%7c'.join(self.colours_within_series))
 
355
            url_bits.append('chco=%s' % '|'.join(self.colours_within_series))
363
356
        ret = self.fill_to_url()
364
357
        if ret:
365
358
            url_bits.append(ret)
376
369
                else:
377
370
                    values = ('1', )
378
371
                style.append(','.join(values))
379
 
            url_bits.append('chls=%s' % '%7c'.join(style))
 
372
            url_bits.append('chls=%s' % '|'.join(style))
380
373
        if self.grid:
381
374
            url_bits.append('chg=%s' % self.grid)
382
375
        return url_bits
402
395
        else:
403
396
            self.title = None
404
397
 
405
 
    def set_title_style(self, colour, font_size):
406
 
        if not colour is None:
407
 
            _check_colour(colour)
408
 
        self.title_colour = colour
409
 
        self.title_font_size = font_size
410
 
 
411
398
    def set_legend(self, legend):
412
399
        """legend needs to be a list, tuple or None"""
413
400
        assert(isinstance(legend, list) or isinstance(legend, tuple) or
460
447
        assert(angle >= 0 and angle <= 90)
461
448
        assert(len(args) % 2 == 0)
462
449
        args = list(args)  # args is probably a tuple and we need to mutate
463
 
        for a in xrange(int(len(args) / 2)):
 
450
        for a in xrange(len(args) / 2):
464
451
            col = args[a * 2]
465
452
            offset = args[a * 2 + 1]
466
453
            _check_colour(col)
487
474
                areas.append('%s,%s,%s' % (area, self.fill_types[area], \
488
475
                    self.fill_area[area]))
489
476
        if areas:
490
 
            return 'chf=' + '%7c'.join(areas)
 
477
            return 'chf=' + '|'.join(areas)
491
478
 
492
479
    # Data
493
480
    # -------------------------------------------------------------------------
616
603
 
617
604
    def set_axis_labels(self, axis_type, values):
618
605
        assert(axis_type in Axis.TYPES)
619
 
        values = [urllib.quote(str(a)) for a in values]
 
606
        values = [urllib.quote(a) for a in values]
620
607
        axis_index = len(self.axis)
621
608
        axis = LabelAxis(axis_index, axis_type, values)
622
609
        self.axis.append(axis)
666
653
        url_bits = []
667
654
        url_bits.append('chxt=%s' % ','.join(available_axis))
668
655
        if label_axis:
669
 
            url_bits.append('chxl=%s' % '%7c'.join(label_axis))
 
656
            url_bits.append('chxl=%s' % '|'.join(label_axis))
670
657
        if range_axis:
671
 
            url_bits.append('chxr=%s' % '%7c'.join(range_axis))
 
658
            url_bits.append('chxr=%s' % '|'.join(range_axis))
672
659
        if positions:
673
 
            url_bits.append('chxp=%s' % '%7c'.join(positions))
 
660
            url_bits.append('chxp=%s' % '|'.join(positions))
674
661
        if styles:
675
 
            url_bits.append('chxs=%s' % '%7c'.join(styles))
 
662
            url_bits.append('chxs=%s' % '|'.join(styles))
676
663
        return '&'.join(url_bits)
677
664
 
678
665
    # Markers, Ranges and Fill area (chm)
679
666
    # -------------------------------------------------------------------------
680
667
 
681
668
    def markers_to_url(self):        
682
 
        return 'chm=%s' % '%7c'.join([','.join(a) for a in self.markers])
 
669
        return 'chm=%s' % '|'.join([','.join(a) for a in self.markers])
683
670
 
684
671
    def add_marker(self, index, point, marker_type, colour, size, priority=0):
685
672
        self.markers.append((marker_type, colour, str(index), str(point), \
689
676
        self.markers.append(('r', colour, '0', str(start), str(stop)))
690
677
 
691
678
    def add_data_line(self, colour, data_set, size, priority=0):
692
 
        self.markers.append(('D', colour, str(data_set), '0', str(size), \
693
 
            str(priority)))
 
679
        self.markers.append(('D', colour, str(data_set), '0', str(size), str(priority)))
694
680
 
695
 
    def add_marker_text(self, string, colour, data_set, data_point, size, \
696
 
            priority=0):
697
 
        self.markers.append((str(string), colour, str(data_set), \
698
 
            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)))        
699
683
 
700
684
    def add_vertical_range(self, colour, start, stop):
701
685
        self.markers.append(('R', colour, '0', str(start), str(stop)))
901
885
    def get_url_bits(self, data_class=None):
902
886
        url_bits = Chart.get_url_bits(self, data_class=data_class)
903
887
        if self.pie_labels:
904
 
            url_bits.append('chl=%s' % '%7c'.join(self.pie_labels))
 
888
            url_bits.append('chl=%s' % '|'.join(self.pie_labels))
905
889
        return url_bits
906
890
 
907
891
    def annotated_data(self):
910
894
        for dataset in self.data:
911
895
            yield ('x', dataset)
912
896
 
913
 
    def scaled_data(self, data_class, x_range=None, y_range=None):
914
 
        if not x_range:
915
 
            x_range = [0, sum(self.data[0])]
916
 
        return Chart.scaled_data(self, data_class, x_range, self.y_range)
917
 
 
918
897
 
919
898
class PieChart2D(PieChart):
920
899
 
956
935
        Chart.__init__(self, *args, **kwargs)
957
936
        self.geo_area = 'world'
958
937
        self.codes = []
959
 
        self.__areas = ('africa', 'asia', 'europe', 'middle_east',
960
 
            'south_america', 'usa', 'world')
961
 
        self.__ccodes = (
962
 
            'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AN', 'AO', 'AQ', 'AR',
963
 
            'AS', 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF',
964
 
            'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BR', 'BS', 'BT',
965
 
            'BV', 'BW', 'BY', 'BZ', 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI',
966
 
            'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CX', 'CY', 'CZ',
967
 
            'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'EH', 'ER',
968
 
            'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD',
969
 
            'GE', 'GF', 'GG', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR',
970
 
            'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM', 'HN', 'HR', 'HT', 'HU',
971
 
            'ID', 'IE', 'IL', 'IM', 'IN', 'IO', 'IQ', 'IR', 'IS', 'IT', 'JE',
972
 
            'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KP', 'KR',
973
 
            'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT',
974
 
            'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK',
975
 
            'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV',
976
 
            'MW', 'MX', 'MY', 'MZ', 'NA', 'NC', 'NE', 'NF', 'NG', 'NI', 'NL',
977
 
            'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH',
978
 
            'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', 'PW', 'PY', 'QA', 'RE',
979
 
            'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH',
980
 
            'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'ST', 'SV', 'SY',
981
 
            'SZ', 'TC', 'TD', 'TF', 'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN',
982
 
            'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'UM', 'US', 'UY',
983
 
            'UZ', 'VA', 'VC', 'VE', 'VG', 'VI', 'VN', 'VU', 'WF', 'WS', 'YE',
984
 
            'YT', 'ZA', 'ZM', 'ZW')
985
 
        
 
938
 
986
939
    def type_to_url(self):
987
940
        return 'cht=t'
988
941
 
989
942
    def set_codes(self, codes):
990
 
        '''Set the country code map for the data.
991
 
        Codes given in a list.
992
 
 
993
 
        i.e. DE - Germany
994
 
             AT - Austria
995
 
             US - United States
996
 
        '''
997
 
 
998
 
        codemap = ''
999
 
        
1000
 
        for cc in codes:
1001
 
            cc = cc.upper()
1002
 
            if cc in self.__ccodes:
1003
 
                codemap += cc
1004
 
            else:
1005
 
                raise UnknownCountryCodeException(cc)
1006
 
            
1007
 
        self.codes = codemap
1008
 
 
1009
 
    def set_geo_area(self, area):
1010
 
        '''Sets the geo area for the map.
1011
 
 
1012
 
        * africa
1013
 
        * asia
1014
 
        * europe
1015
 
        * middle_east
1016
 
        * south_america
1017
 
        * usa
1018
 
        * world
1019
 
        '''
1020
 
        
1021
 
        if area in self.__areas:
1022
 
            self.geo_area = area
1023
 
        else:
1024
 
            raise UnknownChartType('Unknown chart type for maps: %s' %area)
 
943
        self.codes = codes
1025
944
 
1026
945
    def get_url_bits(self, data_class=None):
1027
946
        url_bits = Chart.get_url_bits(self, data_class=data_class)
1030
949
            url_bits.append('chld=%s' % ''.join(self.codes))
1031
950
        return url_bits
1032
951
 
1033
 
    def add_data_dict(self, datadict):
1034
 
        '''Sets the data and country codes via a dictionary.
1035
 
 
1036
 
        i.e. {'DE': 50, 'GB': 30, 'AT': 70}
1037
 
        '''
1038
 
 
1039
 
        self.set_codes(datadict.keys())
1040
 
        self.add_data(datadict.values())
1041
 
 
1042
952
 
1043
953
class GoogleOMeterChart(PieChart):
1044
954
    """Inheriting from PieChart because of similar labeling"""
1074
984
        if self.encoding:
1075
985
            url_bits.append('choe=%s' % self.encoding)
1076
986
        if self.ec_level:
1077
 
            url_bits.append('chld=%s%%7c%s' % (self.ec_level, self.margin))
 
987
            url_bits.append('chld=%s|%s' % (self.ec_level, self.margin))
1078
988
        return url_bits
1079
989
 
1080
990
    def set_encoding(self, encoding):