-
Notifications
You must be signed in to change notification settings - Fork 0
/
isp_maps_template.py
213 lines (177 loc) · 7.34 KB
/
isp_maps_template.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
"""
Updated version of the original. This uses country codes to
map data rather than country names so it is more accurate.
"""
import csv
import math
import pygal
def read_csv_as_list_dict(filename, separator, quote):
"""
Inputs:
filename - name of CSV file
separator - character that separates fields
quote - character used to optionally quote fields
Output:
Returns a list of dictionaries where each item in the list
corresponds to a row in the CSV file. The dictionaries in the
list map the field names to the field values for that row.
"""
with open(filename, "r", newline = '') as csvfile:
reader = csv.DictReader(csvfile, delimiter = separator, quotechar = quote)
lines = []
for row in reader:
lines.append(row)
return lines
def read_csv_as_nested_dict(filename, keyfield, separator, quote):
"""
Inputs:
filename - Name of CSV file
keyfield - Field to use as key for rows
separator - Character that separates fields
quote - Character used to optionally quote fields
Output:
Returns a dictionary of dictionaries where the outer dictionary
maps the value in the key_field to the corresponding row in the
CSV file. The inner dictionaries map the field names to the
field values for that row.
"""
with open(filename, 'r', newline = '') as csvfile:
reader = csv.DictReader(csvfile, delimiter = separator, quotechar = quote)
nested_countries = {}
for country in reader:
nested_countries[country[keyfield]] = country
return nested_countries
def build_country_code_converter(codeinfo):
"""
Inputs:
codeinfo - A country code information dictionary
Output:
A dictionary whose keys are plot country codes and values
are world bank country codes, where the code fields in the
code file are specified in codeinfo.
"""
codes = read_csv_as_list_dict(
codeinfo["codefile"], codeinfo["separator"], codeinfo["quote"])
count_codes = {}
for code in codes:
count_codes[code[codeinfo["plot_codes"]]] = code[codeinfo["data_codes"]]
return count_codes
def reconcile_countries_by_code(codeinfo, plot_countries, gdp_countries):
"""
Inputs:
codeinfo - A country code information dictionary
plot_countries - Dictionary whose keys are plot library country codes
and values are the corresponding country name
gdp_countries - Dictionary whose keys are country codes used in GDP data
Output:
A tuple containing a dictionary and a set. The dictionary maps
country codes from plot_countries to country codes from
gdp_countries. The set contains the country codes from
plot_countries that did not have a country with a corresponding
code in gdp_countries.
Note that all codes should be compared in a case-insensitive
way. However, the returned dictionary and set should include
the codes with the exact same case as they have in
plot_countries and gdp_countries.
"""
converter = build_country_code_converter(codeinfo)
countries = {}
not_found = set()
print(gdp_countries.keys())
for code in plot_countries:
up_code = code.upper()
up_conv = dict((key.upper(), value.upper()) for key, value in converter.items())
up_dict = dict((key.upper(), value) for key, value in gdp_countries.items())
print(up_code, up_conv, up_dict.keys())
try:
if up_conv[up_code] in up_dict:
for data in gdp_countries:
if data.upper() == up_conv[up_code]:
countries[code] = data
else:
not_found.add(code)
except KeyError:
not_found.add(code)
return countries, not_found
def build_map_dict_by_code(gdpinfo, codeinfo, plot_countries, year):
"""
Inputs:
gdpinfo - A GDP information dictionary
codeinfo - A country code information dictionary
plot_countries - Dictionary mapping plot library country codes to country names
year - String year for which to create GDP mapping
Output:
A tuple containing a dictionary and two sets. The dictionary
maps country codes from plot_countries to the log (base 10) of
the GDP value for that country in the specified year. The first
set contains the country codes from plot_countries that were not
found in the GDP data file. The second set contains the country
codes from plot_countries that were found in the GDP data file, but
have no GDP data for the specified year.
"""
gdp_countries = read_csv_as_nested_dict(
gdpinfo["gdpfile"], gdpinfo["country_code"], gdpinfo["separator"], gdpinfo["quote"])
valid_countries = reconcile_countries_by_code(codeinfo, plot_countries, gdp_countries)
plot_codes = valid_countries[0]
gdp_values = {}
no_gdp = set()
print(plot_codes, gdp_countries.keys())
for plot, data in plot_codes.items():
print(plot, data)
try:
gdp_values[plot] = math.log10(float(gdp_countries[data][year]))
except ValueError:
no_gdp.add(plot)
return gdp_values, valid_countries[1], no_gdp
def render_world_map(gdpinfo, codeinfo, plot_countries, year, map_file):
"""
Inputs:
gdpinfo - A GDP information dictionary
codeinfo - A country code information dictionary
plot_countries - Dictionary mapping plot library country codes to country names
year - String year of data
map_file - String that is the output map file name
Output:
Returns None.
Action:
Creates a world map plot of the GDP data in gdp_mapping and outputs
it to a file named by svg_filename.
"""
map_data = build_map_dict_by_code(gdpinfo, codeinfo, plot_countries, year)
worldmap_chart = pygal.maps.world.World()
worldmap_chart.add(f"Global GDP in {year}", map_data[0])
worldmap_chart.add("Country not listed", map_data[1])
worldmap_chart.add(f"No GDP data for {year}", map_data[2])
worldmap_chart.render_in_browser()
worldmap_chart.render_to_file(map_file)
def test_render_world_map():
"""
Test the project code for several years
"""
gdpinfo = {
"gdpfile": "isp_gdp.csv",
"separator": ",",
"quote": '"',
"min_year": 1960,
"max_year": 2015,
"country_name": "Country Name",
"country_code": "Country Code"
}
codeinfo = {
"codefile": "isp_country_codes.csv",
"separator": ",",
"quote": '"',
"plot_codes": "ISO3166-1-Alpha-2",
"data_codes": "ISO3166-1-Alpha-3"
}
# Get pygal country code map
pygal_countries = pygal.maps.world.COUNTRIES
# 1960
render_world_map(gdpinfo, codeinfo, pygal_countries, "1960", "isp_gdp_world_code_1960.svg")
# 1980
render_world_map(gdpinfo, codeinfo, pygal_countries, "1980", "isp_gdp_world_code_1980.svg")
# 2000
render_world_map(gdpinfo, codeinfo, pygal_countries, "2000", "isp_gdp_world_code_2000.svg")
# 2010
render_world_map(gdpinfo, codeinfo, pygal_countries, "2010", "isp_gdp_world_code_2010.svg")
#test_render_world_map()