1.提取2010世界人口數據
先查看json文件數據:
這個文件實際上就是一個很長的Python列表,其中每個元素都是一個包含四個鍵的字典:國家名、國別嗎、年份以及表示人口數量的值。
我們嘗試打印每個國家2010年的人口數量:
import json filename="population_data.json" with open(filename) as f: pop_data=json.load(f) for pop_dict in pop_data: if pop_dict['Year']=='2010': country_name=pop_dict['Country Name'] population=pop_dict['Value'] print(country_name+': '+population)
接下來,我們要將數據轉化為Pygal能夠處理的格式。
2.將字符串轉化為數字值
Python不能直接將包含小數點的字符串轉化為整數,為消除這種錯誤我們可以先將字符串轉換為浮點數,再講浮點數轉換為小數:
population=int(float(pop_dict['Value'])) print(country_name+': '+str(population))
可以發現High income的小數被丟棄了。
3.獲取兩個字母的國別碼
Pygal中的地圖制作工具要求數據為特定的格式:用國別碼表示國家,以及用數字表示人口數量。
因為Pygal使用兩個字母的國別碼,所以我們需要想辦法根據國家名獲取兩個字母的國別碼。
字典COUNTRIES包含的鍵值分別為兩個字母的國別碼和國家名,我們可以從模塊i18n中導入這個字典,並打印其鍵和值:
from pygal_maps_world.i18n import COUNTRIES for country_code in sorted(COUNTRIES.keys()): print(country_code,COUNTRIES[country_code])
編寫一個獲取國別碼的函數放在名為country_codes的模塊中:
from pygal_maps_world.i18n import COUNTRIES def get_country_code(country_name): for code,name in COUNTRIES.items(): if name==country_name: return code return None
修改打印人口數量的代碼:
import json from country_codes import get_country_code filename="population_data.json" with open(filename) as f: pop_data=json.load(f) for pop_dict in pop_data: if pop_dict['Year']=='2010': country_name=pop_dict['Country Name'] population=int(float(pop_dict['Value'])) code=get_country_code(country_name) if code: print(code + ': '+str(population)) else: print('ERROR - ' + country_name)
導致顯示錯誤消息的原因有兩個。首先並非所有人口數量對應的都是國家,有些人口數量對應的是地區(阿拉伯世界)和經濟類群(所有收入水平),其次有些統計數據使用了不同的完整國家名。
4.制作世界地圖
import pygal.maps.world wm = pygal.maps.world.World() wm.title = 'North, Central, and South America' wm.add('North America', ['ca', 'mx', 'us']) wm.add('Central America', ['bz', 'cr', 'gt', 'hn', 'ni', 'pa', 'sv']) wm.add('South America', ['ar', 'bo', 'br', 'cl', 'co', 'ec', 'gf', 'gy', 'pe', 'py', 'sr', 'uy', 've']) wm.render_to_file('americas.svg')
方法add()接受一個標簽和一個列表,其中后者包含我們要突出的國家的國別碼。
每次調用用add()都將為指定的國家選擇一種新顏色,並在圖表左邊顯示該顏色和指定的標簽。
5.繪制完整的世界人口地圖
import json import pygal.maps.world from country_codes import get_country_code filename="population_data.json" with open(filename) as f: pop_data=json.load(f) cc_populations={} for pop_dict in pop_data: if pop_dict['Year']=='2010': country_name=pop_dict['Country Name'] population=int(float(pop_dict['Value'])) code=get_country_code(country_name) if code: cc_populations[code]=population wm=pygal.maps.world.World() wm.title="World Population in 2010,by Country" wm.add('2010',cc_populations) wm.render_to_file('World_population.svg')
有幾個國家沒有相關數據,我們將其顯示為白色,但對於大多數國家,都根據其人口數量進行了着色。
當前地圖中,很多國家都是淺色的,只有兩個國家是深色的。對大多數國家而言,顏色深淺差別不足以反映其人口數量的差別。
為修復這種問題,我們將根據人口數量將國家分組,再分別對每個組着色:
cc_pops_1,cc_pops_2,cc_pops_3={},{},{} for cc,pop in cc_populations.items(): if pop<10000000: cc_pops_1[cc]=pop elif pop<100000000: cc_pops_2[cc]=pop else: cc_pops_3[cc]=pop
6.使用Pygal設置世界地圖的樣式
我們從模塊中導入了樣式RotateStyle,創建這個實例時,需要提供一個參數--十六進制的RGB顏色。
十六進制格式的RGB顏色是一個以井號(#)打頭的字符串,后面跟着6個字符,其中前兩個表示紅色分量,接下來是綠色和藍色。
這里使用的顏色值(#336699)混合了少量的紅色(33)、多一些的綠色(66)和更多一些的藍色(99),它為RotateStyle提供了一種淡藍色基色。
加亮顏色主題
Pygal通常默認使用較暗的顏色主題,為方便印刷,我們使用LightColorizedStyle加亮了地圖顏色。
這個類修改整個圖表的主題,包括背景色、標簽以及各個國家的顏色:
from pygal.style import LightColorizedStyle wm_style=LightColorizedStyle
使用這個類時,不能直接控制使用的顏色,Pygal將選擇默認的基色,要設置顏色,可使用RotateStyle,並將LightColorizedStyle作為基本樣式。
完整代碼:
import json import pygal.maps.world from pygal.style import RotateStyle,LightColorizedStyle from country_codes import get_country_code filename="population_data.json" with open(filename) as f: pop_data=json.load(f) cc_populations={} for pop_dict in pop_data: if pop_dict['Year']=='2010': country_name=pop_dict['Country Name'] population=int(float(pop_dict['Value'])) code=get_country_code(country_name) if code: cc_populations[code]=population cc_pops_1,cc_pops_2,cc_pops_3={},{},{} for cc,pop in cc_populations.items(): if pop<10000000: cc_pops_1[cc]=pop elif pop<100000000: cc_pops_2[cc]=pop else: cc_pops_3[cc]=pop print(len(cc_pops_1),len(cc_pops_2),len(cc_pops_3)) wm_style=RotateStyle('#336699',base_style=LightColorizedStyle) wm=pygal.maps.world.World(style=wm_style) wm.title="World Population in 2010,by Country" wm.add('0-10m',cc_pops_1) wm.add('10m-1bn',cc_pops_2) wm.add('>1bn',cc_pops_3) wm.render_to_file('World_population.svg')