目录
第 16 章 下载数据
16.1 CSV文件格式
16.1.1 分析CSV文件头
16.1.2 打印文件头及其位置
16.1.3 提取并读取数据
16.1.4 绘制气温图表
16.1.5 模块datetime
16.1.8 再绘制一个数据系列
16.1.9 给图表区域着色
16.1.10 错误检查
16.2 制作世界人口地图: JSON格式
16.2.1 下载世界人口数据
16.2.2 提取相关的数据
16.2.4 获取两个字母的国别码
16.2.5 制作世界地图
16.2.8 根据人口数量将国家分组
16.2.9 使用Pygal设置世界地图的样式
16.2.10 加亮颜色主题
代码
第 16 章 下载数据
16.1 CSV文件格式
16.1.1 分析CSV文件头
highs_lows.py
import csv
filename = 'sitka_weather_07-2018_simple.csv'
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
print(header_row)
16.1.2 打印文件头及其位置
highs_lows.py
import csv
filename = 'sitka_weather_07-2018_simple.csv'
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
for index, column_header in enumerate(header_row):
print(index, column_header)
对列表调用enumerate()来获取每个元素的索引及其值
16.1.3 提取并读取数据
highs_lows.py
import csv
# 从文件中获取最高气温
filename = 'sitka_weather_2018_simple.csv'
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
highs = []
for row in reader:
high = int(row[5])
highs.append(high)
print(highs)
16.1.4 绘制气温图表
使用matplotlib创建一个显示每日最高气温的简单图形
highs_lows.py
import csv
from matplotlib import pyplot as plt
# 从文件中获取最高气温
filename = 'sitka_weather_2018_simple.csv'
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
highs = []
for row in reader:
high = int(row[5])
highs.append(high)
print(highs)
# 根据数据绘制图形
fig = plt.figure(dpi=128, figsize=(10, 6))
plt.plot(highs, c='red')
# 设置图形的格式
plt.title("Daily high temperatures, July 2018", fontsize=24)
plt.xlabel('', fontsize=24)
plt.ylabel("Temperature(F)", fontsize=16)
plt.tick_params(axis='both', which='major', labelsize=16)
plt.show()
16.1.5 模块datetime
使用模块datetime 中的方法strptime()
模块datetime中设置日期和时间格式的实参
实参 | 含义 |
%A | 星期的名称, 如Monday |
%B | 月份名, 如January |
%m | 用数字表示的月份(01~12) |
%d | 用数字表示月份中的一天(01~31) |
%Y | 四位的年份, 如2015 |
%y | 两位的年份, 如15 |
%H | 24小时制的小时数(00~23) |
%I | 12小时制的小时数(01~12) |
%p | am或pm |
%M | 分钟数(00~59) |
%S | 秒数(00~61) |
highs_lows.py
import csv
from datetime import datetime
from matplotlib import pyplot as plt
# 从文件中获取最高气温和日期
filename = 'sitka_weather_07-2018_simple.csv'
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
dates,highs = [] , []
for row in reader:
current_date = datetime.strptime(row[2], "%Y-%m-%d")
dates.append(current_date)
high = int(row[5])
highs.append(high)
# 根据数据绘制图形
fig = plt.figure(dpi=128, figsize=(10, 6))
plt.plot(dates, highs, c='red')
# 设置图形的格式
plt.title("Daily high temperatures, July 2018", fontsize=24)
plt.xlabel('', fontsize=16)
fig.autofmt_xdate()
plt.ylabel("Temperature(F)", fontsize=16)
plt.tick_params(axis='both', which='major', labelsize=16)
plt.show()
16.1.8 再绘制一个数据系列
再添加最低气温数据
highs_lows.py
import csv
from datetime import datetime
from matplotlib import pyplot as plt
# 从文件中获取最高气温、最低气温和日期
filename = 'sitka_weather_07-2018_simple.csv'
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
dates,highs,lows = [] , [] , []
for row in reader:
current_date = datetime.strptime(row[2], "%Y-%m-%d")
dates.append(current_date)
high = int(row[5])
highs.append(high)
low = int(row[6])
lows.append(low)
# 根据数据绘制图形
fig = plt.figure(dpi=128, figsize=(10, 6))
plt.plot(dates, highs, c='red')
plt.plot(dates, lows, c='blue')
# 设置图形的格式
plt.title("Daily high and low temperatures, July 2018", fontsize=24)
plt.xlabel('', fontsize=16)
fig.autofmt_xdate()
plt.ylabel("Temperature(F)", fontsize=16)
plt.tick_params(axis='both', which='major', labelsize=16)
plt.show()
16.1.9 给图表区域着色
使用方法fill_between(),接受一个 x 值系列和两个 y 值系列, 并填充两个 y 值系列之间的空间:
highs_lows.py
import csv
from datetime import datetime
from matplotlib import pyplot as plt
# 从文件中获取最高气温、最低气温和日期
filename = 'sitka_weather_07-2018_simple.csv'
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
dates,highs,lows = [] , [] , []
for row in reader:
current_date = datetime.strptime(row[2], "%Y-%m-%d")
dates.append(current_date)
high = int(row[5])
highs.append(high)
low = int(row[6])
lows.append(low)
# 根据数据绘制图形
fig = plt.figure(dpi=128, figsize=(10, 6))
plt.plot(dates, highs, c='red', alpha=0.5)
plt.plot(dates, lows, c='blue', alpha=0.5)
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
# 设置图形的格式
plt.title("Daily high and low temperatures, July 2018", fontsize=24)
plt.xlabel('', fontsize=16)
fig.autofmt_xdate()
plt.ylabel("Temperature(F)", fontsize=16)
plt.tick_params(axis='both', which='major', labelsize=16)
plt.show()
16.1.10 错误检查
highs_lows.py
for row in reader:
try:
current_date = datetime.strptime(row[2], "%Y-%m-%d")
high = int(row[5])
low = int(row[6])
except ValueError:
print(current_date, 'missing data')
else:
dates.append(current_date)
highs.append(high)
lows.append(low)
import csv
from datetime import datetime
from matplotlib import pyplot as plt
# 从文件中获取最高气温、最低气温和日期
filename = 'death_valley_2018_simple.csv'
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
dates,highs,lows = [] , [] , []
for row in reader:
try:
current_date = datetime.strptime(row[2], "%Y-%m-%d")
high = int(row[5])
low = int(row[6])
except ValueError:
print(current_date, 'missing data')
else:
dates.append(current_date)
highs.append(high)
lows.append(low)
# 根据数据绘制图形
fig = plt.figure(dpi=128, figsize=(10, 6))
plt.plot(dates, highs, c='red', alpha=0.5)
plt.plot(dates, lows, c='blue', alpha=0.5)
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
# 设置图形的格式
plt.title("Daily high and low temperatures, July 2018", fontsize=24)
plt.xlabel('', fontsize=16)
fig.autofmt_xdate()
plt.ylabel("Temperature(F)", fontsize=16)
plt.tick_params(axis='both', which='major', labelsize=16)
plt.show()
16.2 制作世界人口地图: JSON格式
16.2.1 下载世界人口数据
为了便于操作方便,更快的学习。
这边附上直接下载csv和json压缩包的链接地址:https://pkgstore.datahub.io/core/population/population_zip/data/4e22dd3646c87e44fcaf119d34439291/population_zip.zip
16.2.2 提取相关的数据
world_population.py
import json #导入json模块
#将数据添加到一个列表
filename='population_json.json'
with open(filename) as f:
pop_data=json.load(f)
#函数json.load()将数据转换为Python能够处理的格式,这里是一个列表
#打印每个国家2010年人口的数量
for pop_dict in pop_data:
if pop_dict['Year']==2010:
country_name = pop_dict["Country Name"]
population = int(float(pop_dict["Value"]))
print(country_name + ":" + str(population))
16.2.4 获取两个字母的国别码
country_codes.py
from pygal_maps_world.i18n import COUNTRIES
for country_code in sorted(COUNTRIES.keys()):
print(country_code, COUNTRIES[country_code])
编写一个函数,在COUNTRIES中查找并返回国别码。将函数放在country_codes的模块中。
country_codes.py
from pygal_maps_world.i18n import COUNTRIES
def get_country_code(country_name):
"""根据指定的国家,返回Pygal使用的两个字母的国别码"""
for code, name in COUNTRIES.items():
if name == country_name:
return code
# 未找到指定的国家输出None
return None
print(get_country_code('China'))
print(get_country_code('Andorra'))
print(get_country_code('Afghanistan'))
在world_population.py文件中导入国别码
world_population.py
import json #导入json模块
from country_codes import get_country_code
#将数据添加到一个列表
filename='population_json.json'
with open(filename) as f:
pop_data=json.load(f)
#函数json.load()将数据转换为Python能够处理的格式,这里是一个列表
#打印每个国家2010年人口的数量
for pop_dict in pop_data:
if pop_dict['Year']==2010:
country_name = pop_dict["Country Name"]
population = int(float(pop_dict["Value"]))
#print(country_name + ":" + str(population))
code=get_country_code(country_name)
if code:
print(code + ":" + str(population))
else:
print('ERROR-' + country_name)
16.2.5 制作世界地图
americas.py
import pygal_maps_world.maps
wm=pygal_maps_world.maps.World() #创建实例
wm.title='North,Center,and South America'
wm.add('North America',['ca','mx','us'])
wm.add('Center 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')
在世界地图上呈现数字数据
na_populations.py
import pygal_maps_world.maps
wm=pygal_maps_world.maps.World()
wm.title='Populations of Countries in North America'
wm.add('North America',{'ca':3412600,'us':309349000,'mx':113423000})
wm.render_to_file('na_populations.svg')
鼠标放在对应的国家会显示人口数据
绘制完整的世界人口地图
world_population.py
import json #导入json模块
from country_codes import get_country_code
import pygal_maps_world.maps
#将数据添加到一个列表
filename='population_json.json'
with open(filename) as f:
pop_data=json.load(f)
#函数json.load()将数据转换为Python能够处理的格式,这里是一个列表
#打印每个国家2010年人口的数量
#创建一个包含人口数量的字典
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"]))
#print(country_name + ":" + str(population))
code=get_country_code(country_name)
if code:
cc_populations[code]=population
wm=pygal_maps_world.maps.World()
wm.title='World Population in 2010,by Country'
wm.add('2010',cc_populations)
wm.render_to_file('World_Population.svg')
cc_populations={}
创建了空字典,用来存储Pypal要求的字典格式要求数据
wm=pygal_maps_world.maps.World()
创建实例,并设置属性
16.2.8 根据人口数量将国家分组
world_population.py
import json #导入json模块
from country_codes import get_country_code
import pygal_maps_world.maps
#将数据添加到一个列表
filename='population_json.json'
with open(filename) as f:
pop_data=json.load(f)
#函数json.load()将数据转换为Python能够处理的格式,这里是一个列表
#打印每个国家2010年人口的数量
#创建一个包含人口数量的字典
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"]))
#print(country_name + ":" + str(population))
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 < 1000000000:
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=pygal_maps_world.maps.World()
wm.title='World Population in 2010,by Country'
wm.add('0~10m', cc_pops_1)
wm.add('10m~1bm', cc_pops_2)
wm.add('>1bm', cc_pops_3)
wm.render_to_file('World_Population_8.svg')
结果显示在1000万以内的国家有81个,1000万~10亿以内的有71个国家,大于10亿的有两个国家
16.2.9 使用Pygal设置世界地图的样式
world_population.py
import json #导入json模块
from country_codes import get_country_code
import pygal_maps_world.maps
from pygal.style import RotateStyle
#将数据添加到一个列表
filename='population_json.json'
with open(filename) as f:
pop_data=json.load(f)
#函数json.load()将数据转换为Python能够处理的格式,这里是一个列表
#打印每个国家2010年人口的数量
#创建一个包含人口数量的字典
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"]))
#print(country_name + ":" + str(population))
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 < 1000000000:
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=pygal_maps_world.maps.World()
wm_style = RotateStyle('#336699')
wm = pygal_maps_world.maps.World(style = wm_style)
wm.title='World Population in 2010,by Country'
wm.add('0~10m', cc_pops_1)
wm.add('10m~1bm', cc_pops_2)
wm.add('>1bm', cc_pops_3)
wm.render_to_file('World_Population_9.svg')
Pygal样式存储在模块style 中, 我们从这个模块中导入了样式RotateStyle (见❶) 。 创建这个类的实例时, 需要提供一个实参——十六进制的RGB颜色(见❷) ; Pygal将根据指定的颜色为每组选择颜色。 十六进制格式 的RGB颜色是一个以井号(#) 打头的字符串, 后面跟着6个字符, 其中前两个字符表示红色分量, 接下来的两个表示绿色分量, 最后两个表示蓝色分量。 每个分量的取值范围为00 (没有相应的颜色) ~FF (包含最多的相应颜色) 。 如果你在线搜索hex color chooser(十六进制颜色选择器 ) , 可找到让你能够尝试选择不同的颜色并显示其RGB值的工具。 这里使用的颜色值(#336699) 混合了少量的红色(33) 、 多一些的绿色(66) 和更多一些的蓝色(99) , 它为RotateStyle 提供了一种淡蓝色基色。
16.2.10 加亮颜色主题
使用LightColorizedStyle
from pygal.style import LightColorizedStyle
wm_style=LightColorizedStyle
使用LightColorizedStyle类时,不能直接控制使用颜色,Pygal所以使用了默认的基色,要设置颜色,则使用RotateStyle,并将LightColorizedStyle作为基本样式
from pygal.style import LightColorizedStyle as LCS,RotateStyle as RS
# wm_style=RotateStyle('#336699',base_style=LightColorizedStyle)
wm_style=RS('#336699',base_style=LCS)
代码
highs_lows.py
import csv
from datetime import datetime
from matplotlib import pyplot as plt
# 从文件中获取最高气温、最低气温和日期
filename = 'sitka_weather_07-2018_simple.csv'
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
dates,highs,lows = [] , [] , []
for row in reader:
current_date = datetime.strptime(row[2], "%Y-%m-%d")
dates.append(current_date)
high = int(row[5])
highs.append(high)
low = int(row[6])
lows.append(low)
# 根据数据绘制图形
fig = plt.figure(dpi=128, figsize=(10, 6))
plt.plot(dates, highs, c='red', alpha=0.5)
plt.plot(dates, lows, c='blue', alpha=0.5)
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
# 设置图形的格式
plt.title("Daily high and low temperatures, July 2018", fontsize=24)
plt.xlabel('', fontsize=16)
fig.autofmt_xdate()
plt.ylabel("Temperature(F)", fontsize=16)
plt.tick_params(axis='both', which='major', labelsize=16)
plt.show()
highs_lows_death.py
import csv
from datetime import datetime
from matplotlib import pyplot as plt
# 从文件中获取最高气温、最低气温和日期
filename = 'death_valley_2018_simple.csv'
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
dates,highs,lows = [] , [] , []
for row in reader:
try:
current_date = datetime.strptime(row[2], "%Y-%m-%d")
high = int(row[5])
low = int(row[6])
except ValueError:
print(current_date, 'missing data')
else:
dates.append(current_date)
highs.append(high)
lows.append(low)
# 根据数据绘制图形
fig = plt.figure(dpi=128, figsize=(10, 6))
plt.plot(dates, highs, c='red', alpha=0.5)
plt.plot(dates, lows, c='blue', alpha=0.5)
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
# 设置图形的格式
plt.title("Daily high and low temperatures, July 2018", fontsize=24)
plt.xlabel('', fontsize=16)
fig.autofmt_xdate()
plt.ylabel("Temperature(F)", fontsize=16)
plt.tick_params(axis='both', which='major', labelsize=16)
plt.show()
world_population.py
import json #导入json模块
from country_codes import get_country_code
import pygal_maps_world.maps
from pygal.style import RotateStyle
from pygal.style import LightColorizedStyle
#将数据添加到一个列表
filename='population_json.json'
with open(filename) as f:
pop_data=json.load(f)
#函数json.load()将数据转换为Python能够处理的格式,这里是一个列表
#打印每个国家2010年人口的数量
#创建一个包含人口数量的字典
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"]))
#print(country_name + ":" + str(population))
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 < 1000000000:
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=pygal_maps_world.maps.World()
##wm_style = RotateStyle('#336699') #颜色不够亮丽
###wm_style = LightColorizedStyle #不能直接控制使用的颜色
wm_style = RotateStyle('#336699', base_style = LightColorizedStyle)
wm = pygal_maps_world.maps.World(style = wm_style)
wm.title='World Population in 2010,by Country'
wm.add('0~10m', cc_pops_1)
wm.add('10m~1bm', cc_pops_2)
wm.add('>1bm', cc_pops_3)
wm.render_to_file('World_Population_10.svg')
country_codes.py
from pygal_maps_world.i18n import COUNTRIES
def get_country_code(country_name):
"""根据指定的国家,返回Pygal使用的两个字母的国别码"""
for code, name in COUNTRIES.items():
if name == country_name:
return code
# 未找到指定的国家输出None
return None
print(get_country_code('China'))
print(get_country_code('Andorra'))
print(get_country_code('Afghanistan'))
americas.py
import pygal_maps_world.maps
wm=pygal_maps_world.maps.World() #创建实例
wm.title='North,Center,and South America'
wm.add('North America',['ca','mx','us'])
wm.add('Center 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')
na_populations.py
import pygal_maps_world.maps
wm=pygal_maps_world.maps.World()
wm.title='Populations of Countries in North America'
wm.add('North America',{'ca':3412600,'us':309349000,'mx':113423000})
wm.render_to_file('na_populations.svg')