Python基础(四)

文章目录

  • Chapter15 数据可视化_生成数据
    • 15.1 安装matplotlib
      • 15.1.1 在 Linux 系统中安装 matplotlib
      • 15.1.3 在 Windows 系统中安装 matplotlib
      • 15.1.4 测试 matplotlib
      • 15.1.5 matplotlib 画廊
    • 15.2 绘制简单的折线图
      • 15.2.1 修改标签文字和线条粗细
      • 15.2.2 校正图形
      • 15.2.3 使用scatter()绘制散点图并设置其样式
      • 15.2.4 使用scatter()绘制一系列点
      • 15.2.5 自动计算数据
      • 15.2.6 删除数据点的轮廓 edgecolor='none'
      • 15.2.7 自定义颜色:参数c
      • 15.2.8 使用颜色映射:colormap
      • 15.2.9 自动保存图表
    • 15.3 随机游走
      • 15.3.1 创建RandomWalk()类
      • 15.3.2 选择方向
      • 15.3.3 绘制随机漫步图
      • 15.3.4 模拟多次随机漫步
      • 15.3.5 设置随机漫步图的样式
      • 15.3.6 给点着色
      • 15.3.7 重新绘制起点和终点
      • 15.3.8 隐藏坐标轴
      • 15.3.9 增加点数
      • 15.3.10 调整尺寸以适合屏幕
  • Chapter16 数据可视化_下载数据
    • 16.1 CSV 文件格式
      • 16.1.1 分析 CSV 文件头
      • 16.1.2 打印文件头及其位置
      • 16.1.3 提取并读取数据
      • 16.1.4 绘制气温图表
      • 16.1.5 模块 datetime
      • 16.1.6 在图表中添加日期
      • 16.1.7 涵盖更长的时间
      • 16.1.8 再绘制一个数据系列(绘制两条曲线)
      • 16.1.9 给图表区域着色
      • 16.1.10 错误检查
    • 16.2 制作世界人口地图:JSON格式
      • 16.2.1 下载世界人口数据
      • 16.2.3 将字符串转换为数字值
      • 16.2.4 获取两个字母的国别码
      • 16.2.5 制作世界地图
      • 16.2.6 在世界地图上呈现数字数据
      • 16.2.7 绘制完整的世界人口地图
      • 16.2.8 根据人口数量将国家分组
      • 16.2.9 使用 Pygal 设置世界地图的样式
      • 16.2.10 加亮颜色主题
  • Chapter17 数据可视化_使用API
    • 17.1 使用 Web API
      • 17.1.1 Git 和 GitHub
      • 17.1.2 使用 API 调用请求数据
      • 17.1.3 安装 requests
      • 17.1.4 处理 API 响应
      • 17.1.5 处理响应字典
      • 17.1.6 概述最受欢迎的仓库
      • 17.1.7 监视 API 的速率限制
    • 17.2 使用 Pygal 可视化仓库
      • 17.2.1 改进 Pygal 图表
      • 17.2.2 添加自定义工具提示
      • 17.2.3 根据数据绘图
      • 17.2.4 在图表中添加可单击的链接:xlink
    • 17.3 Hacker News API

Chapter15 数据可视化_生成数据

数据可视化指的是通过可视化表示来探索数据,它与数据挖掘紧密相关,而数据挖掘指的是使用代码来探索数据集的规律和关联。数据集可以是用一行代码就能表示的小型数字列表,也可以是数以G字节的数据。

学习内容:

  • matplotlib,将使用它来制作简单的图表,如折线图和散点图
  • 还将使用Pygal包,它专注于生成适合在数字设备上显示的图表

15.1 安装matplotlib

15.1.1 在 Linux 系统中安装 matplotlib

系统自带的Python版本:
$ sudo apt-get install python3-matplotlib

Python 2.7:
$ sudo apt-get install python-matplotlib

如果安装了较新的Python版本,就必须安装matplotlib依赖的一些库:
$ sudo apt-get install python3.5-dev python3.5-tk tk-dev
$ sudo apt-get install libfreetype6-dev g++
$ pip install --user matplotlib

15.1.3 在 Windows 系统中安装 matplotlib

首先需要安装Visual Studio

接下来,需要下载matplotlib安装程序。为此,请访问https://pypi.python.org/pypi/matplotlib/,
并查找与你使用的Python版本匹配的wheel文件(扩展名为.whl的文件)

将这个.whl文件复制到你的项目文件夹,打开一个命令窗口,并切换到该项目文件夹

再使用pip来安装matplotlib:
> cd python_work
python_work> python -m pip install --user matplotlib-1.4.3-cp35-none-win32.whl

15.1.4 测试 matplotlib

import matplotlib

15.1.5 matplotlib 画廊

要查看使用matplotlib可制作的各种图表,请访问http://matplotlib.org/的示例画廊。单击画廊中的图表,就可查看用于生成图表的代码。

15.2 绘制简单的折线图

import matplotlib.pyplot as plt
'''导入了模块pyplot,定了别名plt'''

squares = [1, 4, 9, 16, 25]
plt.plot(squares)
plt.show() # 打开matplotlib查看器,并显示绘制的图形

Python基础(四)_第1张图片

15.2.1 修改标签文字和线条粗细

import matplotlib.pyplot as plt

squares = [1, 4, 9, 16, 25]
plt.plot(squares, linewidth=5) # linewidth:线条粗细参数

plt.title("Square Numbers", fontsize=24) # 标题及字体
plt.xlabel("Value", fontsize=14) # x轴标题及字体
plt.ylabel("Square of Value", fontsize=14) # y轴标题及字体
plt.tick_params(axis='both', labelsize=14) # 刻度大小

plt.show()

Python基础(四)_第2张图片

15.2.2 校正图形

'''横坐标的平方对应纵坐标的值'''

import matplotlib.pyplot as plt

input_values = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]

plt.plot(input_values, squares, linewidth=5) # 横坐标的平方对应纵坐标的值

plt.title("Square Numbers", fontsize=24)
plt.xlabel("Value", fontsize=14)
plt.ylabel("Square of Value", fontsize=14)
plt.tick_params(axis='both', labelsize=14)

plt.show()

15.2.3 使用scatter()绘制散点图并设置其样式

可能想以一种颜色显示较小的值,而用另一种颜色显示较大的值。绘制大型数据集时,你还可以对每个点都设置同样的样式,再使用不同的样式选项重新绘制某些点,以突出它们。

import matplotlib.pyplot as plt

plt.scatter(2, 4) # 单点:传递x,y坐标
plt.show()


import matplotlib.pyplot as plt

plt.scatter(2, 4, s=200) # 参数s决定绘制点的尺寸
plt.title("Square Numbers", fontsize=24)
plt.xlabel("Value", fontsize=14)
plt.ylabel("Square of Value", fontsize=14)

plt.tick_params(axis='both', which='major', labelsize=14)

plt.show()

Python基础(四)_第3张图片

15.2.4 使用scatter()绘制一系列点

import matplotlib.pyplot as plt

x_values = [1, 2, 3, 4, 5]
y_values = [1, 4, 9, 16, 25]
plt.scatter(x_values, y_values, s=100) # 一系列点传入

plt.title("Square Numbers", fontsize=24)
plt.xlabel("Value", fontsize=14)
plt.ylabel("Square of Value", fontsize=14)

plt.tick_params(axis='both', which='major', labelsize=14)

plt.show()

Python基础(四)_第4张图片

15.2.5 自动计算数据

import matplotlib.pyplot as plt

x_values = list(range(1, 1001))
y_values = [x**2 for x in x_values] # x的平方值:解析列表

plt.scatter(x_values, y_values, s=40)
plt.axis([0, 1100, 0, 1100000]) # axis指定x,y的取值范围

plt.show()

15.2.6 删除数据点的轮廓 edgecolor=‘none’

plt.scatter(x_values, y_values, edgecolor='none', s=40)
plt.show()

15.2.7 自定义颜色:参数c

plt.scatter(x_values, y_values, c='red', edgecolor='none', s=40)
plt.show()

plt.scatter(x_values, y_values, c=(0, 0, 0.8), edgecolor='none', s=40)
plt.show() # 表示红色,绿色,蓝色的分量。输出是深蓝色,越接近1颜色越浅

15.2.8 使用颜色映射:colormap

颜色映射(colormap)是一系列颜色,它们从起始颜色渐变到结束颜色。在可视化中,颜色映射用于突出数据的规律,例如,你可能用较浅的颜色来显示较小的值,并使用较深的颜色来显示较大的值。

import matplotlib.pyplot as plt

x_values = list(range(1001))
y_values = [x**2 for x in x_values]

plt.scatter(x_values, y_values, c=y_values, cmap=plt.cm.Blues,
    edgecolor='none', s=40) # cmap表示哪种渐变色,y值小的颜色浅大的颜色深

plt.title("Square Numbers", fontsize=24)
plt.xlabel("Value", fontsize=14)
plt.ylabel("Square of Value", fontsize=14)

plt.tick_params(axis='both', which='major', labelsize=14)

plt.show()

Python基础(四)_第5张图片

15.2.9 自动保存图表

要让程序自动将图表保存到文件中,可将对plt.show()的调用替换为对plt.savefig()的调用

plt.savefig('squares_plot.png', bbox_inches='tight')
# 第一个参数表示文件名和路径,第二个参数表示将空白区域减掉,默认是留存

15.3 随机游走

将使用Python来生成随机漫步数据,再使用matplotlib以引人瞩目的方式将这些数据呈现出来。随机漫步是这样行走得到的路径:

  • 每次行走都完全是随机的,没有明确的方向,结果是由一系列随机决策决定的。
  • 可以这样认为,随机漫步就是蚂蚁在晕头转向的情况下,每次都沿随机的方向前行所经过的路径。

15.3.1 创建RandomWalk()类

为模拟随机游走,创建一个名为RandomWalk的类,它随机地选择前进方向。

这个类需要三个属性:
其中一个是存储随机游走次数的变量,其他两个是列表,分别存储随机游走经过的每个点的x和y坐标。

RandomWalk类只包含两个方法:
__init__ ()fill_walk(),其中后者计算随机漫步经过的所有点。

from random import choice

class RandomWalk():
    """一个生成随机漫步数据的类"""

    def __init__(self, num_points=5000): # 默认点数为500
        """初始化随机漫步的属性"""
        self.num_points = num_points

        # 所有随机漫步都始于(0, 0)
        self.x_values = [0]
        self.y_values = [0]

15.3.2 选择方向

# 将其加入到上面的类中
def fill_walk(self):
    """计算随机漫步包含的所有点"""

    # 不断漫步,直到列表达到指定的长度
    while len(self.x_values) < self.num_points:

        # 决定前进方向以及沿这个方向前进的距离
        x_direction = choice([1, -1]) # x的选择,又走1或左走1
        x_distance = choice([0, 1, 2, 3, 4]) # 沿着方向走的距离0~4
        x_step = x_direction * x_distance # 沿着x轴走的距离

        y_direction = choice([1, -1])
        y_distance = choice([0, 1, 2, 3, 4])
        y_step = y_direction * y_distance

        # 拒绝原地踏步
        if x_step == 0 and y_step == 0:
            continue # 接着执行下一个循环

        # 计算下一个点的x和y值,x_values最后一个值和x_step相加
        next_x = self.x_values[-1] + x_step
        next_y = self.y_values[-1] + y_step

        self.x_values.append(next_x) # 下一个点追加到x值的末尾
        self.y_values.append(next_y)

15.3.3 绘制随机漫步图

import matplotlib.pyplot as plt
from random_walk import RandomWalk # 模块random_walk,类RandomWalk

rw = RandomWalk() # 创建一个RandomWalk实例
rw.fill_walk() # 随机游走的5000个点
plt.scatter(rw.x_values, rw.y_values, s=10)
plt.show()

Python基础(四)_第6张图片

15.3.4 模拟多次随机漫步

每次随机漫步都不同,因此探索可能生成的各种模式很有趣。要在不多次运行程序的情况下使用前面的代码模拟多次随机漫步,一种办法是将这些代码放在一个 while 循环中

import matplotlib.pyplot as plt
from random_walk import RandomWalk

# 只要程序处于活动状态,就不断地模拟随机漫步
while True:
    # 创建一个RandomWalk实例,并将其包含的点都绘制出来
    rw = RandomWalk()
    rw.fill_walk()
    plt.scatter(rw.x_values, rw.y_values, s=15)
    plt.show()

    keep_running = input("Make another walk? (y/n): ")
    if keep_running == 'n':
        break

15.3.5 设置随机漫步图的样式

15.3.6 给点着色

import matplotlib.pyplot as plt
from random_walk import RandomWalk

rw = RandomWalk()
rw.fill_walk()

# 参数c,并将其设置为一个列表,其中包含各点的先后顺序。
point_numbers = list(range(rw.num_points))
plt.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues,
            edgecolor='none', s=15)
plt.show()

15.3.7 重新绘制起点和终点

import matplotlib.pyplot as plt
from random_walk import RandomWalk

rw = RandomWalk()
rw.fill_walk()

point_numbers = list(range(rw.num_points))
plt.scatter(rw.x_values, rw.y_values, c=point_numbers,
            cmap=plt.cm.Blues,edgecolor='none', s=15)
plt.scatter(0, 0, c='green', edgecolors='none', s=100)
plt.scatter(rw.x_values[-1], rw.y_values[-1], c='red',
            edgecolors='none',s=100)

plt.show()

15.3.8 隐藏坐标轴

下面来隐藏这个图表中的坐标轴,以免我们注意的是坐标轴而不是随机漫步路径。要隐藏坐标轴

import matplotlib.pyplot as plt
from random_walk import RandomWalk

rw = RandomWalk()
rw.fill_walk()

point_numbers = list(range(rw.num_points))
plt.scatter(rw.x_values, rw.y_values, c=point_numbers,
            cmap=plt.cm.Blues,edgecolor='none', s=15)
plt.scatter(0, 0, c='green', edgecolors='none', s=100)
plt.scatter(rw.x_values[-1], rw.y_values[-1], c='red',
            edgecolors='none',s=100)

# 隐藏坐标轴
plt.axes().get_xaxis().set_visible(False) # 串联的方式
plt.axes().get_yaxis().set_visible(False)

plt.show()

15.3.9 增加点数

rw = RandomWalk(50000) # 即可

15.3.10 调整尺寸以适合屏幕

函数figure()用于指定图表的宽度、高度、分辨率和背景色。你需要给形参figsize指定一个元组,向matplotlib指出绘图窗口的尺寸,单位为英寸

plt.figure(figsize=(10, 6)) # 加入该命令
plt.figure(dpi=128, figsize=(10, 6))

Chapter16 数据可视化_下载数据

  • 将访问并可视化以两种常见格式存储的数据: CSV 和JSON。
  • 将使用Python模块csv来处理以CSV(逗号分隔的值)格式存储数据
  • 将使用matplotlib根据下载的数据创建一个图表
  • 使用模块json来访问以JSON格式存储的人口数据,并使用Pygal绘制一幅按国别划分的人口地图

16.1 CSV 文件格式

要在文本文件中存储数据,最简单的方式是将数据作为一系列以逗号分隔的值(CSV)写入文件。这样的文件称为CSV文件。

16.1.1 分析 CSV 文件头

csv 模块包含在Python标准库中,可用于分析CSV文件中的数据行,让我们能够快速提取感兴趣的值。
Python基础(四)_第7张图片

import csv

filename = '/home/deyouli/PythonCrashCourse/pcc-master/chapter_16/sitka_weather_07-2014.csv'
with open(filename) as f:
    reader = csv.reader(f)
    header_row = next(reader) # next只调用一次,返回的是第一行
    print(header_row)

[‘AKDT’, ‘Max TemperatureF’, ‘Mean TemperatureF’, ‘Min TemperatureF’, ‘Max Dew PointF’, ‘MeanDew PointF’, ‘Min DewpointF’, ‘Max Humidity’, ’ Mean Humidity’, ’ Min Humidity’, ’ Max Sea Level PressureIn’, ’ Mean Sea Level PressureIn’, ’ Min Sea Level PressureIn’, ’ Max VisibilityMiles’, ’ Mean VisibilityMiles’, ’ Min VisibilityMiles’, ’ Max Wind SpeedMPH’, ’ Mean Wind SpeedMPH’, ’ Max Gust SpeedMPH’, ‘PrecipitationIn’, ’ CloudCover’, ’ Events’, ’ WindDirDegrees’]

16.1.2 打印文件头及其位置

import csv

filename = '/home/deyouli/PythonCrashCourse/pcc-master/chapter_16/sitka_weather_07-2014.csv'
with open(filename) as f:
    reader = csv.reader(f)
    header_row = next(reader) # 文件第一行是一个列表

    for index, column_header in enumerate(header_row): # for循环索引列表
        print(index, column_header) # enumerate():获取每个元素的索引及其值

0 AKDT
1 Max TemperatureF
2 Mean TemperatureF
3 Min TemperatureF

16.1.3 提取并读取数据

# 取第二列的数据
import csv

filename = '/home/deyouli/PythonCrashCourse/pcc-master/chapter_16/sitka_weather_07-2014.csv'
with open(filename) as f:
    reader = csv.reader(f)
    header_row = next(reader) # 读完之后reader已无第一行

    highs = [] # 空列表
    for row in reader: # 遍历行,实际上从第二行开始
        high = int(row[1]) # 第二列数据由字符串类型转为整型
        highs.append(high) # 索引1加入最高气温里
    print(highs)

[64, 71, 64, 59, 69, 62, 61, 55, 57, 61, 57, 59, 57, 61, 64, 61, 59, 63, 60, 57, 69, 63, 62, 59, 57, 57, 61, 59, 61, 61, 66]

16.1.4 绘制气温图表

import csv
from matplotlib import pyplot as plt # 画廊模块

filename = '/home/deyouli/PythonCrashCourse/pcc-master/chapter_16/sitka_weather_07-2014.csv'
with open(filename) as f:
    reader = csv.reader(f)
    header_row = next(reader)

    highs = []
    for row in reader:
        high = int(row[1])
        highs.append(high)
    print(highs)

# 根据数据绘制图形
fig = plt.figure(dpi=128, figsize=(10, 6)) # figure像素和长宽
plt.plot(highs, c='red')

# 设置图形的格式
plt.title("Daily high temperatures, July 2014", fontsize=24)
plt.xlabel('', fontsize=16)
plt.ylabel("Temperature (F)", fontsize=16)
plt.tick_params(axis='both', which='major', labelsize=16)

plt.show()

Python基础(四)_第8张图片

16.1.5 模块 datetime

读取该数据时,获得的是一个字符串,因为我们需要想办法将字符串’2014-7-1’转换为一个表示相应日期的对象。为创建一个表示2014年7月1日的对象,可使用模块datetime中的方法strptime()

方法 strptime():

  • 将包含所需日期的字符串作为第一个实参。
  • 第二个实参告诉Python如何设置日期的格式。
from datetime import datetime # 导入模块datetime模块的datetime类

first_date = datetime.strptime('2014-7-1', '%Y-%m-%d') # 转换日期格式
print(first_date) # 2014-07-01 00:00:00

模块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)

16.1.6 在图表中添加日期

import csv
from datetime import datetime
from matplotlib import pyplot as plt

filename = '/home/deyouli/PythonCrashCourse/pcc-master/chapter_16/sitka_weather_07-2014.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[0], "%Y-%m-%d") # 日期在row的第一列
        dates.append(current_date) # 储存在dates列表中
        high = int(row[1]) # 最高气温在第二列
        highs.append(high) # 储存在highs列表中

# 根据数据绘制图形
fig = plt.figure(dpi=128, figsize=(10, 6))
plt.plot(dates, highs, c='red') # 绘制图形

# 设置图形的格式
plt.title("Daily high temperatures, July 2014", 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()

Python基础(四)_第9张图片

16.1.7 涵盖更长的时间

Python基础(四)_第10张图片

16.1.8 再绘制一个数据系列(绘制两条曲线)

添加上最低气温

import csv
from datetime import datetime
from matplotlib import pyplot as plt

filename = '/home/deyouli/PythonCrashCourse/pcc-master/chapter_16/sitka_weather_2014.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[0], "%Y-%m-%d") 
        dates.append(current_date) # 日期列表储存在dates列表中

        high = int(row[1])
        highs.append(high) # 最高气温列表储存在dates列表中

        low = int(row[3])
        lows.append(low) # 最低气温列表储存在dates列表中

# 根据数据绘制图形
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 - 2014", 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()

Python基础(四)_第11张图片

16.1.9 给图表区域着色

使用方法fill_between(),它接受一个x值系列和两个y值系列,并填充两个y值系列之间的空间。

  • 实参alpha指定颜色的透明度:
    alpha值为0表示完全透明,1(默认设置)表示完全不透明。

  • fill_between():
    传递两个关于x轴的序列值,实参facecolor指定了填充区域的颜色

--snip--
# 根据数据绘制图形
fig = plt.figure(dpi=128, figsize=(10, 6))
plt.plot(dates, highs, c='red', alpha=0.5) # alpha=0,无色。点的透明度
plt.plot(dates, lows, c='blue', alpha=0.5)
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)

# 设置图形的格式
--snip--

Python基础(四)_第12张图片

16.1.10 错误检查

某个数据缺失或为空字符串

import csv
from datetime import datetime
from matplotlib import pyplot as plt

filename = '/home/deyouli/PythonCrashCourse/pcc-master/chapter_16/death_valley_2014.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[0], "%Y-%m-%d")
            high = int(row[1])
            low = int(row[3])
        except ValueError:
            print(current_date, 'missing data') # 输出缺失数据的日期
        else: # 没有发生错误则运行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)

# 设置图形的格式
title = "Daily high and low temperatures - 2014\nDeath Valley, CA"
plt.title(title, fontsize=20)
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格式

  • 将下载JSON格式的人口数据,并使用json模块来处理它们。
  • Pygal提供了一个适合初学者使用的地图创建工具,你将使用它来对人口数据进行可视化,以探索全球人口的分布情况。

16.2.1 下载世界人口数据

列表,元素是字典,每个字典包含四个键值对

[
  {
    "Country Name": "Arab World",
    "Country Code": "ARB",
    "Year": "1960",
    "Value": "96388069"
  },
--snip--
]
import json

# 将数据加载到一个列表中
filename = '/home/deyouli/PythonCrashCourse/pcc-master/chapter_16/population_data.json'
with open(filename) as f:
    pop_data = json.load(f) # 将数据储存在此

# 打印每个国家2010年的人口数量
for pop_dict in pop_data: # 遍历每个元素,元素都是字典
    if pop_dict['Year'] == '2010': # 是不是2010年的人数
        country_name = pop_dict['Country Name']
        population = pop_dict['Value']
        print(country_name + ": " + population)

Arab World: 357868000
Caribbean small states: 6880000
East Asia & Pacific (all income levels): 2201536674
East Asia & Pacific (developing only): 1961558757
Euro area: 331766000

16.2.3 将字符串转换为数字值

Python不能直接将包含小数点的字符串’1127437398.85751’转换为整数(这个小数值可能是人口数据缺失时通过插值得到的)。

为消除这种错误,我们先将字符串转换为浮点数,再将浮点数转换为整数

import json

filename = '/home/deyouli/PythonCrashCourse/pcc-master/chapter_16/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']))
        print(country_name + ": " + str(population))

Arab World: 357868000
Caribbean small states: 6880000
East Asia & Pacific (all income levels): 2201536674
East Asia & Pacific (developing only): 1961558757
Euro area: 331766000

16.2.4 获取两个字母的国别码

  • Pygal中的地图制作工具要求数据为特定的格式:用国别码表示国家,以及用数字表示人口数量。
  • population_data.json中包含的是三个字母的国别码,但Pygal使用两个字母的国别码。
  • 我们需要想办法根据国家名获取两个字母的国别码。
  • Pygal使用的国别码存储在模块pygal_maps_world.i18n(internationalization的缩写)中。
  • 字典COUNTRIES包含的键和值分别为两个字母的国别码和国家名。
from pygal_maps_world.i18n import COUNTRIES

for country_code in sorted(COUNTRIES.keys()): # 按国别码排序
    print(country_code, COUNTRIES[country_code]) # cn China


# 在COUNTRIES中查找并返回国别码
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('Andorra')) # ad
print(get_country_code('United Arab Emirates')) # ae
print(get_country_code('China')) # cn

# 在world_population.py中导入上面函数

import json
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

    # 打印每个国家2010年的人口数量
filename = '/home/deyouli/PythonCrashCourse/pcc-master/chapter_16/population_data.json'
with open(filename) as f:
    pop_data = json.load(f) # pop_data文件名

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) # code储存国别码
        if code: # 如果文件里国家名称对应有国别码输出国别码和人口数量
            print(code + ": " + str(population)) # cn: 1338300000
        else: # 否则输出错误,看看是那个国家
            print('ERROR - ' + country_name) # ERROR - Comoros

16.2.5 制作世界地图

pygal_maps_world提供了图表类型Worldmap,可帮助你制作呈现各国数据的世界地图。

from pygal_maps_world import maps

wm = maps.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') # 浏览器打开

Python基础(四)_第13张图片

16.2.6 在世界地图上呈现数字数据

from pygal_maps_world import maps

    # 先看看北美三个国家的人口数量
wm = maps.World() # 创建地图实例
wm.title = 'Populations of Countries in North America'
wm.add('North America', {'ca': 34126000, 'us': 309349000, 'mx': 113423000})
    # 第二个参数传递的是字典
wm.render_to_file('na_populations.svg')

Python基础(四)_第14张图片

16.2.7 绘制完整的世界人口地图

import json
from pygal_maps_world import maps # 画图使用
from pygal_maps_world.i18n import COUNTRIES # 国别码使用

# 定义get_country_code函数输入国家名称返回国别码
def get_country_code(country_name): 
    for code, name in COUNTRIES.items():
        if name == country_name:
            return code
    return None

# 读取文件
filename = '/home/deyouli/PythonCrashCourse/pcc-master/chapter_16/population_data.json'
with open(filename) as f:
    pop_data = json.load(f)

# 根据文件里国家名称利用get_country_code函数得到国别码,二者放在一个字典里
cc_populations = {}
for pop_dict in pop_data:
    if pop_dict['Year'] == '2010':
        country = pop_dict['Country Name']
        population = int(float(pop_dict['Value']))
        code = get_country_code(country) # 利用前面的函数得到国别码

        if code:
            cc_populations[code] = population # 键值对:国别码:人口数量

wm = maps.World() # 创建地图实例
wm.title = 'World Population in 2010, by Country'
wm.add('2010', cc_populations) # 循环后的世界各国国别码和人口数量

wm.render_to_file('world_population.svg')

Python基础(四)_第15张图片

16.2.8 根据人口数量将国家分组

但只有大约3亿。下面不将所有国家都作为一个编组,而是根据人口数量分成三组——少于1000万的、介于1000万和10亿之间的以及超过10亿的

--snip--
    # 根据人口数量将所有的国家分成三组
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 = maps.World()
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')

16.2.9 使用 Pygal 设置世界地图的样式

from pygal.style import RotateStyle # 样式
--snip--
wm_style = RotateStyle('#336699') # 十六进制的RGB颜色
wm = maps.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')

十六进制格式的RGB颜色是一个以井号(#)打头的字符串,后面跟着6个字符,其中前两个字符表示红色分量,接下来的两个表示绿色分量,最后两个表示蓝色分量。每个分量的取值范围为00(没有相应的颜色)~FF(包含最多的相应颜色)。

RotateStyle返回一个样式对象,我们将其存储在wm_style中。
为使用这个样式对象,我们在创建Worldmap实例时以关键字实参的方式传递它。

16.2.10 加亮颜色主题

使用 LightColorizedStyle 加亮了地图的颜色。
这个类修改整个图表的主题,包括背景色、标签以及各个国家的颜色。

from pygal.style import LightColorizedStyle
wm_style = RotateStyle('#336699', base_style=LightColorizedStyle)

Chapter17 数据可视化_使用API

  • 学习如何编写一个独立的程序,并对其获取的数据进行可视化。
  • 这个程序将使用Web应用编程接口(API)自动请求网站的特定信息而不是整个网页,再对这些信息进行可视化。
  • 由于这样编写的程序始终使用最新的数据来生成可视化,因此即便数据瞬息万变,它呈现的信息也都是最新的。

17.1 使用 Web API

Web API是网站的一部分,用于与使用非常具体的URL请求特定信息的程序交互。这种请求称为API调用。请求的数据将以易于处理的格式(如JSON或CSV)返回。依赖于外部数据源的大多数应用程序都依赖于API调用,如集成社交媒体网站的应用程序。

17.1.1 Git 和 GitHub

本章的可视化将基于来自GitHub的信息,这是一个让程序员能够协作开发项目的网站。我们将使用GitHub的API来请求有关该网站中Python项目的信息,然后使用Pygal生成交互式可视化,以呈现这些项目的受欢迎程度。

GitHub(https://github.com/)的名字源自Git,Git是一个分布式版本控制系统,让程序员团队能够协作开发项目。Git帮助大家管理为项目所做的工作,避免一个人所做的修改影响其他人所做的修改。你在项目中实现新功能时,Git将跟踪你对每个文件所做的修改。确定代码可行后,你提交所做的修改,而Git将记录项目最新的状态。如果你犯了错,想撤销所做的修改,可轻松地返回以前的任何可行状态(要更深入地了解如何使用Git进行版本控制,请参阅附录D)。GitHub上的项目都存储在仓库中,后者包含与项目相关联的一切:代码、项目参与者的信息、问题或bug报告等。

对于喜欢的项目,GitHub用户可给它加星(star)以表示支持,用户还可跟踪他可能想使用的项目。在本章中,我们将编写一个程序,它自动下载GitHub上星级最高的Python项目的信息,并对这些信息进行可视化。

17.1.2 使用 API 调用请求数据

GitHub的API让你能够通过API调用来请求各种信息。要知道API调用是什么样的,请在浏览器的地址栏中输入如下地址并按回车键:

https://api.github.com/search/repositories?q=language:python&sort=stars

这个调用返回GitHub当前托管了多少个Python项目,还有有关最受欢迎的Python仓库的信息。下面来仔细研究这个调用。第一部分( https://api.github.com/ )将请求发送到GitHub网站中响应API调用的部分;接下来的一部分( search/repositories )让API搜索GitHub上的所有仓库。

repositories 后面的问号指出我们要传递一个实参。 q 表示查询,而等号让我们能够开始指定查询( q= )。通过使用 language:python ,我们指出只想获取主要语言为Python的仓库的信息。最后一部分( &sort=stars )指定将项目按其获得的星级进行排序。

Python基础(四)_第16张图片

从第二行输出可知,编写本书时, GitHub总共有3874583个Python项目。“incomplete_results"的值为 false ,据此我们知道请求是成功的(它并非不完整的)。倘若GitHub无法全面处理该API,它返回的这个值将为 true 。接下来的列表中显示了返回的"items” ,其中包含GitHub上最受欢迎的Python项目的详细信息。

17.1.3 安装 requests

requests包让Python程序能够轻松地向网站请求信,息以及检查返回的响应。要安装requests,请执行类似于下面的命令:
$ pip install --user requests

17.1.4 处理 API 响应

来编写一个程序,它执行API调用并处理结果,找出GitHub上星级最高的Python项目

import requests

    # 执行API调用并存储响应
url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
r = requests.get(url) # 使用requests执行调用,调用get将URL传递
print("Status code:", r.status_code) # 属性status_code告诉请求是否成功了是的话200
# Status code: 200

    # 将API响应存储在一个变量中,API返回JSON格式的信息
response_dict = r.json() # 使用json将json格式转换为字典
    # 处理结果
print(response_dict.keys()) # dict_keys(['total_count', 'incomplete_results', 'items'])

17.1.5 处理响应字典

将API调用返回的信息存储到字典中后,就可以处理这个字典中的数据了。下面来生成一些概述这些信息的输出。这是一种不错的方式,可确认收到了期望的信息,进而可以开始研究感兴趣的信息:

import requests

url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
r = requests.get(url) # 使用requests执行调用,调用get将URL传递
print("Status code:", r.status_code) # 属性status_code告诉请求是否成功了是的话200

response_dict = r.json()
print("Total repositories:", response_dict['total_count']) # 3847989

    # 探索有关仓库的信息
repo_dicts = response_dict['items']
print("Repositories returned:", len(repo_dicts)) # 30

    # 研究第一个仓库
repo_dict = repo_dicts[0]
print("\nKeys:", len(repo_dict)) # 第一个包含74个键
print("\nSelected information about first repository:")
print('Name:', repo_dict['name'])
print('Owner:', repo_dict['owner']['login'])
print('Stars:', repo_dict['stargazers_count'])
print('Repository:', repo_dict['html_url'])
print('Created:', repo_dict['created_at'])
print('Updated:', repo_dict['updated_at'])
print('Description:', repo_dict['description'])
'''
从输出可知:
    项目名称:awesome-python
    项目所有者:vinta
    星评级:68296
    项目在GitHub仓库的URL: https://github.com/vinta/awesome-python
    项目创建时间:2014-06-27T21:00:06Z
    最近更新时间:2019-05-13T05:45:00Z
    仓库描述:A curated list of awesome Python frameworks, libraries, software and resources
'''

for key in sorted(repo_dict.keys()):
    print(key)

17.1.6 概述最受欢迎的仓库

对这些数据进行可视化时,我们需要涵盖多个仓库。下面就来编写一个循环,打印API调用返回的每个仓库的特定信息,以便能够在可视化中包含所有这些信息:

--snip--
print("\nSelected information about each repository:")
for repo_dict in repo_dicts: # 30个仓库
    print('\nName:', repo_dict['name']) # 项目名称
    print('Owner:', repo_dict['owner']['login']) # 所有者
    print('Stars:', repo_dict['stargazers_count']) # 星级
    print('Repository:', repo_dict['html_url']) # url
    print('Description:', repo_dict['description']) # 描述

17.1.7 监视 API 的速率限制

大多数API都存在速率限制,即你在特定时间内可执行的请求数存在限制。要获悉你是否接近了GitHub的限制,请在浏览器中输入https://api.github.com/rate_limit

很多API都要求你注册获得API密钥后才能执行API调用。编写本书时,GitHub没有这样
的要求,但获得API密钥后,配额将高得多。

17.2 使用 Pygal 可视化仓库

有了一些有趣的数据后,我们来进行可视化,呈现GitHub上Python项目的受欢迎程度。我们将创建一个交互式条形图:条形的高度表示项目获得了多少颗星。

import requests
import pygal # 导入pygal及样式
from pygal.style import LightColorizedStyle as LCS, LightenStyle as LS

url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
r = requests.get(url)
print("Status code:", r.status_code)

response_dict = r.json()
print("Total repositories:", response_dict['total_count']) # 3790192

repo_dicts = response_dict['items']

names, stars = [], [] # 创建两个空列表储存项目名和星级
for repo_dict in repo_dicts:
    names.append(repo_dict['name'])
    stars.append(repo_dict['stargazers_count'])

    # 可视化
my_style = LS('#333366', base_style=LCS) # 定义样式,使用LightColorizedStyle
chart = pygal.Bar(style=my_style, x_label_rotation=45, show_legend=False) # 45°,隐藏图例
chart.title = 'Most-Starred Python Projects on GitHub'
chart.x_labels = names

chart.add('', stars) # 不需要标签
chart.render_to_file('python_repos.svg')

Python基础(四)_第17张图片

17.2.1 改进 Pygal 图表

进行多个方面的定制,因此先来稍微调整代码的结构,创建一个配置对象,在其中包含要传递给Bar()的所有定制

--snip--

my_config = pygal.Config() # 定制外观
my_config.x_label_rotation = 45
my_config.show_legend = False
my_config.title_font_size = 24
my_config.label_font_size = 14
my_config.major_label_font_size = 18
my_config.truncate_label = 15
my_config.show_y_guides = False
my_config.width = 1000
chart = pygal.Bar(my_config, style=my_style) # 创建bar实例

--snip--

17.2.2 添加自定义工具提示

在Pygal中,将鼠标指向条形将显示它表示的信息,这通常称为工具提示创建一个自定义工具提示,以同时显示项目的描述

import pygal
from pygal.style import LightColorizedStyle as LCS, LightenStyle as LS

my_style = LS('#333366', base_style=LCS)
chart = pygal.Bar(style=my_style, x_label_rotation=45, show_legend=False)
chart.title = 'Python Projects'
chart.x_labels = ['httpie', 'django', 'flask'] # x标签

plot_dicts = [
    {'value': 16101, 'label': 'Description of httpie.'},
    {'value': 15028, 'label': 'Description of django.'},
    {'value': 14798, 'label': 'Description of flask.'},
]

chart.add('', plot_dicts) # 方法 add() 接受一个字符串和一个列表
chart.render_to_file('bar_descriptions.svg')

17.2.3 根据数据绘图

--snip--

names, plot_dicts = [], []
for repo_dict in repo_dicts:
    names.append(repo_dict['name'])
    
    plot_dict = {
        'value': repo_dict['stargazers_count'],
        'label': repo_dict['description'],
        }
    plot_dicts.append(plot_dict)
    
chart.add('', plot_dicts)

--snip--

17.2.4 在图表中添加可单击的链接:xlink

--snip--

plot_dict = {
    'value': repo_dict['stargazers_count'],
    'label': repo_dict['description'],
    'xlink': repo_dict['html_url'],
    }
    
plot_dicts.append(plot_dict)

--snip--

17.3 Hacker News API

为探索如何使用其他网站的API调用,我们来看看Hacker News ( http://news.ycombinator. com/)在Hacker News网站,用户分享编程和技术方面的文章,并就这些文章展开积极的讨论HackerNews的API让你能够访问有关该网站所有文章和评论的信息,且不要求你通过注册获得密钥。

https://hacker-news.firebaseio.com/v0/item/9884165.json

import requests
from operator import itemgetter

    # 执行API调用并存储响应
url = 'https://hacker-news.firebaseio.com/v0/topstories.json'
r = requests.get(url)
print("Status code:", r.status_code) # 打印响应状态

    # 处理有关每篇文章的信息
submission_ids = r.json() # 转为Python列表
submission_dicts = [] # 空列表,储存前面的字典

for submission_id in submission_ids[:30]: # 遍历30篇文章的ID

    # 对于每篇文章,都执行一个API调用
    url = ('https://hacker-news.firebaseio.com/v0/item/' +
           str(submission_id) + '.json')
    submission_r = requests.get(url)
    print(submission_r.status_code) # 打印每次请求状态
    response_dict = submission_r.json() # Python列表

    submission_dict = {
        'title': response_dict['title'],
        'link': 'http://news.ycombinator.com/item?id=' + str(submission_id),
        'comments': response_dict.get('descendants', 0)
    }
    submission_dicts.append(submission_dict)

submission_dicts = sorted(submission_dicts, key=itemgetter('comments'),
                          reverse=True)

for submission_dict in submission_dicts:
    print("\nTitle:", submission_dict['title'])
    print("Discussion link:", submission_dict['link'])
    print("Comments:", submission_dict['comments'])

你可能感兴趣的:(Python基础(四))