第三部分 数据可视化
ch15 生成数据
基本目标: 统计数据, 然后以统计图的形式将数据呈现出来.
这里介绍 Matplotlib
, 一个集合了数据可视化工具的包 (就是绘制各种统计图).
jk: 总感觉不如直接看官网. 这个指南只适合入门. 一个感知而已. 细节太少.
jk: 不过符合本书的定位.
15.1 安装 Matplotlib
安装命令:
python -m pip install --user matplotlib
如果在 linux 等系统上, 使用
python3
代替python
.
关于 Matplotlib
可以绘制什么图形, 参考官网.
15.2 绘制简单的折线图
目标: 使用平方数序列来绘制折线图
步骤:
- 安装, 导入
matplotlib
中的pyplot
. - 准备数据 (列表)
- 调用
pyplot
的subplots()
方法来获得 图形 与 绘图 的引用. - 调用绘图的
plot(数据)
方法. - 调用
show()
方法展示.
逻辑上, 图形是整个图, 可以简单理解为容器. 而绘图可以看成是一个具体的图, 放在容器中.
示例代码:
import matplotlib.pyplot as plt
datas = [v ** 2 for v in range(1, 10)]
fig, ax = plt.subplots()
ax.plot(datas)
plt.show()
下面看看如何配置显示.
15.2.1 修改标签文字和线条粗细
# 修改折线粗细
ax.plot(datas, linewidth=3)
# 设置图题, 与坐标上的标签
ax.set_title("平方数", fontsize=24)
ax.set_xlabel("值", fontsize=14)
ax.set_ylabel("序列", fontsize=14)
注意: 中文如果无法正常显示, 有两个方法处理:
- 设置
Matplotlib
使用中文字体. - 使用字体库, 需要安装并导入一个支持中文字体的字体库.
方案1
plt.rcParams['font.sans-serif'] = ['SimSun'] # 指定默认字体为宋体
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
方案2
from matplotlib.font_manager import FontProperties
font = FontProperties(fname="字体文件的路径") # 替换为你自己中文字体文件的路径
plt.title('数的平方', fontproperties=font)
15.2.2 矫正绘图
考虑数据源, 与绘制图, 坐标是错位的.
plot()
参数为一个数值列表时, 默认会认定第 一个 数据项的 x 坐标为 0.
要解决这个问题, 可以给 plot()
出入另一个参数, 被视为 x 坐标向量.
ax.plot(x向量, y向量, linewidth=3)
例如:
x_vector = list(range(1, 6))
y_vector = [v ** 2 for v in range(1, 6)]
fig, ax = plt.subplots()
ax.plot(x_vector, y_vector, linewidth=3)
显示结果:
要修改配置除了使用 ax
的方法外, 还可以在调用 plot()
的时候作为参数传入.
jk: 细节在于有哪些属性可以用, 用来干什么.
15.2.3 使用内置样式
Matplotlib
内置了很多样式, 包括背景色, 网格线, 线条粗细, 字体, 字号等. 执行下面命令可以查看可用内置样式:
import matplotlib.pyplot as plt
for v in plt.style.available:
print(v)
输出:
Solarize_Light2
_classic_test_patch
_mpl-gallery
_mpl-gallery-nogrid
bmh
classic
dark_background
fast
fivethirtyeight
ggplot
grayscale
seaborn-v0_8
seaborn-v0_8-bright
seaborn-v0_8-colorblind
seaborn-v0_8-dark
seaborn-v0_8-dark-palette
seaborn-v0_8-darkgrid
seaborn-v0_8-deep
seaborn-v0_8-muted
seaborn-v0_8-notebook
seaborn-v0_8-paper
seaborn-v0_8-pastel
seaborn-v0_8-poster
seaborn-v0_8-talk
seaborn-v0_8-ticks
seaborn-v0_8-white
seaborn-v0_8-whitegrid
tableau-colorblind10
要使用这些样式, 可以在执行 subplot()
之前执行:
plt.style.use('内置样式名')
15.2.4 使用 scatter() 绘制散点图并设置样式
plot()
是绘制折线图, 使用 scatter()
绘制散点图.
ax.scatter(x_vector, y_vector, ...)
这里的参数可以是向量, 也可以是单个坐标值.
import matplotlib.pyplot as plt
x_vector = list(range(1, 6))
y_vector = [v ** 2 for v in range(1, 6)]
plt.style.use('ggplot')
fig, ax = plt.subplots()
ax.scatter(x_vector, y_vector, s=200)
ax.tick_params(labelsize=14)
plt.show()
同样可以设置标题, 坐标轴标签, 以及刻度标记样式.
15.2.5 使用 scatter() 绘制一些列点 (略)
15.2.4 已说明了该方法, 就是使用向量作为参数.
15.2.6 自动计算 (略)
前面已经介绍了该方法, 就是不用一个个坐标的输入, 使用计算的方法获得 y 向量.
这里介绍一个方法, 可以设置 x, y 轴的取值范围
ax.axis([0, 1100, 0, 1_100_000])
15.2.7 定制刻度标记
默认会使用科学计数法, 如果修改可以使用: ax.ticklabel_format(style='plain')
15.2.8 定制颜色
颜色可以使用名字, 或 rgb
色 (用 [0, 1]
中的数字来映射).
ax.scatter(x_values, y_values, color='red', s=10)
# 或者
ax.scatter(x_values, y_values, color=(0, 0.8, 0), s=10)
15.2.9 使用颜色映射
简单的说, 用颜色来描述下一维度的信息, 让数据用颜色值来呈现另一个信息.
这里演示将较小值用浅色, 较大值用深色的表示.
ax.scatter(x_values, y_values, c=y_values, cmap=plt.cm.Blues, s=10)
这里的 c
就类似与 color
, cmap
可以理解为 color map
可用颜色映射可以参考文档.
15.2.10 自动保存绘图
不使用 show()
方法, 而使用:
plt.savefig('squares_plot.png', bbox_inches='tight')
即可保存到本地, 除此之外, 可以联合使用 Path
, 可以保存在任意位置.
参数 bbox_inches='tight'
, 表示裁剪空白.
15.3 随机游走
简单的说就是生成随机数模拟布朗运动.
15.3.1 创建 RandomWalk 类
创建一个类, 来确定行走方向. 提供三个属性:
- 随机游走次数
x
坐标y
坐标
整个类就两个方法, 一个初始化的构造函数. 另一个是生成随机数据的 fillwalk
.
基本思路是, 根据传入的次数, 循环生成坐标 x, y. 生成的方式是, 随机生成一个方向, 然后随机生成一个步长 ([0, 4]
), 然后加入到属性中. 然后利用绘制散点图的方式将其绘制出来.
注意, 这个类是用来生成数据的, 绘制不在类中.
这里引用的另一个方法:
ax.set_aspect('equal')
表示设置两个轴线的刻度比率相等.
jk: 这个代码可以自行写一写, 代码还是具有一定综合性的.
然后介绍了绘制多个图的方法. 基本思路:
写一个死循环, 和一个用户输入的阻塞, 在用户输入 q 的时候退出, 否则再次绘制.
while True:
show() # 绘图
key = input('输入 q 退出')
if key == 'q':
break
然后介绍了添加样式, 使得更为好看. 使用颜色映射来展示. 这样可以看出行走的路径. 越往后颜色越深.
然后突出显示起点和终点 (使用 (0, 0)
和 (x_vector[-1], y_vector[-1])
).
最后隐藏坐标轴
ax.set_xaxis().set_visable(False)
ax.set_yaxis().set_visable(False)
调整屏幕尺寸
fig, ax = plt.subplots(figsize=(15, 9))
单位为英寸. 也可以传入 dpi
来设置分辨率
fig, ax = plt.subplots(figsize=(15, 9), dpi=128)
15.4 使用 Plotly 模拟掷骰子
使用 plotly 可以生成交互式图形. 可以在浏览器中呈现.
作者首先介绍 plotly express, 然后在配置属性.
plotly express 是 plotly 的子集, 旨在少写代码.
本节会模拟两个骰子投掷的点数, 然后统计绘图.
15.4.1 安装 plotly
python -m pip install --user plotly
python -m pip install --user pandas
plotly express 是依赖于 pandas 的, 所以还需要安装 pandas.
pandas 是一个高效的数据处理库.
15.4.2 创建 Die 类
该类用于描述一个骰子, 有 6 个面, 投掷依次可以生成 1, 6 的一个随机数.
from random import randint
class Die:
def __init__(self, num_sides = 6):
"""骰子默认为 6 个面"""
self.num_sides = num_sides
def roll(self):
"""返回一个属于 [1, 6] 的随机数"""
return randint(1, self.num_sides)
然后作者对代码进行了解释.
15.4.3 掷骰子
实例化, 然后调用 roll()
方法
from die import Die
die = Die()
results = []
for roll_num in range(100):
result = die.roll()
results.append(result)
然后解释了代码.
15.4.4 分析结果
就是对数据进行统计. 统计每一个数字出现的次数, 使用 列表.count(数字)
方法.
最终会得到一个形如 [155, 167, 168, 170, 159, 181]
的数据.
15.4.5 绘制直方图
使用 plotly.express
来绘制直方图:
- 导入
plotly.express
模块, 命名为px
- 调用其
bar()
方法, 传入数据: 分量数据, 统计数据 (逻辑上就是 x 与 y 向量) - 调用
show()
方法绘图
import plotly.express as px
x = [1, 2, 3, 4]
y = [123, 234, 213, 10]
fig = px.bar(x = x, y = y)
fig.show()
运行后会自动打开浏览器
express 的意图在于, 先看看是否复合要求, 再深入其他配置. 所以显示的相对比较捡漏.
对于可用的图可以参考文档.
15.4.6 定制绘图
确定统计图类型后, 再进行配置标签, 样式等外观.
定制也有两个方法:
- 调用
bar()
这类绘图函数时传入配置参数 - 调用绘图函数后, 在显示 (
show()
) 前, 调用配置方法进行配置.
title = '统计显示的结果'
labels = { 'x': '结果', 'y': '频率' }
fig = px.bar(x=..., y=..., title=title, labels=labels)
fig.show()
然后作者对代码进行了一定解释.
15.4.7 同时投两个骰子
基本逻辑是创建两个 Die
对象, 将 roll()
的结果加起来, 存储, 再统计.
这里有几个扩展
- 默认情况下, x 轴不会为每一个条形图添加
label
, 使用fig.update_layout(xaxis_dtick = 1)
进行配置. - 然后又模拟了不同面的骰子进行投掷 (通过构造函数传入面数), 从而抽象了骰子的意义, 可以将其应用到任意概率均衡的选择游戏中. 并利用这个程序可以清晰的模拟出不同频次, 不同点数的结果.
- 最后将统计图呈现出来, 也可以使用
fig.write_html('文件名')
来保存html
文件.
从统计的结果来看, 也是满足正态分布特征的.
ch16 下载数据
对网上下载的数据进行可视化处理, 解析两种格式, 一个 csv
, 一个 json
.
16.1 csv
文件格式
首先解释了 csv
格式的样式 (用逗号分隔数据).
16.1.1 解析 csv
文件头
标准库中的 csv
模块提供解析 csv
功能.
csv
格式的文件第一行为表格头, 从第二行开始才是数据.
基本逻辑:
- 导入
path
中的Path()
函数, 以及csv
模块. - 利用
Path()
函数返回的对象调用read_text()
方法, 读取文件文本. - 利用文本的
splitlines()
方法获得多行数据. - 利用
csv.reader(多行数据)
来解析 csv 数据, 获得迭代器. - 利用内置的
next()
函数来遍历迭代器. 获取每一行数据.
next()
方法是内置方法. 用法有二:
next(iterator)
迭代返回. 逻辑与 C# 中的next()
方法一样. 遇到结尾会抛出StopIteration
异常.next(iterator, default)
, 迭代返回, 在结束时返回default
.
因此解析 csv 代码可以写成:
from pathlib import Path
import csv
lines = Path('./name.csv').read_text().splitlines()
rows = csv.reader(lines)
while True:
res = next(rows, False)
if res == False:
print('遍历结束')
break
print(res)
然后作者介绍了 enumerate()
函数, 对列表调用该函数, 可以返回索引+项
for index, column_header in enumerate(header_row):
print(index, column_header)
单纯的遍历 列表, 仅会返回项, 不会返回列表索引.
然后将数据解析提取出来, 这里对于数据需要转换的会使用到 int()
等类型转换函数.
https://docs.python.org/3/library/functions.html#int
细节还是需要看官方文档.
然后利用 matplotlib
绘制折线图.
以上内容与之前介绍的绘图方式逻辑一样 (细节略).
然后作者介绍 datetime
模块, 来格式化日期.
datetime
是内置模块, 作用与JS
中dayjs
一样, 用来格式化日期.文档: https://docs.python.org/3/library/functions.html#int
from datetime import datetime
date = datetime.strptime('2024-01-25', '%Y-%m-%d')
print(date)
这里使用了
strptime
函数, 即 string parse to time, 还有一个函数strftime
, 即 string from time. 简单这么理解.这里
%Y
4 位年份,%m
2 位月份,%d
从 1 开始的日期天数.详细用法可以参考: https://docs.python.org/zh-cn/3/library/datetime.html#strftime-and-strptime-behavior
然后构建两个向量:
- x 轴使用日期时间作为值的向量
- y 轴记录对应时间气温的数据向量
然后绘制折线图
然后作者又使用了一个更多数据的文件, 绘制了一年的气温变化数据.
最后作者在图中绘制了两组数据, 一个最高温统计数据, 一个最低温统计数据.
实际上就是在一个图中绘制两条折线. 绘制使用的是
ax
变量fig, ax = plt.subplots()
这里只需要使用
ax.plot(...)
绘制两次即可. 每调用依次就绘制一条折线.即可以在 一个图中绘制多个折线.
16.1.9 给图中区域着色
ax.plot()
方法可以带有参数 color
用来给绘制的折线着色.
ax.fill_between()
方法提供一组 x 向量, 两组 y 向量, 然后配置颜色, 可以给两组折线间的区域着色.
ax.fill_between(datas, heights, lows, facecolor='blue', alpha=0.1)
其中
datas
是 x 向量,lows
和heights
为两组 y 向量.