671
615
url_bits.append('chxt=%s' % ','.join(available_axis))
673
url_bits.append('chxl=%s' % '%7c'.join(label_axis))
617
url_bits.append('chxl=%s' % '|'.join(label_axis))
675
url_bits.append('chxr=%s' % '%7c'.join(range_axis))
619
url_bits.append('chxr=%s' % '|'.join(range_axis))
677
url_bits.append('chxp=%s' % '%7c'.join(positions))
621
url_bits.append('chxp=%s' % '|'.join(positions))
679
url_bits.append('chxs=%s' % '%7c'.join(styles))
623
url_bits.append('chxs=%s' % '|'.join(styles))
680
624
return '&'.join(url_bits)
682
626
# Markers, Ranges and Fill area (chm)
683
627
# -------------------------------------------------------------------------
685
def markers_to_url(self):
686
return 'chm=%s' % '%7c'.join([','.join(a) for a in self.markers])
629
def markers_to_url(self):
630
return 'chm=%s' % '|'.join([','.join(a) for a in self.markers])
688
632
def add_marker(self, index, point, marker_type, colour, size, priority=0):
689
633
self.markers.append((marker_type, colour, str(index), str(point), \
690
634
str(size), str(priority)))
692
636
def add_horizontal_range(self, colour, start, stop):
693
self.markers.append(('r', colour, '0', str(start), str(stop)))
695
def add_data_line(self, colour, data_set, size, priority=0):
696
self.markers.append(('D', colour, str(data_set), '0', str(size), \
699
def add_marker_text(self, string, colour, data_set, data_point, size, \
701
self.markers.append((str(string), colour, str(data_set), \
702
str(data_point), str(size), str(priority)))
637
self.markers.append(('r', colour, '1', str(start), str(stop)))
704
639
def add_vertical_range(self, colour, start, stop):
705
self.markers.append(('R', colour, '0', str(start), str(stop)))
640
self.markers.append(('R', colour, '1', str(start), str(stop)))
707
642
def add_fill_range(self, colour, index_start, index_end):
708
643
self.markers.append(('b', colour, str(index_start), str(index_end), \
960
887
Chart.__init__(self, *args, **kwargs)
961
888
self.geo_area = 'world'
963
self.__areas = ('africa', 'asia', 'europe', 'middle_east',
964
'south_america', 'usa', 'world')
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')
990
891
def type_to_url(self):
993
894
def set_codes(self, codes):
994
'''Set the country code map for the data.
995
Codes given in a list.
1006
if cc in self.__ccodes:
1009
raise UnknownCountryCodeException(cc)
1011
self.codes = codemap
1013
def set_geo_area(self, area):
1014
'''Sets the geo area for the map.
1025
if area in self.__areas:
1026
self.geo_area = area
1028
raise UnknownChartType('Unknown chart type for maps: %s' %area)
1030
897
def get_url_bits(self, data_class=None):
1031
898
url_bits = Chart.get_url_bits(self, data_class=data_class)
1034
901
url_bits.append('chld=%s' % ''.join(self.codes))
1037
def add_data_dict(self, datadict):
1038
'''Sets the data and country codes via a dictionary.
1040
i.e. {'DE': 50, 'GB': 30, 'AT': 70}
1043
self.set_codes(datadict.keys())
1044
self.add_data(datadict.values())
1047
905
class GoogleOMeterChart(PieChart):
1048
906
"""Inheriting from PieChart because of similar labeling"""
1050
def __init__(self, *args, **kwargs):
1051
PieChart.__init__(self, *args, **kwargs)
1052
if self.auto_scale and not self.x_range:
1053
warnings.warn('Please specify an x_range with GoogleOMeterChart, '
1054
'otherwise one arrow will always be at the max.')
1056
908
def type_to_url(self):
1057
909
return 'cht=gom'
1060
class QRChart(Chart):
1062
def __init__(self, *args, **kwargs):
1063
Chart.__init__(self, *args, **kwargs)
1064
self.encoding = None
1065
self.ec_level = None
1068
def type_to_url(self):
1071
def data_to_url(self, data_class=None):
1073
raise NoDataGivenException()
1074
return 'chl=%s' % urllib.quote(self.data[0])
1076
def get_url_bits(self, data_class=None):
1077
url_bits = Chart.get_url_bits(self, data_class=data_class)
1079
url_bits.append('choe=%s' % self.encoding)
1081
url_bits.append('chld=%s%%7c%s' % (self.ec_level, self.margin))
1084
def set_encoding(self, encoding):
1085
self.encoding = encoding
1087
def set_ec(self, level, margin):
1088
self.ec_level = level
1089
self.margin = margin
1092
912
class ChartGrammar(object):
1098
def parse(self, grammar):
914
def __init__(self, grammar):
1099
915
self.grammar = grammar
1100
916
self.chart = self.create_chart_instance()
1102
for attr in self.grammar:
1103
if attr in ('w', 'h', 'type', 'auto_scale', 'x_range', 'y_range'):
1104
continue # These are already parsed in create_chart_instance
1105
attr_func = 'parse_' + attr
1106
if not hasattr(self, attr_func):
1107
warnings.warn('No parser for grammar attribute "%s"' % (attr))
1109
getattr(self, attr_func)(grammar[attr])
1113
def parse_data(self, data):
1114
self.chart.data = data
1117
919
def get_possible_chart_types():
1118
920
possible_charts = []
1119
for cls_name in globals().keys():
921
for cls_name in globals():
1120
922
if not cls_name.endswith('Chart'):
1122
924
cls = globals()[cls_name]
1123
925
# Check if it is an abstract class
1125
a = cls(1, 1, auto_scale=False)
1127
928
except AbstractClassException:
1129
930
# Strip off "Class"
1130
931
possible_charts.append(cls_name[:-5])
1131
932
return possible_charts
1133
def create_chart_instance(self, grammar=None):
1135
grammar = self.grammar
1136
assert(isinstance(grammar, dict)) # grammar must be a dict
934
def create_chart_instance(self):
1137
935
assert('w' in grammar) # width is required
1138
936
assert('h' in grammar) # height is required
1139
937
assert('type' in grammar) # type is required
1140
chart_type = grammar['type']
1143
auto_scale = grammar.get('auto_scale', None)
1144
x_range = grammar.get('x_range', None)
1145
y_range = grammar.get('y_range', None)
1146
938
types = ChartGrammar.get_possible_chart_types()
1147
if chart_type not in types:
939
if grammar['type'] not in types:
1148
940
raise UnknownChartType('%s is an unknown chart type. Possible '
1149
'chart types are %s' % (chart_type, ','.join(types)))
1150
return globals()[chart_type + 'Chart'](w, h, auto_scale=auto_scale,
1151
x_range=x_range, y_range=y_range)
941
'chart types are %s' % (grammar['type'], ','.join(types)))
1153
943
def download(self):