Python数据可视化

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

matplotlib是一个数学绘图库,利用这个工具能够厚制作简单的图表。

Pygal是专注于生成适合在数字设备上显示的图表,通过使用 Pygal 可在用户图表交互时突出元素以及调整其大小,还可以轻松地调整整个图表的尺寸,使其适合在微型智能手表或者矩形显示器上显示。

安装matplotlib、Pygal

window 环境下安装 matplotlib

  1. 先安装Visual Studio,打开https://dev.windows.com/,点击Downloads,再查找Visual Studio Community下载运行并安装
  2. 访问https:pypi.python.org/pypi/matplotlib,找到与你使用的Python版本匹配的扩展名为.whl文件,下载之
  3. 将下载的.whl文件复制到你的项目文件夹,在该文件夹下打开命令窗口(ctrl+鼠标右键,选择在此处打开命令窗口
  4. cd python_work python -m pip install --user matplotlib-1.4.3-cp35-none-win32.whl
  5. 安装完成后打开一个命令窗口,进入 python 环境,输入:import matplotlib,如果没有报错则安装成功

windows 环境下安装 Pygal

python -m pip install --user pygal==2.4

绘制折线图

绘制一个平方数序列1、4、9、16、25的图表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 导入模块 pyplot
import matplotlib.pyplot as plt

# 输入的数值
input_value = [1, 2, 3, 4, 5]
# 对应的输入数值的平方
squares = [1, 4, 9, 16, 25]
# plot 函数根据给定的参数去绘制图形,linewidth=5 表示线的粗细
plt.plot(input_value, 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()
  • 结果
  • TODO: 上传图片
  • plot(input_value, squares, linewidth=5)函数根据给定的参数去绘制图形,参数1:输入的内容,参数2:输入的内容对应的输出内容,参数3:线的粗细

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

绘制一个平方数序列为1~1000以内数平方根的散点图

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
import matplotlib.pyplot as plt

# 1~1000 的数值
x_values = list(range(1,1000))
# 对应值的结果
y_values = [x**2 for x in x_values]

# s 表示线的粗细, edgecolor='none'表示删除数据点的轮廓, c = 'red' 修改线条颜色
# plt.scatter(x_values, y_values, s = 40)
# plt.scatter(x_values, y_values, edgecolor='none', s = 40)
# plt.scatter(x_values, y_values, c = 'red', edgecolor='none', s = 40)

# 颜色值还可以用RGB表示,值越接近0,指定的颜色越深,越接近1指定的颜色越浅
# plt.scatter(x_values, y_values, c = (0, 0, 0.8), edgecolor='none', s = 40)

# 将参数c设置成y值列表,用参数cmap告诉pyplot使用哪个颜色映射
# c = y_values, cmap = plt.cm.Blues 将y值较小的点显示为浅蓝色,将 y 值较大的设置为深蓝色
plt.scatter(x_values, y_values, c = y_values, cmap = plt.cm.Blues, edgecolor='none', s = 40)

# 设置图表标签,坐标轴标签
plt.title("Square Numbers", fontsize = 24)
plt.xlabel("Value", fontsize = 14)
plt.ylabel("Square on Value ", fontsize = 14)

# 设置标记刻度的大小,axis = 'both',x轴和y轴的刻度为粗体
plt.tick_params(axis = 'both', which = 'major', labelsize = 14)

# 设置每个坐标轴的取值范围,x轴的范围为(0~1100),y轴的范围为(0, 1100000)
plt.axis([0, 1100, 0, 1100000])

# 展示
# plt.show()

# 自动保存图片,参数1:文件名(下面这么写是保存在当前文件的目录下),参数2:将图表多余的空白区域裁剪掉
plt.savefig('squares_plot.png', bbox_inches = 'tight')
  • 结果
  • TODO: 上传图片
  • scatter(x_values, y_values, c = y_values, cmap = plt.cm.Blues, edgecolor='none', s = 40),参数1:输入值,参数2:输出值;参数 3 和参数 4 :将参数 3 的值较小的点显示为浅蓝色,将参数 3 的值较大的设置为深蓝色;参数5:none 表示删除数据点的轮廓,参数6:线的粗细,默认为20。
  • tick_params(axis = 'both', which = 'major', labelsize = 14),参数1:表示 x 轴 和 y 轴设置为粗体,参数2:值为 ‘major’、’minor’、’both’,分别代表设置主刻度线、副刻度线以及同时设置,默认值为’major’,参数3:刻度线标签的字体大小
  • axis([0, 1100, 0, 1100000]),参数1、2:X 轴的坐标范围,参数3、4:Y 轴的坐标范围
  • savefig('squares_plot.png', bbox_inches = 'tight'),参数1:保存的路径,参数2:将图表多余的空白区域裁剪掉

随机漫步

每次行走路线完全是随机的,没有明确的方向,结果是由一行一列交叉点随机决策决定的。

主要代码有 random_walk.py 和 rw_visual.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
# random_walk.py 代码如下
from random import choice

class RandomWalk():
"""一个生成随机漫步数据的类"""
def __init__(self, num_points = 5000):
"""初始化随机漫步的属性"""
self.num_points = num_points

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

def fill_walk(self):
"""计算漫步包含的所有点"""

# 不断漫步,直到列表的达到指定的长度
while len(self.x_values) < self.num_points:
# choice([1,-1]):表示要么向右走1,要么向左走-1
x_direction = choice([1, -1])
# choice([1,-1]:随机选择一个0~4之间的整数(包含0),告诉Python沿指定的方向走多远
x_distance = choice([0, 1, 2, 3, 4])
# 移动的方向 * 距离,以确定沿 x 轴和 y 轴移动的距离,x_step为正表示右移,为负表示左移,为0表示垂直移动
x_step = x_direction * x_distance
# y 轴同理 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[-1] 最后一个值 + x_step 作为下一个 x 值
next_x = self.x_values[-1] + x_step
next_y = self.y_values[-1] + y_step

self.x_values.append(next_x)
self.y_values.append(next_y)


# rw_visual.py 的代码如下
import matplotlib.pyplot as plt
from random_walk import RandomWalk

# 只要程序属于活动状态,就不断的模拟随机漫步
while True:
# 创建一个RandomWalk实例,并将其包含的点都绘制出来
# 增加点数,运行时间也会变长
# rw = RandomWalk(50000)
rw = RandomWalk()
# 计算漫步包含的所有点
rw.fill_walk()

# 设置窗口的尺寸
# plt.figure(figsize = (10, 6))

# 传递屏幕分辨率
plt.figure(dpi = 128, figsize = (10, 6))

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 = 1)

# 突出起点和终点
plt.scatter(0, 0, c = 'green', edgecolor='none', s = 100)
plt.scatter(rw.x_values[-1], rw.y_values[-1], c = 'red', edgecolor='none', s = 100)

# 隐藏坐标轴
plt.axes().get_xaxis().set_visible(False)
plt.axes().get_yaxis().set_visible(False)


plt.show()

# plt.savefig('rw_visual.png', bbox_inches = 'tight')

# 关闭matplotlib时会提示是否要再模拟一次,输入y可以再运行一次,输入n则退出
keep_running = input("Make another walk ? (y/n): ")
if keep_running == 'n':
break
  • 隐藏坐标轴:x 轴:plt.axes().get_xaxis().set_visible(False),y 轴:plt.axes().get_yaxis().set_visible(False)
  • 设置分辨率:plt.figure(dpi = 128, figsize = (10, 6))

同时掷两个面数相同的骰子,掷1000次骰子每次得到的值的概率

用直方图展示掷 2 个骰子出现点数的值的概率

  1. 创建骰子类
  2. 循环得到模拟掷 1000 次骰子各个值的数量
  3. 用 Pygal 可视化展示直方图
  • 创建骰子对象
1
2
3
4
5
6
7
8
9
10
11
12
1. 创建一个骰子类,用于模拟掷出去的骰子点数
from random import randint

class Die():
"""表示一个骰子的类"""
def __init__(self, num_sides = 6):
"""骰子默认为6面"""
self.num_sides = num_sides

def roll(self):
"""返回一个位于1和骰子面数之间的随机值"""
return randint(1, self.num_sides)
  • 分析数据并展示结果
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
import pygal
from die import Die

# 创建两个D6骰子
die_1 = Die()
die_2 = Die()

# 掷几次骰子,并将结果存储在一个列表中
results = []
for roll_num in range(1000):
result = die_1.roll() + die_2.roll()
results.append(result)

# 分析结果,得到掷一次(2个)骰子的和,存在集合中
frequencies = []
max_result = die_1.num_sides + die_2.num_sides
for value in range(2, max_result + 1):
frequency = results.count(value)
frequencies.append(frequency)

# 对结果进行可视化
hist = pygal.Bar()

hist.title = "Results of rolling on D6 1000 times."
hist.x_labels = ['2', '3', '4', '5', '6', '7', '8', '10', '11', '12']
hist.x_title = "Results"
hist.y_title = "Frequency of Result"

# 颜色块对应的区域表示的含义
hist.add('D6 + D6', frequencies)
# 将图表渲染为一个SVG文件,这种文件的扩展名必须为svg
hist.render_to_file('die_visual.svg')

print(frequencies)
  • pygal.Bar():将结果可视化
  • hist.render_to_file('die_visual.svg'):将图表渲染为一个 svg 文件且文件扩展名必须为 svg

同时掷两个面数不同的骰子

  • 创建的骰子类的点数不同
  • x 轴的范围不一样

提取CSV文件的数据,让数据可视化

CSV 文件的内容是一系列以逗号分割的值,测试的文件名为death_valley_2014.csv可在该项目下找到

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
import csv
from datetime import datetime
from matplotlib import pyplot as plt

# 从文件中获取最高气温和最低气温
filename = 'death_valley_2014.csv'
with open(filename) as f:
reader = csv.reader(f)

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 Exception as e:
print(current_date, 'missing data')
else:
highs.append(high)
dates.append(current_date)
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 temperature - 2014\nDeath Valley, CA", 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()
  • 读取 CSV 文件:csv.reader(f)
  • 时间格式化:datetime.strptime(row[0], "%Y-%m-%d")
  • 两个插值之间绘制颜色:plt.fill_between(dates, highs, lows, facecolor = 'blue', alpha = 0.1)
  • 绘制 X 轴的日期为倾斜:fig.autofmt_xdate()

制作世界人口地图

在世界地图上显示各个国家 2010 年的人口数,通过不同颜色来区别,用国别码表示国家,数字表示人口数量。

数据可以去Open Knowledge寻找,这里用到的文件名是population.json,可在项目地址中找到

1
2
3
4
5
6
7
8
9
10
11
# 获取国别码
# 通过 pygal.i18n 模块导入,字典 COUNITRIES 中包含了键和值分别为国别码和国家名
from pygal.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
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
# 获取国别码对应国家的人口数
import json
import pygal

# 高亮主题,用于更好的区别各个国家的人口数,LightColorizedStyle作为基本样式,RotateStyle用于设置颜色
from pygal.style import LightColorizedStyle as LCS, RotateStyle as RS
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 < 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_style = RS('#336699', base_style=LCS)

# 绘制世界地图
wm = pygal.Worldmap(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)

# 输出为svg为文件
wm.render_to_file('world_population.svg')
  • 读取 json 数据 :json.load(f),参数为文件名
  • 绘制世界地图:pygal.Worldmap(style=wm_style)

获取Web应用程序接口(API),让数据可视化

使用GitHub的API来请求有关该网站中 Python 项目的信息,然后使用 Pygal 生成交互可视化的图形界面,用以展示这些 Python 项目受欢迎的程度

  1. 获取 API
  2. 安装 requests
  3. 处理返回的结果,分析出我们需要的数据项
  4. Pygal 根据数据绘图展示
  • 获取API

去GitHub主页的底部找到API,之后能不能找到你要的内容就看英文水平了(可以安装谷歌翻译插件,一键翻译…),这里用到的API地址为:https://api.github.com/search/repositories?q=language:python&sort=stars

  • 安装 requests

pip install --user requests

  • 处理返回的结果,分析出我们需要的数据项

再安装一个json数据查看的插件,找出你需要的字段,例如这里需要拿到:Name,Owner,Stars,Repository,Description,分别对应的是,仓库的名称、作者、星数、链接、描述

  • Pygal 根据数据绘图展示,代码如下
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
import requests
import pygal
from pygal.style import LightColorizedStyle as LCS, LightenStyle as LS

# 执行API调用,并存储响应
url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
r = requests.get(url)

# 200 表示访问成功
print("Status code:", r.status_code)

# 将API响应存储在一个变量中
response_dict = r.json()
print("Total repositores:", response_dict['total_count'])

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

# 横纵坐标值
names, stars = [], []

# 研究第一个仓库
repo_dict = repo_dicts[0]
print("\nSelected information about each repository:")

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'],
'xlink': repo_dict['html_url']
}

# 得到纵坐标
plot_dicts.append(plot_dict)

# 设置颜色值,基本样式
my_style = LS('#333366', base_style = LCS)

my_config = pygal.Config()

# 创建Bar实例需要的实参,这里通过关键字传递
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

# 将较长的项目名缩短为15个字符
my_config.truncate_label = 15
# 隐藏图表中的隐藏线
my_config.show_y_guides = False
# 设置图表的自定义宽度
my_config.width = 1000

chart = pygal.Bar(my_config, style = my_style)

# chart = pygal.Bar(style = my_style, x_label_rotation = 45, show_legend = False)
chart.title = "GitHub 上点赞最多的仓库"
chart.x_labels = names

chart.add('', plot_dicts)
chart.render_to_file('python_repos.svg')
  • 配置 Pygal 的数据:my_config = pygal.Config()
  • 使用配置的参数展示直方图:chart = pygal.Bar(my_config, style = my_style)
  • 获取网络数据:requests.get(url)
  • 可以用字典来存储自定义提示的内容
小额支持我写出更好的文章~