615
671
url_bits.append('chxt=%s' % ','.join(available_axis))
617
url_bits.append('chxl=%s' % '|'.join(label_axis))
673
url_bits.append('chxl=%s' % '%7c'.join(label_axis))
619
url_bits.append('chxr=%s' % '|'.join(range_axis))
675
url_bits.append('chxr=%s' % '%7c'.join(range_axis))
621
url_bits.append('chxp=%s' % '|'.join(positions))
677
url_bits.append('chxp=%s' % '%7c'.join(positions))
623
url_bits.append('chxs=%s' % '|'.join(styles))
679
url_bits.append('chxs=%s' % '%7c'.join(styles))
624
680
return '&'.join(url_bits)
626
682
# Markers, Ranges and Fill area (chm)
627
683
# -------------------------------------------------------------------------
629
def markers_to_url(self):
630
return 'chm=%s' % '|'.join([','.join(a) for a in self.markers])
685
def markers_to_url(self):
686
return 'chm=%s' % '%7c'.join([','.join(a) for a in self.markers])
632
688
def add_marker(self, index, point, marker_type, colour, size, priority=0):
633
689
self.markers.append((marker_type, colour, str(index), str(point), \
634
690
str(size), str(priority)))
636
692
def add_horizontal_range(self, colour, start, stop):
637
self.markers.append(('r', colour, '1', str(start), str(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)))
639
704
def add_vertical_range(self, colour, start, stop):
640
self.markers.append(('R', colour, '1', str(start), str(stop)))
705
self.markers.append(('R', colour, '0', str(start), str(stop)))
642
707
def add_fill_range(self, colour, index_start, index_end):
643
708
self.markers.append(('b', colour, str(index_start), str(index_end), \
887
960
Chart.__init__(self, *args, **kwargs)
888
961
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')
891
990
def type_to_url(self):
894
993
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)
897
1030
def get_url_bits(self, data_class=None):
898
1031
url_bits = Chart.get_url_bits(self, data_class=data_class)
901
1034
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())
905
1047
class GoogleOMeterChart(PieChart):
906
1048
"""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.')
908
1056
def type_to_url(self):
909
1057
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
912
1092
class ChartGrammar(object):
914
def __init__(self, grammar):
1098
def parse(self, grammar):
915
1099
self.grammar = grammar
916
1100
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
919
1117
def get_possible_chart_types():
920
1118
possible_charts = []
921
for cls_name in globals():
1119
for cls_name in globals().keys():
922
1120
if not cls_name.endswith('Chart'):
924
1122
cls = globals()[cls_name]
925
1123
# Check if it is an abstract class
1125
a = cls(1, 1, auto_scale=False)
928
1127
except AbstractClassException:
930
1129
# Strip off "Class"
931
1130
possible_charts.append(cls_name[:-5])
932
1131
return possible_charts
934
def create_chart_instance(self):
1133
def create_chart_instance(self, grammar=None):
1135
grammar = self.grammar
1136
assert(isinstance(grammar, dict)) # grammar must be a dict
935
1137
assert('w' in grammar) # width is required
936
1138
assert('h' in grammar) # height is required
937
1139
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)
938
1146
types = ChartGrammar.get_possible_chart_types()
939
if grammar['type'] not in types:
1147
if chart_type not in types:
940
1148
raise UnknownChartType('%s is an unknown chart type. Possible '
941
'chart types are %s' % (grammar['type'], ','.join(types)))
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)
943
1153
def download(self):