/+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: Gustav Hartvigsson
  • Date: 2011-01-03 21:57:12 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20110103215712-1yeiw9tl7oiwh8w1
forgot the the the images in the examples folder...

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-2008 Gerald Kaszuba
 
6
Copyright 2007-2009 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
23
23
 
24
24
import os
25
25
import urllib
26
 
import urllib2
 
26
import urllib.request, urllib.error
27
27
import math
28
28
import random
29
29
import re
33
33
# Helper variables and functions
34
34
# -----------------------------------------------------------------------------
35
35
 
36
 
__version__ = '0.2.2'
 
36
__version__ = '0.3.0'
37
37
__author__ = 'Gerald Kaszuba'
38
38
 
39
39
reo_colour = re.compile('^([A-Fa-f0-9]{2,2}){3,4}$')
85
85
class UnknownChartType(PyGoogleChartException):
86
86
    pass
87
87
 
 
88
class UnknownCountryCodeException(PyGoogleChartException):
 
89
    pass
88
90
 
89
91
# Data Classes
90
92
# -----------------------------------------------------------------------------
282
284
    of the chart. legend requires a list that corresponds to datasets.
283
285
    """
284
286
 
285
 
    BASE_URL = 'http://chart.apis.google.com/chart?'
 
287
    BASE_URL = 'http://chart.apis.google.com/chart'
286
288
    BACKGROUND = 'bg'
287
289
    CHART = 'c'
288
290
    ALPHA = 'a'
330
332
        self.markers = []
331
333
        self.line_styles = {}
332
334
        self.grid = None
 
335
        self.title_colour = None
 
336
        self.title_font_size = None
333
337
 
334
338
    # URL generation
335
339
    # -------------------------------------------------------------------------
336
 
 
 
340
        
337
341
    def get_url(self, data_class=None):
 
342
        return self.BASE_URL + '?' + self.get_url_extension(data_class)
 
343
    
 
344
    def get_url_extension(self, data_class=None):
338
345
        url_bits = self.get_url_bits(data_class=data_class)
339
 
        return self.BASE_URL + '&'.join(url_bits)
 
346
        return '&'.join(url_bits)
340
347
 
341
348
    def get_url_bits(self, data_class=None):
342
349
        url_bits = []
368
375
            url_bits.append(self.markers_to_url())        
369
376
        if self.line_styles:
370
377
            style = []
371
 
            for index in xrange(max(self.line_styles) + 1):
 
378
            for index in range(max(self.line_styles) + 1):
372
379
                if index in self.line_styles:
373
380
                    values = self.line_styles[index]
374
381
                else:
382
389
    # Downloading
383
390
    # -------------------------------------------------------------------------
384
391
 
385
 
    def download(self, file_name):
386
 
        opener = urllib2.urlopen(self.get_url())
 
392
    def download(self, file_name, use_post=True):
 
393
        if use_post:
 
394
            opener = urllib.request.urlopen(self.BASE_URL, self.get_url_extension())
 
395
        else:
 
396
            opener = urllib.request.urlopen(self.get_url())
387
397
 
388
398
        if opener.headers['content-type'] != 'image/png':
389
399
            raise BadContentTypeException('Server responded with a ' \
396
406
 
397
407
    def set_title(self, title):
398
408
        if title:
399
 
            self.title = urllib.quote(title)
 
409
            self.title = urllib.parse.quote(title)
400
410
        else:
401
411
            self.title = None
402
412
 
403
 
    def set_title_style(self, colour, font_size):
 
413
    def set_title_style(self, colour=None, font_size=None):
404
414
        if not colour is None:
405
415
            _check_colour(colour)
406
 
        self.title_colour = colour
407
 
        self.title_font_size = font_size
 
416
        if not colour and not font_size:
 
417
            return
 
418
        self.title_colour = colour or '333333'
 
419
        self.title_font_size = font_size or 13.5
408
420
 
409
421
    def set_legend(self, legend):
410
422
        """legend needs to be a list, tuple or None"""
411
423
        assert(isinstance(legend, list) or isinstance(legend, tuple) or
412
424
            legend is None)
413
425
        if legend:
414
 
            self.legend = [urllib.quote(a) for a in legend]
 
426
            self.legend = [urllib.parse.quote(a) for a in legend]
415
427
        else:
416
428
            self.legend = None
417
429
 
418
430
    def set_legend_position(self, legend_position):
419
431
        if legend_position:
420
 
            self.legend_position = urllib.quote(legend_position)
 
432
            self.legend_position = urllib.parse.quote(legend_position)
421
433
        else:    
422
434
            self.legend_position = None
423
435
 
458
470
        assert(angle >= 0 and angle <= 90)
459
471
        assert(len(args) % 2 == 0)
460
472
        args = list(args)  # args is probably a tuple and we need to mutate
461
 
        for a in xrange(int(len(args) / 2)):
 
473
        for a in range(int(len(args) / 2)):
462
474
            col = args[a * 2]
463
475
            offset = args[a * 2 + 1]
464
476
            _check_colour(col)
614
626
 
615
627
    def set_axis_labels(self, axis_type, values):
616
628
        assert(axis_type in Axis.TYPES)
617
 
        values = [urllib.quote(str(a)) for a in values]
 
629
        values = [urllib.parse.quote(str(a)) for a in values]
618
630
        axis_index = len(self.axis)
619
631
        axis = LabelAxis(axis_index, axis_type, values)
620
632
        self.axis.append(axis)
800
812
            url_bits.append('chbh=%i' % self.bar_width)
801
813
        zero_line = []
802
814
        if self.zero_lines:
803
 
            for index in xrange(max(self.zero_lines) + 1):
 
815
            for index in range(max(self.zero_lines) + 1):
804
816
                if index in self.zero_lines:
805
817
                    zero_line.append(str(self.zero_lines[index]))
806
818
                else:
894
906
                (self.__class__.__name__))
895
907
 
896
908
    def set_pie_labels(self, labels):
897
 
        self.pie_labels = [urllib.quote(a) for a in labels]
 
909
        self.pie_labels = [urllib.parse.quote(a) for a in labels]
898
910
 
899
911
    def get_url_bits(self, data_class=None):
900
912
        url_bits = Chart.get_url_bits(self, data_class=data_class)
954
966
        Chart.__init__(self, *args, **kwargs)
955
967
        self.geo_area = 'world'
956
968
        self.codes = []
957
 
 
 
969
        self.__areas = ('africa', 'asia', 'europe', 'middle_east',
 
970
            'south_america', 'usa', 'world')
 
971
        self.__ccodes = (
 
972
            'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AN', 'AO', 'AQ', 'AR',
 
973
            'AS', 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF',
 
974
            'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BR', 'BS', 'BT',
 
975
            'BV', 'BW', 'BY', 'BZ', 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI',
 
976
            'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CX', 'CY', 'CZ',
 
977
            'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'EH', 'ER',
 
978
            'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD',
 
979
            'GE', 'GF', 'GG', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR',
 
980
            'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM', 'HN', 'HR', 'HT', 'HU',
 
981
            'ID', 'IE', 'IL', 'IM', 'IN', 'IO', 'IQ', 'IR', 'IS', 'IT', 'JE',
 
982
            'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KP', 'KR',
 
983
            'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT',
 
984
            'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK',
 
985
            'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV',
 
986
            'MW', 'MX', 'MY', 'MZ', 'NA', 'NC', 'NE', 'NF', 'NG', 'NI', 'NL',
 
987
            'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH',
 
988
            'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', 'PW', 'PY', 'QA', 'RE',
 
989
            'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH',
 
990
            'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'ST', 'SV', 'SY',
 
991
            'SZ', 'TC', 'TD', 'TF', 'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN',
 
992
            'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'UM', 'US', 'UY',
 
993
            'UZ', 'VA', 'VC', 'VE', 'VG', 'VI', 'VN', 'VU', 'WF', 'WS', 'YE',
 
994
            'YT', 'ZA', 'ZM', 'ZW')
 
995
        
958
996
    def type_to_url(self):
959
997
        return 'cht=t'
960
998
 
961
999
    def set_codes(self, codes):
962
 
        self.codes = codes
 
1000
        '''Set the country code map for the data.
 
1001
        Codes given in a list.
 
1002
 
 
1003
        i.e. DE - Germany
 
1004
             AT - Austria
 
1005
             US - United States
 
1006
        '''
 
1007
 
 
1008
        codemap = ''
 
1009
        
 
1010
        for cc in codes:
 
1011
            cc = cc.upper()
 
1012
            if cc in self.__ccodes:
 
1013
                codemap += cc
 
1014
            else:
 
1015
                raise UnknownCountryCodeException(cc)
 
1016
            
 
1017
        self.codes = codemap
 
1018
 
 
1019
    def set_geo_area(self, area):
 
1020
        '''Sets the geo area for the map.
 
1021
 
 
1022
        * africa
 
1023
        * asia
 
1024
        * europe
 
1025
        * middle_east
 
1026
        * south_america
 
1027
        * usa
 
1028
        * world
 
1029
        '''
 
1030
        
 
1031
        if area in self.__areas:
 
1032
            self.geo_area = area
 
1033
        else:
 
1034
            raise UnknownChartType('Unknown chart type for maps: %s' %area)
963
1035
 
964
1036
    def get_url_bits(self, data_class=None):
965
1037
        url_bits = Chart.get_url_bits(self, data_class=data_class)
968
1040
            url_bits.append('chld=%s' % ''.join(self.codes))
969
1041
        return url_bits
970
1042
 
 
1043
    def add_data_dict(self, datadict):
 
1044
        '''Sets the data and country codes via a dictionary.
 
1045
 
 
1046
        i.e. {'DE': 50, 'GB': 30, 'AT': 70}
 
1047
        '''
 
1048
 
 
1049
        self.set_codes(datadict.keys())
 
1050
        self.add_data(datadict.values())
 
1051
 
971
1052
 
972
1053
class GoogleOMeterChart(PieChart):
973
1054
    """Inheriting from PieChart because of similar labeling"""
996
1077
    def data_to_url(self, data_class=None):
997
1078
        if not self.data:
998
1079
            raise NoDataGivenException()
999
 
        return 'chl=%s' % urllib.quote(self.data[0])
 
1080
        return 'chl=%s' % urllib.parse.quote(self.data[0])
1000
1081
 
1001
1082
    def get_url_bits(self, data_class=None):
1002
1083
        url_bits = Chart.get_url_bits(self, data_class=data_class)