1.下载并处理数据
制作地图需要 JSON 文件。JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。《python编程从入门到实践》中给出的网址已经更改为https://datahub.io/,进入网站后在搜索框中输入population
然后找到population total这个选项,左击进入后选择json文件,点击进入后另存为data.json即可。
PS:http://www.ourd3js.com/wordpress/668/这个网站上也有丰富的json格式的人口数据可以下载。
下载好json数据后进行处理
import json
if __name__ == '__main__':
#打开data.json文件
filename = 'data.json'
with open(filename) as f:
pop_data = json.load(f)
#查看json文件的数据,不难发现是一个很长的json列表,每一元素为包含4个键的字典:国别码、国家名、年份以及人口数。
#我们取年份为2016,注意该文件中的年份为int型,原书自带的文件中年份为字符型。
for pop_dict in pop_data:
if pop_dict['Year'] == 2016:
country_name = pop_dict['Country Name']
#由于存在小数,所以用int取整
population = int(pop_dict['Value'])
print(country_name + ':' + str(population))
运行结果如下:
考虑到Pygal的地图制作工具要求数据为特定的格式:用两位字母的国别码表示国家,而本json文件为三位字母的国别码,所以需要进一步处理。创建获取两位国别码的函数get_country_code。
注意:原书中import pygal.i18n,目前pygal中已经不包含这个模块。所以需要安装pygal_maps_world(pip安装即可,不详说)
from pygal_maps_world.i18n import COUNTRIES
def get_country_code(country_name):
#在COUNTRIES中查找并返回国别码
for code, name in COUNTRIES.items():
if name == country_name:
return code
return None
修改主函数,将原先输出的国家名改为国别码,同时将人口分为3类,小于1亿,小于10亿,和超过10亿
if __name__ == '__main__':
#打开data.json文件
filename = 'data.json'
with open(filename) as f:
pop_data = json.load(f)
#查看json文件的数据,不难发现是一个很长的json列表,每一元素为包含4个键的字典:国别码、国家名、年份以及人口数。
#cc_pop1,cc_pop2,cc_pop3分别存放小于1亿,小于10亿,超过10亿的数据
cc_pop1, cc_pop2, cc_pop3 = {},{},{}
for pop_dict in pop_data:
#我们取年份为2016,注意该文件中的年份为int型,原书自带的文件中年份为字符型。
if pop_dict['Year'] == 2016:
country_name = pop_dict['Country Name']
#获取国别码
country_code = get_country_code(country_name)
if country_code:
#由于存在小数,所以用int取整
population = int(pop_dict['Value'])
print(country_code + ':' + str(population))
#进行分类
if population < 100000000:
cc_pop1[country_code] = population
elif population < 1000000000:
cc_pop2[country_code] = population
else:
cc_pop3[country_code] = population
else:
print("Error: " + country_name)
运行结果如下:
目前为止,数据处理完毕,可以正式开始绘制地图。
2.绘制地图并优化
创建绘制地图的函数draw_map。
注意:原书用的pygal.worldmap(),目前也不存在,改用pygal.maps.world.World()
import pygal
def draw_map(pcc_pop1, cc_pop2, cc_pop3):
#绘制地图
wn = pygal.maps.world.World()
#添加标题
wn.title = '2016世界人口地图'
#add()将一系列值添加到图表中
wn.add('0-1亿',cc_pop1)
wn.add('1亿-10亿',cc_pop2)
wn.add('超过10亿',cc_pop3)
#渲染为SVG文件,直接用浏览器打开即可
wn.render_to_file('world_population.svg')
主函数中添加一句:
draw_map(cc_pop1, cc_pop2, cc_pop3)
运行结果:
地图基本成型,现在进一步优化一下,主要改一改样式
from pygal.style import RotateStyle
from pygal.style import LightColorizedStyle
#使用#336699的颜色,让地图呈现淡蓝色基色
#使用LightColorizedStyle加量地图主题
wn = pygal.maps.world.World(style = RotateStyle('#336699',base_style=LightColorizedStyle))
最终运行结果:
总程序:
import json
from pygal_maps_world.i18n import COUNTRIES
import pygal.maps
from pygal.style import RotateStyle
from pygal.style import LightColorizedStyle
def get_country_code(country_name):
#在COUNTRIES中查找并返回国别码
for code, name in COUNTRIES.items():
if name == country_name:
return code
return None
def draw_map(pcc_pop1, cc_pop2, cc_pop3):
#绘制地图
#使用#336699的颜色,让地图呈现淡蓝色基色
#使用LightColorizedStyle加量地图主题
wn = pygal.maps.world.World(style = RotateStyle('#336699',base_style=LightColorizedStyle))
#添加标题
wn.title = '2016世界人口地图'
#add()将一系列值添加到图表中
wn.add('0-1亿',cc_pop1)
wn.add('1亿-10亿',cc_pop2)
wn.add('超过10亿',cc_pop3)
#渲染为SVG文件,直接用浏览器打开即可
wn.render_to_file('world_population.svg')
if __name__ == '__main__':
#打开data.json文件
filename = 'data.json'
with open(filename) as f:
pop_data = json.load(f)
#查看json文件的数据,不难发现是一个很长的json列表,每一元素为包含4个键的字典:国别码、国家名、年份以及人口数。
#cc_pop1,cc_pop2,cc_pop3分别存放小于1亿,小于10亿,超过10亿的数据
cc_pop1, cc_pop2, cc_pop3 = {},{},{}
for pop_dict in pop_data:
#我们取年份为2016,注意该文件中的年份为int型,原书自带的文件中年份为字符型。
if pop_dict['Year'] == 2016:
country_name = pop_dict['Country Name']
#获取国别码
country_code = get_country_code(country_name)
if country_code:
#由于存在小数,所以用int取整
population = int(pop_dict['Value'])
print(country_code + ':' + str(population))
#进行分类
if population < 100000000:
cc_pop1[country_code] = population
elif population < 1000000000:
cc_pop2[country_code] = population
else:
cc_pop3[country_code] = population
else:
print("Error: " + country_name)
draw_map(cc_pop1, cc_pop2, cc_pop3)